NTP-50790| Distance optimization for case listing page (#1145)

This commit is contained in:
Aishwarya Srivastava
2025-04-23 18:40:11 +05:30
committed by GitHub
parent 5437e3dca2
commit fa2089b864
7 changed files with 93 additions and 26 deletions

View File

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

View File

@@ -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<ApiKeys, string> = {} as Record<ApiKeys, string>;
@@ -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,

View File

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

View File

@@ -194,9 +194,9 @@ const ListItem: React.FC<IListItem> = (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 = {

View File

@@ -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<string, number>();
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;
});
};

View File

@@ -383,4 +383,10 @@ export interface ICaseStatus {
export interface IFeedbackStatus{
caseListItemDetailObj: ICaseItemCaseDetailObj;
}
}
export interface ICaseItemLatLongData {
id: string;
latitude: number;
longitude: number;
}

View File

@@ -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<string, CaseDetail>
) => {
try {
const deviceGeolocationCoordinate = store?.getState()?.foregroundService?.deviceGeolocationCoordinate || {};
let caseIdsToDistancesFromCurrentLocationMap: Map<string, number> = 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<string, number> = 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;