Merge branch 'master' into sync_2

This commit is contained in:
Aman Singh
2024-04-29 13:03:42 +05:30
committed by GitHub
17 changed files with 176 additions and 82 deletions

View File

@@ -134,8 +134,8 @@ def reactNativeArchitectures() {
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
def VERSION_CODE = 143
def VERSION_NAME = "2.9.2"
def VERSION_CODE = 146
def VERSION_NAME = "2.9.5"
android {
ndkVersion rootProject.ext.ndkVersion

View File

@@ -1,7 +1,7 @@
{
"name": "AV_APP",
"version": "2.9.2",
"buildNumber": "143",
"version": "2.9.5",
"buildNumber": "146",
"private": true,
"scripts": {
"android:dev": "yarn move:dev && react-native run-android",

View File

@@ -1,26 +1,30 @@
import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper';
import { AppDispatch } from '../store/store';
import { logError } from '../components/utlis/errorUtils';
import {ITelephoneNumbers, setTelephoneNumbers} from "@reducers/telephoneNumbersSlice";
import {GenericObject} from "@common/GenericTypes";
import { ITelephoneNumbers, setTelephoneNumbers } from '@reducers/telephoneNumbersSlice';
import { isFunction } from '@components/utlis/commonFunctions';
type FetchTelephoneNumbersParams = {
caseId: string;
loanAccountNumber: string;
setLoading: (value: boolean) => void;
}
export const fetchTelephoneNumber = ({caseId, loanAccountNumber, setLoading}: FetchTelephoneNumbersParams ) => (dispatch: AppDispatch) => {
const url = getApiUrl(ApiKeys.GET_TELEPHONE_NUMBERS, {loanAccountNumber: loanAccountNumber},)
setLoading(true);
axiosInstance.get(url).then((res: {data: ITelephoneNumbers[]}) => {
dispatch(setTelephoneNumbers({caseId: caseId, telephoneNumbers: res.data}));
}).catch((err: Error)=>{
logError(err);
console.log('error while fetching telephone numbers', err);
}).finally(()=>{
setLoading(false);
});
caseId: string;
loanAccountNumber: string;
setLoading?: (value: boolean) => void;
};
export const fetchTelephoneNumber =
({ caseId, loanAccountNumber, setLoading }: FetchTelephoneNumbersParams) =>
(dispatch: AppDispatch) => {
const url = getApiUrl(ApiKeys.GET_TELEPHONE_NUMBERS, { loanAccountNumber: loanAccountNumber });
const isSetLoadingFunction = isFunction(setLoading);
if (isSetLoadingFunction) setLoading(true);
axiosInstance
.get(url)
.then((res: { data: ITelephoneNumbers[] }) => {
dispatch(setTelephoneNumbers({ caseId: caseId, telephoneNumbers: res.data }));
})
.catch((err: Error) => {
logError(err);
})
.finally(() => {
if (isSetLoadingFunction) setLoading(false);
});
};

View File

@@ -820,77 +820,77 @@ export const CLICKSTREAM_EVENT_NAMES = {
},
// CSA
FA_TASKS_CLICKED : {
FA_TASKS_CLICKED: {
name: 'FA_TASKS_CLICKED',
description: 'FA_TASK_CLICKED'
description: 'FA_TASK_CLICKED',
},
FA_CREATE_TASK_CLICKED:{
FA_CREATE_TASK_CLICKED: {
name: 'FA_CREATE_TASK_CLICKED',
description: 'FA_CREATE_TASK_CLICKED'
description: 'FA_CREATE_TASK_CLICKED',
},
FA_VIEW_TASK_HISTORY_CLICKED: {
name: 'FA_VIEW_TASK_HISTORY_CLICKED',
description: 'FA_VIEW_TASK_HISTORY_CLICKED'
description: 'FA_VIEW_TASK_HISTORY_CLICKED',
},
FA_TASKS_UNREAD_TOGGLE_CLICKED: {
name: 'FA_TASKS_UNREAD_TOGGLE_CLICKED',
description: 'FA_TASKS_UNREAD_TOGGLE_CLICKED'
description: 'FA_TASKS_UNREAD_TOGGLE_CLICKED',
},
FA_TASKS_FILTER_APPLIED: {
name: 'FA_TASKS_FILTER_APPLIED',
description: 'FA_TASKS_FILTER_APPLIED'
description: 'FA_TASKS_FILTER_APPLIED',
},
FA_TASKS_FILTER_BUTTON_CLICKED: {
name: 'FA_TASKS_FILTER_BUTTON_CLICKED',
description: 'FA_TASKS_FILTER_BUTTON_CLICKED'
description: 'FA_TASKS_FILTER_BUTTON_CLICKED',
},
FA_NOTIFICATION_TASKS_TAB_CLICKED: {
name: 'FA_NOTIFICATION_TASKS_TAB_CLICKED',
description: 'FA_NOTIFICATION_TASKS_TAB_CLICKED'
description: 'FA_NOTIFICATION_TASKS_TAB_CLICKED',
},
FA_TASK_VIEW_DETAIL_CLICKED: {
name: 'FA_TASK_VIEW_DETAIL_CLICKED',
description: 'FA_TASK_VIEW_DETAIL_CLICKED'
description: 'FA_TASK_VIEW_DETAIL_CLICKED',
},
FA_TASK_COMMENT_ADDED: {
name: 'FA_TASK_COMMENT_ADDED',
description: 'FA_TASK_COMMENT_ADDED'
description: 'FA_TASK_COMMENT_ADDED',
},
FA_TASK_MARKED_SUCCESSFUL: {
name: 'FA_TASK_MARKED_SUCCESSFUL',
description: 'FA_TASK_MARKED_SUCCESSFUL'
description: 'FA_TASK_MARKED_SUCCESSFUL',
},
FA_TASK_MARKED_DONE: {
name: 'FA_TASK_MARKED_DONE',
description: 'FA_TASK_MARKED_DONE'
description: 'FA_TASK_MARKED_DONE',
},
FA_TASKS_TAB_BUTTON_CLICKED: {
name: 'FA_TASKS_TAB_BUTTON_CLICKED',
description: 'FA_TASKS_TAB_BUTTON_CLICKED'
description: 'FA_TASKS_TAB_BUTTON_CLICKED',
},
FA_MY_TASKS_LOAD_SUCCESSFUL: {
name: 'FA_MY_TASKS_LOAD_SUCCESSFUL',
description: 'FA_MY_TASKS_LOAD_SUCCESSFUL'
description: 'FA_MY_TASKS_LOAD_SUCCESSFUL',
},
FA_FE_TASKS_LOAD_SUCCESSFUL: {
name: 'FA_FE_TASKS_LOAD_SUCCESSFUL',
description: 'FA_FE_TASKS_LOAD_SUCCESSFUL'
description: 'FA_FE_TASKS_LOAD_SUCCESSFUL',
},
FA_TASKS_BUTTON_CLICKED: {
name: 'FA_TASKS_BUTTON_CLICKED',
description: 'FA_TASKS_BUTTON_CLICKED'
description: 'FA_TASKS_BUTTON_CLICKED',
},
FA_TASKS_PAGE_LOAD_SUCCESSFUL: {
name: 'FA_TASKS_PAGE_LOAD_SUCCESSFUL',
description: 'FA_TASKS_PAGE_LOAD_SUCCESSFUL'
description: 'FA_TASKS_PAGE_LOAD_SUCCESSFUL',
},
FA_TASK_DETAIL_CLICKED: {
name: 'FA_TASK_DETAIL_CLICKED',
description: 'FA_TASK_DETAIL_CLICKED'
description: 'FA_TASK_DETAIL_CLICKED',
},
FA_TASK_DETAIL_LOAD_SUCCESSFUL: {
name: 'FA_TASK_DETAIL_LOAD_SUCCESSFUL',
description: 'FA_TASK_DETAIL_LOAD_SUCCESSFUL'
description: 'FA_TASK_DETAIL_LOAD_SUCCESSFUL',
},
FA_PHOTO_UPLOAD_ERROR: {
name: 'FA_PHOTO_UPLOAD_ERROR',
@@ -942,6 +942,11 @@ export const CLICKSTREAM_EVENT_NAMES = {
name: 'FA_DEVICE_DETAILS',
description: 'FA_DEVICE_DETAILS',
},
FA_COPY_ADDRESS_CLICKED: {
name: 'FA_COPY_ADDRESS_CLICKED',
description: 'FA_COPY_ADDRESS_CLICKED',
},
} as const;
export enum MimeType {

View File

@@ -16,7 +16,6 @@ const DropDownWrapper: React.FC<IDropdown> = (props) => {
const onAnimationEndHandler = (id: number | null) => {
if (!id) return;
console.log('dropdown opened', id);
setBottomSheetView(id);
};

View File

@@ -515,3 +515,5 @@ export const sendDeviceDetailsToClickstream = async () => {
phoneLanguage,
});
};
export const isFunction = (fn: unknown): fn is (...args: any[]) => void => typeof fn === 'function';

View File

@@ -5,7 +5,7 @@ import {
saveToGlobalDocumentMap,
storeImageLocallyReturnRelativePath,
} from '../components/utlis/commonFunctions';
import { DOCUMENT_TYPE, TDocumentObj } from '../screens/caseDetails/interface';
import { DOCUMENT_TYPE, IDocument, TDocumentObj } from '../screens/caseDetails/interface';
import { getSignedApi, ISignedRequest } from '../action/dataActions';
import { GlobalDocumentMap } from '../../App';
import { IFetchDocumentCaseDetailObj } from '../screens/allCases/interface';
@@ -83,16 +83,17 @@ const useFetchDocument = (
useEffect(() => {
if (!retryForDocuments?.length) return;
let imageReferenceId: string | undefined;
let imageDocument: IDocument | undefined;
for (let retryForDocumentsItem of retryForDocuments) {
imageReferenceId = findDocumentByDocumentType(
imageDocument = findDocumentByDocumentType(
caseDetailObj?.documentList,
retryForDocumentsItem
)?.referenceId;
);
const { referenceId, unSignedUri} = imageDocument || {};
(async () => {
if (!imageReferenceId) {
if (!referenceId) {
setDocumentObj((documentObj) => ({
...documentObj,
[retryForDocumentsItem]: '',
@@ -100,15 +101,16 @@ const useFetchDocument = (
return;
}
if (apiInProgressReferenceIds.current.includes(imageReferenceId)) return;
if (apiInProgressReferenceIds.current.includes(referenceId)) return;
apiInProgressReferenceIds.current.push(imageReferenceId);
apiInProgressReferenceIds.current.push(referenceId);
const signedRequestPayload: ISignedRequest = [
{
documentReferenceId: imageReferenceId,
documentReferenceId: referenceId,
caseId: '' + caseDetailObj.caseId,
caseType: caseDetailObj.caseType,
unSignedUri: unSignedUri
},
];

View File

@@ -5,6 +5,7 @@ import axiosInstance, { ApiKeys, getApiUrl } from '../../components/utlis/apiHel
import { navigateToScreen } from '../../components/utlis/navigationUtlis';
import { Source, Tag } from './const';
import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack';
import { isFunction } from '@components/utlis/commonFunctions';
interface IAddNewNumberApi {
tag: Tag;
@@ -13,7 +14,11 @@ interface IAddNewNumberApi {
customerReferenceId: string;
caseId: string;
}
export const addNewNumberApi = (data: IAddNewNumberApi, afterApiCallback?: GenericFunctionArgs) => {
export const addNewNumberApi = (
data: IAddNewNumberApi,
afterApiCallback?: GenericFunctionArgs,
successCallbackFn?: GenericFunctionArgs
) => {
const { tag, source, number, customerReferenceId, caseId } = data;
const url = getApiUrl(ApiKeys.TELEPHONES);
const payload = [
@@ -38,6 +43,7 @@ export const addNewNumberApi = (data: IAddNewNumberApi, afterApiCallback?: Gener
navigateToScreen(CaseDetailStackEnum.COLLECTION_CASE_DETAIL, {
caseId: caseId,
});
if (isFunction(successCallbackFn)) successCallbackFn();
}
})
.catch((error) => {

View File

@@ -13,8 +13,9 @@ import { Source, Tag } from './const';
import DropdownItem from '../registerPayements/DropdownItem';
import { getDynamicBottomSheetHeightPercentageFn } from '../../components/utlis/commonFunctions';
import { addNewNumberApi } from './apiHelper';
import { useAppSelector } from '../../hooks';
import { useAppDispatch, useAppSelector } from '../../hooks';
import DropDownWrapper from '../../common/DropDownWrapper';
import { fetchTelephoneNumber } from '@actions/fetchTelephoneNumber';
interface IAddNewNumber {
number: string;
@@ -35,7 +36,10 @@ interface IAddNewNumber {
const AddNewNumber: React.FC<IAddNewNumber> = (props) => {
const [loading, setLoading] = useState(false);
const { caseId } = props.route.params;
const { customerReferenceId } = useAppSelector((state) => state.allCases.caseDetails[caseId]);
const { customerReferenceId, loanAccountNumber } = useAppSelector(
(state) => state.allCases.caseDetails[caseId] || {}
);
const dispatch = useAppDispatch();
const {
control,
getValues,
@@ -73,7 +77,8 @@ const AddNewNumber: React.FC<IAddNewNumber> = (props) => {
},
() => {
setLoading(false);
}
},
() => dispatch(fetchTelephoneNumber({ loanAccountNumber, caseId }))
);
};

View File

@@ -17,6 +17,8 @@ import { type GenericFunctionArgs } from '../../common/GenericTypes';
import relativeDistanceFormatter from './utils/relativeDistanceFormatter';
import { addClickstreamEvent } from '@services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
import CopyIcon from '@rn-ui-lib/icons/CopyIcon';
import { copyAddressToClipboard } from './utils/copyAddressText';
interface IAddressItem {
addressItem: IAddress;
@@ -101,6 +103,10 @@ function AddressItem({
}
};
const copyAddress = () => {
copyAddressToClipboard(addressItem?.addressText, caseId);
};
return (
<View style={[GenericStyles.row]}>
{isGroupedAddress ? (
@@ -214,6 +220,17 @@ function AddressItem({
{showActionButtons ? (
<View style={[styles.container, GenericStyles.row, GenericStyles.pt12]}>
<TouchableOpacity
activeOpacity={0.7}
onPress={copyAddress}
hitSlop={{ top: 25, bottom: 25, left: 15, right: 15 }}
style={GenericStyles.mr16}
>
<View style={[GenericStyles.centerAlignedRow]}>
<CopyIcon fillColor={COLORS.TEXT.BLUE} />
<Text style={styles.actionBtn}>Copy</Text>
</View>
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.7}
onPress={handleAddFeedback}

View File

@@ -1,12 +1,5 @@
import React from 'react';
import {
View,
StyleSheet,
type ViewStyle,
TouchableOpacity,
ScrollView,
Linking,
} from 'react-native';
import { View, StyleSheet, type ViewStyle, TouchableOpacity, 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';
@@ -18,7 +11,6 @@ import {
} 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';
@@ -30,26 +22,28 @@ import { toast } from '../../../RN-UI-LIB/src/components/toast';
import { ToastMessages } from '../allCases/constants';
import AddressSource from './AddressSource';
import relativeDistanceFormatter from './utils/relativeDistanceFormatter';
import CopyIcon from '@rn-ui-lib/icons/CopyIcon';
import { copyAddressToClipboard } from './utils/copyAddressText';
interface IAddressItem {
addressItem: IAddress;
containerStyle?: ViewStyle;
isGroupedAddress?: boolean;
showRelativeDistance?: boolean;
showActionButtons?: boolean;
contactabilityStatus?: string;
groupedAddressIdx?: number;
caseId?: string;
handleCloseRouting?: GenericFunctionArgs;
handleOldFeedbackRouting?: GenericFunctionArgs;
showSource?: boolean;
showAddFeedbackBtn?: boolean;
showOldFeedbackBtn?: boolean;
}
function SimilarAddressItem({
addressItem,
containerStyle = {},
isGroupedAddress = false,
showActionButtons = false,
showRelativeDistance = false,
contactabilityStatus = '',
groupedAddressIdx = 1,
@@ -57,6 +51,8 @@ function SimilarAddressItem({
handleCloseRouting,
handleOldFeedbackRouting,
showSource = false,
showAddFeedbackBtn = false,
showOldFeedbackBtn = false,
}: IAddressItem) {
const { currentGeolocationCoordinates, prefilledAddressScreenTemplate } = useAppSelector(
(state) => ({
@@ -123,6 +119,10 @@ function SimilarAddressItem({
}
};
const copyAddress = () => {
copyAddressToClipboard(addressItem?.addressText, caseId);
};
return (
<View style={[GenericStyles.row]}>
{isGroupedAddress ? (
@@ -178,24 +178,39 @@ function SimilarAddressItem({
) : null}
{showSource ? <AddressSource addressItem={addressItem} /> : null}
</Text>
{showActionButtons ? (
<View style={[styles.container, GenericStyles.row, GenericStyles.pt12]}>
<View style={[GenericStyles.row, GenericStyles.pt12]}>
<TouchableOpacity
activeOpacity={0.7}
onPress={copyAddress}
hitSlop={{ top: 25, bottom: 25, left: 15, right: 15 }}
style={GenericStyles.mr8}
>
<View style={[GenericStyles.centerAlignedRow]}>
<CopyIcon fillColor={COLORS.TEXT.BLUE} />
<Text style={styles.actionBtn}>Copy</Text>
</View>
</TouchableOpacity>
{showAddFeedbackBtn ? (
<TouchableOpacity
activeOpacity={0.7}
onPress={handleAddFeedback}
style={[{ flexBasis: '35%' }]}
hitSlop={{ top: 25, bottom: 25, left: 15, right: 15 }}
style={GenericStyles.mh8}
>
<Text style={styles.actionBtn}>Add Feedback</Text>
</TouchableOpacity>
) : null}
{showOldFeedbackBtn ? (
<TouchableOpacity
activeOpacity={0.7}
onPress={handleOldFeedbackRouting}
style={[{ flexBasis: '30%' }]}
hitSlop={{ top: 25, bottom: 25, left: 15, right: 15 }}
style={GenericStyles.ml8}
>
<Text style={styles.actionBtn}>Old feedbacks</Text>
</TouchableOpacity>
</View>
) : null}
) : null}
</View>
</View>
</View>
);

View File

@@ -0,0 +1,24 @@
import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
import { copyToClipboard } from '@components/utlis/commonFunctions';
import { toast } from '@rn-ui-lib/components/toast';
import { ToastMessages } from '@screens/allCases/constants';
import { addClickstreamEvent } from '@services/clickstreamEventService';
export const copyAddressToClipboard = (text: string, caseId?: string) => {
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_COPY_ADDRESS_CLICKED, {
addressText: text,
caseId: caseId,
});
if (text) {
copyToClipboard(text);
toast({
text1: ToastMessages.SUCCESS_COPYING_ADDRESS,
type: 'info',
});
} else {
toast({
text1: ToastMessages.ERROR_COPYING_ADDRESS,
type: 'error',
});
}
};

View File

@@ -68,25 +68,28 @@ const CaseItemAvatar: React.FC<ICaseItemAvatar> = ({
}
for (let retryForDocumentsItem of requiredDocumentTypeList) {
// Doc referenceId => needed to get a signed url of the expired s3 url.
const imageReferenceId = findDocumentByDocumentType(
const imageDocument = findDocumentByDocumentType(
caseDetailObj?.documentList,
retryForDocumentsItem
)?.referenceId;
);
if (!imageReferenceId) {
const { referenceId, unSignedUri} = imageDocument || {};
if (!referenceId) {
return;
}
(async (caseDetail) => {
if (apiInProgressReferenceIds.current.includes(imageReferenceId)) return;
if (apiInProgressReferenceIds.current.includes(referenceId)) return;
apiInProgressReferenceIds.current.push(imageReferenceId);
apiInProgressReferenceIds.current.push(referenceId);
const signedRequestPayload: ISignedRequest = [
{
documentReferenceId: imageReferenceId,
documentReferenceId: referenceId,
caseId: '' + caseDetail.caseId,
caseType: caseDetail.caseType,
unSignedUri: unSignedUri
},
];
const response = await getSignedApi(signedRequestPayload, enableRetry);

View File

@@ -89,6 +89,7 @@ export const ToastMessages = {
FILE_DOWNLOAD_FAILURE: 'File download failed',
COMMITMENT_SUBMITTED_SUCCESSFULLY: 'Commitment submitted successfully',
SUCCESS_COPYING_ADDRESS: 'Address copied successfully',
ERROR_COPYING_ADDRESS: 'Error copying address',
};
export enum BOTTOM_TAB_ROUTES {

View File

@@ -99,7 +99,7 @@ const CustomerProfile: React.FC<ICustomerProfile> = (props) => {
DOCUMENT_TYPE.AADHAR_PHOTO,
DOCUMENT_TYPE.AADHAR,
DOCUMENT_TYPE.DRIVING_LICENSE,
DOCUMENT_TYPE.PAN
];
updatedDocList.forEach((documentType) => {
const document = findDocumentByDocumentType(docList, documentType);

View File

@@ -92,6 +92,17 @@ export const getDocumentDetails = async (document: IDocument) => {
documentRefId: document.referenceId,
};
case DOCUMENT_TYPE.PAN:
return {
icon: <ImageIcon />,
title: DocumentTitle.PAN,
docType: DOCUMENT_TYPE.PAN,
docContentType: docType,
url: imageUrl,
unSignedUri: document.unSignedUri,
documentRefId: document.referenceId,
};
default:
break;
}