TP-31697 | Optimized feedback image changes
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bam.tech/react-native-image-resizer": "3.0.5",
|
||||
"@cobo/apm-rum-react-native": "^0.6.0",
|
||||
"@elastic/apm-rum-core": "^5.17.0",
|
||||
"@nozbe/watermelondb": "0.24.0",
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import React from 'react';
|
||||
import { View, Button, Image } from 'react-native';
|
||||
import ImagePicker, { ImageLibraryOptions, launchImageLibrary } from 'react-native-image-picker';
|
||||
|
||||
class ImageUploader extends React.Component {
|
||||
state = {
|
||||
image: null,
|
||||
};
|
||||
|
||||
selectImage = () => {
|
||||
const options: ImageLibraryOptions = {
|
||||
mediaType: 'photo',
|
||||
quality: 1,
|
||||
};
|
||||
|
||||
launchImageLibrary(options, (response) => {
|
||||
if (!response.didCancel) {
|
||||
console.log('response:', response);
|
||||
this.setState({ image: response.assets?.[0] });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
uploadImage = async () => {
|
||||
const { image } = this.state;
|
||||
|
||||
if (image) {
|
||||
const formData = new FormData();
|
||||
console.log('image:', image);
|
||||
|
||||
// try {
|
||||
// const response = await fetch(image.uri);
|
||||
// const blobData = await response.blob();
|
||||
|
||||
// formData.append('avatar', blobData, 'avatar.png');
|
||||
|
||||
// const result = await axios.post('https://0ac3-115-111-223-26.in.ngrok.io/upload', formData, {
|
||||
// headers: {
|
||||
// 'Content-Type': 'multipart/form-data',
|
||||
// },
|
||||
// });
|
||||
|
||||
// console.log('Request successful', result.data);
|
||||
// } catch (error) {
|
||||
// console.error('Request failed', error);
|
||||
// }
|
||||
console.log('image', image);
|
||||
formData.append('file[]', {
|
||||
uri: image.uri,
|
||||
name: 'image1.png',
|
||||
type: image.type,
|
||||
});
|
||||
formData.append('file[]', {
|
||||
uri: image.uri,
|
||||
name: 'image2.png',
|
||||
type: image.type,
|
||||
});
|
||||
formData.append('file[]', {
|
||||
uri: image.uri,
|
||||
name: 'image3.png',
|
||||
type: image.type,
|
||||
});
|
||||
|
||||
const response = await axios.post(
|
||||
'https://8ee6-115-111-223-26.in.ngrok.io/upload',
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { image } = this.state;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Button title="Select Image" onPress={this.selectImage} />
|
||||
{image && <Image source={{ uri: image.uri }} style={{ width: 200, height: 200 }} />}
|
||||
<Button title="Upload Image" onPress={this.uploadImage} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ImageUploader;
|
||||
@@ -12,9 +12,9 @@ import { GenericType } from '../common/GenericTypes';
|
||||
import { addClickstreamEvent } from '../services/clickstreamEventService';
|
||||
import { CLICKSTREAM_EVENT_NAMES } from '../common/Constants';
|
||||
import { PageRouteEnum } from '../screens/auth/ProtectedRouter';
|
||||
import { IDocument, removeDocuments, setDocumentReferenceId } from '../reducer/allCasesSlice';
|
||||
import { _map } from '../../RN-UI-LIB/src/utlis/common';
|
||||
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';
|
||||
|
||||
// TODO: Need to add respective interfaces instead of any
|
||||
interface IUnifiedData {
|
||||
@@ -145,58 +145,42 @@ export const getCaseUnifiedData =
|
||||
});
|
||||
};
|
||||
|
||||
const uploadFeedbackImages =
|
||||
(caseId: string, payload: IUploadImagePayload[]) => (dispatch: AppDispatch) => {
|
||||
const url = getApiUrl(ApiKeys.UPLOAD_FEEDBACK_IMAGES);
|
||||
axiosInstance
|
||||
.post(url, payload)
|
||||
.then(() => {
|
||||
dispatch(removeDocuments({ caseId, docs: payload }));
|
||||
})
|
||||
.catch((err) => {
|
||||
// Add to retry queue
|
||||
});
|
||||
};
|
||||
|
||||
export const uploadImages =
|
||||
(caseId: string, documents: Record<string, IDocument>, interactionId: string) =>
|
||||
(caseKey: string, documents: Record<string, IDocument>, interactionReferenceId: string) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
_map(documents, (questionKey) => {
|
||||
if (!documents) {
|
||||
return;
|
||||
}
|
||||
const fileDoc = documents[questionKey];
|
||||
if (!interactionId || !fileDoc) {
|
||||
if (!interactionReferenceId || !fileDoc) {
|
||||
return;
|
||||
}
|
||||
const { fileUri } = fileDoc;
|
||||
const formData = new FormData();
|
||||
formData.append('images', {
|
||||
formData.append(
|
||||
'originalImageData',
|
||||
JSON.stringify({
|
||||
interactionReferenceId,
|
||||
questionKey,
|
||||
})
|
||||
);
|
||||
formData.append('image', {
|
||||
uri: fileUri,
|
||||
name: `image_${caseId}_${new Date().getTime()}`,
|
||||
name: `image_${interactionReferenceId}`,
|
||||
type: 'image/jpeg',
|
||||
} as any);
|
||||
const url = getApiUrl(ApiKeys.UPLOAD_IMAGES);
|
||||
const url = getApiUrl(ApiKeys.UPLOAD_FEEDBACK_IMAGES);
|
||||
axiosInstance
|
||||
.post(url, formData, {
|
||||
.put(url, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
donotHandleError: true,
|
||||
},
|
||||
timeout: 5 * MILLISECONDS_IN_A_MINUTE,
|
||||
})
|
||||
.then((res) => {
|
||||
const originalImageDocumentReferenceId = res?.data?.referenceId;
|
||||
dispatch(
|
||||
setDocumentReferenceId({ caseId, questionKey, originalImageDocumentReferenceId })
|
||||
);
|
||||
dispatch(
|
||||
uploadFeedbackImages(caseId, [
|
||||
{
|
||||
interactionId,
|
||||
questionKey,
|
||||
originalImageDocumentReferenceId,
|
||||
},
|
||||
])
|
||||
);
|
||||
dispatch(removeDocumentByQuestionKey({ caseKey, questionKey }));
|
||||
})
|
||||
.catch((err) => {
|
||||
logError(err as Error, 'Error uploading image to document service');
|
||||
@@ -204,25 +188,8 @@ export const uploadImages =
|
||||
});
|
||||
};
|
||||
|
||||
const getDocsWithAndWithoutReferenceId = (docs: Record<string, IDocument>) => {
|
||||
const docsWithReferenceId: IDocument[] = [];
|
||||
const docsWithoutReferenceId: IDocument[] = [];
|
||||
_map(docs, (questionKey: string) => {
|
||||
const docRefId = docs?.[questionKey]?.originalImageDocumentReferenceId;
|
||||
if (docRefId) {
|
||||
docsWithReferenceId.push(docs?.[questionKey]);
|
||||
} else {
|
||||
docsWithoutReferenceId.push(docs?.[questionKey]);
|
||||
}
|
||||
});
|
||||
return {
|
||||
docsWithReferenceId,
|
||||
docsWithoutReferenceId,
|
||||
};
|
||||
};
|
||||
|
||||
export const uploadUnsyncedImages =
|
||||
(caseId: string, docs: Record<string, IDocument>) => (dispatch: AppDispatch) => {
|
||||
const { docsWithReferenceId, docsWithoutReferenceId } = getDocsWithAndWithoutReferenceId(docs);
|
||||
// dispatch(uploadFeedbackImages(caseId, docs))
|
||||
(caseId: string, interactionId: string, docs: Record<string, IDocument>) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
dispatch(uploadImages(caseId, docs, interactionId));
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
resetTodoList,
|
||||
setLoading,
|
||||
setVisitPlansUpdating,
|
||||
updateUnsyncedCaseDetail,
|
||||
updateSingleCase,
|
||||
} from '../reducer/allCasesSlice';
|
||||
import {
|
||||
@@ -71,12 +70,10 @@ export const postPinnedList =
|
||||
export const syncCaseDetail =
|
||||
(
|
||||
payload: any,
|
||||
updatedCaseDetail?: any,
|
||||
callbacks?: {
|
||||
onSuccessCB?: (data: any, actions?: any, interactionId?: string) => void;
|
||||
onErrorCB?: (e: Error) => void;
|
||||
},
|
||||
nextActions?: any
|
||||
}
|
||||
) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
const offlineImageIdList = getOfflineImageId(payload);
|
||||
@@ -104,7 +101,7 @@ export const syncCaseDetail =
|
||||
text1: ToastMessages.FEEDBACK_SUCCESSFUL,
|
||||
});
|
||||
if (callbacks?.onSuccessCB != null && typeof callbacks?.onSuccessCB === 'function') {
|
||||
callbacks?.onSuccessCB(payload.data.answers, nextActions, interactionId);
|
||||
callbacks?.onSuccessCB(payload.data.answers, interactionId);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
@@ -113,14 +110,6 @@ export const syncCaseDetail =
|
||||
type: 'error',
|
||||
text1: ToastMessages.FEEDBACK_FAILED,
|
||||
});
|
||||
if (updatedCaseDetail && !updatedCaseDetail.offlineCaseKey) {
|
||||
dispatch(
|
||||
updateUnsyncedCaseDetail({
|
||||
caseId: payload.data.caseReferenceId,
|
||||
updatedCaseDetail,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
if (callbacks?.onErrorCB != null && typeof callbacks?.onErrorCB === 'function') {
|
||||
callbacks?.onErrorCB(e);
|
||||
|
||||
@@ -8,9 +8,10 @@ interface IExpandableImage {
|
||||
imageSrc?: string;
|
||||
close?: () => void;
|
||||
title?: string;
|
||||
fallbackImage?: string;
|
||||
}
|
||||
|
||||
const imageHtml = (imageSrc?: string) => `
|
||||
const imageHtml = (imageSrc?: string, fallbackImage?: string) => `
|
||||
<html>
|
||||
<head>
|
||||
<title>Image Viewer</title>
|
||||
@@ -24,19 +25,37 @@ const imageHtml = (imageSrc?: string) => `
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.parent {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.image1 {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: calc(100vw - 32px);
|
||||
max-height: calc(100vh - 32px)
|
||||
}
|
||||
.image2 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: calc(100vw - 32px);
|
||||
max-height: calc(100vh - 32px)
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page pinch-zoom-parent">
|
||||
<div class="pinch-zoom">
|
||||
<img style="width: calc(100vw - 32px); max-height: calc(100vh - 32px)" src=${imageSrc} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="parent">
|
||||
<img class="image1" src=${fallbackImage} />
|
||||
<img class="image2" src=${imageSrc} />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const ExpandableImage: React.FC<IExpandableImage> = ({ imageSrc, title, close }) => {
|
||||
const ExpandableImage: React.FC<IExpandableImage> = ({ imageSrc, fallbackImage, title, close }) => {
|
||||
return (
|
||||
<View style={GenericStyles.fill}>
|
||||
<NavigationHeader onBack={close} title={title} />
|
||||
@@ -44,7 +63,7 @@ const ExpandableImage: React.FC<IExpandableImage> = ({ imageSrc, title, close })
|
||||
scalesPageToFit={true}
|
||||
bounces={false}
|
||||
scrollEnabled={false}
|
||||
source={{ html: imageHtml(imageSrc) }}
|
||||
source={{ html: imageHtml(imageSrc, fallbackImage) }}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -15,11 +15,18 @@ import { AnswerType } from '../interface';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import OfflineImageDAO from '../../../wmDB/dao/OfflineImageDAO';
|
||||
import { CLICKSTREAM_EVENT_NAMES, PrefixJpegBase64Image } from '../../../common/Constants';
|
||||
import {
|
||||
CLICKSTREAM_EVENT_NAMES,
|
||||
PrefixJpegBase64Image,
|
||||
getPrefixBase64Image,
|
||||
} from '../../../common/Constants';
|
||||
import { addClickstreamEvent } from '../../../services/clickstreamEventService';
|
||||
import { isQuestionMandatory, validateInput } from '../services/validation.service';
|
||||
import { CaseAllocationType } from '../../../screens/allCases/interface';
|
||||
import { addDocumentToUpload } from '../../../reducer/allCasesSlice';
|
||||
import {
|
||||
addIntermediateDocument,
|
||||
deleteIntermediateDocument,
|
||||
} from '../../../reducer/feedbackImagesSlice';
|
||||
|
||||
interface IOfflineImage {
|
||||
idx: string;
|
||||
@@ -70,7 +77,7 @@ const ImageUpload: React.FC<IImageUpload> = (props) => {
|
||||
if (!fileUri) {
|
||||
return;
|
||||
}
|
||||
dispatch(addDocumentToUpload({ caseId, fileUri, questionKey }));
|
||||
dispatch(addIntermediateDocument({ caseId, fileUri, questionKey }));
|
||||
};
|
||||
|
||||
const handleChange = async (clickedImage: IImageDetails, onChange: (...event: any[]) => void) => {
|
||||
@@ -98,6 +105,11 @@ const ImageUpload: React.FC<IImageUpload> = (props) => {
|
||||
await OfflineImageDAO.addImage(base64Image, uniqueId);
|
||||
};
|
||||
|
||||
const handleImageDelete = () => {
|
||||
setImageId('');
|
||||
dispatch(deleteIntermediateDocument({ caseId, questionKey: questionId }));
|
||||
};
|
||||
|
||||
// TODO : add the validator back when firestore is fixed.
|
||||
return (
|
||||
<View style={[GenericStyles.mt12]}>
|
||||
@@ -126,7 +138,7 @@ const ImageUpload: React.FC<IImageUpload> = (props) => {
|
||||
uri: props.offlineImages?.find((image) => image.idx === imageId)?.imageData || '',
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity onPress={() => setImageId('')} style={styles.deleteButton}>
|
||||
<TouchableOpacity onPress={handleImageDelete} style={styles.deleteButton}>
|
||||
<DeleteIcon />
|
||||
</TouchableOpacity>
|
||||
</ImageBackground>
|
||||
|
||||
@@ -17,8 +17,7 @@ import useIsOnline from '../../hooks/useIsOnline';
|
||||
import {
|
||||
getUpdatedAVCaseDetail,
|
||||
getUpdatedCollectionCaseDetail,
|
||||
setDocumentInteractionId,
|
||||
updateUnsyncedCaseDetail,
|
||||
updateCaseDetail,
|
||||
} from '../../reducer/allCasesSlice';
|
||||
import { deleteInteraction, deleteJourney, updateInteraction } from '../../reducer/caseReducer';
|
||||
import { CaseAllocationType } from '../../screens/allCases/interface';
|
||||
@@ -43,8 +42,8 @@ import Submit from './Submit';
|
||||
import { toast } from '../../../RN-UI-LIB/src/components/toast';
|
||||
import { ToastMessages } from '../../screens/allCases/constants';
|
||||
import { uploadImages } from '../../action/caseApiActions';
|
||||
import { isEmpty } from '../../../RN-UI-LIB/src/utlis/common';
|
||||
import { GenericFunctionArgs } from '../../common/GenericTypes';
|
||||
import { setDocumentInteractionId, setDocumentsToUpload } from '../../reducer/feedbackImagesSlice';
|
||||
|
||||
interface IWidget {
|
||||
route: {
|
||||
@@ -63,20 +62,26 @@ const Widget: React.FC<IWidget> = (props) => {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const { params } = props.route;
|
||||
const { caseId, journey, handleCloseRouting } = params;
|
||||
const { caseType, templateData, caseData, dataToBeValidated, docsToBeUploaded } = useAppSelector(
|
||||
(state) => {
|
||||
const caseType =
|
||||
state.allCases.caseDetails[caseId]?.caseType ||
|
||||
CaseAllocationType.ADDRESS_VERIFICATION_CASE;
|
||||
return {
|
||||
caseType,
|
||||
templateData: state.case.templateData[caseType],
|
||||
caseData: state.allCases.caseDetails[caseId],
|
||||
dataToBeValidated: state.case.caseForm?.[caseId]?.[journey],
|
||||
docsToBeUploaded: state.allCases.docsToBeUploaded?.[caseId]?.documents,
|
||||
};
|
||||
}
|
||||
);
|
||||
let caseKey = useRef<string>('');
|
||||
const {
|
||||
caseType,
|
||||
templateData,
|
||||
caseData,
|
||||
dataToBeValidated,
|
||||
docsToBeUploaded,
|
||||
intermediateDocsToBeUploaded,
|
||||
} = useAppSelector((state) => {
|
||||
const caseType =
|
||||
state.allCases.caseDetails[caseId]?.caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE;
|
||||
return {
|
||||
caseType,
|
||||
templateData: state.case.templateData[caseType],
|
||||
caseData: state.allCases.caseDetails[caseId],
|
||||
dataToBeValidated: state.case.caseForm?.[caseId]?.[journey],
|
||||
docsToBeUploaded: state.feedbackImages.docsToBeUploaded,
|
||||
intermediateDocsToBeUploaded: state.feedbackImages.intermediateDocsToBeUploaded,
|
||||
};
|
||||
});
|
||||
const name = getWidgetNameFromRoute(props.route.name, caseType);
|
||||
const { sections, conditionActions: widgetConditionActions, isLeaf } = templateData.widget[name];
|
||||
const sectionMap = templateData.sections;
|
||||
@@ -140,19 +145,16 @@ const Widget: React.FC<IWidget> = (props) => {
|
||||
setError(data);
|
||||
};
|
||||
|
||||
// Upload original doc to document service => get docRefId
|
||||
const uploadOriginalDocs = (interactionId: string) => {
|
||||
if (isEmpty(docsToBeUploaded)) {
|
||||
const docs = intermediateDocsToBeUploaded?.[caseId]?.documents;
|
||||
if (!docs) {
|
||||
return;
|
||||
}
|
||||
dispatch(setDocumentInteractionId({ caseId, interactionId }));
|
||||
if (isOnline) {
|
||||
dispatch(uploadImages(caseId, docsToBeUploaded, interactionId));
|
||||
} else {
|
||||
}
|
||||
dispatch(setDocumentInteractionId({ caseKey: caseKey.current, interactionId }));
|
||||
dispatch(uploadImages(caseKey.current, docs, interactionId));
|
||||
};
|
||||
|
||||
const onSuccessfulSubmit = (data: any, nextActions?: any, interactionId?: string) => {
|
||||
const onSuccessfulSubmit = (data: any, interactionId: string, nextActions?: any) => {
|
||||
setIsSubmitting(false);
|
||||
navigateToScreen(
|
||||
caseType === CaseAllocationType.COLLECTION_CASE ? 'collectionCaseDetail' : 'caseDetail',
|
||||
@@ -193,6 +195,16 @@ const Widget: React.FC<IWidget> = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
const onErrorSubmit = (updatedCaseDetails: any) => {
|
||||
setIsSubmitting(false);
|
||||
dispatch(
|
||||
updateCaseDetail({
|
||||
caseKey: caseKey.current,
|
||||
updatedCaseDetails,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleSubmitJourney = async (data: any, coords: Geolocation.GeoCoordinates) => {
|
||||
dispatch(
|
||||
updateInteraction({
|
||||
@@ -203,6 +215,8 @@ const Widget: React.FC<IWidget> = (props) => {
|
||||
})
|
||||
);
|
||||
if (caseType === CaseAllocationType.COLLECTION_CASE) {
|
||||
caseKey.current = `${caseId}_${Date.now()}`;
|
||||
dispatch(setDocumentsToUpload({ caseId, caseKey: caseKey.current }));
|
||||
const updatedCase = getUpdatedCollectionCaseDetail({
|
||||
caseData,
|
||||
answer: data,
|
||||
@@ -215,17 +229,16 @@ const Widget: React.FC<IWidget> = (props) => {
|
||||
const unSyncedCase = getUnSyncedCase(updatedCase);
|
||||
const transformedPayload = await getTransformedCollectionCaseItem(unSyncedCase);
|
||||
dispatch(
|
||||
syncCaseDetail(transformedPayload, updatedCase, {
|
||||
onSuccessCB: onSuccessfulSubmit,
|
||||
onErrorCB: () => {
|
||||
setIsSubmitting(false);
|
||||
},
|
||||
syncCaseDetail(transformedPayload, {
|
||||
onSuccessCB: (apiCaseData, interactionId: string) =>
|
||||
onSuccessfulSubmit(apiCaseData, interactionId),
|
||||
onErrorCB: () => onErrorSubmit(updatedCase),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
dispatch(
|
||||
updateUnsyncedCaseDetail({
|
||||
caseId,
|
||||
updateCaseDetail({
|
||||
caseKey: caseKey.current,
|
||||
updatedCaseDetail: updatedCase,
|
||||
})
|
||||
);
|
||||
@@ -267,22 +280,16 @@ const Widget: React.FC<IWidget> = (props) => {
|
||||
const unSyncedCase = getUnSyncedCase(updatedCase);
|
||||
const transformedPayload = await getTransformedAvCase(unSyncedCase, templateId);
|
||||
dispatch(
|
||||
syncCaseDetail(
|
||||
transformedPayload,
|
||||
updatedCase,
|
||||
{
|
||||
onSuccessCB: onSuccessfulSubmit,
|
||||
onErrorCB: () => {
|
||||
setIsSubmitting(false);
|
||||
},
|
||||
},
|
||||
nextActions
|
||||
)
|
||||
syncCaseDetail(transformedPayload, {
|
||||
onSuccessCB: (apiCaseData, interactionId: string) =>
|
||||
onSuccessfulSubmit(apiCaseData, interactionId, nextActions),
|
||||
onErrorCB: () => onErrorSubmit(updatedCase),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
dispatch(
|
||||
updateUnsyncedCaseDetail({
|
||||
caseId,
|
||||
updateCaseDetail({
|
||||
caseKey: caseId,
|
||||
updatedCaseDetail: updatedCase,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -49,8 +49,8 @@ export enum ApiKeys {
|
||||
CASES_SEND_ID = 'CASES_SEND_ID',
|
||||
FETCH_CASES = 'FETCH_CASES',
|
||||
GET_FORECLOSURE_AMOUNT = 'GET_FORECLOSURE_AMOUNT',
|
||||
UPLOAD_IMAGES = 'UPLOAD_IMAGES',
|
||||
UPLOAD_FEEDBACK_IMAGES = 'UPLOAD_FEEDBACK_IMAGES',
|
||||
ORIGINAL_IMAGES = 'ORIGINAL_IMAGES',
|
||||
}
|
||||
|
||||
export const API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
|
||||
@@ -86,8 +86,8 @@ API_URLS[ApiKeys.CASES_SYNC_STATUS] = '/cases/agents/sync-status';
|
||||
API_URLS[ApiKeys.CASES_SEND_ID] = '/cases/sync';
|
||||
API_URLS[ApiKeys.FETCH_CASES] = '/cases/agents/{agentReferenceId}';
|
||||
API_URLS[ApiKeys.GET_FORECLOSURE_AMOUNT] = '/{loanAccountNumber}/pre-closure-amount';
|
||||
API_URLS[ApiKeys.UPLOAD_IMAGES] = '/cases/images';
|
||||
API_URLS[ApiKeys.UPLOAD_FEEDBACK_IMAGES] = '/cases/feedback/original-images';
|
||||
API_URLS[ApiKeys.UPLOAD_FEEDBACK_IMAGES] = '/feedback/persist-original-images';
|
||||
API_URLS[ApiKeys.ORIGINAL_IMAGES] = '/feedback/original-images';
|
||||
|
||||
export const API_STATUS_CODE = {
|
||||
OK: 200,
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
const express = require('express');
|
||||
const multer = require('multer');
|
||||
const path = require('path');
|
||||
|
||||
const app = express();
|
||||
// const storage = multer.diskStorage({
|
||||
// destination: 'uploads/',
|
||||
// filename: (req, file, cb) => {
|
||||
// cb(null, file.originalname);
|
||||
// },
|
||||
// });
|
||||
const upload = multer({ dest: 'uploads/' });
|
||||
|
||||
app.post('/upload', upload.array('file[]'), (req, res) => {
|
||||
const files = req.files;
|
||||
console.log('request.file:::', files);
|
||||
// if (!req.files) {
|
||||
// res.status(400).json({ error: 'No image file provided' });
|
||||
// } else {
|
||||
// const imagePath = req.files[0].path;
|
||||
// res.json({ message: 'Image uploaded successfully', imagePath });
|
||||
// }
|
||||
res.send('Files uploaded successfully');
|
||||
});
|
||||
|
||||
app.listen(3000, () => {
|
||||
console.log('Server is running on port 3000');
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { toast } from '../../RN-UI-LIB/src/components/toast';
|
||||
import { _map, isEmpty } from '../../RN-UI-LIB/src/utlis/common';
|
||||
import { _map } from '../../RN-UI-LIB/src/utlis/common';
|
||||
import { findDocumentByDocumentType } from '../components/utlis/commonFunctions';
|
||||
import { CLICKSTREAM_EVENT_NAMES, FirestoreUpdateTypes } from '../common/Constants';
|
||||
import { getCurrentScreen, navigateToScreen } from '../components/utlis/navigationUtlis';
|
||||
@@ -18,21 +18,9 @@ import { addClickstreamEvent } from '../services/clickstreamEventService';
|
||||
import { getLoanAccountNumber } from '../components/utlis/commonFunctions';
|
||||
import { getVisitedWidgetsNodeList } from '../components/form/services/forms.service';
|
||||
import { CollectionCaseWidgetId, CommonCaseWidgetId } from '../types/template.types';
|
||||
import { IUploadImagePayload } from '../action/caseApiActions';
|
||||
import { IAvatarUri } from '../action/caseListAction';
|
||||
|
||||
export type ICasesMap = { [key: string]: ICaseItem };
|
||||
|
||||
export interface IDocument {
|
||||
questionKey: string;
|
||||
originalImageDocumentReferenceId: string;
|
||||
fileUri?: string;
|
||||
}
|
||||
|
||||
interface IDocumentDetail {
|
||||
interactionId: string;
|
||||
documents: Record<string, IDocument>;
|
||||
}
|
||||
interface IAllCasesSlice {
|
||||
casesList: ICaseItem[];
|
||||
casesListMap: ICasesMap;
|
||||
@@ -47,8 +35,6 @@ interface IAllCasesSlice {
|
||||
newlyPinnedCases: number;
|
||||
completedCases: number;
|
||||
caseDetails: Record<string, CaseDetail>;
|
||||
unsyncedCaseDetail: Record<string, CaseDetail>;
|
||||
docsToBeUploaded: Record<string, IDocumentDetail>;
|
||||
searchQuery: string;
|
||||
isOnboarded: boolean;
|
||||
visitPlansUpdating: boolean;
|
||||
@@ -72,8 +58,6 @@ const initialState: IAllCasesSlice = {
|
||||
newlyPinnedCases: 0,
|
||||
completedCases: 0,
|
||||
caseDetails: {},
|
||||
unsyncedCaseDetail: {},
|
||||
docsToBeUploaded: {},
|
||||
searchQuery: '',
|
||||
isOnboarded: false,
|
||||
visitPlansUpdating: false,
|
||||
@@ -406,14 +390,12 @@ const allCasesSlice = createSlice({
|
||||
}
|
||||
}
|
||||
},
|
||||
updateUnsyncedCaseDetail: (state, action) => {
|
||||
const { caseId, updatedCaseDetail } = action.payload;
|
||||
let caseKey: string = caseId;
|
||||
updateCaseDetail: (state, action) => {
|
||||
const { caseKey, updatedCaseDetail } = action.payload;
|
||||
if (updatedCaseDetail.caseType === CaseAllocationType.COLLECTION_CASE) {
|
||||
caseKey += '_' + Date.now();
|
||||
updatedCaseDetail.offlineCaseKey = caseKey;
|
||||
}
|
||||
state.unsyncedCaseDetail[caseKey] = updatedCaseDetail;
|
||||
state.caseDetails[caseKey] = updatedCaseDetail;
|
||||
},
|
||||
updateSingleCase: (state, action) => {
|
||||
const { data, id, caseType, offlineCaseKey } = action.payload;
|
||||
@@ -425,7 +407,7 @@ const allCasesSlice = createSlice({
|
||||
isSynced: true,
|
||||
};
|
||||
if (offlineCaseKey) {
|
||||
delete state.unsyncedCaseDetail[offlineCaseKey];
|
||||
delete state.caseDetails[offlineCaseKey];
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -583,55 +565,6 @@ const allCasesSlice = createSlice({
|
||||
}
|
||||
});
|
||||
},
|
||||
addDocumentToUpload: (state, action) => {
|
||||
const { caseId, questionKey, fileUri } = action.payload;
|
||||
const doc = {
|
||||
questionKey,
|
||||
fileUri,
|
||||
originalImageDocumentReferenceId: '',
|
||||
};
|
||||
if (state.docsToBeUploaded?.[caseId]) {
|
||||
const newDocsMap = { ...state.docsToBeUploaded[caseId].documents, doc };
|
||||
state.docsToBeUploaded[caseId].documents = newDocsMap;
|
||||
} else {
|
||||
state.docsToBeUploaded[caseId] = {
|
||||
interactionId: '',
|
||||
documents: {
|
||||
[questionKey]: doc,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
removeDocuments: (state, action) => {
|
||||
const { docs, caseId } = action.payload;
|
||||
docs?.forEach((doc: IUploadImagePayload) => {
|
||||
const { questionKey } = doc;
|
||||
// delete respective document
|
||||
if (state.docsToBeUploaded?.[caseId]?.documents?.[questionKey]) {
|
||||
delete state.docsToBeUploaded?.[caseId]?.documents?.[questionKey];
|
||||
}
|
||||
// delete the whole object if no documents remaining
|
||||
if (isEmpty(state.docsToBeUploaded?.[caseId]?.documents)) {
|
||||
delete state.docsToBeUploaded?.[caseId];
|
||||
}
|
||||
});
|
||||
},
|
||||
setDocumentInteractionId: (state, action) => {
|
||||
const { caseId, interactionId } = action.payload;
|
||||
if (state.docsToBeUploaded[caseId]) {
|
||||
state.docsToBeUploaded[caseId].interactionId = interactionId;
|
||||
}
|
||||
},
|
||||
setDocumentReferenceId: (state, action) => {
|
||||
const { caseId, questionKey, originalImageDocumentReferenceId } = action.payload;
|
||||
if (state.docsToBeUploaded[caseId]) {
|
||||
const doc = state.docsToBeUploaded[caseId].documents[questionKey];
|
||||
state.docsToBeUploaded[caseId].documents[questionKey] = {
|
||||
...doc,
|
||||
originalImageDocumentReferenceId,
|
||||
};
|
||||
}
|
||||
},
|
||||
setCasesImageUri: (state, action) => {
|
||||
const imageUris: IAvatarUri[] = action.payload;
|
||||
imageUris.forEach(({ caseId, imageUri }) => {
|
||||
@@ -651,7 +584,7 @@ export const {
|
||||
deleteIntermediateTodoListItem,
|
||||
setSelectedTodoListMap,
|
||||
resetSelectedTodoList,
|
||||
updateUnsyncedCaseDetail,
|
||||
updateCaseDetail,
|
||||
updateSingleCase,
|
||||
updateCaseDetailsFirestore,
|
||||
toggleNewlyAddedCase,
|
||||
@@ -660,10 +593,6 @@ export const {
|
||||
setVisitPlansUpdating,
|
||||
resetNewVisitedCases,
|
||||
syncCasesByFallback,
|
||||
addDocumentToUpload,
|
||||
setDocumentReferenceId,
|
||||
removeDocuments,
|
||||
setDocumentInteractionId,
|
||||
setCasesImageUri,
|
||||
} = allCasesSlice.actions;
|
||||
|
||||
|
||||
94
src/reducer/feedbackImagesSlice.ts
Normal file
94
src/reducer/feedbackImagesSlice.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { isEmpty } from '../../RN-UI-LIB/src/utlis/common';
|
||||
|
||||
export interface IDocument {
|
||||
fileUri?: string;
|
||||
}
|
||||
|
||||
interface IDocumentDetail {
|
||||
interactionId: string;
|
||||
documents: Record<string, IDocument>;
|
||||
}
|
||||
|
||||
interface IImagesSlice {
|
||||
intermediateDocsToBeUploaded: Record<string, IDocumentDetail>;
|
||||
docsToBeUploaded: Record<string, IDocumentDetail>;
|
||||
}
|
||||
|
||||
const initialState: IImagesSlice = {
|
||||
intermediateDocsToBeUploaded: {},
|
||||
docsToBeUploaded: {},
|
||||
};
|
||||
|
||||
const feedbackImagesSlice = createSlice({
|
||||
name: 'feedbackImages',
|
||||
initialState,
|
||||
reducers: {
|
||||
addIntermediateDocument: (state, action) => {
|
||||
const { caseId, questionKey, fileUri } = action.payload;
|
||||
const doc = {
|
||||
questionKey,
|
||||
fileUri,
|
||||
originalImageDocumentReferenceId: '',
|
||||
};
|
||||
if (state.intermediateDocsToBeUploaded?.[caseId]) {
|
||||
const newDocsMap = { ...state.intermediateDocsToBeUploaded[caseId].documents, doc };
|
||||
state.intermediateDocsToBeUploaded[caseId].documents = newDocsMap;
|
||||
} else {
|
||||
state.intermediateDocsToBeUploaded[caseId] = {
|
||||
interactionId: '',
|
||||
documents: {
|
||||
[questionKey]: doc,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
deleteIntermediateDocument: (state, action) => {
|
||||
const { caseId, questionKey } = action.payload;
|
||||
// delete respective document
|
||||
if (state.intermediateDocsToBeUploaded?.[caseId]?.documents?.[questionKey]) {
|
||||
delete state.intermediateDocsToBeUploaded?.[caseId]?.documents?.[questionKey];
|
||||
}
|
||||
// delete the whole object if no documents remaining
|
||||
if (isEmpty(state.intermediateDocsToBeUploaded?.[caseId]?.documents)) {
|
||||
delete state.intermediateDocsToBeUploaded?.[caseId];
|
||||
}
|
||||
},
|
||||
setDocumentsToUpload: (state, action) => {
|
||||
const { caseId, caseKey } = action.payload;
|
||||
if (state.intermediateDocsToBeUploaded?.[caseId]) {
|
||||
state.docsToBeUploaded[caseKey] = {
|
||||
...state.intermediateDocsToBeUploaded[caseId],
|
||||
};
|
||||
delete state.intermediateDocsToBeUploaded?.[caseId];
|
||||
}
|
||||
},
|
||||
setDocumentInteractionId: (state, action) => {
|
||||
const { caseKey, interactionId } = action.payload;
|
||||
if (state.docsToBeUploaded[caseKey]) {
|
||||
state.docsToBeUploaded[caseKey].interactionId = interactionId;
|
||||
}
|
||||
},
|
||||
removeDocumentByQuestionKey: (state, action) => {
|
||||
const { caseKey, questionKey } = action.payload;
|
||||
// delete respective document
|
||||
if (state.docsToBeUploaded[caseKey]?.documents?.[questionKey]) {
|
||||
delete state.docsToBeUploaded[caseKey]?.documents?.[questionKey];
|
||||
}
|
||||
// delete the whole object if no documents remaining
|
||||
if (isEmpty(state.docsToBeUploaded?.[caseKey]?.documents)) {
|
||||
delete state.docsToBeUploaded?.[caseKey];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
addIntermediateDocument,
|
||||
deleteIntermediateDocument,
|
||||
setDocumentsToUpload,
|
||||
setDocumentInteractionId,
|
||||
removeDocumentByQuestionKey,
|
||||
} = feedbackImagesSlice.actions;
|
||||
|
||||
export default feedbackImagesSlice.reducer;
|
||||
@@ -28,7 +28,10 @@ const FeedbackDetailImageItem: React.FC<IFeedbackDetailImageItem> = ({ image })
|
||||
};
|
||||
|
||||
const questionText = getQuestionText(image);
|
||||
|
||||
const originalImageUri = image.metadata?.originalDocumentSignedUri || image.inputText;
|
||||
// [TODO]: Lat long is merely for testing in UAT, will remove it once get the signoff.
|
||||
const latitude = image.metadata?.image_latitude;
|
||||
const longitude = image.metadata?.image_longitude;
|
||||
return (
|
||||
<View style={[GenericStyles.mv8]}>
|
||||
<Text style={[styles.textContainer, styles.questionText]}>{questionText}</Text>
|
||||
@@ -47,6 +50,9 @@ const FeedbackDetailImageItem: React.FC<IFeedbackDetailImageItem> = ({ image })
|
||||
onPress={handleExpandImage}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<Text>
|
||||
Geolocation: (Lat:{latitude}, Long:{longitude})
|
||||
</Text>
|
||||
<Modal
|
||||
visible={isImageExpanded}
|
||||
transparent
|
||||
@@ -54,7 +60,8 @@ const FeedbackDetailImageItem: React.FC<IFeedbackDetailImageItem> = ({ image })
|
||||
animationType="fade"
|
||||
>
|
||||
<ExpandableImage
|
||||
imageSrc={image.inputText}
|
||||
imageSrc={originalImageUri}
|
||||
fallbackImage={image.inputText}
|
||||
title={questionText}
|
||||
close={handleExpandedImageClose}
|
||||
/>
|
||||
|
||||
@@ -11,7 +11,8 @@ import {
|
||||
import { addClickstreamEvent } from '../../services/clickstreamEventService';
|
||||
import { CaseAllocationType } from '../allCases/interface';
|
||||
import { CaseDetail } from './interface';
|
||||
import { uploadUnsyncedImages } from '../../action/caseApiActions';
|
||||
import { uploadImages, uploadUnsyncedImages } from '../../action/caseApiActions';
|
||||
import { setDocumentInteractionId } from '../../reducer/feedbackImagesSlice';
|
||||
|
||||
export const getUnSyncedCase = (updatedCaseDetail: CaseDetail | undefined): any => {
|
||||
const caseId = updatedCaseDetail?.id;
|
||||
@@ -22,9 +23,9 @@ export const getUnSyncedCase = (updatedCaseDetail: CaseDetail | undefined): any
|
||||
const interactionsHandler = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const isOnline = useIsOnline();
|
||||
const { unsyncedCasesDetails, docsToBeUploaded } = useAppSelector((state) => ({
|
||||
unsyncedCasesDetails: state.allCases.unsyncedCaseDetail,
|
||||
docsToBeUploaded: state.allCases.docsToBeUploaded,
|
||||
const { allCasesDetails, docsToBeUploaded } = useAppSelector((state) => ({
|
||||
allCasesDetails: state.allCases.caseDetails,
|
||||
docsToBeUploaded: state.feedbackImages.docsToBeUploaded,
|
||||
}));
|
||||
const { templateId } = useAppSelector(
|
||||
(state) => state.case.templateData[CaseAllocationType.ADDRESS_VERIFICATION_CASE]
|
||||
@@ -36,17 +37,26 @@ const interactionsHandler = () => {
|
||||
|
||||
const inProgressCaseIds = useRef<string[]>([]);
|
||||
|
||||
const handleSuccessSubmit = (caseKey: string, interactionId: string) => {
|
||||
const docs = docsToBeUploaded?.[caseKey]?.documents;
|
||||
if (!docs) {
|
||||
return;
|
||||
}
|
||||
dispatch(setDocumentInteractionId({ caseKey, interactionId }));
|
||||
dispatch(uploadImages(caseKey, docs, interactionId));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!unsyncedCasesDetails) return;
|
||||
if (!allCasesDetails) return;
|
||||
let notSyncedCases: Array<any> = [];
|
||||
// [DISCUSS]: isApiCalled not getting true anywhere.
|
||||
_map(unsyncedCasesDetails, (el) => {
|
||||
_map(allCasesDetails, (el) => {
|
||||
if (
|
||||
unsyncedCasesDetails[el]?.isSynced === false &&
|
||||
unsyncedCasesDetails[el]?.isApiCalled === false &&
|
||||
allCasesDetails[el]?.isSynced === false &&
|
||||
allCasesDetails[el]?.isApiCalled === false &&
|
||||
!inProgressCaseIds.current.includes(el)
|
||||
) {
|
||||
const unSyncedCase = getUnSyncedCase(unsyncedCasesDetails[el]);
|
||||
const unSyncedCase = getUnSyncedCase(allCasesDetails[el]);
|
||||
notSyncedCases.push(unSyncedCase);
|
||||
}
|
||||
});
|
||||
@@ -59,18 +69,23 @@ const interactionsHandler = () => {
|
||||
* inProgressCaseIds not removing the processed ID,
|
||||
* this will prevent processing of failed api cases again.
|
||||
*/
|
||||
inProgressCaseIds.current.push(caseItem.offlineCaseKey || caseItem.id);
|
||||
const caseKey = caseItem.offlineCaseKey || caseItem.id;
|
||||
inProgressCaseIds.current.push(caseKey);
|
||||
let modifiedCaseItem: any;
|
||||
if (caseItem?.caseType === CaseAllocationType.COLLECTION_CASE) {
|
||||
modifiedCaseItem = await getTransformedCollectionCaseItem(caseItem);
|
||||
} else {
|
||||
modifiedCaseItem = await getTransformedAvCase(caseItem, templateId);
|
||||
}
|
||||
dispatch(syncCaseDetail(modifiedCaseItem));
|
||||
dispatch(
|
||||
syncCaseDetail(modifiedCaseItem, {
|
||||
onSuccessCB: (_, interactionId) => handleSuccessSubmit(caseKey, interactionId),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [unsyncedCasesDetails, isOnline]);
|
||||
}, [allCasesDetails, isOnline]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOnline) {
|
||||
@@ -81,13 +96,14 @@ const interactionsHandler = () => {
|
||||
}
|
||||
_map(docsToBeUploaded, (caseId) => {
|
||||
const interactionId = docsToBeUploaded[caseId]?.interactionId;
|
||||
// No interactionId means form is not submitted yet
|
||||
if (!interactionId) {
|
||||
return;
|
||||
}
|
||||
const doc = docsToBeUploaded[caseId].documents;
|
||||
dispatch(uploadUnsyncedImages(caseId, doc));
|
||||
dispatch(uploadUnsyncedImages(caseId, interactionId, doc));
|
||||
});
|
||||
}, [docsToBeUploaded, isOnline]);
|
||||
}, [isOnline]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@ import feedbackHistorySlice from '../reducer/feedbackHistorySlice';
|
||||
import notificationsSlice from '../reducer/notificationsSlice';
|
||||
import MetadataSlice from '../reducer/metadataSlice';
|
||||
import foregroundServiceSlice from '../reducer/foregroundServiceSlice';
|
||||
import feedbackImagesSlice from '../reducer/feedbackImagesSlice';
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
case: caseReducer,
|
||||
@@ -44,6 +45,7 @@ const rootReducer = combineReducers({
|
||||
notifications: notificationsSlice,
|
||||
metadata: MetadataSlice,
|
||||
foregroundService: foregroundServiceSlice,
|
||||
feedbackImages: feedbackImagesSlice,
|
||||
});
|
||||
|
||||
const persistConfig = {
|
||||
@@ -61,6 +63,7 @@ const persistConfig = {
|
||||
'repayments',
|
||||
'feedbackHistory',
|
||||
'address',
|
||||
'feedbackImages',
|
||||
],
|
||||
blackList: ['case', 'filters'],
|
||||
};
|
||||
|
||||
@@ -16,6 +16,11 @@ export enum OPTION_TAG {
|
||||
IMAGE_UPLOAD = 'IMAGE_UPLOAD',
|
||||
}
|
||||
|
||||
interface IImageMetadata {
|
||||
image_created_at: string;
|
||||
originalDocumentSignedUri: string;
|
||||
}
|
||||
|
||||
export interface IAnswerView {
|
||||
interactionId?: number;
|
||||
referenceId?: string;
|
||||
@@ -30,6 +35,7 @@ export interface IAnswerView {
|
||||
inputDate?: string;
|
||||
inputText?: string;
|
||||
questionTag?: OPTION_TAG;
|
||||
metadata?: IImageMetadata;
|
||||
}
|
||||
|
||||
export enum FEEDBACK_TYPE {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 MiB |
196
yarn.lock
196
yarn.lock
@@ -957,6 +957,11 @@
|
||||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@bam.tech/react-native-image-resizer@3.0.5":
|
||||
version "3.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@bam.tech/react-native-image-resizer/-/react-native-image-resizer-3.0.5.tgz#6661ba020de156268f73bdc92fbb93ef86f88a13"
|
||||
integrity sha512-u5QGUQGGVZiVCJ786k9/kd7pPRZ6eYfJCYO18myVCH8FbVI7J8b5GT2Svjj2x808DlWeqfaZOOzxPqo27XYvrQ==
|
||||
|
||||
"@bcoe/v8-coverage@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
@@ -1729,48 +1734,123 @@
|
||||
redux-thunk "^2.4.2"
|
||||
reselect "^4.1.7"
|
||||
|
||||
"@sentry/browser@7.29.0":
|
||||
version "7.29.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.29.0.tgz#eb162b50adec33ac49ecd3dc930bdffbfda8098e"
|
||||
integrity sha512-Af+dIcntaw405Wt7myDOMGDxiszfy4aBdshrEKYbGgcfHjgXBIdF3iKlNatvl6nrOm+IOVuKgSpCLOr2hiCwzw==
|
||||
"@sentry-internal/tracing@7.52.0":
|
||||
version "7.52.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.52.0.tgz#c4e0750ad0c3949c5bb4b59cbb708b0fef274080"
|
||||
integrity sha512-o1YPcRGtC9tjeFCvWRJsbgK94zpExhzfxWaldAKvi3PuWEmPeewSdO/Q5pBIY1QonvSI+Q3gysLRcVlLYHhO5A==
|
||||
dependencies:
|
||||
"@sentry/core" "7.29.0"
|
||||
"@sentry/replay" "7.29.0"
|
||||
"@sentry/types" "7.29.0"
|
||||
"@sentry/utils" "7.29.0"
|
||||
"@sentry/core" "7.52.0"
|
||||
"@sentry/types" "7.52.0"
|
||||
"@sentry/utils" "7.52.0"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/core@7.29.0":
|
||||
version "7.29.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.29.0.tgz#bc4b54d56cf7652598d4430cf43ea97cc069f6fe"
|
||||
integrity sha512-+e9aIp2ljtT4EJq3901z6TfEVEeqZd5cWzbKEuQzPn2UO6If9+Utd7kY2Y31eQYb4QnJgZfiIEz1HonuYY6zqQ==
|
||||
"@sentry/browser@7.52.0":
|
||||
version "7.52.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.52.0.tgz#55d266c89ed668389ff687e5cc885c27016ea85c"
|
||||
integrity sha512-Sib0T24cQCqqqAhg+nZdfI7qNYGE03jiM3RbY7yG5UoycdnJzWEwrBVSzRTgg3Uya9TRTEGJ+d9vxPIU5TL7TA==
|
||||
dependencies:
|
||||
"@sentry/types" "7.29.0"
|
||||
"@sentry/utils" "7.29.0"
|
||||
"@sentry-internal/tracing" "7.52.0"
|
||||
"@sentry/core" "7.52.0"
|
||||
"@sentry/replay" "7.52.0"
|
||||
"@sentry/types" "7.52.0"
|
||||
"@sentry/utils" "7.52.0"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/replay@7.29.0":
|
||||
version "7.29.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.29.0.tgz#75d5bb9df39e0a31994be245032c9998af62a304"
|
||||
integrity sha512-Gw7HgviJQu6pX5RFQGVY38Av4qFn9otrZdwSSl/QK5hIyg6yhlh5h7U0ydZkrYYGiW6Z6SYYRpEWCJc/Wbh+ZQ==
|
||||
"@sentry/cli@2.17.5":
|
||||
version "2.17.5"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.17.5.tgz#d41e24893a843bcd41e14274044a7ddea9332824"
|
||||
integrity sha512-0tXjLDpaKB46851EMJ6NbP0o9/gdEaDSLAyjEtXxlVO6+RyhUj6x6jDwn0vis8n/7q0AvbIjAcJrot+TbZP+WQ==
|
||||
dependencies:
|
||||
"@sentry/core" "7.29.0"
|
||||
"@sentry/types" "7.29.0"
|
||||
"@sentry/utils" "7.29.0"
|
||||
https-proxy-agent "^5.0.0"
|
||||
node-fetch "^2.6.7"
|
||||
progress "^2.0.3"
|
||||
proxy-from-env "^1.1.0"
|
||||
which "^2.0.2"
|
||||
|
||||
"@sentry/types@7.29.0":
|
||||
version "7.29.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.29.0.tgz#ed829b6014ee19049035fec6af2b4fea44ff28b8"
|
||||
integrity sha512-DmoEpoqHPty3VxqubS/5gxarwebHRlcBd/yuno+PS3xy++/i9YPjOWLZhU2jYs1cW68M9R6CcCOiC9f2ckJjdw==
|
||||
|
||||
"@sentry/utils@7.29.0":
|
||||
version "7.29.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.29.0.tgz#cbf8f87dd851b0fdc7870db9c68014c321c3bab8"
|
||||
integrity sha512-ICcBwTiBGK8NQA8H2BJo0JcMN6yCeKLqNKNMVampRgS6wSfSk1edvcTdhRkW3bSktIGrIPZrKskBHyMwDGF2XQ==
|
||||
"@sentry/core@7.52.0":
|
||||
version "7.52.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.52.0.tgz#6c820ca48fe2f06bfd6b290044c96de2375f2ad4"
|
||||
integrity sha512-BWdG6vCMeUeMhF4ILpxXTmw70JJvT1MGJcnv09oSupWHTmqy6I19YP6YcEyFuBL4jXPN51eCl7luIdLGJrPbOg==
|
||||
dependencies:
|
||||
"@sentry/types" "7.29.0"
|
||||
"@sentry/types" "7.52.0"
|
||||
"@sentry/utils" "7.52.0"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/hub@7.52.0":
|
||||
version "7.52.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.52.0.tgz#ffc087d58c745d57108862faa0f701b15503dcc2"
|
||||
integrity sha512-w3d8Pmp3Fx2zbbjz6hAeIbsFEkLyrUs9YTGG2y8oCoTlAtGK+AjdG+Z0H/clAZONflD/je2EmFHCI0EuXE9tEw==
|
||||
dependencies:
|
||||
"@sentry/core" "7.52.0"
|
||||
"@sentry/types" "7.52.0"
|
||||
"@sentry/utils" "7.52.0"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/integrations@7.52.0":
|
||||
version "7.52.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.52.0.tgz#632aa5e54bdfdab910a24057c2072634a2670409"
|
||||
integrity sha512-tqxYzgc71XdFD8MTCsVMCPef08lPY9jULE5Zi7TzjyV2AItDRJPkixG0qjwjOGwCtN/6KKz0lGPGYU8ZDxvsbg==
|
||||
dependencies:
|
||||
"@sentry/types" "7.52.0"
|
||||
"@sentry/utils" "7.52.0"
|
||||
localforage "^1.8.1"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/react-native@5.5.0":
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-5.5.0.tgz#b1283f68465b1772ad6059ebba149673cef33f2d"
|
||||
integrity sha512-xrES+OAIu3HFhoQSuJjd16Hh02/mByuNoKUjF7e4WDGIiTew3aqlqeLjU7x4npmg5Vbt+ND5jR12u/NmdfArwg==
|
||||
dependencies:
|
||||
"@sentry/browser" "7.52.0"
|
||||
"@sentry/cli" "2.17.5"
|
||||
"@sentry/core" "7.52.0"
|
||||
"@sentry/hub" "7.52.0"
|
||||
"@sentry/integrations" "7.52.0"
|
||||
"@sentry/react" "7.52.0"
|
||||
"@sentry/types" "7.52.0"
|
||||
"@sentry/utils" "7.52.0"
|
||||
|
||||
"@sentry/react@7.52.0":
|
||||
version "7.52.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.52.0.tgz#d12d270ec82dea0474e69deb9112181affe7c524"
|
||||
integrity sha512-VQxquyFFlvB81k7UER7tTJxjzbczNI2jqsw6nN1TVDrAIDt8/hT2x7m/M0FlWc88roBKuaMmbvzfNGWaL9abyQ==
|
||||
dependencies:
|
||||
"@sentry/browser" "7.52.0"
|
||||
"@sentry/types" "7.52.0"
|
||||
"@sentry/utils" "7.52.0"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/replay@7.52.0":
|
||||
version "7.52.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.52.0.tgz#4d78e88282d2c1044ea4b648a68d1b22173e810d"
|
||||
integrity sha512-RRPALjDST2s7MHiMcUJ7Wo4WW7EWfUDYSG0LuhMT8DNc+ZsxQoFsLYX/yz8b3f0IUSr7xKBXP+aPeIy3jDAS2g==
|
||||
dependencies:
|
||||
"@sentry/core" "7.52.0"
|
||||
"@sentry/types" "7.52.0"
|
||||
"@sentry/utils" "7.52.0"
|
||||
|
||||
"@sentry/types@7.52.0":
|
||||
version "7.52.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.52.0.tgz#b7d5372f17355e3991cbe818ad567f3fe277cc6b"
|
||||
integrity sha512-XnEWpS6P6UdP1FqbmeqhI96Iowqd2jM5R7zJ97txTdAd5NmdHHH0pODTR9NiQViA1WlsXDut7ZLxgPzC9vIcMA==
|
||||
|
||||
"@sentry/utils@7.52.0":
|
||||
version "7.52.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.52.0.tgz#cacc36d905036ba7084c14965e964fc44239d7f0"
|
||||
integrity sha512-X1NHYuqW0qpZfP731YcVe+cn36wJdAeBHPYPIkXCl4o4GePCJfH/CM/+9V9cZykNjyLrs2Xy/TavSAHNCj8j7w==
|
||||
dependencies:
|
||||
"@sentry/types" "7.52.0"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@shopify/flash-list@1.4.3":
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@shopify/flash-list/-/flash-list-1.4.3.tgz#b7a4fe03d64f3c5ce9646859b49b9d95307f203d"
|
||||
integrity sha512-jtIReAbwWzYBV0dQ6Io9wBX+pD0C4qQFMrb5/fkEvX8PYDgBl5KRYvpfr9WLLj8CV2Jsn1X0mYOsB+ysWrI/8g==
|
||||
dependencies:
|
||||
recyclerlistview "4.2.0"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@sideway/address@^4.1.3":
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0"
|
||||
@@ -4858,6 +4938,11 @@ image-size@^0.6.0:
|
||||
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.6.3.tgz#e7e5c65bb534bd7cdcedd6cb5166272a85f75fb2"
|
||||
integrity sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA==
|
||||
|
||||
immediate@~3.0.5:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
|
||||
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
|
||||
|
||||
immer@^9.0.16:
|
||||
version "9.0.16"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.16.tgz#8e7caab80118c2b54b37ad43e05758cdefad0198"
|
||||
@@ -5977,6 +6062,13 @@ levn@~0.3.0:
|
||||
prelude-ls "~1.1.2"
|
||||
type-check "~0.3.2"
|
||||
|
||||
lie@3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
|
||||
integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==
|
||||
dependencies:
|
||||
immediate "~3.0.5"
|
||||
|
||||
lilconfig@2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
|
||||
@@ -6020,6 +6112,13 @@ listr2@^5.0.7:
|
||||
through "^2.3.8"
|
||||
wrap-ansi "^7.0.0"
|
||||
|
||||
localforage@^1.8.1:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4"
|
||||
integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==
|
||||
dependencies:
|
||||
lie "3.1.1"
|
||||
|
||||
locate-path@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
|
||||
@@ -6062,7 +6161,7 @@ lodash.compact@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/lodash.compact/-/lodash.compact-3.0.1.tgz#540ce3837745975807471e16b4a2ba21e7256ca5"
|
||||
integrity sha512-2ozeiPi+5eBXW1CLtzjk8XQFhQOEMwwfxblqeq6EGyTxZJ1bPATqilY0e6g2SLQpP4KuMeuioBhEnWz5Pr7ICQ==
|
||||
|
||||
lodash.debounce@^4.0.8:
|
||||
lodash.debounce@4.0.8, lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
|
||||
@@ -6825,6 +6924,13 @@ node-fetch@^2.2.0, node-fetch@^2.6.0:
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.6.7:
|
||||
version "2.6.11"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25"
|
||||
integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-int64@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
||||
@@ -7387,6 +7493,11 @@ process-nextick-args@~2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
progress@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
|
||||
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
|
||||
|
||||
promise-polyfill@^8.1.3:
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.3.0.tgz#9284810268138d103807b11f4e23d5e945a4db63"
|
||||
@@ -7407,7 +7518,7 @@ prompts@^2.0.1, prompts@^2.4.0:
|
||||
kleur "^3.0.3"
|
||||
sisteransi "^1.0.5"
|
||||
|
||||
prop-types@^15.7.2, prop-types@^15.8.0, prop-types@^15.8.1:
|
||||
prop-types@15.8.1, prop-types@^15.7.2, prop-types@^15.8.0, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@@ -7872,6 +7983,15 @@ recursive-fs@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/recursive-fs/-/recursive-fs-2.1.0.tgz#1e20cf7836b292ed81208c4817550a58ad0e15ff"
|
||||
integrity sha512-oed3YruYsD52Mi16s/07eYblQOLi5dTtxpIJNdfCEJ7S5v8dDgVcycar0pRWf4IBuPMIkoctC8RTqGJzIKMNAQ==
|
||||
|
||||
recyclerlistview@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/recyclerlistview/-/recyclerlistview-4.2.0.tgz#a140149aaa470c9787a1426452651934240d69ef"
|
||||
integrity sha512-uuBCi0c+ggqHKwrzPX4Z/mJOzsBbjZEAwGGmlwpD/sD7raXixdAbdJ6BTcAmuWG50Cg4ru9p12M94Njwhr/27A==
|
||||
dependencies:
|
||||
lodash.debounce "4.0.8"
|
||||
prop-types "15.8.1"
|
||||
ts-object-utils "0.0.5"
|
||||
|
||||
redux-persist@6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8"
|
||||
@@ -9004,6 +9124,11 @@ tr46@~0.0.3:
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||
|
||||
ts-object-utils@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/ts-object-utils/-/ts-object-utils-0.0.5.tgz#95361cdecd7e52167cfc5e634c76345e90a26077"
|
||||
integrity sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA==
|
||||
|
||||
tsconfig-paths@^3.14.1:
|
||||
version "3.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
|
||||
@@ -9014,6 +9139,11 @@ tsconfig-paths@^3.14.1:
|
||||
minimist "^1.2.6"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
tslib@2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
|
||||
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||
|
||||
tslib@^1.8.1, tslib@^1.9.3:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
|
||||
Reference in New Issue
Block a user