Files
address-verification-app/src/common/TrackingComponent.tsx
Aman Chaturvedi c06aa33507 Merge pull request #435 from medici/feat/tp-29659
visit plan automation(phase-1) | tp-29659 | Aman Sethi
2023-06-07 10:09:49 +05:30

177 lines
5.5 KiB
TypeScript

import { ReactNode, useEffect, useRef } from 'react';
import UnstoppableService, {
IForegroundTask,
} from '../services/foregroundServices/foreground.service';
import useIsOnline from '../hooks/useIsOnline';
import { getSyncTime, sendLocationToServer } from '../hooks/capturingApi';
import { isTimeDifferenceWithinRange } from '../components/utlis/commonFunctions';
import { setIsTimeSynced } from '../reducer/foregroundServiceSlice';
import { CaptureGeolocation } from '../components/form/services/geoLocation.service';
import { AppState, AppStateStatus } from 'react-native';
import { logError } from '../components/utlis/errorUtils';
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';
import { VisitPlanStatus, setLockData } from '../reducer/userSlice';
export enum FOREGROUND_TASKS {
GEOLOCATION = 'GEOLOCATION',
TIME_SYNC = 'TIME_SYNC',
DATA_SYNC = 'DATA_SYNC',
FIRESTORE_FALLBACK = 'FIRESTORE_FALLBACK',
}
interface ITrackingComponent {
children?: ReactNode;
}
let MAX_BG_TRACKING_WINDOW = 1000 * 60 * 10; //10 mins;
const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
const isOnline = useIsOnline();
const dispatch = useAppDispatch();
const appState = useRef(AppState.currentState);
const bgTrackingTimeoutId = useRef<number>();
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();
if (timestamp) {
const isTimeDifferenceLess = isTimeDifferenceWithinRange(timestamp, 5);
dispatch(setIsTimeSynced(isTimeDifferenceLess));
}
} catch (e: any) {
logError(e, 'Error during fetching timestamp from server.');
}
};
const handleSendGeolocation = async () => {
try {
const location = await CaptureGeolocation.fetchLocation(Date.now() + '', 0, appState.current);
if (location && user.isLoggedIn) {
await sendLocationToServer(location);
}
} catch (e: any) {
logError(e, 'Error during background location sending.');
}
};
const handleGetCaseSyncStatus = async () => {
try {
const { syncStatus, visitPlanStatus } = (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));
}
}
if (visitPlanStatus) {
dispatch(
setLockData({
visitPlanStatus,
})
);
}
} catch (e) {
logError(e as Error, 'Error during fetching case sync status');
}
};
const tasks: IForegroundTask[] = [
{
taskId: FOREGROUND_TASKS.TIME_SYNC,
task: handleTimeSync,
delay: 5 * MILLISECONDS_IN_A_MINUTE, // 5 minutes,
onLoop: true,
},
{
taskId: FOREGROUND_TASKS.GEOLOCATION,
task: handleSendGeolocation,
delay: 3 * MILLISECONDS_IN_A_MINUTE, // 3 minutes
onLoop: true,
},
{
taskId: FOREGROUND_TASKS.FIRESTORE_FALLBACK,
task: handleGetCaseSyncStatus,
delay: 5 * MILLISECONDS_IN_A_MINUTE, // 5 minutes
onLoop: true,
},
];
if (IS_DATA_SYNC_REQUIRED) {
tasks.push({
taskId: FOREGROUND_TASKS.DATA_SYNC,
task: dataSyncService,
delay: DATA_SYNC_TIME_INTERVAL,
onLoop: true,
});
}
const handleAppStateChange = async (nextAppState: AppStateStatus) => {
// App comes to foreground from background
if (nextAppState === 'active') {
handleGetCaseSyncStatus();
UnstoppableService.start(tasks);
if (bgTrackingTimeoutId.current) {
clearTimeout(bgTrackingTimeoutId.current);
}
}
// App goes to background from foreground
if (appState.current === 'active' && nextAppState.match(/inactive|background/)) {
if (UnstoppableService.isRunning()) {
bgTrackingTimeoutId.current = setTimeout(
() => UnstoppableService.stopAll(),
MAX_BG_TRACKING_WINDOW
);
}
}
appState.current = nextAppState;
};
useEffect(() => {
if (isOnline) {
AppState.addEventListener('change', handleAppStateChange);
} else {
if (UnstoppableService.isRunning()) {
UnstoppableService.stopAll();
}
}
}, [isOnline]);
useIsLocationEnabled();
return <>{children}</>;
};
export default TrackingComponent;