diff --git a/App.tsx b/App.tsx
index 5ebe0dde..122a881b 100644
--- a/App.tsx
+++ b/App.tsx
@@ -19,7 +19,13 @@ import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader';
import { toastConfigs, ToastContainer } from './RN-UI-LIB/src/components/toast';
import * as Sentry from '@sentry/browser';
-import { APM_APP_NAME, APM_BASE_URL, ENV, SENTRY_DSN } from './src/constants/config';
+import {
+ APM_APP_NAME,
+ APM_BASE_URL,
+ ENV,
+ MS_CLARITY_PROJECT_ID,
+ SENTRY_DSN,
+} from './src/constants/config';
import { COLORS } from './RN-UI-LIB/src/styles/colors';
import codePush from 'react-native-code-push';
import AsyncStorage from '@react-native-async-storage/async-storage';
@@ -31,12 +37,16 @@ import ErrorBoundary from './src/common/ErrorBoundary';
import CodePush from 'react-native-code-push';
import { TDocumentObj } from './src/screens/caseDetails/interface';
import AuthRouter from './src/screens/auth/AuthRouter';
+import { initialize } from 'react-native-clarity';
Sentry.init({ dsn: SENTRY_DSN });
-if (ENV !== 'prod') {
- // mockApiServer();
+if (ENV === 'prod') {
+ if (MS_CLARITY_PROJECT_ID) {
+ initialize(MS_CLARITY_PROJECT_ID);
+ }
}
+
setJsErrorHandler();
LogBox.ignoreAllLogs();
diff --git a/config/dev/config.js b/config/dev/config.js
index 0b20b602..350ade2b 100644
--- a/config/dev/config.js
+++ b/config/dev/config.js
@@ -8,3 +8,4 @@ export const APM_APP_NAME = 'cosmos-app';
export const APM_BASE_URL = 'https://dev-longhorn-portal.np.navi-tech.in/apm-events';
export const GOOGLE_SSO_CLIENT_ID =
'60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com';
+export const MS_CLARITY_PROJECT_ID = '';
diff --git a/config/prod/config.js b/config/prod/config.js
index 8ef9052b..4cf9cadd 100644
--- a/config/prod/config.js
+++ b/config/prod/config.js
@@ -12,3 +12,4 @@ export const IS_DATA_SYNC_REQUIRED = true;
export const DATA_SYNC_TIME_INTERVAL = 2 * MINUTES_IN_AN_HOUR * MILLISECONDS_IN_A_MINUTE; // 2hr
export const GOOGLE_SSO_CLIENT_ID =
'136591056725-ev8db4hrlud2m23n0o03or3cmmp3a3cq.apps.googleusercontent.com';
+export const MS_CLARITY_PROJECT_ID = 'gobifvjiac';
diff --git a/config/qa/config.js b/config/qa/config.js
index 6fa05aeb..5df41c0d 100644
--- a/config/qa/config.js
+++ b/config/qa/config.js
@@ -12,3 +12,4 @@ export const IS_DATA_SYNC_REQUIRED = true;
export const DATA_SYNC_TIME_INTERVAL = 2 * MINUTES_IN_AN_HOUR * MILLISECONDS_IN_A_MINUTE; // 2hr
export const GOOGLE_SSO_CLIENT_ID =
'60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com';
+export const MS_CLARITY_PROJECT_ID = '';
diff --git a/package.json b/package.json
index 6a9606c2..c9d5313d 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@
"react-hook-form": "7.40.0",
"react-native": "0.70.6",
"react-native-call-log": "2.1.2",
+ "react-native-clarity": "0.0.3",
"react-native-code-push": "7.1.0",
"react-native-contacts": "7.0.5",
"react-native-date-picker": "4.2.10",
diff --git a/src/action/firebaseFallbackActions.ts b/src/action/firebaseFallbackActions.ts
new file mode 100644
index 00000000..6f246977
--- /dev/null
+++ b/src/action/firebaseFallbackActions.ts
@@ -0,0 +1,63 @@
+import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper';
+import { logError } from '../components/utlis/errorUtils';
+import { FilterResponse } from '../screens/allCases/interface';
+import { CaseDetail } from '../screens/caseDetails/interface';
+
+export enum SyncStatus {
+ SEND_CASES = 'SEND_CASES',
+ FETCH_CASES = 'FETCH_CASES',
+ SKIP = 'SKIP',
+}
+
+interface IFilterSync {
+ filterComponentList: FilterResponse[];
+}
+
+export interface ISyncedCases {
+ cases: CaseDetail[];
+ filters: IFilterSync;
+ deletedCaseIds: string[];
+ payloadCreatedAt: number;
+}
+
+interface ICases {
+ caseId: string;
+ caseViewCreatedAt?: number;
+}
+
+export interface ISyncCaseIdPayload {
+ agentId: string;
+ cases: ICases[];
+}
+
+export const getCasesSyncStatus = async (userReferenceId: string) => {
+ try {
+ const url = getApiUrl(ApiKeys.CASES_SYNC_STATUS, {}, { userReferenceId });
+ const response = await axiosInstance.get(url, { headers: { donotHandleError: true } });
+ return response?.data?.syncStatus;
+ } catch (err) {
+ logError(err as Error, 'Error getting sync status');
+ }
+};
+
+export const sendSyncCaseIds = async (payload: ISyncCaseIdPayload) => {
+ try {
+ const url = getApiUrl(ApiKeys.CASES_SEND_ID);
+ const response = await axiosInstance.post(url, payload, {
+ headers: { donotHandleError: true },
+ });
+ return response?.data;
+ } catch (err) {
+ logError(err as Error, 'Error sending case ids sync');
+ }
+};
+
+export const fetchCasesToSync = async (agentReferenceId: string) => {
+ try {
+ const url = getApiUrl(ApiKeys.FETCH_CASES, { agentReferenceId });
+ const response = await axiosInstance.get(url, { headers: { donotHandleError: true } });
+ return response?.data;
+ } catch (err) {
+ logError(err as Error, 'Error fetching cases to be synced');
+ }
+};
diff --git a/src/common/BlockerScreen.tsx b/src/common/BlockerScreen.tsx
index 24432dfe..3a50fc9e 100644
--- a/src/common/BlockerScreen.tsx
+++ b/src/common/BlockerScreen.tsx
@@ -23,6 +23,8 @@ const BlockerScreen = (props: IBlockerScreen) => {
const { isTimeSynced, isDeviceLocationEnabled } = useAppSelector(
(state) => state.foregroundService
);
+ const { isWifiOrCellularOn } = useAppSelector((state) => state.metadata);
+
const [showActionBtnLoader, setShowActionBtnLoader] = useState(false);
const dispatch = useAppDispatch();
@@ -110,6 +112,20 @@ const BlockerScreen = (props: IBlockerScreen) => {
);
}
+ if (!isWifiOrCellularOn) {
+ const { heading, instructions } = BLOCKER_SCREEN_DATA.DEVICE_WIFI_OR_CELLULAR_OFF;
+ return (
+
+ );
+ }
+
return <>{props.children}>;
};
diff --git a/src/common/Constants.ts b/src/common/Constants.ts
index b1439476..d02c4fb9 100644
--- a/src/common/Constants.ts
+++ b/src/common/Constants.ts
@@ -562,6 +562,13 @@ export const BLOCKER_SCREEN_DATA = {
`Please retry connecting using the button below, if it doesn't automatically detect.`,
],
},
+ DEVICE_WIFI_OR_CELLULAR_OFF: {
+ heading: `Please turn on your internet`,
+ instructions: [
+ 'Open the Settings app on your Android device.',
+ 'Check you wifi/cellular settings',
+ ],
+ },
};
export const SCREEN_ANIMATION_DURATION = 300;
diff --git a/src/common/TrackingComponent.tsx b/src/common/TrackingComponent.tsx
index 2aeb83e4..1bd766ac 100644
--- a/src/common/TrackingComponent.tsx
+++ b/src/common/TrackingComponent.tsx
@@ -13,11 +13,23 @@ import { useAppDispatch, useAppSelector } from '../hooks';
import { dataSyncService } from '../services/dataSync.service';
import { DATA_SYNC_TIME_INTERVAL, IS_DATA_SYNC_REQUIRED } from '../constants/config';
import useIsLocationEnabled from '../hooks/useIsLocationEnabled';
+import {
+ ISyncCaseIdPayload,
+ ISyncedCases,
+ SyncStatus,
+ fetchCasesToSync,
+ getCasesSyncStatus,
+ sendSyncCaseIds,
+} from '../action/firebaseFallbackActions';
+import { getSyncCaseIds } from '../components/utlis/firebaseFallbackUtils';
+import { syncCasesByFallback } from '../reducer/allCasesSlice';
+import { MILLISECONDS_IN_A_MINUTE } from '../../RN-UI-LIB/src/utlis/common';
export enum FOREGROUND_TASKS {
GEOLOCATION = 'GEOLOCATION',
TIME_SYNC = 'TIME_SYNC',
DATA_SYNC = 'DATA_SYNC',
+ FIRESTORE_FALLBACK = 'FIRESTORE_FALLBACK',
}
interface ITrackingComponent {
@@ -33,6 +45,16 @@ const TrackingComponent: React.FC = ({ children }) => {
const bgTrackingTimeoutId = useRef();
const user = useAppSelector((state) => state.user);
+ const {
+ referenceId,
+ pendingList = [],
+ pinnedList = [],
+ } = useAppSelector((state) => ({
+ referenceId: state.user.user?.referenceId!!,
+ pendingList: state.allCases.pendingList,
+ pinnedList: state.allCases.pinnedList,
+ }));
+
const handleTimeSync = async () => {
try {
const timestamp = await getSyncTime();
@@ -56,17 +78,44 @@ const TrackingComponent: React.FC = ({ children }) => {
}
};
+ const handleGetCaseSyncStatus = async () => {
+ try {
+ const syncStatus = await getCasesSyncStatus(referenceId);
+ if (syncStatus === SyncStatus.SEND_CASES) {
+ const cases = getSyncCaseIds([...pendingList, ...pinnedList]);
+ const payload: ISyncCaseIdPayload = {
+ agentId: referenceId,
+ cases,
+ };
+ sendSyncCaseIds(payload);
+ } else if (syncStatus === SyncStatus.FETCH_CASES) {
+ const updatedDetails: ISyncedCases = await fetchCasesToSync(referenceId);
+ if (updatedDetails?.cases?.length) {
+ dispatch(syncCasesByFallback(updatedDetails));
+ }
+ }
+ } catch (e) {
+ logError(e as Error, 'Error during fetching case sync status');
+ }
+ };
+
const tasks: IForegroundTask[] = [
{
taskId: FOREGROUND_TASKS.TIME_SYNC,
task: handleTimeSync,
- delay: 1000 * 60 * 5, // 5 minutes,
+ delay: 5 * MILLISECONDS_IN_A_MINUTE, // 5 minutes,
onLoop: true,
},
{
taskId: FOREGROUND_TASKS.GEOLOCATION,
task: handleSendGeolocation,
- delay: 1000 * 60 * 3, // 3 minutes
+ delay: 3 * MILLISECONDS_IN_A_MINUTE, // 3 minutes
+ onLoop: true,
+ },
+ {
+ taskId: FOREGROUND_TASKS.FIRESTORE_FALLBACK,
+ task: handleGetCaseSyncStatus,
+ delay: 30 * MILLISECONDS_IN_A_MINUTE, // 30 minutes
onLoop: true,
},
];
diff --git a/src/components/utlis/apiHelper.ts b/src/components/utlis/apiHelper.ts
index 530736e0..bd80f7a3 100644
--- a/src/components/utlis/apiHelper.ts
+++ b/src/components/utlis/apiHelper.ts
@@ -43,6 +43,9 @@ export enum ApiKeys {
DATA_SYNC_UPLOAD_COMPLETED = 'DATA_SYNC_UPLOAD_COMPLETED',
IMPERSONATION = 'IMPERSONATION',
TELEPHONES = 'TELEPHONES',
+ CASES_SYNC_STATUS = 'CASES_SYNC_STATUS',
+ CASES_SEND_ID = 'CASES_SEND_ID',
+ FETCH_CASES = 'FETCH_CASES',
}
export const API_URLS: Record = {} as Record;
@@ -72,6 +75,9 @@ API_URLS[ApiKeys.GET_PRE_SIGNED_URL_DATA_SYNC] = '/sync-data/get-pre-signed-url'
API_URLS[ApiKeys.DATA_SYNC_UPLOAD_COMPLETED] = '/sync-data/upload-completed';
API_URLS[ApiKeys.IMPERSONATION] = '/auth/impersonation';
API_URLS[ApiKeys.TELEPHONES] = '/telephones';
+API_URLS[ApiKeys.CASES_SYNC_STATUS] = '/cases/agents/sync-status';
+API_URLS[ApiKeys.CASES_SEND_ID] = '/cases/sync';
+API_URLS[ApiKeys.FETCH_CASES] = '/cases/agents/{agentReferenceId}';
export const API_STATUS_CODE = {
OK: 200,
diff --git a/src/components/utlis/commonFunctions.ts b/src/components/utlis/commonFunctions.ts
index 122ad899..2ffc0e2e 100644
--- a/src/components/utlis/commonFunctions.ts
+++ b/src/components/utlis/commonFunctions.ts
@@ -319,3 +319,13 @@ export const getMaxByPropFromList = (arr: GenericType, prop: string) => {
const max = Math.max(...mappedArray);
return arr.find((x: GenericType) => x[prop] == max);
};
+
+
+export const getGoogleMapUrl = (latitude: string | number, longitude: string | number) => {
+ if (!latitude || !longitude) return;
+ return `https://www.google.com/maps/search/${latitude},+${longitude}`;
+}
+
+export const isValidAmountEntered = (value: number) => {
+ return typeof value === 'number' && !isNaN(value);
+};
diff --git a/src/components/utlis/firebaseFallbackUtils.ts b/src/components/utlis/firebaseFallbackUtils.ts
new file mode 100644
index 00000000..ec1a7942
--- /dev/null
+++ b/src/components/utlis/firebaseFallbackUtils.ts
@@ -0,0 +1,8 @@
+import { ICaseItem } from '../../screens/allCases/interface';
+
+export const getSyncCaseIds = (casesList: ICaseItem[] = []) => {
+ return casesList.map((caseItem) => ({
+ caseId: caseItem.caseReferenceId,
+ caseViewCreatedAt: caseItem.caseViewCreatedAt,
+ }));
+};
diff --git a/src/constants/Global.ts b/src/constants/Global.ts
index 704917cf..9a6c1f1a 100644
--- a/src/constants/Global.ts
+++ b/src/constants/Global.ts
@@ -1,3 +1,4 @@
+import { setCustomUserId } from 'react-native-clarity';
import { isNullOrUndefined } from '../components/utlis/commonFunctions';
export enum DEVICE_TYPE_ENUM {
@@ -21,6 +22,10 @@ interface IGlobalUserData {
isImpersonated?: boolean;
}
+interface IClarityConfiguration {
+ customUserId?: string;
+}
+
export const setGlobalUserData = (userData: IGlobalUserData) => {
const { token, deviceId, agentId, deviceType, isImpersonated } = userData;
if (!isNullOrUndefined(token)) GLOBAL.SESSION_TOKEN = `${token}`;
@@ -29,3 +34,9 @@ export const setGlobalUserData = (userData: IGlobalUserData) => {
if (!isNullOrUndefined(deviceType)) GLOBAL.DEVICE_TYPE = deviceType as DEVICE_TYPE_ENUM;
if (!isNullOrUndefined(isImpersonated)) GLOBAL.IS_IMPERSONATED = isImpersonated ?? false;
};
+
+export const setMsClarityConfig = (clarityConfig: IClarityConfiguration) => {
+ if (clarityConfig?.customUserId) {
+ setCustomUserId(clarityConfig.customUserId);
+ }
+};
diff --git a/src/constants/config.js b/src/constants/config.js
index 6fa05aeb..5df41c0d 100644
--- a/src/constants/config.js
+++ b/src/constants/config.js
@@ -12,3 +12,4 @@ export const IS_DATA_SYNC_REQUIRED = true;
export const DATA_SYNC_TIME_INTERVAL = 2 * MINUTES_IN_AN_HOUR * MILLISECONDS_IN_A_MINUTE; // 2hr
export const GOOGLE_SSO_CLIENT_ID =
'60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com';
+export const MS_CLARITY_PROJECT_ID = '';
diff --git a/src/hooks/useFirestoreUpdates.ts b/src/hooks/useFirestoreUpdates.ts
index 9c601701..7fcd7438 100644
--- a/src/hooks/useFirestoreUpdates.ts
+++ b/src/hooks/useFirestoreUpdates.ts
@@ -167,14 +167,6 @@ const useFirestoreUpdates = () => {
.catch((error) => {
dispatch(setLoading(false));
logError(error as Error, 'Error in signInUserToFirebase');
- setGlobalUserData({ token: '', agentId: '', deviceId: '' });
- dispatch(
- setAuthData({
- sessionDetails: null,
- user: null,
- isLoggedIn: false,
- })
- );
toast({
type: 'error',
text1: ToastMessages.FIRESTORE_SIGNIN_FAILED,
diff --git a/src/reducer/allCasesSlice.ts b/src/reducer/allCasesSlice.ts
index bb8f7097..1cf7b8cd 100644
--- a/src/reducer/allCasesSlice.ts
+++ b/src/reducer/allCasesSlice.ts
@@ -199,6 +199,18 @@ export const getUpdatedAVCaseDetail = ({
return updatedValue;
};
+const getCaseListItem = (
+ caseReferenceId: string,
+ pinRank?: number | null,
+ caseViewCreatedAt?: number
+) => {
+ return {
+ caseReferenceId,
+ pinRank: pinRank || null,
+ caseViewCreatedAt,
+ };
+};
+
const allCasesSlice = createSlice({
name: 'cases',
initialState,
@@ -219,7 +231,7 @@ const allCasesSlice = createSlice({
let newVisitCollectionCases: string[] = [];
let removedVisitedCasesLoanIds: string[] = [];
caseUpdates.forEach(({ updateType, updatedCaseDetail }) => {
- const { caseType, caseReferenceId, id, pinRank } = updatedCaseDetail;
+ const { caseType, caseReferenceId, id, pinRank, caseViewCreatedAt } = updatedCaseDetail;
const caseId = caseReferenceId || id;
switch (updateType) {
@@ -272,10 +284,7 @@ const allCasesSlice = createSlice({
if (pinRank && caseType === CaseAllocationType.COLLECTION_CASE) {
newVisitCollectionCases.push(caseId);
}
- const caseListItem = {
- caseReferenceId: caseId,
- pinRank: pinRank || null,
- };
+ const caseListItem = getCaseListItem(caseId, pinRank, caseViewCreatedAt);
state.casesList.unshift(caseListItem);
let currentTask = null;
if (caseType !== CaseAllocationType.COLLECTION_CASE) {
@@ -494,6 +503,33 @@ const allCasesSlice = createSlice({
resetNewVisitedCases: (state) => {
state.newVisitedCases = [];
},
+ syncCasesByFallback: (state, action) => {
+ const { cases = [], deletedCaseIds = [], payloadCreatedAt } = action.payload;
+ cases.forEach((caseItem: CaseDetail) => {
+ const { caseViewCreatedAt, caseReferenceId, isSynced, pinRank } = caseItem;
+ if (
+ !state.caseDetails[caseReferenceId] ||
+ (isSynced && caseViewCreatedAt && caseViewCreatedAt < payloadCreatedAt)
+ ) {
+ const caseListItem = getCaseListItem(caseReferenceId, pinRank, caseViewCreatedAt);
+ state.casesList.unshift(caseListItem);
+ state.caseDetails[caseReferenceId] = { ...caseItem, isSynced: true };
+ const { pendingList, completedList, pinnedList } = getCaseListComponents(
+ state.casesList,
+ state.caseDetails
+ );
+ state.pendingList = pendingList;
+ state.completedList = completedList;
+ state.pinnedList = pinnedList;
+ }
+ });
+ deletedCaseIds.forEach((caseItem: CaseDetail) => {
+ const { caseViewCreatedAt, caseReferenceId } = caseItem;
+ if (caseViewCreatedAt && caseViewCreatedAt < payloadCreatedAt) {
+ delete state.caseDetails[caseReferenceId];
+ }
+ });
+ },
},
});
@@ -513,6 +549,7 @@ export const {
updateCaseDetailBeforeApiCall,
setVisitPlansUpdating,
resetNewVisitedCases,
+ syncCasesByFallback,
} = allCasesSlice.actions;
export default allCasesSlice.reducer;
diff --git a/src/reducer/metadataSlice.ts b/src/reducer/metadataSlice.ts
index 0ccf05b7..71ec5d8d 100644
--- a/src/reducer/metadataSlice.ts
+++ b/src/reducer/metadataSlice.ts
@@ -7,11 +7,13 @@ export interface UninstallInformation {
interface IMetadata {
isOnline: boolean;
forceUninstall: Record;
+ isWifiOrCellularOn: boolean;
}
const initialState = {
isOnline: true,
forceUninstall: {},
+ isWifiOrCellularOn: true,
} as IMetadata;
const MetadataSlice = createSlice({
@@ -24,9 +26,12 @@ const MetadataSlice = createSlice({
setForceUninstallData: (state, action) => {
state.forceUninstall = action.payload;
},
+ setIsWifiOrCellularOn: (state, action) => {
+ state.isWifiOrCellularOn = action.payload;
+ },
},
});
-export const { setIsOnline, setForceUninstallData } = MetadataSlice.actions;
+export const { setIsOnline, setForceUninstallData, setIsWifiOrCellularOn } = MetadataSlice.actions;
export default MetadataSlice.reducer;
diff --git a/src/screens/addressGeolocation/GeolocationItem.tsx b/src/screens/addressGeolocation/GeolocationItem.tsx
index 5237e5e9..fb0911a7 100644
--- a/src/screens/addressGeolocation/GeolocationItem.tsx
+++ b/src/screens/addressGeolocation/GeolocationItem.tsx
@@ -7,7 +7,7 @@ import {
BUSINESS_TIME_FORMAT,
dateFormat,
} from '../../../RN-UI-LIB/src/utlis/dates';
-import { sanitizeString } from '../../components/utlis/commonFunctions';
+import { getGoogleMapUrl, sanitizeString } from '../../components/utlis/commonFunctions';
import { IGeoLocation } from '../../types/addressGeolocation.types';
import { addClickstreamEvent } from '../../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
@@ -30,7 +30,7 @@ const GeolocationItem = ({ geolocationItem, showSeparator = true }: IGeolocation
latitude: geolocationItem.latitude,
longitude: geolocationItem.longitude,
});
- const geolocationUrl = `http://maps.google.com/?q=${geolocationItem?.latitude},${geolocationItem?.longitude}`;
+ const geolocationUrl = getGoogleMapUrl(geolocationItem?.latitude, geolocationItem?.longitude);
if (!geolocationUrl) return;
return Linking.openURL(geolocationUrl);
diff --git a/src/screens/allCases/Filters.tsx b/src/screens/allCases/Filters.tsx
index 9025bf6a..e234672c 100644
--- a/src/screens/allCases/Filters.tsx
+++ b/src/screens/allCases/Filters.tsx
@@ -45,7 +45,14 @@ const Filters: React.FC = ({
return (
-
+
}
diff --git a/src/screens/allCases/interface.ts b/src/screens/allCases/interface.ts
index 53b52b9b..38c205c6 100644
--- a/src/screens/allCases/interface.ts
+++ b/src/screens/allCases/interface.ts
@@ -112,6 +112,7 @@ export const caseVerdictAndColor = {
export interface ICaseItem {
type?: CaseTypes; // this is for maintaining frontend
pinRank: number | null;
+ caseViewCreatedAt?: number;
updatedAt?: any;
allocatedAt?: any;
caseReferenceId: string;
diff --git a/src/screens/auth/AuthRouter.tsx b/src/screens/auth/AuthRouter.tsx
index 7a244738..96d597df 100644
--- a/src/screens/auth/AuthRouter.tsx
+++ b/src/screens/auth/AuthRouter.tsx
@@ -5,7 +5,7 @@ import { useSelector } from 'react-redux';
import { RootState } from '../../store/store';
import { getUniqueId, isTablet } from 'react-native-device-info';
import { setDeviceId } from '../../reducer/userSlice';
-import { DEVICE_TYPE_ENUM, setGlobalUserData } from '../../constants/Global';
+import { DEVICE_TYPE_ENUM, setGlobalUserData, setMsClarityConfig } from '../../constants/Global';
import { registerNavigateAndDispatch } from '../../components/utlis/apiHelper';
import ProtectedRouter from './ProtectedRouter';
import useNativeButtons from '../../hooks/useNativeButton';
@@ -38,6 +38,8 @@ const AuthRouter = () => {
isImpersonated: user?.isImpersonated ?? false,
});
+ setMsClarityConfig({ customUserId: user?.user?.phoneNumber || user?.user?.emailId });
+
// Sets the dispatch for apiHelper
registerNavigateAndDispatch(dispatch);
diff --git a/src/screens/caseDetails/feedback/FeedbackDetailImageItem.tsx b/src/screens/caseDetails/feedback/FeedbackDetailImageItem.tsx
index c833c0a5..b35953a6 100644
--- a/src/screens/caseDetails/feedback/FeedbackDetailImageItem.tsx
+++ b/src/screens/caseDetails/feedback/FeedbackDetailImageItem.tsx
@@ -47,7 +47,12 @@ const FeedbackDetailImageItem: React.FC = ({ image })
onPress={handleExpandImage}
/>
-
+
{
latitude: latitude,
longitude: longitude,
});
-
- if (!latitude || !longitude) return;
- const geolocationUrl = `http://maps.google.com/?q=${latitude},${longitude}`;
+ const geolocationUrl = getGoogleMapUrl(latitude, longitude);
+ if (!geolocationUrl) return;
return Linking.openURL(geolocationUrl);
};
diff --git a/src/screens/caseDetails/interface.ts b/src/screens/caseDetails/interface.ts
index 6622dcb2..917da295 100644
--- a/src/screens/caseDetails/interface.ts
+++ b/src/screens/caseDetails/interface.ts
@@ -181,6 +181,7 @@ export interface CaseDetail {
addresses?: Address[];
currentAllocationReferenceId: string;
customerReferenceId: string;
+ caseViewCreatedAt?: number;
// collection case
addressString?: string;
currentOutstandingEmi?: number;
diff --git a/src/screens/registerPayements/RegisterPayments.tsx b/src/screens/registerPayements/RegisterPayments.tsx
index f8cb5546..40d7c103 100644
--- a/src/screens/registerPayements/RegisterPayments.tsx
+++ b/src/screens/registerPayements/RegisterPayments.tsx
@@ -15,6 +15,7 @@ import {
copyToClipboard,
getDynamicBottomSheetHeightPercentageFn,
getPhoneNumberString,
+ isValidAmountEntered,
} from '../../components/utlis/commonFunctions';
import useIsOnline from '../../hooks/useIsOnline';
import { RootState } from '../../store/store';
@@ -29,6 +30,7 @@ import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
import QrCodeModal from './QrCodeModal';
import ModalWrapper from '../../../RN-UI-LIB/src/components/modalWrapper/ModalWrapper';
import OfflineScreen from '../../common/OfflineScreen';
+import { formatAmount } from '../../../RN-UI-LIB/src/utlis/amount';
interface IRegisterForm {
selectedPhoneNumber: string;
@@ -116,10 +118,10 @@ const RegisterPayments: React.FC = ({ route }) => {
errorMessage = 'This is a required field';
break;
case 'min':
- errorMessage = 'Amount should be greater than min amount';
- break;
case 'max':
- errorMessage = 'Amount should be less than max amount';
+ errorMessage = `The entered amount should be between ${formatAmount(1)} and ${formatAmount(
+ maxAmount
+ )}`;
break;
}
@@ -217,7 +219,12 @@ const RegisterPayments: React.FC = ({ route }) => {
/>
)}
name="amount"
- rules={{ required: true, min: 1, max: maxAmount }}
+ rules={{
+ required: true,
+ min: 1,
+ max: maxAmount,
+ validate: (value) => isValidAmountEntered(Number(value)),
+ }}
/>