Files
address-verification-app/src/hooks/useResyncFirebase.ts
2024-11-20 16:25:11 +05:30

212 lines
7.2 KiB
TypeScript

import firestore from '@react-native-firebase/firestore';
import { useAppDispatch, useAppSelector } from '@hooks';
import store, { type RootState } from '@store';
import { updateCaseDetailsFirestore } from '@reducers/allCasesSlice';
import { CLICKSTREAM_EVENT_NAMES, FirestoreUpdateTypes, SyncedSource } from '@common/Constants';
import axiosInstance, { ApiKeys, getApiUrl } from '@utils/apiHelper';
import { getSyncCaseIds } from '@utils/firebaseFallbackUtils';
import { logError } from '@utils/errorUtils';
import { addClickstreamEvent } from '@services/clickstreamEventService';
import { GenericObject } from '@common/GenericTypes';
import { setLastFirebaseResyncTimestamp } from '@reducers/metadataSlice';
import dayJs from 'dayjs';
import {
getEnableFirestoreResync,
getFirestoreResyncIntervalInMinutes,
} from '@common/AgentActivityConfigurableConstants';
import AsyncStorage from '@react-native-async-storage/async-storage';
const selectedAgentReferenceIDForMyCases = 'MY_CASES';
type CasesToFetchPayload = {
data: {
allocatedCaseIds: string[];
deallocatedCaseIds: string[];
updatedCaseIds: string[];
};
};
const useResyncFirebase = () => {
const dispatch = useAppDispatch();
const refId = store?.getState()?.user?.user?.referenceId || '';
const selectedAgent = store?.getState()?.user?.selectedAgent;
const selectedAgentRefId = store?.getState()?.user?.selectedAgent?.referenceId || '';
const refIdForLoggedInAndSelectedUser =
selectedAgentRefId === selectedAgentReferenceIDForMyCases ? refId : selectedAgentRefId;
const _getCaseDetailsFromApi = async (caseId: string) => {
const getCaseDetailsFromApiUrl = getApiUrl(ApiKeys.GET_CASE_DETAILS_FROM_API_V2, {
caseId: caseId,
});
return axiosInstance.get(getCaseDetailsFromApiUrl, {
params: {
allocatedAgentReferenceId: refIdForLoggedInAndSelectedUser,
},
});
};
const updateCaseInRedux = (
updateType: FirestoreUpdateTypes,
caseDetails: GenericObject,
selectedAgent: GenericObject
) => {
dispatch(
updateCaseDetailsFirestore({
caseUpdates: [
{
updateType: updateType,
updatedCaseDetail: caseDetails,
},
],
isInitialLoad: false,
isVisitPlanLocked: false,
selectedAgent,
})
);
};
return async (): Promise<void> => {
console.log('firebase resync called');
const now = dayJs().toString();
const FIRST_DATE = new Date(1970, 1, 1);
const lastFirebaseResyncTimestamp =
(await AsyncStorage.getItem('lastFirebaseResyncTimestamp')) || dayJs(FIRST_DATE).toString();
const minutesSinceLastResync = dayJs(now).diff(dayJs(lastFirebaseResyncTimestamp), 'minutes');
if (!getEnableFirestoreResync()) {
return;
}
if (minutesSinceLastResync < getFirestoreResyncIntervalInMinutes()) {
return;
}
void addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FIREBASE_RESYNC_STARTED);
const getFirestoreInconsistencyUrl = getApiUrl(ApiKeys.FIRESTORE_INCONSISTENCY_INFO_V2);
const casesList = store?.getState()?.allCases?.casesList || [];
const casesPath = `allocations/${refIdForLoggedInAndSelectedUser}/cases`;
const localCases = getSyncCaseIds(casesList);
const casesToFetch: CasesToFetchPayload = await axiosInstance.post(
getFirestoreInconsistencyUrl,
{
agentId: refIdForLoggedInAndSelectedUser,
cases: localCases,
}
);
const allocatedCases = casesToFetch?.data?.allocatedCaseIds;
const unallocatedCases = casesToFetch?.data?.deallocatedCaseIds;
const updatedCases = casesToFetch?.data?.updatedCaseIds;
allocatedCases.forEach((caseId: string) => {
if (!caseId) {
return null;
}
firestore()
.collection(casesPath)
.doc(caseId.toString())
.get({ source: 'server' })
.then((res) => {
const firebaseCase = res?.data() || {};
if (!firebaseCase?.caseReferenceId) {
throw new Error('could not find case in firebase');
}
dispatch(
updateCaseDetailsFirestore({
caseUpdates: [
{
updateType: FirestoreUpdateTypes.ADDED,
updatedCaseDetail: firebaseCase,
},
],
isInitialLoad: false,
isVisitPlanLocked: false,
selectedAgent,
})
);
void addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FIREBASE_RESYNC, {
added: caseId,
syncedSource: SyncedSource.FIREBASE,
});
})
.catch((err) => {
logError(err as Error, 'Error fetching cases from firestore');
void _getCaseDetailsFromApi(caseId).then((res: { data: GenericObject }) => {
const caseDetails = res?.data;
updateCaseInRedux(FirestoreUpdateTypes.ADDED, caseDetails, selectedAgent);
void addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FIREBASE_RESYNC, {
updated: caseId,
syncedSource: SyncedSource.API,
});
});
});
});
unallocatedCases.forEach((caseId: string) => {
if (!caseId) {
return null;
}
dispatch(
updateCaseDetailsFirestore({
caseUpdates: [
{
updateType: FirestoreUpdateTypes.REMOVED,
updatedCaseDetail: {
caseType: '',
caseReferenceId: caseId,
id: '',
pinRank: '',
caseViewCreatedAt: '',
},
},
],
isInitialLoad: false,
isVisitPlanLocked: false,
selectedAgent,
})
);
void addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FIREBASE_RESYNC, { deleted: caseId });
});
updatedCases.forEach((caseId: string) => {
if (!caseId) {
return null;
}
firestore()
.collection(casesPath)
.doc(caseId.toString())
.get({ source: 'server' })
.then((res) => {
const firebaseCase = res?.data() || {};
if (!firebaseCase?.caseReferenceId) {
throw new Error('could not find case in firebase');
}
updateCaseInRedux(FirestoreUpdateTypes.MODIFIED, firebaseCase, selectedAgent);
void addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FIREBASE_RESYNC, {
updated: caseId,
syncedSource: SyncedSource.FIREBASE,
});
})
.catch((err) => {
void _getCaseDetailsFromApi(caseId).then((res: { data: GenericObject }) => {
const caseDetails = res?.data || {};
updateCaseInRedux(FirestoreUpdateTypes.MODIFIED, caseDetails, selectedAgent);
void addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FIREBASE_RESYNC, {
updated: caseId,
syncedSource: SyncedSource.API,
});
});
logError(err as Error, 'Error fetching cases from firestore');
console.log('cases err:', err);
});
});
dispatch(setLastFirebaseResyncTimestamp(dayJs().toString()));
await AsyncStorage.setItem('lastFirebaseResyncTimestamp', dayJs().toString());
await Promise.resolve();
};
};
export default useResyncFirebase;