TP-31303|master back merge|Aman Singh
This commit is contained in:
55
App.tsx
55
App.tsx
@@ -1,34 +1,34 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
AppState,
|
||||
LogBox,
|
||||
Permission,
|
||||
type Permission,
|
||||
PermissionsAndroid,
|
||||
Platform,
|
||||
StatusBar,
|
||||
} from 'react-native';
|
||||
import { Provider } from 'react-redux';
|
||||
import { init as initApm } from '@cobo/apm-rum-react-native';
|
||||
import store, { persistor } from './src/store/store';
|
||||
import { PersistGate } from 'redux-persist/integration/react';
|
||||
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
import codePush from 'react-native-code-push';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import CodePush from 'react-native-code-push';
|
||||
import store, { persistor } from './src/store/store';
|
||||
|
||||
import { navigationRef } from './src/components/utlis/navigationUtlis';
|
||||
import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader';
|
||||
import { toastConfigs, ToastContainer } from './RN-UI-LIB/src/components/toast';
|
||||
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
import { APM_APP_NAME, APM_BASE_URL, ENV } from './src/constants/config';
|
||||
import { COLORS } from './RN-UI-LIB/src/styles/colors';
|
||||
import codePush from 'react-native-code-push';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { 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';
|
||||
import ErrorBoundary from './src/common/ErrorBoundary';
|
||||
import CodePush from 'react-native-code-push';
|
||||
import { TDocumentObj } from './src/screens/caseDetails/interface';
|
||||
import { type TDocumentObj } from './src/screens/caseDetails/interface';
|
||||
import AuthRouter from './src/screens/auth/AuthRouter';
|
||||
import { initSentry } from './src/components/utlis/sentry';
|
||||
import {
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
import usePolling from './src/hooks/usePolling';
|
||||
import { MILLISECONDS_IN_A_SECOND } from './RN-UI-LIB/src/utlis/common';
|
||||
import { GlobalImageMap, hydrateGlobalImageMap } from './src/common/CachedImage';
|
||||
import analytics from '@react-native-firebase/analytics';
|
||||
|
||||
initSentry();
|
||||
|
||||
@@ -66,9 +67,10 @@ function handleAppStateChange(nextAppState: any) {
|
||||
|
||||
const PERMISSION_CHECK_POLL_INTERVAL = 5 * MILLISECONDS_IN_A_SECOND;
|
||||
|
||||
const App = () => {
|
||||
function App() {
|
||||
const [permissions, setPermissions] = React.useState(true);
|
||||
const [isGlobalDocumentMapLoaded, setIsGlobalDocumentMapLoaded] = React.useState(false);
|
||||
const [routeName, setRouteName] = useState('Unknown');
|
||||
|
||||
const askForPermissions = async () => {
|
||||
const permissionsToRequest = await getPermissionsToRequest();
|
||||
@@ -90,6 +92,17 @@ const App = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const getActiveRouteName = (state) => {
|
||||
if (!state || typeof state.index !== 'number') {
|
||||
return 'Unknown';
|
||||
}
|
||||
const route = state.routes[state.index];
|
||||
if (route.state) {
|
||||
return getActiveRouteName(route.state);
|
||||
}
|
||||
return route?.name || '';
|
||||
};
|
||||
|
||||
usePolling(askForPermissions, PERMISSION_CHECK_POLL_INTERVAL);
|
||||
|
||||
initApm({
|
||||
@@ -123,7 +136,25 @@ const App = () => {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<PersistGate loading={<FullScreenLoader loading />} persistor={persistor}>
|
||||
<NavigationContainer ref={navigationRef}>
|
||||
<NavigationContainer
|
||||
ref={navigationRef}
|
||||
onStateChange={async (state) => {
|
||||
const currentRouteName = getActiveRouteName(state);
|
||||
if (routeName !== currentRouteName) {
|
||||
await analytics().logScreenView({
|
||||
screen_name: currentRouteName,
|
||||
screen_class: currentRouteName,
|
||||
});
|
||||
|
||||
await analytics().logEvent('screen_view', {
|
||||
screen_name: currentRouteName,
|
||||
screen_class: currentRouteName,
|
||||
});
|
||||
|
||||
setRouteName(currentRouteName);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<StatusBar backgroundColor={COLORS.BACKGROUND.INDIGO_DARK} />
|
||||
<SuspenseLoader
|
||||
fallBack={<FullScreenLoader loading />}
|
||||
@@ -137,7 +168,7 @@ const App = () => {
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const AppWithSentry = Sentry.wrap(App);
|
||||
|
||||
|
||||
Submodule RN-UI-LIB updated: 62784ff4f5...3ab183e532
@@ -131,8 +131,8 @@ def reactNativeArchitectures() {
|
||||
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
||||
}
|
||||
|
||||
def VERSION_CODE = 81
|
||||
def VERSION_NAME = "2.3.8"
|
||||
def VERSION_CODE = 83
|
||||
def VERSION_NAME = "2.3.10"
|
||||
|
||||
android {
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
@@ -326,3 +326,4 @@ def isNewArchitectureEnabled() {
|
||||
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
||||
}
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avapp;
|
||||
|
||||
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import com.facebook.react.PackageList;
|
||||
@@ -16,8 +18,12 @@ import com.microsoft.codepush.react.CodePush;
|
||||
import android.database.CursorWindow;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
|
||||
|
||||
|
||||
public class MainApplication extends Application implements ReactApplication {
|
||||
|
||||
|
||||
private final ReactNativeHost mReactNativeHost =
|
||||
new ReactNativeHost(this) {
|
||||
@Override
|
||||
@@ -30,7 +36,6 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
// packages.add(new MyReactNativePackage());
|
||||
packages.add(new DeviceUtilsModulePackage());
|
||||
return packages;
|
||||
}
|
||||
@@ -65,6 +70,9 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
SoLoader.init(this, /* native exopackage */ false);
|
||||
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||
|
||||
|
||||
|
||||
|
||||
// https://github.com/rt2zz/redux-persist/issues/284#issuecomment-1011214066
|
||||
try {
|
||||
Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
"project_info": {
|
||||
"project_number": "60755663443",
|
||||
"project_id": "address-verification-app",
|
||||
"storage_bucket": "address-verification-app.appspot.com"
|
||||
"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:988149d3da3c00d38584a6",
|
||||
"mobilesdk_app_id": "1:60755663443:android:4a948ee9d0b4e3098584a6",
|
||||
"android_client_info": {
|
||||
"package_name": "com.avapp"
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"@react-native-async-storage/async-storage": "1.17.11",
|
||||
"@react-native-clipboard/clipboard": "^1.11.2",
|
||||
"@react-native-community/netinfo": "9.3.7",
|
||||
"@react-native-firebase/analytics": "16.4.6",
|
||||
"@react-native-firebase/app": "16.4.6",
|
||||
"@react-native-firebase/auth": "16.5.0",
|
||||
"@react-native-firebase/crashlytics": "16.5.0",
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import { type AxiosResponse } from 'axios';
|
||||
import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper';
|
||||
import { AppDispatch } from '../store/store';
|
||||
import { IGroupedGeolocationAddressItem } from '../types/addressGeolocation.types';
|
||||
import { type AppDispatch } from '../store/store';
|
||||
import { type IGroupedGeolocationAddressItem } from '../types/addressGeolocation.types';
|
||||
import { setEmiSchedule, setEmiScheduleLoading } from '../reducer/emiScheduleSlice';
|
||||
import { setFeedbackHistory, setFeedbackHistoryLoading } from '../reducer/feedbackHistorySlice';
|
||||
import { setRepayments, setRepaymentsLoading } from '../reducer/repaymentsSlice';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { setAddresses, setAddressLoading } from '../reducer/addressSlice';
|
||||
import { IFeedback } from '../types/feedback.types';
|
||||
import { type IFeedback } from '../types/feedback.types';
|
||||
import { allSettled } from '../components/utlis/commonFunctions';
|
||||
import { GenericType } from '../common/GenericTypes';
|
||||
import { type GenericType } from '../common/GenericTypes';
|
||||
import { addClickstreamEvent } from '../services/clickstreamEventService';
|
||||
import { CLICKSTREAM_EVENT_NAMES } from '../common/Constants';
|
||||
import { PageRouteEnum } from '../screens/auth/ProtectedRouter';
|
||||
import { MILLISECONDS_IN_A_MINUTE, _map } from '../../RN-UI-LIB/src/utlis/common';
|
||||
import { logError } from '../components/utlis/errorUtils';
|
||||
import { IDocument, removeDocumentByQuestionKey } from '../reducer/feedbackImagesSlice';
|
||||
import { type IDocument, removeDocumentByQuestionKey } from '../reducer/feedbackImagesSlice';
|
||||
|
||||
// TODO: Need to add respective interfaces instead of any
|
||||
interface IUnifiedData {
|
||||
addressesAndGeoLocations: IGroupedGeolocationAddressItem;
|
||||
feedbacks: Array<any>;
|
||||
emiSchedule: Array<any>;
|
||||
repayments: Array<any>;
|
||||
feedbacks: any[];
|
||||
emiSchedule: any[];
|
||||
repayments: any[];
|
||||
}
|
||||
|
||||
export interface IUploadImagePayload {
|
||||
@@ -35,6 +35,7 @@ export enum UnifiedCaseDetailsTypes {
|
||||
FEEDBACKS = 'includeFeedbacks',
|
||||
EMI_SCHEDULE = 'includeEmiSchedule',
|
||||
REPAYMENTS = 'includeRepayments',
|
||||
INCLUDE_ADDRESS_FEEDBACK = 'includeAddressFeedback',
|
||||
}
|
||||
|
||||
const initialUrlParams = {
|
||||
@@ -42,6 +43,7 @@ const initialUrlParams = {
|
||||
[UnifiedCaseDetailsTypes.FEEDBACKS]: false,
|
||||
[UnifiedCaseDetailsTypes.EMI_SCHEDULE]: false,
|
||||
[UnifiedCaseDetailsTypes.REPAYMENTS]: false,
|
||||
[UnifiedCaseDetailsTypes.INCLUDE_ADDRESS_FEEDBACK]: false,
|
||||
};
|
||||
|
||||
const setUnifiedDataLoading =
|
||||
@@ -65,13 +67,13 @@ const setUnifiedData =
|
||||
(
|
||||
queryParams: Record<UnifiedCaseDetailsTypes, boolean>,
|
||||
loanAccountNumbers: string[],
|
||||
unifiedPromiseData: PromiseSettledResult<AxiosResponse<IUnifiedData>>[]
|
||||
unifiedPromiseData: Array<PromiseSettledResult<AxiosResponse<IUnifiedData>>>
|
||||
) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
unifiedPromiseData.forEach((promiseResult, index) => {
|
||||
const { status } = promiseResult;
|
||||
if (status === 'fulfilled' && promiseResult.value) {
|
||||
const { addressesAndGeoLocations, feedbacks, emiSchedule, repayments } =
|
||||
const { addressesAndGeoLocations, feedbacks, emiSchedule, repayments, addressFeedbacks } =
|
||||
promiseResult.value.data;
|
||||
const loanAccountNumber = loanAccountNumbers[index];
|
||||
if (queryParams[UnifiedCaseDetailsTypes.EMI_SCHEDULE]) {
|
||||
@@ -93,12 +95,15 @@ const setUnifiedData =
|
||||
if (queryParams[UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS]) {
|
||||
dispatch(setAddresses({ loanAccountNumber, addressesAndGeoLocations }));
|
||||
}
|
||||
if (queryParams[UnifiedCaseDetailsTypes.INCLUDE_ADDRESS_FEEDBACK]) {
|
||||
dispatch(setAddresses({ loanAccountNumber, addressFeedbacks, addressesAndGeoLocations }));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const getCaseUnifiedData =
|
||||
(loanAccountNumbers: string[], infoToGet: Array<UnifiedCaseDetailsTypes>) =>
|
||||
(loanAccountNumbers: string[], infoToGet: UnifiedCaseDetailsTypes[]) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
const queryParams = { ...initialUrlParams };
|
||||
for (const key of infoToGet) {
|
||||
@@ -109,7 +114,7 @@ export const getCaseUnifiedData =
|
||||
requestedEntities: JSON.stringify(infoToGet || []),
|
||||
});
|
||||
dispatch(setUnifiedDataLoading(queryParams, loanAccountNumbers));
|
||||
const promisesList: Promise<AxiosResponse<any, any>>[] = [];
|
||||
const promisesList: Array<Promise<AxiosResponse<any, any>>> = [];
|
||||
loanAccountNumbers.forEach((loanAccountNumber) => {
|
||||
const url = getApiUrl(ApiKeys.CASE_UNIFIED_DETAILS, { loanAccountNumber }, queryParams);
|
||||
const promise = axiosInstance.get(url, {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { IGroupedGeolocationAddressItem } from '../types/addressGeolocation.types';
|
||||
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
||||
import { type IGroupedGeolocationAddressItem } from '../types/addressGeolocation.types';
|
||||
|
||||
interface IAddressState {
|
||||
[loanAccountNumber: string]: {
|
||||
type IAddressState = Record<
|
||||
string,
|
||||
{
|
||||
addressFeedbacks: never[];
|
||||
addressesAndGeoLocations: IGroupedGeolocationAddressItem;
|
||||
isLoading: boolean;
|
||||
timestamp: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
>;
|
||||
|
||||
const initialState: IAddressState = {};
|
||||
|
||||
@@ -16,9 +18,10 @@ const AddressSlice = createSlice({
|
||||
initialState,
|
||||
reducers: {
|
||||
setAddresses: (state, action) => {
|
||||
const { loanAccountNumber, addressesAndGeoLocations } = action.payload;
|
||||
const { loanAccountNumber, addressesAndGeoLocations, addressFeedbacks } = action.payload;
|
||||
state[loanAccountNumber] = {
|
||||
addressesAndGeoLocations,
|
||||
addressFeedbacks: addressFeedbacks || [],
|
||||
timestamp: new Date().toISOString(),
|
||||
isLoading: false,
|
||||
};
|
||||
|
||||
@@ -4,29 +4,39 @@ import Accordion from '../../../RN-UI-LIB/src/components/accordian/Accordian';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import { IAddress, IGroupedAddressesItem } from '../../types/addressGeolocation.types';
|
||||
import { type IAddress, type IGroupedAddressesItem } from '../../types/addressGeolocation.types';
|
||||
import AddressItem from './AddressItem';
|
||||
import { addClickstreamEvent } from '../../services/clickstreamEventService';
|
||||
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
|
||||
import GeolocationItem from './GeolocationItem';
|
||||
import { PageRouteEnum } from '../auth/ProtectedRouter';
|
||||
import { GenericFunctionArgs } from '../../common/GenericTypes';
|
||||
import { type GenericFunctionArgs } from '../../common/GenericTypes';
|
||||
import SimilarAddressItem from './SimilarAddressItem';
|
||||
import filterFarAwayMetaAddresses from './utils/FilterFarAwayMetaAddresses';
|
||||
import filterNearMetaAddresses from './utils/FilterNearMetaAddresses';
|
||||
import { useAppSelector } from '../../hooks';
|
||||
import { MAXIMUM_ALLOWED_DISTANCE_FOR_GROUPED_ADDRESSES } from './constants';
|
||||
|
||||
interface IAddressContainer {
|
||||
groupedAddressList?: IGroupedAddressesItem[];
|
||||
caseId?: string;
|
||||
handlePageRouting?: GenericFunctionArgs;
|
||||
addressFeedbacks?: any;
|
||||
}
|
||||
|
||||
const SeparatorBorderComponent = () => {
|
||||
return <View style={[styles.borderLine, GenericStyles.mv16]}></View>;
|
||||
};
|
||||
function SeparatorBorderComponent() {
|
||||
return <View style={[styles.borderLine, GenericStyles.mv16]} />;
|
||||
}
|
||||
|
||||
const AddressContainer: React.FC<IAddressContainer> = ({
|
||||
groupedAddressList,
|
||||
caseId,
|
||||
handlePageRouting,
|
||||
addressFeedbacks,
|
||||
}) => {
|
||||
const { currentGeolocationCoordinates } = useAppSelector((state) => ({
|
||||
currentGeolocationCoordinates: state.foregroundService?.deviceGeolocationCoordinate,
|
||||
}));
|
||||
const handleOpenOldFeedbacks = (groupedAddress: IGroupedAddressesItem) => {
|
||||
const similarAddressIds = groupedAddress?.similarAddresses?.map((item) => item.id) || [];
|
||||
const commonParams = {
|
||||
@@ -46,51 +56,67 @@ const AddressContainer: React.FC<IAddressContainer> = ({
|
||||
|
||||
return (
|
||||
<View>
|
||||
{groupedAddressList?.map((groupedAddress: IGroupedAddressesItem, index: number) => (
|
||||
<View>
|
||||
<Accordion
|
||||
accordionStyle={[GenericStyles.pv24, GenericStyles.ph16]}
|
||||
accordionHeader={
|
||||
<AddressItem
|
||||
caseId={caseId}
|
||||
key={groupedAddress.metaAddress?.id}
|
||||
addressItem={groupedAddress.metaAddress}
|
||||
isGroupedAddress={true}
|
||||
showRelativeDistance={true}
|
||||
showActionButtons={true}
|
||||
contactabilityStatus={groupedAddress.contactabilityStatus}
|
||||
groupedAddressIdx={index + 1}
|
||||
handleOldFeedbackRouting={() => handleOpenOldFeedbacks(groupedAddress)}
|
||||
handleCloseRouting={() => handlePageRouting?.(PageRouteEnum.ADDRESS_GEO)}
|
||||
/>
|
||||
}
|
||||
onExpanded={(isExpanded) =>
|
||||
handleAccordionExpand(isExpanded, groupedAddress?.metaAddress?.id)
|
||||
}
|
||||
>
|
||||
{groupedAddress?.similarAddresses.length ? (
|
||||
<View>
|
||||
<SeparatorBorderComponent />
|
||||
<Text
|
||||
style={[styles.textContainer, styles.accordionDetailHeading, GenericStyles.pb8]}
|
||||
>
|
||||
Similar addresses
|
||||
</Text>
|
||||
{groupedAddress.similarAddresses.map((similarAddress: IAddress) => (
|
||||
<View style={{ flex: 1 }}>
|
||||
<AddressItem
|
||||
key={similarAddress?.id}
|
||||
addressItem={similarAddress}
|
||||
containerStyle={styles.card}
|
||||
showSource={true}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
) : null}
|
||||
</Accordion>
|
||||
</View>
|
||||
))}
|
||||
{filterNearMetaAddresses({
|
||||
metaAddresses: groupedAddressList,
|
||||
maximumDistance: MAXIMUM_ALLOWED_DISTANCE_FOR_GROUPED_ADDRESSES,
|
||||
currentLocationCoordinates: currentGeolocationCoordinates,
|
||||
})?.map((groupedAddress: IGroupedAddressesItem, index: number) => {
|
||||
const lastFeedbackForAddress = addressFeedbacks.find(
|
||||
(addressFeedback) =>
|
||||
addressFeedback?.addressReferenceId === groupedAddress?.metaAddress?.id
|
||||
);
|
||||
return (
|
||||
<View>
|
||||
<Accordion
|
||||
accordionStyle={[GenericStyles.pv24, GenericStyles.ph16]}
|
||||
isExpansionDisabled={!groupedAddress?.similarAddresses.length}
|
||||
touchableOpacity={0.8}
|
||||
touchableDelay={50}
|
||||
accordionHeader={
|
||||
<AddressItem
|
||||
caseId={caseId}
|
||||
key={groupedAddress.metaAddress?.id}
|
||||
addressItem={groupedAddress.metaAddress}
|
||||
isGroupedAddress
|
||||
showRelativeDistance
|
||||
showActionButtons
|
||||
contactabilityStatus={groupedAddress.contactabilityStatus}
|
||||
groupedAddressIdx={index + 1}
|
||||
handleOldFeedbackRouting={() => {
|
||||
handleOpenOldFeedbacks(groupedAddress);
|
||||
}}
|
||||
handleCloseRouting={() => handlePageRouting?.(PageRouteEnum.ADDRESS_GEO)}
|
||||
lastFeedbackForAddress={lastFeedbackForAddress}
|
||||
/>
|
||||
}
|
||||
onExpanded={(isExpanded) => {
|
||||
handleAccordionExpand(isExpanded, groupedAddress?.metaAddress?.id);
|
||||
}}
|
||||
>
|
||||
{groupedAddress?.similarAddresses.length ? (
|
||||
<View>
|
||||
<SeparatorBorderComponent />
|
||||
<Text
|
||||
style={[styles.textContainer, styles.accordionDetailHeading, GenericStyles.pb8]}
|
||||
>
|
||||
Similar addresses
|
||||
</Text>
|
||||
{groupedAddress.similarAddresses.map((similarAddress: IAddress) => (
|
||||
<View style={{ flex: 1 }}>
|
||||
<SimilarAddressItem
|
||||
key={similarAddress?.id}
|
||||
addressItem={similarAddress}
|
||||
containerStyle={styles.card}
|
||||
showSource
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
) : null}
|
||||
</Accordion>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import React from 'react';
|
||||
import { View, StyleSheet, ViewStyle, TouchableOpacity, ScrollView, Linking } from 'react-native';
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
type ViewStyle,
|
||||
TouchableOpacity,
|
||||
ScrollView,
|
||||
Linking,
|
||||
} from 'react-native';
|
||||
import dayjs from 'dayjs';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import { IAddress, IGeolocationCoordinate } from '../../types/addressGeolocation.types';
|
||||
import { type IAddress, type IGeolocationCoordinate } from '../../types/addressGeolocation.types';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import {
|
||||
@@ -18,10 +26,11 @@ import { updatePreDefinedCaseFormJourney } from '../../reducer/caseReducer';
|
||||
import { getCollectionFeedbackOnAddressPreDefinedJourney } from '../../components/utlis/addressGeolocationUtils';
|
||||
import { _map } from '../../../RN-UI-LIB/src/utlis/common';
|
||||
import { getTemplateRoute, navigateToScreen } from '../../components/utlis/navigationUtlis';
|
||||
import { GenericFunctionArgs } from '../../common/GenericTypes';
|
||||
import { type GenericFunctionArgs } from '../../common/GenericTypes';
|
||||
import { toast } from '../../../RN-UI-LIB/src/components/toast';
|
||||
import { ToastMessages } from '../allCases/constants';
|
||||
import AddressSource from './AddressSource';
|
||||
import relativeDistanceFormatter from './utils/relativeDistanceFormatter';
|
||||
|
||||
interface IAddressItem {
|
||||
addressItem: IAddress;
|
||||
@@ -35,9 +44,10 @@ interface IAddressItem {
|
||||
handleCloseRouting?: GenericFunctionArgs;
|
||||
handleOldFeedbackRouting?: GenericFunctionArgs;
|
||||
showSource?: boolean;
|
||||
lastFeedbackForAddress?: any;
|
||||
}
|
||||
|
||||
const AddressItem = ({
|
||||
function AddressItem({
|
||||
addressItem,
|
||||
containerStyle = {},
|
||||
isGroupedAddress = false,
|
||||
@@ -49,7 +59,8 @@ const AddressItem = ({
|
||||
handleCloseRouting,
|
||||
handleOldFeedbackRouting,
|
||||
showSource = false,
|
||||
}: IAddressItem) => {
|
||||
lastFeedbackForAddress,
|
||||
}: IAddressItem) {
|
||||
const { currentGeolocationCoordinates, prefilledAddressScreenTemplate } = useAppSelector(
|
||||
(state) => ({
|
||||
currentGeolocationCoordinates: state.foregroundService?.deviceGeolocationCoordinate,
|
||||
@@ -72,22 +83,8 @@ const AddressItem = ({
|
||||
addressGeolocationCoordinated
|
||||
);
|
||||
}
|
||||
|
||||
const openGeolocation = () => {
|
||||
const geolocationUrl = getGoogleMapUrl(addressItem?.latitude, addressItem?.longitude);
|
||||
if (!geolocationUrl) {
|
||||
toast({
|
||||
type: 'error',
|
||||
text1: ToastMessages.GEOLOCATION_COORDINATES_INCORRECT,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return Linking.openURL(geolocationUrl);
|
||||
};
|
||||
|
||||
const handleAddFeedback = () => {
|
||||
if (prefilledAddressScreenTemplate) {
|
||||
if (prefilledAddressScreenTemplate != null) {
|
||||
const addressKey = '{{addressReferenceId}}';
|
||||
const { visitedWidgets, widgetContext } = getCollectionFeedbackOnAddressPreDefinedJourney(
|
||||
prefilledAddressScreenTemplate,
|
||||
@@ -104,14 +101,13 @@ const AddressItem = ({
|
||||
})
|
||||
);
|
||||
if (visitedWidgets.length) {
|
||||
_map(visitedWidgets, (visited) =>
|
||||
_map(visitedWidgets, (visited) => {
|
||||
navigateToScreen(getTemplateRoute(visited, CaseAllocationType.COLLECTION_CASE), {
|
||||
caseId: caseId,
|
||||
caseId,
|
||||
journey: TaskTitleUIMapping.COLLECTION_FEEDBACK,
|
||||
handleCloseRouting: handleCloseRouting,
|
||||
})
|
||||
);
|
||||
return;
|
||||
handleCloseRouting,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -132,6 +128,7 @@ const AddressItem = ({
|
||||
<Text
|
||||
style={{
|
||||
color: groupedAddressIdx === 1 ? COLORS.BASE.BLUE : COLORS.TEXT.DARK,
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
>
|
||||
{groupedAddressIdx}
|
||||
@@ -141,62 +138,111 @@ const AddressItem = ({
|
||||
<View
|
||||
style={[styles.container, GenericStyles.columnDirection, containerStyle, , { flex: 1 }]}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
style={[styles.textContainer, styles.cardBoldTitle]}
|
||||
>
|
||||
{sanitizeString([addressItem?.pinCode, addressItem?.city].filter(Boolean).join(', '))}
|
||||
</Text>
|
||||
<View style={[styles.container, GenericStyles.row, { alignItems: 'center' }]}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
style={[styles.textContainer, styles.cardBoldTitle, { fontWeight: 'bold' }]}
|
||||
>
|
||||
{sanitizeString([addressItem?.pinCode, addressItem?.city].filter(Boolean).join(', '))}
|
||||
</Text>
|
||||
<Text numberOfLines={1} ellipsizeMode="tail" style={[GenericStyles.ml4]}>
|
||||
{showRelativeDistance && relativeDistanceBwLatLong ? (
|
||||
<>({relativeDistanceFormatter(relativeDistanceBwLatLong)} km away)</>
|
||||
) : null}
|
||||
</Text>
|
||||
</View>
|
||||
{lastFeedbackForAddress?.feedbackPresent ? (
|
||||
<View style={[styles.container, { marginVertical: 8 }]}>
|
||||
<View>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
style={{
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontSize: 12 }}>Last visit: </Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
fontWeight: 'bold',
|
||||
color: lastFeedbackForAddress?.feedbackColourCode
|
||||
? lastFeedbackForAddress?.feedbackColourCode
|
||||
: COLORS.TEXT.BLACK,
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
{lastFeedbackForAddress?.latestFeedbackStatus || ''}{' '}
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[GenericStyles.row, styles.container]}>
|
||||
<Text style={{ fontSize: 12 }}>Visited on: </Text>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
style={{ fontSize: 12, fontWeight: 'bold' }}
|
||||
>
|
||||
{dayjs(lastFeedbackForAddress?.latestFeedbackTimestamp).format('DD MMM, YYYY')}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
style={{
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontSize: 12 }}>Last visit: </Text>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
style={{ color: '#E92C2C', fontSize: 12, fontWeight: 'bold' }}
|
||||
>
|
||||
Unvisited address
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
{isGroupedAddress && contactabilityStatus ? (
|
||||
<View style={GenericStyles.mv8}>
|
||||
<Tag variant={TagVariant.yellow} text={contactabilityStatus} />
|
||||
</View>
|
||||
) : null}
|
||||
<Text
|
||||
numberOfLines={3}
|
||||
ellipsizeMode="tail"
|
||||
style={[styles.textContainer, styles.cardLightTitle]}
|
||||
>
|
||||
<Text style={[styles.textContainer, styles.cardLightTitle, { color: COLORS.TEXT.BLACK }]}>
|
||||
{sanitizeString(addressItem?.addressText)}
|
||||
</Text>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
style={[styles.textContainer, styles.cardFooterText, GenericStyles.fontSize12]}
|
||||
>
|
||||
{sanitizeString(`${dateFormat(new Date(addressItem?.updatedAt), BUSINESS_DATE_FORMAT)}`)}
|
||||
{showRelativeDistance && relativeDistanceBwLatLong ? (
|
||||
<>
|
||||
<Text style={GenericStyles.tiny}> ● </Text>
|
||||
{!isNaN(relativeDistanceBwLatLong) ? relativeDistanceBwLatLong.toFixed(2) : '--'} km
|
||||
away
|
||||
</>
|
||||
) : null}
|
||||
{showSource ? <AddressSource addressItem={addressItem} /> : null}
|
||||
</Text>
|
||||
|
||||
{showActionButtons ? (
|
||||
<View style={[styles.container, GenericStyles.row, GenericStyles.pt12]}>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
onPress={handleAddFeedback}
|
||||
style={[{ flexBasis: '35%' }]}
|
||||
style={[{ flexBasis: '38%' }]}
|
||||
hitSlop={{ top: 25, bottom: 25, left: 15, right: 15 }}
|
||||
>
|
||||
<Text style={styles.actionBtn}>Add Feedback</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
onPress={handleOldFeedbackRouting}
|
||||
style={[{ flexBasis: '30%' }]}
|
||||
>
|
||||
<Text style={styles.actionBtn}>Old feedbacks</Text>
|
||||
</TouchableOpacity>
|
||||
{lastFeedbackForAddress?.feedbackPresent ? (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
onPress={handleOldFeedbackRouting}
|
||||
style={[{ flexBasis: '38%' }]}
|
||||
hitSlop={{ top: 25, bottom: 25, left: 15, right: 15 }}
|
||||
>
|
||||
<Text style={styles.actionBtn}>Old feedbacks</Text>
|
||||
</TouchableOpacity>
|
||||
) : null}
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Linking, StyleSheet, Text, TextStyle, TouchableOpacity, View } from 'react-native';
|
||||
import { Linking, StyleSheet, Text, type TextStyle, TouchableOpacity, View } from 'react-native';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import {
|
||||
@@ -12,12 +12,16 @@ import {
|
||||
getGoogleMapUrl,
|
||||
sanitizeString,
|
||||
} from '../../components/utlis/commonFunctions';
|
||||
import { IGeoLocation, IGeolocationCoordinate } from '../../types/addressGeolocation.types';
|
||||
import {
|
||||
type IGeoLocation,
|
||||
type IGeolocationCoordinate,
|
||||
} from '../../types/addressGeolocation.types';
|
||||
import { addClickstreamEvent } from '../../services/clickstreamEventService';
|
||||
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
|
||||
import { RootState } from '../../store/store';
|
||||
import { type RootState } from '../../store/store';
|
||||
import { useAppSelector } from '../../hooks';
|
||||
import CustomLocationSmallIcon from '../../assets/icons/CustomLocationSmallIcon';
|
||||
import relativeDistanceFormatter from './utils/relativeDistanceFormatter';
|
||||
|
||||
interface IGeolocationItem {
|
||||
geolocationItem: IGeoLocation;
|
||||
@@ -26,16 +30,16 @@ interface IGeolocationItem {
|
||||
containerStyle?: TextStyle;
|
||||
}
|
||||
|
||||
const SeparatorBorderComponent = () => {
|
||||
return <View style={[styles.borderLine, { marginHorizontal: 16 }]}></View>;
|
||||
};
|
||||
function SeparatorBorderComponent() {
|
||||
return <View style={[styles.borderLine, { marginHorizontal: 16 }]} />;
|
||||
}
|
||||
|
||||
const GeolocationItem = ({
|
||||
function GeolocationItem({
|
||||
geolocationItem,
|
||||
showSeparator = true,
|
||||
highlightIcon = false,
|
||||
containerStyle,
|
||||
}: IGeolocationItem) => {
|
||||
}: IGeolocationItem) {
|
||||
const currentGeolocationCoordinates: IGeolocationCoordinate = useAppSelector(
|
||||
(state: RootState) => state.foregroundService?.deviceGeolocationCoordinate
|
||||
);
|
||||
@@ -53,7 +57,7 @@ const GeolocationItem = ({
|
||||
const locationDate = dateFormat(new Date(geolocationItem?.timestamp), BUSINESS_DATE_FORMAT);
|
||||
const locationTime = dateFormat(new Date(geolocationItem?.timestamp), BUSINESS_TIME_FORMAT);
|
||||
|
||||
const openGeolocation = () => {
|
||||
const openGeolocation = async () => {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VIEW_MAP_GEO_CLICKED, {
|
||||
latitude: geolocationItem.latitude,
|
||||
longitude: geolocationItem.longitude,
|
||||
@@ -61,31 +65,28 @@ const GeolocationItem = ({
|
||||
const geolocationUrl = getGoogleMapUrl(geolocationItem?.latitude, geolocationItem?.longitude);
|
||||
if (!geolocationUrl) return;
|
||||
|
||||
return Linking.openURL(geolocationUrl);
|
||||
return await Linking.openURL(geolocationUrl);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={[GenericStyles.columnDirection, styles.container, containerStyle]}>
|
||||
<View style={[GenericStyles.row]}>
|
||||
{
|
||||
<View
|
||||
style={[
|
||||
styles.iconContainer,
|
||||
{
|
||||
backgroundColor: highlightIcon ? COLORS.BACKGROUND.BLUE : COLORS.BACKGROUND.SILVER,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CustomLocationSmallIcon
|
||||
fillColor={highlightIcon ? COLORS.BASE.BLUE : COLORS.TEXT.LIGHT}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
<View
|
||||
style={[
|
||||
styles.iconContainer,
|
||||
{
|
||||
backgroundColor: highlightIcon ? COLORS.BACKGROUND.BLUE : COLORS.BACKGROUND.SILVER,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CustomLocationSmallIcon
|
||||
fillColor={highlightIcon ? COLORS.BASE.BLUE : COLORS.TEXT.LIGHT}
|
||||
/>
|
||||
</View>
|
||||
<View style={[GenericStyles.columnDirection]}>
|
||||
<View style={[styles.contentContainer]}>
|
||||
<Text style={[styles.titleText, GenericStyles.mb4]}>
|
||||
{!isNaN(relativeDistanceBwLatLong) ? relativeDistanceBwLatLong.toFixed(2) : '--'} km
|
||||
away
|
||||
{relativeDistanceFormatter(relativeDistanceBwLatLong)} km away
|
||||
</Text>
|
||||
<Text style={[styles.textContainer, GenericStyles.mb12]}>
|
||||
{sanitizeString(locationDate)}
|
||||
@@ -105,7 +106,7 @@ const GeolocationItem = ({
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
||||
@@ -137,7 +137,7 @@ const NewAddressContainer: React.FC<INewAddressContainer> = ({ route: routeParam
|
||||
title="House, flat, building"
|
||||
onChangeText={(s) => onChange(s)}
|
||||
onBlur={onBlur}
|
||||
placeholder="Enter here"
|
||||
placeholder="Eg. A-101"
|
||||
value={value}
|
||||
required
|
||||
/>
|
||||
@@ -155,7 +155,7 @@ const NewAddressContainer: React.FC<INewAddressContainer> = ({ route: routeParam
|
||||
title="Street, locality, colony"
|
||||
onChangeText={(s) => onChange(s)}
|
||||
onBlur={onBlur}
|
||||
placeholder="Enter here"
|
||||
placeholder="Eg. Chandni Chowk"
|
||||
value={value}
|
||||
required
|
||||
/>
|
||||
@@ -175,7 +175,7 @@ const NewAddressContainer: React.FC<INewAddressContainer> = ({ route: routeParam
|
||||
maxLength={6}
|
||||
onChangeText={(s) => onChange(s)}
|
||||
onBlur={onBlur}
|
||||
placeholder="Enter here"
|
||||
placeholder="Eg. 110006"
|
||||
value={value}
|
||||
required
|
||||
/>
|
||||
@@ -193,7 +193,7 @@ const NewAddressContainer: React.FC<INewAddressContainer> = ({ route: routeParam
|
||||
title="City"
|
||||
onChangeText={(s) => onChange(s)}
|
||||
onBlur={onBlur}
|
||||
placeholder="Enter here"
|
||||
placeholder="Eg. Delhi"
|
||||
value={value}
|
||||
required
|
||||
/>
|
||||
|
||||
244
src/screens/addressGeolocation/SimilarAddressItem.tsx
Normal file
244
src/screens/addressGeolocation/SimilarAddressItem.tsx
Normal file
@@ -0,0 +1,244 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
type ViewStyle,
|
||||
TouchableOpacity,
|
||||
ScrollView,
|
||||
Linking,
|
||||
} from 'react-native';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import { type IAddress, type IGeolocationCoordinate } from '../../types/addressGeolocation.types';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import {
|
||||
getDistanceFromLatLonInKm,
|
||||
getGoogleMapUrl,
|
||||
sanitizeString,
|
||||
} from '../../components/utlis/commonFunctions';
|
||||
import { BUSINESS_DATE_FORMAT, dateFormat } from '../../../RN-UI-LIB/src/utlis/dates';
|
||||
import { useAppDispatch, useAppSelector } from '../../hooks';
|
||||
import { RootState } from '../../store/store';
|
||||
import Tag, { TagVariant } from '../../../RN-UI-LIB/src/components/Tag';
|
||||
import { CaseAllocationType, TaskTitleUIMapping } from '../allCases/interface';
|
||||
import { updatePreDefinedCaseFormJourney } from '../../reducer/caseReducer';
|
||||
import { getCollectionFeedbackOnAddressPreDefinedJourney } from '../../components/utlis/addressGeolocationUtils';
|
||||
import { _map } from '../../../RN-UI-LIB/src/utlis/common';
|
||||
import { getTemplateRoute, navigateToScreen } from '../../components/utlis/navigationUtlis';
|
||||
import { type GenericFunctionArgs } from '../../common/GenericTypes';
|
||||
import { toast } from '../../../RN-UI-LIB/src/components/toast';
|
||||
import { ToastMessages } from '../allCases/constants';
|
||||
import AddressSource from './AddressSource';
|
||||
|
||||
interface IAddressItem {
|
||||
addressItem: IAddress;
|
||||
containerStyle?: ViewStyle;
|
||||
isGroupedAddress?: boolean;
|
||||
showRelativeDistance?: boolean;
|
||||
showActionButtons?: boolean;
|
||||
contactabilityStatus?: string;
|
||||
groupedAddressIdx?: number;
|
||||
caseId?: string;
|
||||
handleCloseRouting?: GenericFunctionArgs;
|
||||
handleOldFeedbackRouting?: GenericFunctionArgs;
|
||||
showSource?: boolean;
|
||||
}
|
||||
|
||||
function SimilarAddressItem({
|
||||
addressItem,
|
||||
containerStyle = {},
|
||||
isGroupedAddress = false,
|
||||
showActionButtons = false,
|
||||
showRelativeDistance = false,
|
||||
contactabilityStatus = '',
|
||||
groupedAddressIdx = 1,
|
||||
caseId,
|
||||
handleCloseRouting,
|
||||
handleOldFeedbackRouting,
|
||||
showSource = false,
|
||||
}: IAddressItem) {
|
||||
const { currentGeolocationCoordinates, prefilledAddressScreenTemplate } = useAppSelector(
|
||||
(state) => ({
|
||||
currentGeolocationCoordinates: state.foregroundService?.deviceGeolocationCoordinate,
|
||||
prefilledAddressScreenTemplate:
|
||||
state.case.templateData[CaseAllocationType.COLLECTION_CASE]?.prefilledAddressScreenTemplate,
|
||||
})
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
let relativeDistanceBwLatLong = 0;
|
||||
|
||||
if (isGroupedAddress) {
|
||||
const addressGeolocationCoordinated: IGeolocationCoordinate = {
|
||||
latitude: addressItem.latitude,
|
||||
longitude: addressItem.longitude,
|
||||
};
|
||||
relativeDistanceBwLatLong = getDistanceFromLatLonInKm(
|
||||
currentGeolocationCoordinates,
|
||||
addressGeolocationCoordinated
|
||||
);
|
||||
}
|
||||
|
||||
const openGeolocation = async () => {
|
||||
const geolocationUrl = getGoogleMapUrl(addressItem?.latitude, addressItem?.longitude);
|
||||
if (!geolocationUrl) {
|
||||
toast({
|
||||
type: 'error',
|
||||
text1: ToastMessages.GEOLOCATION_COORDINATES_INCORRECT,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return await Linking.openURL(geolocationUrl);
|
||||
};
|
||||
|
||||
const handleAddFeedback = () => {
|
||||
if (prefilledAddressScreenTemplate != null) {
|
||||
const addressKey = '{{addressReferenceId}}';
|
||||
const { visitedWidgets, widgetContext } = getCollectionFeedbackOnAddressPreDefinedJourney(
|
||||
prefilledAddressScreenTemplate,
|
||||
addressKey,
|
||||
addressItem.id
|
||||
);
|
||||
|
||||
dispatch(
|
||||
updatePreDefinedCaseFormJourney({
|
||||
caseId,
|
||||
journeyId: TaskTitleUIMapping.COLLECTION_FEEDBACK,
|
||||
visitedWidgets,
|
||||
widgetContext,
|
||||
})
|
||||
);
|
||||
if (visitedWidgets.length) {
|
||||
_map(visitedWidgets, (visited) => {
|
||||
navigateToScreen(getTemplateRoute(visited, CaseAllocationType.COLLECTION_CASE), {
|
||||
caseId,
|
||||
journey: TaskTitleUIMapping.COLLECTION_FEEDBACK,
|
||||
handleCloseRouting,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={[GenericStyles.row]}>
|
||||
{isGroupedAddress ? (
|
||||
<View
|
||||
style={[
|
||||
styles.iconContainer,
|
||||
{
|
||||
borderColor: groupedAddressIdx === 1 ? COLORS.BORDER.BLUE_CC : COLORS.BORDER.PRIMARY,
|
||||
backgroundColor:
|
||||
groupedAddressIdx === 1 ? COLORS.BACKGROUND.BLUE : COLORS.BACKGROUND.SILVER,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: groupedAddressIdx === 1 ? COLORS.BASE.BLUE : COLORS.TEXT.DARK,
|
||||
}}
|
||||
>
|
||||
{groupedAddressIdx}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
<View
|
||||
style={[styles.container, GenericStyles.columnDirection, containerStyle, , { flex: 1 }]}
|
||||
>
|
||||
<Text style={[styles.textContainer, styles.cardBoldTitle, { fontWeight: 'bold' }]}>
|
||||
{sanitizeString([addressItem?.pinCode, addressItem?.city].filter(Boolean).join(', '))}
|
||||
</Text>
|
||||
{isGroupedAddress && contactabilityStatus ? (
|
||||
<View style={GenericStyles.mv8}>
|
||||
<Tag variant={TagVariant.yellow} text={contactabilityStatus} />
|
||||
</View>
|
||||
) : null}
|
||||
<Text
|
||||
numberOfLines={3}
|
||||
ellipsizeMode="tail"
|
||||
style={[styles.textContainer, styles.cardLightTitle, { color: COLORS.TEXT.BLACK }]}
|
||||
>
|
||||
{sanitizeString(addressItem?.addressText)}
|
||||
</Text>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
style={[styles.textContainer, styles.cardFooterText, GenericStyles.fontSize12]}
|
||||
>
|
||||
{sanitizeString(`${dateFormat(new Date(addressItem?.updatedAt), BUSINESS_DATE_FORMAT)}`)}
|
||||
{showRelativeDistance && relativeDistanceBwLatLong ? (
|
||||
<>
|
||||
<Text style={GenericStyles.tiny}> ● </Text>
|
||||
{!isNaN(relativeDistanceBwLatLong) ? relativeDistanceBwLatLong.toFixed(2) : '--'} km
|
||||
away
|
||||
</>
|
||||
) : null}
|
||||
{showSource ? <AddressSource addressItem={addressItem} /> : null}
|
||||
</Text>
|
||||
{showActionButtons ? (
|
||||
<View style={[styles.container, GenericStyles.row, GenericStyles.pt12]}>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
onPress={handleAddFeedback}
|
||||
style={[{ flexBasis: '35%' }]}
|
||||
>
|
||||
<Text style={styles.actionBtn}>Add Feedback</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
onPress={handleOldFeedbackRouting}
|
||||
style={[{ flexBasis: '30%' }]}
|
||||
>
|
||||
<Text style={styles.actionBtn}>Old feedbacks</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: COLORS.BACKGROUND.PRIMARY,
|
||||
},
|
||||
textContainer: {
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
},
|
||||
iconContainer: {
|
||||
marginRight: 8,
|
||||
borderRadius: 12.5,
|
||||
width: 25,
|
||||
height: 25,
|
||||
backgroundColor: COLORS.BACKGROUND.GREY_D9,
|
||||
alignItems: 'center',
|
||||
borderWidth: 0.5,
|
||||
},
|
||||
cardBoldTitle: {
|
||||
fontWeight: '500',
|
||||
color: COLORS.TEXT.DARK,
|
||||
},
|
||||
cardLightTitle: {
|
||||
fontWeight: '400',
|
||||
color: '#BCBCBC',
|
||||
},
|
||||
cardFooterText: {
|
||||
fontWeight: '400',
|
||||
color: COLORS.TEXT.LIGHT,
|
||||
},
|
||||
actionBtn: {
|
||||
fontSize: 13,
|
||||
lineHeight: 20,
|
||||
fontWeight: '500',
|
||||
color: COLORS.TEXT.BLUE,
|
||||
},
|
||||
dotStyle: {
|
||||
fontSize: 11,
|
||||
color: COLORS.TEXT.LIGHT,
|
||||
},
|
||||
});
|
||||
|
||||
export default SimilarAddressItem;
|
||||
@@ -5,7 +5,7 @@ import { goBack, navigateToScreen } from '../../components/utlis/navigationUtlis
|
||||
import useIsOnline from '../../hooks/useIsOnline';
|
||||
import OfflineScreen from '../../common/OfflineScreen';
|
||||
import { getUngroupedAddress } from '../../action/addressGeolocationAction';
|
||||
import { IAddress } from '../../types/addressGeolocation.types';
|
||||
import { type IAddress } from '../../types/addressGeolocation.types';
|
||||
import AddressItem from './AddressItem';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import { PageRouteEnum } from '../auth/ProtectedRouter';
|
||||
@@ -16,6 +16,10 @@ import SuspenseLoader from '../../../RN-UI-LIB/src/components/suspense_loader/Su
|
||||
import LineLoader from '../../../RN-UI-LIB/src/components/suspense_loader/LineLoader';
|
||||
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
|
||||
import { addClickstreamEvent } from '../../services/clickstreamEventService';
|
||||
import filterFarAwayMetaAddresses from './utils/FilterFarAwayMetaAddresses';
|
||||
import { useAppSelector } from '../../hooks';
|
||||
import { CaseAllocationType } from '../allCases/interface';
|
||||
import SimilarAddressItem from './SimilarAddressItem';
|
||||
|
||||
const PAGE_TITLE = 'Additional addresses';
|
||||
|
||||
@@ -25,13 +29,14 @@ interface IUngroupedAddress {
|
||||
loanAccountNumber: string;
|
||||
caseId: string;
|
||||
customerReferenceId: string;
|
||||
fetchUngroupedAddress: (lan: string) => Promise<IAddress[]>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const UngroupedAddressContainer: React.FC<IUngroupedAddress> = ({ route: routeParams }) => {
|
||||
const {
|
||||
params: { loanAccountNumber, caseId, customerReferenceId },
|
||||
params: { loanAccountNumber, caseId, customerReferenceId, fetchUngroupedAddress },
|
||||
} = routeParams;
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -47,9 +52,10 @@ const UngroupedAddressContainer: React.FC<IUngroupedAddress> = ({ route: routePa
|
||||
useEffect(() => {
|
||||
if (isOnline) {
|
||||
setLoading(true);
|
||||
getUngroupedAddress(loanAccountNumber)
|
||||
fetchUngroupedAddress(loanAccountNumber)
|
||||
.then((res: IAddress[]) => {
|
||||
setUngroupedAddressList(res);
|
||||
setLoading(true);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
@@ -90,7 +96,7 @@ const UngroupedAddressContainer: React.FC<IUngroupedAddress> = ({ route: routePa
|
||||
<>
|
||||
{[...Array(8).keys()].map(() => (
|
||||
<LineLoader
|
||||
width={'100%'}
|
||||
width="100%"
|
||||
height={75}
|
||||
style={[GenericStyles.br6, { marginBottom: 20 }]}
|
||||
/>
|
||||
@@ -104,16 +110,18 @@ const UngroupedAddressContainer: React.FC<IUngroupedAddress> = ({ route: routePa
|
||||
<View>
|
||||
<AddressItem
|
||||
caseId={caseId}
|
||||
showRelativeDistance={true}
|
||||
showRelativeDistance
|
||||
containerStyle={styles.addressItemContainer}
|
||||
key={ungroupedAddressItem?.id}
|
||||
addressItem={ungroupedAddressItem}
|
||||
showActionButtons={true}
|
||||
handleOldFeedbackRouting={() => handleOpenOldFeedbacks(ungroupedAddressItem)}
|
||||
handleCloseRouting={() =>
|
||||
navigateToScreen(PageRouteEnum.ADDITIONAL_ADDRESSES, commonParams)
|
||||
}
|
||||
showSource={true}
|
||||
showActionButtons
|
||||
handleOldFeedbackRouting={() => {
|
||||
handleOpenOldFeedbacks(ungroupedAddressItem);
|
||||
}}
|
||||
handleCloseRouting={() => {
|
||||
navigateToScreen(PageRouteEnum.ADDITIONAL_ADDRESSES, commonParams);
|
||||
}}
|
||||
showSource
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
|
||||
1
src/screens/addressGeolocation/constants.ts
Normal file
1
src/screens/addressGeolocation/constants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const MAXIMUM_ALLOWED_DISTANCE_FOR_GROUPED_ADDRESSES = 100;
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { SafeAreaView, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import NavigationHeader from '../../../RN-UI-LIB/src/components/NavigationHeader';
|
||||
import { goBack, navigateToScreen } from '../../components/utlis/navigationUtlis';
|
||||
import { useAppDispatch } from '../../hooks';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { RootState } from '../../store/store';
|
||||
import { type RootState } from '../../store/store';
|
||||
import GeolocationContainer from './GeolocationContainer';
|
||||
import AddressContainer from './AddressContainer';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
@@ -23,6 +23,11 @@ import SuspenseLoader from '../../../RN-UI-LIB/src/components/suspense_loader/Su
|
||||
import LineLoader from '../../../RN-UI-LIB/src/components/suspense_loader/LineLoader';
|
||||
import { CaptureGeolocation } from '../../components/form/services/geoLocation.service';
|
||||
import { setDeviceGeolocation } from '../../reducer/foregroundServiceSlice';
|
||||
import Layout from '../layout/Layout';
|
||||
import { getUngroupedAddress } from '../../action/addressGeolocationAction';
|
||||
import { type IAddress } from '../../types/addressGeolocation.types';
|
||||
import filterFarAwayMetaAddresses from './utils/FilterFarAwayMetaAddresses';
|
||||
import { MAXIMUM_ALLOWED_DISTANCE_FOR_GROUPED_ADDRESSES } from './constants';
|
||||
|
||||
const PAGE_TITLE = 'All addresses';
|
||||
|
||||
@@ -41,18 +46,20 @@ const AddressGeolocation: React.FC<IAddressGeolocation> = ({ route: routeParams
|
||||
params: { loanAccountNumber, customerReferenceId, caseId },
|
||||
} = routeParams;
|
||||
|
||||
const [ungroupedAddress, setUngroupedAddress] = useState<IAddress[]>([]);
|
||||
|
||||
const [retryBtnToggle, setRetryBtnToggle] = useState(false);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const isOnline = useIsOnline();
|
||||
|
||||
const { addressGeolocation, isLoading, currentGeolocationCoordinates } = useSelector(
|
||||
(state: RootState) => ({
|
||||
const { addressGeolocation, isLoading, currentGeolocationCoordinates, addressFeedbacks } =
|
||||
useSelector((state: RootState) => ({
|
||||
addressGeolocation: state.address?.[loanAccountNumber]?.addressesAndGeoLocations || {},
|
||||
isLoading: state.address?.[loanAccountNumber]?.isLoading || false,
|
||||
currentGeolocationCoordinates: state.foregroundService?.deviceGeolocationCoordinate || {},
|
||||
})
|
||||
);
|
||||
addressFeedbacks: state.address?.[loanAccountNumber]?.addressFeedbacks || [],
|
||||
}));
|
||||
|
||||
const commonParams = {
|
||||
loanAccountNumber,
|
||||
@@ -73,11 +80,40 @@ const AddressGeolocation: React.FC<IAddressGeolocation> = ({ route: routeParams
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ADD_NEW_ADDRESS_CLICKED, commonParams);
|
||||
};
|
||||
|
||||
const fetchUngroupedAddress = async (loanAccountNumber) =>
|
||||
await getUngroupedAddress(loanAccountNumber).then((res: IAddress[]) => {
|
||||
const farAwayAddresses = filterFarAwayMetaAddresses({
|
||||
metaAddresses: addressGeolocation?.groupedAddresses,
|
||||
maximumDistance: MAXIMUM_ALLOWED_DISTANCE_FOR_GROUPED_ADDRESSES,
|
||||
currentLocationCoordinates: currentGeolocationCoordinates,
|
||||
});
|
||||
const metaAddresses = farAwayAddresses.map((farAwayAddress) => farAwayAddress?.metaAddress);
|
||||
|
||||
setUngroupedAddress([...res, ...metaAddresses]);
|
||||
return [...res, ...metaAddresses];
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
async function getUngroupedAddress() {
|
||||
await fetchUngroupedAddress(loanAccountNumber);
|
||||
return null;
|
||||
}
|
||||
if (addressGeolocation?.groupedAddresses?.length > 0) {
|
||||
getUngroupedAddress();
|
||||
}
|
||||
}, [addressGeolocation?.groupedAddresses, isLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOnline) {
|
||||
dispatch(setAddressLoading({ loanAccountNumbers: [loanAccountNumber], isLoading: true }));
|
||||
dispatch(
|
||||
getCaseUnifiedData([loanAccountNumber], [UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS])
|
||||
getCaseUnifiedData(
|
||||
[loanAccountNumber],
|
||||
[
|
||||
UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS,
|
||||
UnifiedCaseDetailsTypes.INCLUDE_ADDRESS_FEEDBACK,
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}, [retryBtnToggle, isOnline]);
|
||||
@@ -87,9 +123,9 @@ const AddressGeolocation: React.FC<IAddressGeolocation> = ({ route: routeParams
|
||||
|
||||
if (!currentGeolocationCoordinates.latitude || !currentGeolocationCoordinates.longitude) {
|
||||
(async () => {
|
||||
const location = await CaptureGeolocation.fetchLocation(Date.now() + '', 0);
|
||||
const location = await CaptureGeolocation.fetchLocation(`${Date.now()}`, 0);
|
||||
|
||||
if (location) {
|
||||
if (location != null) {
|
||||
dispatch(
|
||||
setDeviceGeolocation({
|
||||
latitude: location.latitude,
|
||||
@@ -109,68 +145,81 @@ const AddressGeolocation: React.FC<IAddressGeolocation> = ({ route: routeParams
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollView>
|
||||
<NavigationHeader title={PAGE_TITLE} onBack={goBack} />
|
||||
<SuspenseLoader
|
||||
loading={isLoading}
|
||||
fallBack={
|
||||
<>
|
||||
{[...Array(8).keys()].map(() => (
|
||||
<LineLoader
|
||||
width={'100%'}
|
||||
height={75}
|
||||
style={[GenericStyles.br6, { marginBottom: 20 }]}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<View>
|
||||
<AddressContainer
|
||||
groupedAddressList={addressGeolocation.groupedAddresses}
|
||||
caseId={caseId}
|
||||
handlePageRouting={handleRouting}
|
||||
/>
|
||||
<View
|
||||
style={[
|
||||
GenericStyles.row,
|
||||
GenericStyles.pv24,
|
||||
GenericStyles.ph16,
|
||||
{ backgroundColor: COLORS.BACKGROUND.PRIMARY },
|
||||
]}
|
||||
<Layout>
|
||||
<SafeAreaView style={[GenericStyles.fill]}>
|
||||
<NavigationHeader title={PAGE_TITLE} onBack={goBack} />
|
||||
<ScrollView>
|
||||
<SuspenseLoader
|
||||
loading={isLoading}
|
||||
fallBack={
|
||||
<>
|
||||
{[...Array(8).keys()].map(() => (
|
||||
<LineLoader
|
||||
width="100%"
|
||||
height={75}
|
||||
style={[GenericStyles.br6, { marginBottom: 20 }]}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<View style={styles.iconContainer}>
|
||||
<HomeIconSmall />
|
||||
</View>
|
||||
<View style={[GenericStyles.columnDirection]}>
|
||||
<View style={[styles.contentContainer]}>
|
||||
<Text style={[styles.titleText, GenericStyles.mb4]}>Additional addresses</Text>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
onPress={() => handleRouting(PageRouteEnum.ADDITIONAL_ADDRESSES)}
|
||||
<View>
|
||||
<AddressContainer
|
||||
groupedAddressList={addressGeolocation.groupedAddresses}
|
||||
addressFeedbacks={addressFeedbacks}
|
||||
caseId={caseId}
|
||||
handlePageRouting={handleRouting}
|
||||
/>
|
||||
{ungroupedAddress?.length > 0 ? (
|
||||
<View
|
||||
style={[
|
||||
GenericStyles.row,
|
||||
GenericStyles.pv24,
|
||||
GenericStyles.ph16,
|
||||
{ backgroundColor: COLORS.BACKGROUND.PRIMARY },
|
||||
]}
|
||||
>
|
||||
<Text style={styles.actionBtn}>View all addresses</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<Text style={[styles.textContainer, GenericStyles.p16]}>User geolocations</Text>
|
||||
<GeolocationContainer geolocationList={addressGeolocation.geoLocations} />
|
||||
<View style={[GenericStyles.p16, styles.btnContainer]}>
|
||||
<Button
|
||||
title="New address"
|
||||
style={GenericStyles.w100}
|
||||
onPress={handleNewAddressCta}
|
||||
leftIcon={
|
||||
<View style={GenericStyles.mr10}>
|
||||
<PlusIcon />
|
||||
<View style={styles.iconContainer}>
|
||||
<HomeIconSmall />
|
||||
</View>
|
||||
<View style={[GenericStyles.columnDirection]}>
|
||||
<View style={[styles.contentContainer]}>
|
||||
<Text style={[styles.titleText, GenericStyles.mb4]}>
|
||||
Additional addresses
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.2}
|
||||
onPress={() => {
|
||||
handleRouting(PageRouteEnum.ADDITIONAL_ADDRESSES, {
|
||||
fetchUngroupedAddress,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Text style={styles.actionBtn}>View all addresses</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
<Text style={[styles.textContainer, GenericStyles.p16]}>User geolocations</Text>
|
||||
<GeolocationContainer geolocationList={addressGeolocation.geoLocations} />
|
||||
</View>
|
||||
</SuspenseLoader>
|
||||
</ScrollView>
|
||||
<View style={[GenericStyles.p16, styles.btnContainer]}>
|
||||
<Button
|
||||
title="New address"
|
||||
style={GenericStyles.w100}
|
||||
onPress={handleNewAddressCta}
|
||||
leftIcon={
|
||||
<View style={GenericStyles.mr10}>
|
||||
<PlusIcon />
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</SuspenseLoader>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { getDistanceFromLatLonInKm } from '../../../components/utlis/commonFunctions';
|
||||
|
||||
interface FilterFarAwayMetaAddressesParams {
|
||||
metaAddresses: any[];
|
||||
maximumDistance: number;
|
||||
currentLocationCoordinates: { latitude: number; longitude: number };
|
||||
}
|
||||
const filterFarAwayMetaAddresses = ({
|
||||
metaAddresses = [],
|
||||
maximumDistance,
|
||||
currentLocationCoordinates,
|
||||
}: FilterFarAwayMetaAddressesParams) =>
|
||||
metaAddresses?.filter((metaAddress) => {
|
||||
const distance = getDistanceFromLatLonInKm(currentLocationCoordinates, {
|
||||
latitude: metaAddress?.metaAddress?.latitude,
|
||||
longitude: metaAddress?.metaAddress?.longitude,
|
||||
});
|
||||
if (distance >= maximumDistance) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
export default filterFarAwayMetaAddresses;
|
||||
@@ -0,0 +1,24 @@
|
||||
import { getDistanceFromLatLonInKm } from '../../../components/utlis/commonFunctions';
|
||||
|
||||
interface FilterNearMetaAddressesParams {
|
||||
metaAddresses: any[];
|
||||
maximumDistance: number;
|
||||
currentLocationCoordinates: { latitude: number; longitude: number };
|
||||
}
|
||||
const filterNearMetaAddresses = ({
|
||||
metaAddresses = [],
|
||||
maximumDistance,
|
||||
currentLocationCoordinates,
|
||||
}: FilterNearMetaAddressesParams) =>
|
||||
metaAddresses?.filter((metaAddress) => {
|
||||
const distance = getDistanceFromLatLonInKm(currentLocationCoordinates, {
|
||||
latitude: metaAddress?.metaAddress?.latitude,
|
||||
longitude: metaAddress?.metaAddress?.longitude,
|
||||
});
|
||||
if (distance <= maximumDistance) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
export default filterNearMetaAddresses;
|
||||
@@ -0,0 +1,13 @@
|
||||
const MAXIMUM_DISTANCE_WITH_DECIMAL = 10;
|
||||
const relativeDistanceFormatter = (relativeDistance: number) => {
|
||||
if (isNaN(relativeDistance)) {
|
||||
return '--';
|
||||
}
|
||||
if (relativeDistance >= MAXIMUM_DISTANCE_WITH_DECIMAL) {
|
||||
return Math.round(relativeDistance, 0);
|
||||
}
|
||||
|
||||
return relativeDistance.toFixed(2);
|
||||
};
|
||||
|
||||
export default relativeDistanceFormatter;
|
||||
@@ -166,10 +166,6 @@ const ListItem: React.FC<IListItem> = (props) => {
|
||||
]
|
||||
);
|
||||
|
||||
if (!isCompleted && caseStatus === CaseStatuses.CLOSED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isCaseItemPinnedMainView = getCaseItemAvatarCaseDetailObj.isPinned && allCasesView;
|
||||
const caseCompleted = COMPLETED_STATUSES.includes(caseStatus);
|
||||
|
||||
|
||||
@@ -13,7 +13,17 @@ interface ICollectionCaseData {
|
||||
}
|
||||
|
||||
const CollectionCaseData: React.FC<ICollectionCaseData> = ({ caseData }) => {
|
||||
const { fatherName, currentDpd, loanAccountNumber, dpdBucket, pos, collectionTag } = caseData;
|
||||
const {
|
||||
fatherName,
|
||||
currentDpd,
|
||||
loanAccountNumber,
|
||||
dpdBucket,
|
||||
pos,
|
||||
collectionTag,
|
||||
employmentDetail,
|
||||
} = caseData;
|
||||
|
||||
const showEmploymentDetails = false;
|
||||
|
||||
return (
|
||||
<View>
|
||||
@@ -37,6 +47,23 @@ const CollectionCaseData: React.FC<ICollectionCaseData> = ({ caseData }) => {
|
||||
POS {formatAmount(pos)}
|
||||
</Text>
|
||||
</View>
|
||||
{showEmploymentDetails ? (
|
||||
<View style={[GenericStyles.row, GenericStyles.alignCenter, GenericStyles.mt4]}>
|
||||
{employmentDetail?.employmentType && (
|
||||
<Text style={[styles.greyText]} small>
|
||||
{employmentDetail.employmentType}
|
||||
</Text>
|
||||
)}
|
||||
{employmentDetail?.employmentType && employmentDetail?.employerName && (
|
||||
<View style={styles.lineStyle} />
|
||||
)}
|
||||
{employmentDetail?.employerName && (
|
||||
<Text style={[styles.greyText]} small numberOfLines={1}>
|
||||
{employmentDetail.employerName}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
) : null}
|
||||
{collectionTag ? (
|
||||
<Text style={[styles.greyText]} small>
|
||||
{collectionTag}
|
||||
|
||||
@@ -214,6 +214,8 @@ const FeedbackDetailContainer: React.FC<IFeedbackDetailContainer> = ({ route: ro
|
||||
<Accordion
|
||||
accordionStyle={[GenericStyles.pv12, GenericStyles.br8, getShadowStyle(4)]}
|
||||
isActive={feedback.referenceId === activeFeedbackReferenceId}
|
||||
touchableDelay={50}
|
||||
touchableOpacity={0.8}
|
||||
accordionHeader={
|
||||
<FeedbackDetailItem
|
||||
key={feedback.referenceId}
|
||||
|
||||
@@ -163,6 +163,11 @@ export enum PaymentStatus {
|
||||
'Closed' = 'Closed',
|
||||
}
|
||||
|
||||
export interface EmploymentDetails {
|
||||
employmentType: string;
|
||||
employerName: string;
|
||||
}
|
||||
|
||||
export interface CaseDetail {
|
||||
id: string;
|
||||
allocationReferenceId?: string;
|
||||
@@ -212,6 +217,7 @@ export interface CaseDetail {
|
||||
feedbackStatus?: FeedbackStatus;
|
||||
attemptedAt?: number;
|
||||
forceSubmit?: boolean;
|
||||
employmentDetail?: EmploymentDetails;
|
||||
}
|
||||
|
||||
export interface AddressesGeolocationPayload {
|
||||
|
||||
@@ -1603,6 +1603,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@react-native-community/netinfo/-/netinfo-9.3.7.tgz#92407f679f00bae005c785a9284e61d63e292b34"
|
||||
integrity sha512-+taWmE5WpBp0uS6kf+bouCx/sn89G9EpR4s2M/ReLvctVIFL2Qh8WnWfBxqK9qwgmFha/uqjSr2Gq03OOtiDcw==
|
||||
|
||||
"@react-native-firebase/analytics@16.4.6":
|
||||
version "16.4.6"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-firebase/analytics/-/analytics-16.4.6.tgz#833b871014de49091cc3f50f98dbc1920b346097"
|
||||
integrity sha512-Gp6kD3RCIy3f9u0pQgGfp5jGwNwLLxo2blsXbTsj/yHOE4g+leH/wojPPENs1yc2g6OMhzGYbO19/beCP6bIng==
|
||||
|
||||
"@react-native-firebase/app@16.4.6":
|
||||
version "16.4.6"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-firebase/app/-/app-16.4.6.tgz#929a86894b401352259e21d4cb4dab1d37de2bc7"
|
||||
@@ -3419,7 +3424,7 @@ data-urls@^2.0.0:
|
||||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^8.0.0"
|
||||
|
||||
dayjs@1.11.9:
|
||||
dayjs@^1.11.9:
|
||||
version "1.11.9"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a"
|
||||
integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==
|
||||
|
||||
Reference in New Issue
Block a user