From fa2089b8646398bb2c5cd1c2b67fd64e6a9f940e Mon Sep 17 00:00:00 2001 From: Aishwarya Srivastava Date: Wed, 23 Apr 2025 18:40:11 +0530 Subject: [PATCH] NTP-50790| Distance optimization for case listing page (#1145) --- src/common/Constants.ts | 1 + src/components/utlis/apiHelper.ts | 4 +- src/screens/allCases/CaseItem/CaseStatus.tsx | 4 +- src/screens/allCases/ListItem.tsx | 4 +- src/screens/allCases/allCasesActions.ts | 27 ++++++++ src/screens/allCases/interface.ts | 8 ++- src/screens/allCases/utils.ts | 71 ++++++++++++++------ 7 files changed, 93 insertions(+), 26 deletions(-) create mode 100644 src/screens/allCases/allCasesActions.ts diff --git a/src/common/Constants.ts b/src/common/Constants.ts index 5884615d..9fa62445 100644 --- a/src/common/Constants.ts +++ b/src/common/Constants.ts @@ -1674,6 +1674,7 @@ export const REQUEST_TO_UNBLOCK_FOR_IMPERSONATION = [ getApiUrl(ApiKeys.LOGOUT), getApiUrl(ApiKeys.PAST_FEEDBACK), getApiUrl(ApiKeys.GET_CSA_TICKETS), + getApiUrl(ApiKeys.GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION), ]; export const NAVI_AGENCY_CODE = '1000'; diff --git a/src/components/utlis/apiHelper.ts b/src/components/utlis/apiHelper.ts index e7f30cf1..f508e4b4 100644 --- a/src/components/utlis/apiHelper.ts +++ b/src/components/utlis/apiHelper.ts @@ -119,7 +119,8 @@ export enum ApiKeys { GET_FEEDBACK_ADDRESSES = 'GET_FEEDBACK_ADDRESSES', GET_TRAINING_MATERIAL_LIST = 'GET_TRAINING_MATERIAL_LIST', GET_TRAINING_MATERIAL_DETAILS = 'GET_TRAINING_MATERIAL_DETAILS', - SELF_CALL_ACK= '/api/v1/self-call' + SELF_CALL_ACK= '/api/v1/self-call', + GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION = "GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION" } export const API_URLS: Record = {} as Record; @@ -228,6 +229,7 @@ API_URLS[ApiKeys.GET_TRAINING_MATERIAL_DETAILS] = '/training-page/{docRefId}'; API_URLS[ApiKeys.SELF_CALL_ACK] = '/sync-data/self-call-metadata'; API_URLS[ApiKeys.GET_TOP_ADDRESSES] = '/collection-cases/unified-locations'; API_URLS[ApiKeys.GET_FEEDBACK_ADDRESSES] = '/collection-cases/unified-locations/lite'; +API_URLS[ApiKeys.GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION] = '/geolocation-distance/single-source' export const API_STATUS_CODE = { OK: 200, diff --git a/src/screens/allCases/CaseItem/CaseStatus.tsx b/src/screens/allCases/CaseItem/CaseStatus.tsx index fff0c925..16cab586 100644 --- a/src/screens/allCases/CaseItem/CaseStatus.tsx +++ b/src/screens/allCases/CaseItem/CaseStatus.tsx @@ -13,10 +13,10 @@ const CaseStatus = (props: ICaseStatus) => { const { caseListItemDetailObj, isVisitPlan } = props; const { collectionTag, paymentStatus, caseReferenceId } = caseListItemDetailObj || {}; const distanceMapOfNearbyCases = - useAppSelector((state) => state.nearbyCasesSlice.caseReferenceIdToDistanceMap) || {}; + useAppSelector((state) => state.nearbyCasesSlice.caseReferenceIdToDistanceMap) || new Map(); const selectedTab = useAppSelector((state) => state?.nearbyCasesSlice?.sortTabSelected); - const distanceOfCaseItem = distanceMapOfNearbyCases.get(caseReferenceId); + const distanceOfCaseItem = distanceMapOfNearbyCases?.get(caseReferenceId); const isNearestCaseView = selectedTab === TABS_KEYS.NEAREST_CASE; return ( diff --git a/src/screens/allCases/ListItem.tsx b/src/screens/allCases/ListItem.tsx index ce71b783..6baa9cd9 100644 --- a/src/screens/allCases/ListItem.tsx +++ b/src/screens/allCases/ListItem.tsx @@ -194,9 +194,9 @@ const ListItem: React.FC = (props) => { const is1To30FieldAgent = useAppSelector((state) => state.user?.is1To30FieldAgent); const distanceMapOfNearbyCases = - useAppSelector((state) => state.nearbyCasesSlice.caseReferenceIdToDistanceMap) || {}; + useAppSelector((state) => state.nearbyCasesSlice.caseReferenceIdToDistanceMap) || new Map(); const selectedTab = useAppSelector((state) => state?.nearbyCasesSlice?.sortTabSelected); - const distanceOfCaseItem = distanceMapOfNearbyCases.get(caseListItemDetailObj?.caseReferenceId); + const distanceOfCaseItem = distanceMapOfNearbyCases?.get(caseListItemDetailObj?.caseReferenceId); const isNearestCaseView = selectedTab === TABS_KEYS.NEAREST_CASE; const showInVisitPlanTag = isCaseItemPinnedMainView && !caseCompleted; const widthStyle = { diff --git a/src/screens/allCases/allCasesActions.ts b/src/screens/allCases/allCasesActions.ts new file mode 100644 index 00000000..4cce9f54 --- /dev/null +++ b/src/screens/allCases/allCasesActions.ts @@ -0,0 +1,27 @@ +import axiosInstance, { API_STATUS_CODE, ApiKeys, getApiUrl } from '@components/utlis/apiHelper'; +import { logError } from '@components/utlis/errorUtils'; +import { ICaseItemLatLongData } from './interface'; + +export const getGeolocationDistance = (payload: { + source: ICaseItemLatLongData; + destinations: ICaseItemLatLongData[]; +}) => { + const url = getApiUrl(ApiKeys.GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION); + const caseIdsToCaseItemLatLongDataMap = new Map(); + return axiosInstance + .post(url, payload) + .then((res) => { + if (res?.status === API_STATUS_CODE.OK) { + const response = res?.data?.destinationDistances; + for (const caseId in response) { + const distanceInKm = response[caseId]?.distanceInMetres * 0.001; //To convert m into km + caseIdsToCaseItemLatLongDataMap.set(caseId, distanceInKm); + } + return caseIdsToCaseItemLatLongDataMap; + } + return caseIdsToCaseItemLatLongDataMap; + }) + .catch((err) => { + return caseIdsToCaseItemLatLongDataMap; + }); +}; diff --git a/src/screens/allCases/interface.ts b/src/screens/allCases/interface.ts index 6fa9dfba..b5774ff7 100644 --- a/src/screens/allCases/interface.ts +++ b/src/screens/allCases/interface.ts @@ -383,4 +383,10 @@ export interface ICaseStatus { export interface IFeedbackStatus{ caseListItemDetailObj: ICaseItemCaseDetailObj; -} \ No newline at end of file +} + +export interface ICaseItemLatLongData { + id: string; + latitude: number; + longitude: number; +} diff --git a/src/screens/allCases/utils.ts b/src/screens/allCases/utils.ts index 42e18ce2..22312bd3 100644 --- a/src/screens/allCases/utils.ts +++ b/src/screens/allCases/utils.ts @@ -16,7 +16,7 @@ import { NEARBY_CASES_THRESHOLD_DISTANCE, ToastMessages, } from './constants'; -import { ICaseItem, IReportee, ISectionListData } from './interface'; +import { ICaseItem, ICaseItemLatLongData, IReportee, ISectionListData } from './interface'; import store, { AppDispatch } from '@store'; import { setCaseReferenceIdToDistanceMap, @@ -31,6 +31,7 @@ import { useWindowDimensions } from 'react-native'; import { toast } from '@rn-ui-lib/components/toast'; import { TagVariant } from '@rn-ui-lib/components/Tag'; import { COLORS } from '@rn-ui-lib/colors'; +import { getGeolocationDistance } from './allCasesActions'; export const getAttemptedList = ( filteredCasesList: ICaseItem[], @@ -92,7 +93,7 @@ export const sectionListTranformData = (agentList: IReportee[]): ISectionListDat }; export const getAddressLocation = (address?: IGeolocationCoordinate) => { - if(address?.latitude && address?.longitude) { + if (address?.latitude && address?.longitude) { return address; } return null; @@ -184,33 +185,53 @@ export const handleCheckAndUpdatePullToRefreshStateForNearbyCases = () => { return false; }; -export const updateNearbyCasesListAndLocation = ( +export const updateNearbyCasesListAndLocation = async ( allCasesList: ICaseItem[], caseDetails: Record ) => { try { - const deviceGeolocationCoordinate = store?.getState()?.foregroundService?.deviceGeolocationCoordinate || {}; - let caseIdsToDistancesFromCurrentLocationMap: Map = new Map(); + const deviceGeolocationCoordinate = + store?.getState()?.foregroundService?.deviceGeolocationCoordinate || {}; + const agentId = store?.getState()?.user?.user?.referenceId!; + const source = { + id: agentId, + latitude: deviceGeolocationCoordinate?.latitude, + longitude: deviceGeolocationCoordinate?.longitude, + }; + const destinations: ICaseItemLatLongData[] = []; allCasesList?.forEach((pinnedId) => { const caseDetail = caseDetails?.[pinnedId?.caseReferenceId] || {}; const addressLocation = getAddressLocation(caseDetail?.addressLocation); if (addressLocation) { - const distanceInKm = getDistanceFromLatLonInKm( - addressLocation, - deviceGeolocationCoordinate - ); - if (distanceInKm) { - caseIdsToDistancesFromCurrentLocationMap?.set(pinnedId?.caseReferenceId, distanceInKm); - } + destinations.push({ + id: caseDetail?.caseReferenceId, + latitude: addressLocation?.latitude, + longitude: addressLocation?.longitude, + }); } }); + let caseIdsToDistancesFromCurrentLocationMap: Map = new Map(); + caseIdsToDistancesFromCurrentLocationMap = await getGeolocationDistance({ + source, + destinations, + }); const casesListCopy = [...allCasesList]; + if ( + !caseIdsToDistancesFromCurrentLocationMap || + caseIdsToDistancesFromCurrentLocationMap?.size === 0 + ) { + destinations?.forEach((destination) => { + const distanceInKm = getDistanceFromLatLonInKm(destination, deviceGeolocationCoordinate); + if (distanceInKm) { + caseIdsToDistancesFromCurrentLocationMap?.set(destination?.id, distanceInKm); + } + }); + } casesListCopy.sort((a, b) => { - const distanceA = caseIdsToDistancesFromCurrentLocationMap.get(a.caseReferenceId) ?? 0; - const distanceB = caseIdsToDistancesFromCurrentLocationMap.get(b.caseReferenceId) ?? 0; + const distanceA = caseIdsToDistancesFromCurrentLocationMap?.get(a.caseReferenceId) ?? 0; + const distanceB = caseIdsToDistancesFromCurrentLocationMap?.get(b.caseReferenceId) ?? 0; return distanceA - distanceB; }); - store.dispatch(setNearbyCasesList(casesListCopy)); store.dispatch(setLocationNearbyCasesListUpdated(deviceGeolocationCoordinate)); store.dispatch(setIsPullToRefreshNearbyCasesVisible(false)); @@ -237,7 +258,12 @@ export const getCustomerDocuments = async ( const transformedData = {}; Object.keys(data ?? {}).forEach((categoryKey) => { const categoryData = data[categoryKey]; - const documentsArray = categoryData?.documentsData?.map((documentItem: IDocumentItem) => ({...documentItem, unsignedUri: documentItem?.unSignedUri,})); + const documentsArray = categoryData?.documentsData?.map( + (documentItem: IDocumentItem) => ({ + ...documentItem, + unsignedUri: documentItem?.unSignedUri, + }) + ); transformedData[categoryKey] = { tabName: categoryData?.tabName, tabKey: categoryKey, @@ -292,11 +318,16 @@ export const sendCommunicationViaNaviAccount = async ( phoneNumberRefId: string, communicationChannel: string ) => { - const url = getApiUrl(ApiKeys.SEND_COMMUNICATION_NAVI_ACCOUNT, {loanAccountNumber}); + const url = getApiUrl(ApiKeys.SEND_COMMUNICATION_NAVI_ACCOUNT, { loanAccountNumber }); const response = await axiosInstance - .post(url, { documentType, language: language ? language : 'ENGLISH', phoneNumberRefId, communicationChannel }) + .post(url, { + documentType, + language: language ? language : 'ENGLISH', + phoneNumberRefId, + communicationChannel, + }) .then((res) => { - if(res.status === API_STATUS_CODE.OK) { + if (res.status === API_STATUS_CODE.OK) { toast({ type: 'success', text1: ToastMessages.WHATSAPP_SHARE_SUCCESS, @@ -315,7 +346,7 @@ export const sendCommunicationViaNaviAccount = async ( }); logError(err); }); -} +}; export const calculateBottomSheetHeight = (rowLength = 0) => { const rowHeight = 48;