took master pull

This commit is contained in:
Sayed Owais Ali
2023-09-28 16:46:01 +05:30
22 changed files with 450 additions and 39 deletions

19
App.tsx
View File

@@ -18,12 +18,12 @@ import CodePush from 'react-native-code-push';
import store, { persistor } from './src/store/store';
import { navigationRef } from './src/components/utlis/navigationUtlis';
import FullScreenLoaderWrapper from './src/common/FullScreenLoaderWrapper';
import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader';
import { toastConfigs, ToastContainer } from './RN-UI-LIB/src/components/toast';
import { APM_APP_NAME, APM_BASE_URL, ENV } from './src/constants/config';
import { COLORS } from './RN-UI-LIB/src/styles/colors';
import { LocalStorageKeys } from './src/common/Constants';
import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from './src/common/Constants';
import Permissions from './src/screens/permissions/Permissions';
import { setJsErrorHandler } from './src/services/exception-handler.service';
import SuspenseLoader from './RN-UI-LIB/src/components/suspense_loader/SuspenseLoader';
@@ -37,9 +37,13 @@ import {
} from './src/components/utlis/PermissionUtils';
import usePolling from './src/hooks/usePolling';
import { MILLISECONDS_IN_A_SECOND } from './RN-UI-LIB/src/utlis/common';
import { setItem } from './src/components/utlis/storageHelper';
import { StorageKeys } from './src/types/storageKeys';
import dayJs from 'dayjs';
import { GlobalImageMap, hydrateGlobalImageMap } from './src/common/CachedImage';
import analytics from '@react-native-firebase/analytics';
import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader';
import handleUpdatedConfigureValuesFromFirebase from './src/services/firebaseFetchAndUpdate.service';
import { addClickstreamEvent } from './src/services/clickstreamEventService';
initSentry();
@@ -104,6 +108,12 @@ function App() {
return route?.name || '';
};
async function setForegroundTimeStampAndClickstream() {
const now = dayJs().toString();
await setItem(StorageKeys.APP_FOREGROUND_TIMESTAMP, now);
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_APP_FOREGROUND, { now });
}
usePolling(askForPermissions, PERMISSION_CHECK_POLL_INTERVAL);
initApm({
@@ -129,6 +139,9 @@ function App() {
setIsGlobalDocumentMapLoaded(true);
})();
checkCodePushAndSync();
handleUpdatedConfigureValuesFromFirebase();
setForegroundTimeStampAndClickstream();
return () => {
appStateChange.remove();
};

View File

@@ -131,16 +131,10 @@ def reactNativeArchitectures() {
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
def VERSION_CODE = 85
def VERSION_NAME = "2.4.1"
def VERSION_CODE = 86
def VERSION_NAME = "2.4.2"
android {
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
pickFirst 'lib/x86_64/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
}
ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion

View File

@@ -47,6 +47,7 @@ public class MainApplication extends Application implements ReactApplication {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
packages.add(new DeviceUtilsModulePackage());
packages.add(new ScreenshotBlockerModulePackage());
return packages;
}

View File

@@ -0,0 +1,101 @@
package com.avapp;
import android.app.Activity;
import android.view.WindowManager;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
import android.os.Handler;
import android.os.Looper;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.provider.MediaStore;
public class ScreenshotBlockerModule extends ReactContextBaseJavaModule {
private ReactApplicationContext reactContext;
private ContentObserver contentObserver;
private boolean isTracking = false;
public ScreenshotBlockerModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
@Override
public String getName() {
return "ScreenshotBlocker";
}
@ReactMethod
public void blockScreenshots() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
Activity activity = getCurrentActivity();
@Override
public void run() {
if (activity != null) {
activity.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
);
}
}
});
}
@ReactMethod
public void unblockScreenshots() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
Activity activity = getCurrentActivity();
@Override
public void run() {
if (activity != null) {
activity.getWindow().clearFlags(
WindowManager.LayoutParams.FLAG_SECURE
);
}
}
});
}
@ReactMethod
public void startScreenshotTracking() {
if (!isTracking) {
isTracking = true;
ContentResolver contentResolver = getCurrentActivity().getContentResolver();
contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
long lastEventTimestamp = 0;
@Override
public void onChange(boolean selfChange, Uri uri) {
long currentTimeMillis = System.currentTimeMillis();
if (currentTimeMillis - lastEventTimestamp > 1000) {
sendScreenshotEvent();
lastEventTimestamp = currentTimeMillis;
}
}
};
contentResolver.registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
true,
contentObserver
);
}
}
private void sendScreenshotEvent() {
WritableMap params = Arguments.createMap();
params.putBoolean("isScreenshotDetected", true);
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("screenshotTaken", params);
}
}

View File

@@ -0,0 +1,27 @@
package com.avapp;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ScreenshotBlockerModulePackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ScreenshotBlockerModule(reactContext));
return modules;
}
}

View File

@@ -8,7 +8,24 @@ module.exports = {
cwd: 'babelrc',
extensions: ['.ts', '.tsx', '.js', '.ios.js', '.android.js'],
alias: {
'@cuteapp': './app',
'@root': './src',
'@components': './src/components',
'@hooks': './src/hooks',
'@actions': './src/action',
'@reducers': './src/reducer',
'@constants': './src/constants',
'@screens': './src/screens',
'@services': './src/services',
'@types': './src/types',
'@common': './src/common',
'@assets': './src/assets',
'@store': './src/store/store',
'@utils': './src/components/utlis',
'@rn-ui-lib/components': './RN-UI-LIB/src/components',
'@rn-ui-lib/icons': './RN-UI-LIB/src/Icons',
'@rn-ui-lib/styles': './RN-UI-LIB/src/styles/index',
'@rn-ui-lib/colors': './RN-UI-LIB/src/styles/colors',
'@rn-ui-lib/utils': './RN-UI-LIB/src/utlis',
},
},
],

View File

@@ -1,6 +1,6 @@
{
"name": "AV_APP",
"version": "2.4.1",
"version": "2.4.2",
"private": true,
"scripts": {
"android:dev": "yarn move:dev && react-native run-android",
@@ -11,7 +11,7 @@
"android-field:prod": "yarn move:prod && react-native run-android --variant=fieldAgentsQADebug",
"release-field:dev": "yarn move:dev && react-native run-android --variant=fieldAgentsQARelease && cd android && ./gradlew assemblefieldAgentsQARelease",
"release-field:qa": "yarn move:qa && react-native run-android --variant=fieldAgentsQARelease && cd android && ./gradlew assemblefieldAgentsQARelease",
"release-field:prod": "yarn move:dev && react-native run-android --variant=fieldAgentsProdRelease && cd android && ./gradlew assemblefieldAgentsProdRelease",
"release-field:prod": "yarn move:prod && react-native run-android --variant=fieldAgentsProdRelease && cd android && ./gradlew assemblefieldAgentsProdRelease",
"android-calling:dev": "yarn move:dev && react-native run-android --variant=callingAgentsQADebug",
"android-calling:qa": "yarn move:qa && react-native run-android --variant=callingAgentsQADebug",
"android-calling:prod": "yarn move:prod && react-native run-android --variant=callingAgentsQADebug",
@@ -49,6 +49,7 @@
"@react-native-firebase/database": "16.4.6",
"@react-native-firebase/firestore": "16.5.0",
"@react-native-firebase/messaging": "17.4.0",
"@react-native-firebase/remote-config": "16.4.6",
"@react-native-google-signin/google-signin": "9.0.2",
"@react-navigation/bottom-tabs": "6.5.5",
"@react-navigation/native": "6.1.4",
@@ -80,6 +81,7 @@
"react-native-gzip": "1.0.0",
"react-native-image-picker": "4.10.2",
"react-native-pager-view": "6.1.2",
"react-native-pdf-renderer": "1.1.1",
"react-native-permissions": "3.6.1",
"react-native-qrcode-svg": "^6.2.0",
"react-native-safe-area-context": "4.4.1",

View File

@@ -0,0 +1,19 @@
let ACTIVITY_TIME_ON_APP: number = 5; //5 seconds
let ACTIVITY_TIME_WINDOW_HIGH: number = 10; //10 minutes
let ACTIVITY_TIME_WINDOW_MEDIUM: number = 30; //30 minutes
export const getActivityTimeOnApp = () => ACTIVITY_TIME_ON_APP;
export const getActivityTimeWindowHigh = () => ACTIVITY_TIME_WINDOW_HIGH;
export const getActivityTimeWindowMedium = () => ACTIVITY_TIME_WINDOW_MEDIUM;
export const setActivityTimeOnApp = (activityTimeOnApp: number) => {
ACTIVITY_TIME_ON_APP = activityTimeOnApp;
};
export const setActivityTimeWindowHigh = (activityTimeWindowHigh: number) => {
ACTIVITY_TIME_WINDOW_HIGH = activityTimeWindowHigh;
};
export const setActivityTimeWindowMedium = (activityTimeWindowMedium: number) => {
ACTIVITY_TIME_WINDOW_MEDIUM = activityTimeWindowMedium;
};

View File

@@ -95,6 +95,10 @@ export const CLICKSTREAM_EVENT_NAMES = {
name: 'FA_LOGIN_SCREEN_SEND_OTP_API_FAILED',
description: 'Send OTP API failed',
},
FA_SCREENSHOT_TAKEN: {
name: 'FA_SCREENSHOT_TAKEN',
description: 'Screenshot atempt detected',
},
// OTP screen
AV_OTP_SCREEN_LOAD: { name: 'FA_OTP_SCREEN_LOAD', description: 'OTP screen loaded' },

View File

@@ -34,8 +34,17 @@ import { setLockData } from '../reducer/userSlice';
import { getConfigData } from '../action/configActions';
import { AppStates } from '../types/appStates';
import { StorageKeys } from '../types/storageKeys';
import { AgentActivity } from '../types/agentActivity';
import {
getActivityTimeOnApp,
getActivityTimeWindowMedium,
getActivityTimeWindowHigh,
} from './AgentActivityConfigurableConstants';
import RNFS from 'react-native-fs';
import { GlobalImageMap } from './CachedImage';
import { get } from 'react-hook-form';
import { addClickstreamEvent } from '../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from './Constants';
export enum FOREGROUND_TASKS {
GEOLOCATION = 'GEOLOCATION',
@@ -43,6 +52,7 @@ export enum FOREGROUND_TASKS {
DATA_SYNC = 'DATA_SYNC',
FIRESTORE_FALLBACK = 'FIRESTORE_FALLBACK',
UPDATE_AGENT_ACTIVENESS = 'UPDATE_AGENT_ACTIVENESS',
UPDATE_AGENT_ACTIVITY = 'UPDATE_AGENT_ACTIVITY',
DELETE_CACHE = 'DELETE_CACHE',
}
@@ -51,7 +61,6 @@ interface ITrackingComponent {
}
let LAST_SYNC_STATUS = 'SKIP';
const ACTIVITY_TIME_ON_APP = 5; // 5 seconds
const ACTIVITY_TIME_WINDOW = 10; // 10 minutes
const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
@@ -94,12 +103,16 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
return;
}
const isActiveOnApp: string | boolean = (await getItem(StorageKeys.IS_USER_ACTIVE)) || false;
const userActivityonApp: string =
(await getItem(StorageKeys.USER_ACTIVITY_ON_APP)) || AgentActivity.LOW;
const geolocation: IGeolocationPayload = {
latitude: location.latitude,
longitude: location.longitude,
accuracy: location.accuracy,
timestamp: Date.now(),
isActiveOnApp: Boolean(isActiveOnApp),
userActivityOnApp: String(userActivityonApp),
};
dispatch(sendLocationAndActivenessToServer([geolocation]));
} catch (e: any) {
@@ -169,6 +182,7 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
const isForegroundTimeWithInRange =
diffBetweenCurrentTimeAndForegroundTime <= ACTIVITY_TIME_WINDOW;
const isForegroundTimeAfterBackground = dayJs(foregroundTimestamp).isAfter(backgroundTimestamp);
const ACTIVITY_TIME_ON_APP = getActivityTimeOnApp();
if (isForegroundTimeWithInRange) {
if (
@@ -184,6 +198,60 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
return;
};
const handleUpdateActivity = async () => {
const foregroundTimestamp = await getItem(StorageKeys.APP_FOREGROUND_TIMESTAMP);
const backgroundTimestamp = await getItem(StorageKeys.APP_BACKGROUND_TIMESTAMP);
const stateSetTimestamp = await getItem(StorageKeys.STATE_SET_TIMESTAMP);
if (foregroundTimestamp == null) {
console.log('fts set after installation');
await setItem(StorageKeys.APP_FOREGROUND_TIMESTAMP, dayJs().toString());
}
const foregroundTime = dayJs(foregroundTimestamp);
const backgroundTime = dayJs(backgroundTimestamp);
const stateSetTime = dayJs(stateSetTimestamp);
const diffBetweenCurrentTimeAndForegroundTime =
dayJs().diff(foregroundTime, 'seconds') < 0 ? 0 : dayJs().diff(foregroundTime, 'seconds');
const diffBetweenCurrentTimeAndSetStateTime =
dayJs().diff(stateSetTime, 'minutes') < 0 ? 0 : dayJs().diff(stateSetTime, 'minutes');
const ACTIVITY_TIME_ON_APP = getActivityTimeOnApp();
const ACTIVITY_TIME_WINDOW_HIGH = getActivityTimeWindowHigh();
const ACTIVITY_TIME_WINDOW_MEDIUM = getActivityTimeWindowMedium();
const isStateSetTimeWithinHighRange =
diffBetweenCurrentTimeAndSetStateTime < ACTIVITY_TIME_WINDOW_HIGH;
const isStateSetTimeWithinMediumRange =
diffBetweenCurrentTimeAndSetStateTime < ACTIVITY_TIME_WINDOW_MEDIUM;
const isForegroundTimeAfterBackground = dayJs(foregroundTimestamp).isAfter(backgroundTimestamp);
if (AppState.currentState === AppStates.ACTIVE) {
if (diffBetweenCurrentTimeAndForegroundTime >= ACTIVITY_TIME_ON_APP) {
await setItem(StorageKeys.USER_ACTIVITY_ON_APP, AgentActivity.HIGH);
return;
}
return;
}
if (isForegroundTimeAfterBackground) {
if (diffBetweenCurrentTimeAndForegroundTime >= ACTIVITY_TIME_ON_APP) {
await setItem(StorageKeys.USER_ACTIVITY_ON_APP, AgentActivity.HIGH);
return;
}
return;
} else if (isStateSetTimeWithinHighRange) {
return;
} else if (isStateSetTimeWithinMediumRange) {
await setItem(StorageKeys.USER_ACTIVITY_ON_APP, AgentActivity.MEDIUM);
return;
} else {
await setItem(StorageKeys.USER_ACTIVITY_ON_APP, AgentActivity.LOW);
return;
}
};
const deleteCache = () => {
const directoryPath = RNFS.CachesDirectoryPath;
const currentDate = new Date().getTime();
@@ -239,6 +307,12 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
delay: ACTIVITY_TIME_WINDOW * MILLISECONDS_IN_A_MINUTE, // 10 minutes
onLoop: true,
},
{
taskId: FOREGROUND_TASKS.UPDATE_AGENT_ACTIVITY,
task: handleUpdateActivity,
delay: ACTIVITY_TIME_WINDOW * MILLISECONDS_IN_A_MINUTE, // 10 minutes
onLoop: true,
},
{
taskId: FOREGROUND_TASKS.DELETE_CACHE,
task: deleteCache,
@@ -272,17 +346,39 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
});
}
const userActivityUpdateOnBackground = async () => {
const foregroundTimestamp = await getItem(StorageKeys.APP_FOREGROUND_TIMESTAMP);
const backgroundTimestamp = await getItem(StorageKeys.APP_BACKGROUND_TIMESTAMP);
const foregroundTime = dayJs(foregroundTimestamp);
const backgroundTime = dayJs(backgroundTimestamp);
const diffBetweenBackgroundAndForegroundTime = dayJs(backgroundTime).diff(
foregroundTime,
'seconds'
);
const ACTIVITY_TIME_ON_APP = getActivityTimeOnApp();
if (diffBetweenBackgroundAndForegroundTime >= ACTIVITY_TIME_ON_APP) {
await setItem(StorageKeys.USER_ACTIVITY_ON_APP, AgentActivity.HIGH);
await setItem(StorageKeys.STATE_SET_TIMESTAMP, dayJs().toString());
return;
}
return;
};
const handleAppStateChange = async (nextAppState: AppStateStatus) => {
// App comes to foreground from background
const now = dayJs().toString();
if (nextAppState === AppStates.ACTIVE) {
await setItem(StorageKeys.APP_FOREGROUND_TIMESTAMP, now);
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_APP_FOREGROUND, { now });
handleGetCaseSyncStatus();
dispatch(getConfigData());
CosmosForegroundService.start(tasks);
}
if (nextAppState === AppStates.BACKGROUND) {
await setItem(StorageKeys.APP_BACKGROUND_TIMESTAMP, now);
userActivityUpdateOnBackground();
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_APP_BACKGROUND, { now });
}
appState.current = nextAppState;
};
@@ -306,12 +402,8 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
useEffect(() => {
let appStateSubscription: NativeEventSubscription;
CosmosForegroundService.isRunning().then((isFGSRunning) => {
if (!isFGSRunning) {
appStateSubscription = AppState.addEventListener('change', handleAppStateChange);
CosmosForegroundService.start(tasks);
}
});
appStateSubscription = AppState.addEventListener('change', handleAppStateChange);
CosmosForegroundService.start(tasks);
return () => {
appStateSubscription?.remove();
};

View File

@@ -0,0 +1,5 @@
import { NativeModules } from 'react-native';
const { ScreenshotBlocker } = NativeModules;
export default ScreenshotBlocker;

View File

@@ -13,6 +13,7 @@ export interface IGeolocationPayload {
accuracy: number;
timestamp: number;
isActiveOnApp: boolean;
userActivityOnApp: string;
}
export const sendLocationAndActivenessToServer =

View File

@@ -0,0 +1,39 @@
import { useEffect, useMemo } from 'react';
import { NativeEventEmitter } from 'react-native';
import { useAppSelector } from '.';
import { CLICKSTREAM_EVENT_NAMES } from '../common/Constants';
import { getCurrentScreen } from '../components/utlis/navigationUtlis';
import ScreenshotBlocker from '../components/utlis/ScreenshotBlocker';
import { addClickstreamEvent } from '../services/clickstreamEventService';
const useScreenshotTracking = () => {
const { user, allCases } = useAppSelector((state) => ({
user: state.user,
allCases: state.allCases,
}));
const screenshotEventEmitter = useMemo(() => new NativeEventEmitter(ScreenshotBlocker), []);
useEffect(() => {
ScreenshotBlocker.startScreenshotTracking();
const screenshotTakenSubscription = screenshotEventEmitter.addListener(
'screenshotTaken',
(event) => {
if (event?.isScreenshotDetected) {
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_SCREENSHOT_TAKEN, {
userId: user?.user?.referenceId ?? '',
caseId: allCases.selectedCaseId ?? '',
page: getCurrentScreen()?.name,
});
return;
}
}
);
return () => {
if (screenshotTakenSubscription) screenshotTakenSubscription.remove();
};
}, [allCases?.selectedCaseId, user?.user?.referenceId]);
};
export default useScreenshotTracking;

View File

@@ -44,6 +44,7 @@ interface IAllCasesSlice {
completedList: ICaseItem[];
pinnedList: ICaseItem[];
newVisitedCases: string[];
selectedCaseId: string;
}
const initialState: IAllCasesSlice = {
@@ -67,6 +68,7 @@ const initialState: IAllCasesSlice = {
completedList: [],
pinnedList: [],
newVisitedCases: [],
selectedCaseId: '',
};
const getCaseListComponents = (casesList: ICaseItem[], caseDetails: Record<string, CaseDetail>) => {
@@ -563,6 +565,9 @@ const allCasesSlice = createSlice({
}
});
},
setSelectedCaseId: (state, action) => {
state.selectedCaseId = action.payload;
},
},
});
@@ -584,6 +589,7 @@ export const {
resetNewVisitedCases,
syncCasesByFallback,
setCasesImageUri,
setSelectedCaseId,
} = allCasesSlice.actions;
export default allCasesSlice.reducer;

View File

@@ -1,28 +1,28 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { useAppDispatch, useAppSelector } from '../../hooks';
import React, { useEffect, useMemo } from 'react';
import { useAppDispatch, useAppSelector } from '@hooks';
import CasesList from './CasesList';
import { RootState } from '../../store/store';
import { initCrashlytics } from '../../components/utlis/firebaseUtils';
import { RootState } from '@store';
import { initCrashlytics } from '@utils/firebaseUtils';
import Layout from '../layout/Layout';
import BottomNavigator, { ITabScreen } from '../../../RN-UI-LIB/src/components/bottomNavigator';
import CasesIcon from '../../../RN-UI-LIB/src/Icons/CasesIcon';
import BottomNavigator, { ITabScreen } from '@rn-ui-lib/components/bottomNavigator';
import CasesIcon from '@rn-ui-lib/icons/CasesIcon';
import Profile from '../Profile';
import ProfileIcon from '../../../RN-UI-LIB/src/Icons/ProfileIcon';
import VisitPlanIcon from '../../../RN-UI-LIB/src/Icons/VisitPlanIcon';
import ProfileIcon from '@rn-ui-lib/icons/ProfileIcon';
import VisitPlanIcon from '@rn-ui-lib/icons/VisitPlanIcon';
import CasesActionButtons from './CasesActionButtons';
import FullScreenLoaderWrapper from '../../common/FullScreenLoaderWrapper';
import { getCurrentScreen } from '../../components/utlis/navigationUtlis';
import FullScreenLoader from '@rn-ui-lib/components/FullScreenLoader';
import { getCurrentScreen } from '@utils/navigationUtlis';
import {
resetSelectedTodoList,
resetTodoList,
setLoading,
setVisitPlansUpdating,
} from '../../reducer/allCasesSlice';
import { addClickstreamEvent } from '../../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
} from '@reducers/allCasesSlice';
import { addClickstreamEvent } from '@services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
import { BOTTOM_TAB_ROUTES } from './constants';
import { getSelfieDocument } from '../../action/profileActions';
import ErrorBoundary from '../../common/ErrorBoundary';
import { getSelfieDocument } from '@actions/profileActions';
import FullScreenLoaderWrapper from '@common/FullScreenLoaderWrapper';
const AllCasesMain = () => {
const { pendingList, pinnedList, completedList, loading } = useAppSelector(

View File

@@ -23,6 +23,7 @@ import {
} from '../../components/utlis/DeviceUtils';
import { getAppVersion, getPhoneNumberString } from '../../components/utlis/commonFunctions';
import AnswerRender from '../../components/form/AnswerRender';
import useScreenshotTracking from '../../hooks/useScreenshotTracking';
const AuthRouter = () => {
const dispatch = useAppDispatch();
@@ -98,6 +99,7 @@ const AuthRouter = () => {
// Firebase cloud messaging listener
useFCM();
useScreenshotTracking();
return isLoggedIn ? (
<TrackingComponent>

View File

@@ -42,6 +42,7 @@ import { getLoanAccountNumber } from '../../components/utlis/commonFunctions';
import EmiBreakupBottomSheet from '../emiSchedule/EmiBreakupBottomSheet';
import { CollectionCaseWidgetId } from '../../types/template.types';
import { useIsFocused } from '@react-navigation/native';
import { setSelectedCaseId } from '../../reducer/allCasesSlice';
interface ICaseDetails {
route: {
@@ -78,6 +79,14 @@ const CollectionCaseDetails: React.FC<ICaseDetails> = (props) => {
},
} = props;
useEffect(() => {
if (caseId) dispatch(setSelectedCaseId(caseId));
return () => {
dispatch(setSelectedCaseId(''));
};
}, [caseId]);
const dispatch = useAppDispatch();
const isFocused = useIsFocused();
const isOnline = useIsOnline();

View File

@@ -0,0 +1,37 @@
import remoteConfig from '@react-native-firebase/remote-config';
import {
setActivityTimeOnApp,
setActivityTimeWindowHigh,
setActivityTimeWindowMedium,
} from '../common/AgentActivityConfigurableConstants';
const FIREBASE_FETCH_TIME = 15 * 60;
async function handleUpdatedConfigureValuesFromFirebase() {
await remoteConfig().fetch(FIREBASE_FETCH_TIME); //15 minutes
remoteConfig()
.activate()
.then((fetchedRemotely) => {
if (fetchedRemotely) {
console.log('Configs were fetched.');
} else {
console.log('No configs were fetched.');
}
})
.catch((error) => {
console.error(error);
})
.finally(() => {
const ACTIVITY_TIME_ON_APP = remoteConfig().getValue('ACTIVITY_TIME_ON_APP').asNumber();
const ACTIVITY_TIME_WINDOW_HIGH = remoteConfig()
.getValue('ACTIVITY_TIME_WINDOW_HIGH')
.asNumber();
const ACTIVITY_TIME_WINDOW_MEDIUM = remoteConfig()
.getValue('ACTIVITY_TIME_WINDOW_MEDIUM')
.asNumber();
setActivityTimeOnApp(ACTIVITY_TIME_ON_APP);
setActivityTimeWindowHigh(ACTIVITY_TIME_WINDOW_HIGH);
setActivityTimeWindowMedium(ACTIVITY_TIME_WINDOW_MEDIUM);
});
}
export default handleUpdatedConfigureValuesFromFirebase;

View File

@@ -0,0 +1,5 @@
export enum AgentActivity {
HIGH = 'HIGH',
MEDIUM = 'MEDIUM',
LOW = 'LOW',
}

View File

@@ -2,4 +2,6 @@ export enum StorageKeys {
APP_FOREGROUND_TIMESTAMP = 'appForegroundTimestamp',
APP_BACKGROUND_TIMESTAMP = 'appBackgroundTimestamp',
IS_USER_ACTIVE = 'isUserActive',
USER_ACTIVITY_ON_APP = 'userActivityOnApp',
STATE_SET_TIMESTAMP = 'stateSetTimestamp',
}

View File

@@ -5,9 +5,34 @@
/* Visit https://aka.ms/tsconfig.json to read more about this file */
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["dom","es5","es2020"],
"lib": [
"dom",
"es5",
"es2020"
],
/* Completeness */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
"baseUrl": ".",
"paths": {
"@root/*": ["."],
"@components/*": ["src/components/*"],
"@hooks": ["src/hooks/index"],
"@hooks/*": ["src/hooks/*"],
"@actions/*": ["src/action/*"],
"@reducers/*": ["src/reducer/*"],
"@constants/*": ["src/constants/*"],
"@screens/*": ["src/screens/*"],
"@services/*": ["src/services/*"],
"@types/*": ["src/types/*"],
"@common/*": ["src/common/*"],
"@assets/*": ["src/assets/*"],
"@store": ["src/store/store"],
"@utils/*": ["src/components/utlis/*"],
"@rn-ui-lib/components/*": ["RN-UI-LIB/src/components/*"],
"@rn-ui-lib/icons/*": ["RN-UI-LIB/src/Icons/*"],
"@rn-ui-lib/styles": ["RN-UI-LIB/src/styles/index"],
"@rn-ui-lib/colors": ["RN-UI-LIB/src/styles/colors"],
"@rn-ui-lib/utils/*": ["RN-UI-LIB/src/utlis/*"],
}
},
}

View File

@@ -1648,6 +1648,11 @@
resolved "https://registry.yarnpkg.com/@react-native-firebase/messaging/-/messaging-17.4.0.tgz#9e1df987183d0ca367d0922a14b14b7a53a140cf"
integrity sha512-RSiBBfyJ3K9G6TQfZc09XaGpxB9xlP5m9DYkqjbNIqnnTiahF90770lTAS65L1Ha78vCwVO2swIlk32XbcMcMQ==
"@react-native-firebase/remote-config@16.4.6":
version "16.4.6"
resolved "https://registry.yarnpkg.com/@react-native-firebase/remote-config/-/remote-config-16.4.6.tgz#dec215f2448f555cdba893a31f5cdf419b47b33e"
integrity sha512-2KPUao9xby+gp+JQUmikx9N0zcCLb0+6GkgI8//sYJ6Z3EaI53kx5kJHJDgYqdjF/zFjv3rm+yhm5LAgARPMHA==
"@react-native-google-signin/google-signin@9.0.2":
version "9.0.2"
resolved "https://registry.yarnpkg.com/@react-native-google-signin/google-signin/-/google-signin-9.0.2.tgz#fd9d0cbb58591265c2ea9404b2d2ea7e514b9ea9"
@@ -7775,6 +7780,11 @@ react-native-pager-view@6.1.2:
resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.1.2.tgz#3522079b9a9d6634ca5e8d153bc0b4d660254552"
integrity sha512-qs2KSFc+7N7B+UZ6SG2sTvCkppagm5fVyRclv1KFKc7lDtrhXLzN59tXJw575LDP/dRJoXsNwqUAhZJdws6ABQ==
react-native-pdf-renderer@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/react-native-pdf-renderer/-/react-native-pdf-renderer-1.1.1.tgz#73a5428c034a7c76bc5fe3435e584cd6493bdfb2"
integrity sha512-XNtSwtMKvH90YcJxZfUu0HRE/DjiXxXIaSa0PCAPPROFOXB5bQPTgZ5n70w98tzjQ5smKMJnMYDFJQV5/pA01w==
react-native-permissions@3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/react-native-permissions/-/react-native-permissions-3.6.1.tgz#73adcc1cef8cd57a9ef167b4507405f4ff5749c4"