Merge pull request #576 from navi-medici/agent-activity

TP-38613 | Added LOW, MEDIUM HIGH based on agent activity
This commit is contained in:
Aman Chaturvedi
2023-09-28 00:16:39 +05:30
committed by GitHub
11 changed files with 222 additions and 45 deletions

16
App.tsx
View File

@@ -23,7 +23,7 @@ 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,8 +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 handleUpdatedConfigureValuesFromFirebase from './src/services/firebaseFetchAndUpdate.service';
import { addClickstreamEvent } from './src/services/clickstreamEventService';
initSentry();
@@ -103,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({
@@ -128,6 +139,9 @@ function App() {
setIsGlobalDocumentMapLoaded(true);
})();
checkCodePushAndSync();
handleUpdatedConfigureValuesFromFirebase();
setForegroundTimeStampAndClickstream();
return () => {
appStateChange.remove();
};

View File

@@ -1,39 +1,40 @@
{
"project_info": {
"project_number": "60755663443",
"project_id": "address-verification-app",
"storage_bucket": "address-verification-app.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:60755663443:android:988149d3da3c00d38584a6",
"android_client_info": {
"package_name": "com.avapp"
}
},
"oauth_client": [
{
"client_id": "60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyA70_d2M2ke-Mu0OHGZ6iZilBbD6A-_z0c"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com",
"client_type": 3
}
]
}
"project_info": {
"project_number": "60755663443",
"project_id": "address-verification-app",
"storage_bucket": "address-verification-app.appspot.com",
"firebase_url": "https://address-verification-app-default-rtdb.firebaseio.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:60755663443:android:4a948ee9d0b4e3098584a6",
"android_client_info": {
"package_name": "com.avapp"
}
},
"oauth_client": [
{
"client_id": "60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyA70_d2M2ke-Mu0OHGZ6iZilBbD6A-_z0c"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
],
"configuration_version": "1"
}
}
],
"configuration_version": "1"
}

View File

@@ -37,6 +37,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",

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

@@ -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

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

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

@@ -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"