Original Image Load Fix, clean code, improve defination of useFetchDocument hook (move onSuccess logic to the hook) (#202)

* TP-23666 | Original Image caching Fix + improve useFetchDocument Hook

* TP-23666 | QA bug fixes
This commit is contained in:
Himanshu Kansal
2023-04-03 22:37:02 +05:30
committed by GitHub Enterprise
parent a87f3cfa11
commit 0e4189a6c8
4 changed files with 116 additions and 104 deletions

View File

@@ -1,6 +1,6 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import RNFetchBlob from "rn-fetch-blob";
import { Address, PhoneNumber, TDocumentObj } from "../../screens/caseDetails/interface";
import { Address, DOCUMENT_TYPE, IDocument, PhoneNumber, TDocumentObj } from "../../screens/caseDetails/interface";
import { getPrefixBase64Image, LocalStorageKeys, MimeType } from "../../common/Constants";
import NetInfo from "@react-native-community/netinfo";
import Clipboard from '@react-native-clipboard/clipboard';
@@ -12,6 +12,7 @@ import { GenericType } from '../../common/GenericTypes';
import { CaseDetail } from '../../screens/caseDetails/interface';
import { logError } from './errorUtils';
import packageJson from '../../../package.json';
import { CaseAllocationType } from '../../screens/allCases/interface';
const fs = RNFetchBlob.fs;
@@ -19,7 +20,8 @@ const fs = RNFetchBlob.fs;
const RespHeaderContentTypeKey = 'Content-Type';
const DEFAULT_TEXT = '--';
const MAX_SHEET_HEIGHT_PERCENTAGE = 50;
const RELATIVE_PATH_PREFIX = 'file://';
export const RELATIVE_PATH_PREFIX = 'file://';
export const decideLoadingState = (textData: string): boolean => {
@@ -88,7 +90,7 @@ export const fetchCopiedText = async () => {
export const setAsyncStorageItem = async (key: string, value: any) => {
try {
const stringifiedValue = stringify(value);
const stringifiedValue = JSON.stringify(value);
await AsyncStorage.setItem(key, stringifiedValue);
} catch(err) {
console.error('JSON stringify errored',err);
@@ -177,4 +179,14 @@ export const getLoanAccountNumber = (caseDetail: CaseDetail) => {
export function getAppVersion(): string {
return packageJson.version;
}
}
export const getDocumentList = (caseDetails: CaseDetail) => {
return caseDetails.caseType === CaseAllocationType.ADDRESS_VERIFICATION_CASE ?
caseDetails.customerInfo?.documents :
caseDetails.documents;
}
export const findDocumentByDocumentType = (documentList: IDocument[] = [], documentType: DOCUMENT_TYPE) => {
return documentList?.find((documentItem) => documentItem.type === documentType);
}

View File

@@ -1,23 +1,14 @@
import { useEffect, useRef, useState } from 'react';
import { saveToGlobalDocumentMap, storeImageLocallyReturnRelativePath } from '../components/utlis/commonFunctions';
import { CaseDetail, DOCUMENT_TYPE, IDocument, TDocumentObj } from '../screens/caseDetails/interface';
import { findDocumentByDocumentType, getDocumentList, RELATIVE_PATH_PREFIX,
saveToGlobalDocumentMap, storeImageLocallyReturnRelativePath } from '../components/utlis/commonFunctions';
import { CaseDetail, DOCUMENT_TYPE, TDocumentObj } from '../screens/caseDetails/interface';
import { getSignedApi, ISignedRequest } from '../action/dataActions';
import { GlobalDocumentMap } from '../../App';
import { CaseAllocationType } from '../screens/allCases/interface';
const findDocumentByDocumentType = (documentList: IDocument[] = [], documentType: DOCUMENT_TYPE) => {
return documentList?.find((documentItem) => documentItem.type === documentType);
}
const getDocumentList = (caseDetails: CaseDetail) => {
return caseDetails.caseType === CaseAllocationType.ADDRESS_VERIFICATION_CASE ?
caseDetails.customerInfo?.documents :
caseDetails.documents;
}
const getDocumentUrlFromCaseDetails = (caseDetails: CaseDetail, documentType: DOCUMENT_TYPE) => {
if (caseDetails?.id && caseDetails.id in GlobalDocumentMap) {
return GlobalDocumentMap[caseDetails.id]?.[documentType];
if (GlobalDocumentMap?.[caseDetails?.id]?.[documentType]) {
return GlobalDocumentMap[caseDetails.id][documentType];
}
const documentList = getDocumentList(caseDetails);
@@ -40,74 +31,102 @@ const useFetchDocument = (caseDetails: CaseDetail, documentTypeList: DOCUMENT_TY
const apiInProgressReferenceIds = useRef<string[]>([]);
const [retryForDocumentType, setRetryForDocumentType] = useState<DOCUMENT_TYPE>();
const [retryForDocuments, setRetryForDocuments] = useState<DOCUMENT_TYPE[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!retryForDocumentType) return;
if (enableCaching) {
let localDocumentObj = { ...documentObj } as TDocumentObj;
(async () => {
(async () => {
for (const [documentType, documentValue] of Object.entries(localDocumentObj)) {
if (documentValue && documentType in DOCUMENT_TYPE && !documentValue?.startsWith(RELATIVE_PATH_PREFIX)) {
const localImagePath = await storeImageLocallyReturnRelativePath(documentValue);
localDocumentObj = {
...localDocumentObj,
[documentType]: localImagePath
}
}
}
})().then(async () => {
setDocumentObj(localDocumentObj);
})
})();
}
}, []);
useEffect(() => {
if (enableCaching && documentObj) {
(async () => {
await saveToGlobalDocumentMap(caseDetails?.id, documentObj);
})();
}
}, [documentObj, enableCaching]);
useEffect(() => {
if (!retryForDocuments?.length) return;
const documentList = getDocumentList(caseDetails);
const imageReferenceId = findDocumentByDocumentType(documentList, retryForDocumentType)?.referenceId;
(async () => {
if (!imageReferenceId) {
setDocumentObj({
...documentObj,
[retryForDocumentType]: ''
})
return;
}
let imageReferenceId: string | undefined;
if (apiInProgressReferenceIds.current.includes(imageReferenceId)) return;
for (let retryForDocumentsItem of retryForDocuments) {
imageReferenceId = findDocumentByDocumentType(documentList, retryForDocumentsItem)?.referenceId;
apiInProgressReferenceIds.current.push(imageReferenceId);
const signedRequestPayload: ISignedRequest = [
{
documentReferenceId: imageReferenceId,
caseId: caseDetails.id,
caseType: caseDetails.caseType,
},
];
setLoading(true);
const response = await getSignedApi(signedRequestPayload);
setLoading(false);
const url = response?.imageUrl;
if (!url) {
setDocumentObj({
...documentObj,
[retryForDocumentType]: ''
})
return;
}
const localImagePath = await storeImageLocallyReturnRelativePath(url);
if (localImagePath) {
setDocumentObj({
...documentObj,
[retryForDocumentType]: localImagePath
});
if (enableCaching) {
saveToGlobalDocumentMap(caseDetails?.id, {
(async () => {
if (!imageReferenceId) {
setDocumentObj(documentObj => ({
...documentObj,
[retryForDocumentType]: localImagePath
})
[retryForDocumentsItem]: ''
}))
return;
}
}
})();
if (apiInProgressReferenceIds.current.includes(imageReferenceId)) return;
apiInProgressReferenceIds.current.push(imageReferenceId);
const signedRequestPayload: ISignedRequest = [
{
documentReferenceId: imageReferenceId,
caseId: caseDetails.id,
caseType: caseDetails.caseType,
},
];
setLoading(true);
const response = await getSignedApi(signedRequestPayload);
setLoading(false);
const url = response?.imageUrl;
if (!url) {
setDocumentObj(documentObj => ({
...documentObj,
[retryForDocumentsItem]: ''
}))
return;
}
const localImagePath = await storeImageLocallyReturnRelativePath(url);
if (localImagePath) {
setDocumentObj(documentObj => ({
...documentObj,
[retryForDocumentsItem]: localImagePath
}));
}
})();
}
return () => {
apiInProgressReferenceIds.current = apiInProgressReferenceIds.current.filter(item => item !== imageReferenceId);
}
}, [retryForDocumentType]);
}, [retryForDocuments]);
return {
documentObj,
setDocumentObj,
setRetryForUnsignedDocuments: setRetryForDocumentType,
retryForUnsignedDocuments: retryForDocumentType,
setRetryForUnsignedDocuments: setRetryForDocuments,
retryForUnsignedDocuments: retryForDocuments,
loading
};
};

View File

@@ -1,10 +1,8 @@
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { GlobalDocumentMap } from '../../../App';
import Avatar from '../../../RN-UI-LIB/src/components/Avatar';
import UnsyncedIcon from '../../../RN-UI-LIB/src/Icons/UnsyncedIcon';
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
import { saveToGlobalDocumentMap, storeImageLocallyReturnRelativePath } from '../../components/utlis/commonFunctions';
import { useAppSelector } from '../../hooks';
import useFetchDocument from '../../hooks/useFetchDocument';
import { DOCUMENT_TYPE } from '../caseDetails/interface';
@@ -38,8 +36,9 @@ const CaseItemAvatar: React.FC<ICaseItemAvatar> = ({
);
const requiredDocumentTypeList = [DOCUMENT_TYPE.OPTIMIZED_SELFIE];
const isPinned = pinnedList.find(item => item.caseReferenceId === referenceId)?.pinRank;
if (pinnedList.find(item => item.caseReferenceId === referenceId)?.caseReferenceId) {
if (isPinned) {
requiredDocumentTypeList.push(DOCUMENT_TYPE.SELFIE)
}
@@ -49,21 +48,7 @@ const CaseItemAvatar: React.FC<ICaseItemAvatar> = ({
const onError = async () => {
if (enableRetry) {
setRetryForUnsignedDocuments(DOCUMENT_TYPE.OPTIMIZED_SELFIE);
}
};
const onImageLoadSuccess = async () => {
if (!GlobalDocumentMap?.[caseDetails.id]?.[DOCUMENT_TYPE.OPTIMIZED_SELFIE]) {
const localImagePath = await storeImageLocallyReturnRelativePath(documentObj[DOCUMENT_TYPE.OPTIMIZED_SELFIE]);
if (!localImagePath) return;
saveToGlobalDocumentMap(caseDetails.id, {
...GlobalDocumentMap[caseDetails.id],
[DOCUMENT_TYPE.OPTIMIZED_SELFIE]: localImagePath
})
setRetryForUnsignedDocuments(requiredDocumentTypeList);
}
};
@@ -82,7 +67,6 @@ const CaseItemAvatar: React.FC<ICaseItemAvatar> = ({
onErrorFallback={onError}
style={[showBorder && styles.border]}
loading={loading}
onSuccess={onImageLoadSuccess}
/>
{!isSynced ? (
<View style={styles.unsyncedIcon}>

View File

@@ -18,8 +18,9 @@ import CloseIcon from '../../../RN-UI-LIB/src/Icons/CloseIcon';
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
import { dateFormat } from '../../../RN-UI-LIB/src/utlis/dates';
import { decideLoadingState, saveToGlobalDocumentMap, storeImageLocallyReturnRelativePath } from '../../components/utlis/commonFunctions';
import { decideLoadingState, findDocumentByDocumentType, getDocumentList, RELATIVE_PATH_PREFIX } from '../../components/utlis/commonFunctions';
import useFetchDocument from '../../hooks/useFetchDocument';
import useIsOnline from '../../hooks/useIsOnline';
import CaseItemAvatar from '../allCases/CaseItemAvatar';
import AvCaseData from './AvCaseData';
import CollectionCaseData from './CollectionCaseData';
@@ -76,22 +77,19 @@ const UserDetailsSection: React.FC<IUserDetailsSection> = props => {
caseDetail?.customerInfo?.customerName ||
caseDetail?.customerName;
const onImageLoadSuccess = async () => {
if (!GlobalDocumentMap?.[caseDetail?.id]?.[DOCUMENT_TYPE.SELFIE]) {
const localImagePath = await storeImageLocallyReturnRelativePath(documentObj[DOCUMENT_TYPE.SELFIE]);
if (localImagePath) {
saveToGlobalDocumentMap(caseDetail.id, {
...GlobalDocumentMap[caseDetail.id],
[DOCUMENT_TYPE.SELFIE]: localImagePath
})
};
}
};
const isOnline = useIsOnline();
const getImageURI = () => {
if (!isOnline) {
if (documentObj[DOCUMENT_TYPE.SELFIE]?.startsWith(RELATIVE_PATH_PREFIX)) {
return documentObj[DOCUMENT_TYPE.SELFIE];
}
return documentObj[DOCUMENT_TYPE.OPTIMIZED_SELFIE] || '';
}
return documentObj[DOCUMENT_TYPE.SELFIE] ||
documentObj[DOCUMENT_TYPE.OPTIMIZED_SELFIE] ||
findDocumentByDocumentType(getDocumentList(caseDetail), DOCUMENT_TYPE.SELFIE)?.uri ||
'';
}
@@ -208,11 +206,10 @@ const UserDetailsSection: React.FC<IUserDetailsSection> = props => {
source={{ uri: getImageURI() }}
resizeMode={'stretch'}
onError={() => {
setRetryForUnsignedDocuments(DOCUMENT_TYPE.SELFIE)
setRetryForUnsignedDocuments([DOCUMENT_TYPE.SELFIE])
setErrorModalImage(true)
}}
onLoadEnd={() => {
onImageLoadSuccess()
setErrorModalImage(false)
}}
/>