TP-31697 | Image optimization changes

This commit is contained in:
Aman Chaturvedi
2023-06-14 14:30:03 +05:30
parent c6177a0017
commit b2410f0114
13 changed files with 411 additions and 55 deletions

90
src/ImageUploader.tsx Normal file
View File

@@ -0,0 +1,90 @@
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;

View File

@@ -12,6 +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 { logError } from '../components/utlis/errorUtils';
// TODO: Need to add respective interfaces instead of any
interface IUnifiedData {
@@ -21,6 +24,12 @@ interface IUnifiedData {
repayments: Array<any>;
}
export interface IUploadImagePayload {
interactionId: string;
questionKey: string;
originalImageDocumentReferenceId: string;
}
export enum UnifiedCaseDetailsTypes {
ADDRESS_AND_GEOLOCATIONS = 'includeAddressesAndGeoLocations',
FEEDBACKS = 'includeFeedbacks',
@@ -135,3 +144,85 @@ export const getCaseUnifiedData =
dispatch(setAddressLoading({ isLoading: false, loanAccountNumbers }));
});
};
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) =>
(dispatch: AppDispatch) => {
_map(documents, (questionKey) => {
if (!documents) {
return;
}
const fileDoc = documents[questionKey];
if (!interactionId || !fileDoc) {
return;
}
const { fileUri } = fileDoc;
const formData = new FormData();
formData.append('images', {
uri: fileUri,
name: `image_${caseId}_${new Date().getTime()}`,
type: 'image/jpeg',
} as any);
const url = getApiUrl(ApiKeys.UPLOAD_IMAGES);
axiosInstance
.post(url, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then((res) => {
const originalImageDocumentReferenceId = res?.data?.referenceId;
dispatch(
setDocumentReferenceId({ caseId, questionKey, originalImageDocumentReferenceId })
);
dispatch(
uploadFeedbackImages(caseId, [
{
interactionId,
questionKey,
originalImageDocumentReferenceId,
},
])
);
})
.catch((err) => {
logError(err as Error, 'Error uploading image to document service');
});
});
};
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))
};

View File

@@ -7,7 +7,7 @@ import {
resetTodoList,
setLoading,
setVisitPlansUpdating,
updateCaseDetail,
updateUnsyncedCaseDetail,
updateSingleCase,
} from '../reducer/allCasesSlice';
import {
@@ -24,6 +24,7 @@ import { setFilters } from '../reducer/filtersSlice';
import { toast } from '../../RN-UI-LIB/src/components/toast';
import { ToastMessages } from '../screens/allCases/constants';
import { GenericFunctionArgs } from '../common/GenericTypes';
import axios from 'axios';
let _signedApiCallBucket: { req: any; added_At: number; callback: GenericFunctionArgs }[] = [];
let _signedApiCallBucketTimer: number = 0;
@@ -72,7 +73,7 @@ export const syncCaseDetail =
payload: any,
updatedCaseDetail?: any,
callbacks?: {
onSuccessCB?: (data: any, actions?: any) => void;
onSuccessCB?: (data: any, actions?: any, interactionId?: string) => void;
onErrorCB?: (e: Error) => void;
},
nextActions?: any
@@ -88,6 +89,7 @@ export const syncCaseDetail =
})
.then((res) => {
const caseType = payload.caseType;
const interactionId = res.data?.referenceId;
dispatch(
updateSingleCase({
data: res.data,
@@ -102,7 +104,7 @@ export const syncCaseDetail =
text1: ToastMessages.FEEDBACK_SUCCESSFUL,
});
if (callbacks?.onSuccessCB != null && typeof callbacks?.onSuccessCB === 'function') {
callbacks?.onSuccessCB(payload.data.answers, nextActions);
callbacks?.onSuccessCB(payload.data.answers, nextActions, interactionId);
}
})
.catch((e) => {
@@ -111,9 +113,9 @@ export const syncCaseDetail =
type: 'error',
text1: ToastMessages.FEEDBACK_FAILED,
});
if (updatedCaseDetail) {
if (updatedCaseDetail && !updatedCaseDetail.offlineCaseKey) {
dispatch(
updateCaseDetail({
updateUnsyncedCaseDetail({
caseId: payload.data.caseReferenceId,
updatedCaseDetail,
})

View File

@@ -1,13 +1,15 @@
import React, { useEffect, useState } from 'react';
import { Control, Controller } from 'react-hook-form';
import { ImageBackground, StyleSheet, TouchableOpacity, View } from 'react-native';
import PhotoUpload from '../../../../RN-UI-LIB/src/components/photoUpload/PhotoUpload';
import PhotoUpload, {
IImageDetails,
} from '../../../../RN-UI-LIB/src/components/photoUpload/PhotoUpload';
import { useSelector } from 'react-redux';
import Text from '../../../../RN-UI-LIB/src/components/Text';
import DeleteIcon from '../../../../RN-UI-LIB/src/Icons/DeleteIcon';
import { GenericStyles } from '../../../../RN-UI-LIB/src/styles';
import { COLORS } from '../../../../RN-UI-LIB/src/styles/colors';
import { useAppSelector } from '../../../hooks';
import { useAppDispatch, useAppSelector } from '../../../hooks';
import { RootState } from '../../../store/store';
import { AnswerType } from '../interface';
import ErrorMessage from './ErrorMessage';
@@ -17,6 +19,7 @@ import { CLICKSTREAM_EVENT_NAMES, PrefixJpegBase64Image } from '../../../common/
import { addClickstreamEvent } from '../../../services/clickstreamEventService';
import { isQuestionMandatory, validateInput } from '../services/validation.service';
import { CaseAllocationType } from '../../../screens/allCases/interface';
import { addDocumentToUpload } from '../../../reducer/allCasesSlice';
interface IOfflineImage {
idx: string;
@@ -51,6 +54,8 @@ const ImageUpload: React.FC<IImageUpload> = (props) => {
]?.questionContext?.[questionId]?.answer
);
const dispatch = useAppDispatch();
useEffect(() => {
if (dataFromRedux) {
setImageId(dataFromRedux);
@@ -61,8 +66,20 @@ const ImageUpload: React.FC<IImageUpload> = (props) => {
return null;
}
const handleChange = async (clickedImage: string | null, onChange: (...event: any[]) => void) => {
const data = `${PrefixJpegBase64Image}${clickedImage}`;
const addOriginalFileUriToDocs = (caseId: string, fileUri: string, questionKey: string) => {
if (!fileUri) {
return;
}
dispatch(addDocumentToUpload({ caseId, fileUri, questionKey }));
};
const handleChange = async (clickedImage: IImageDetails, onChange: (...event: any[]) => void) => {
const { base64, uri } = clickedImage;
addOriginalFileUriToDocs(caseId, uri, questionId);
if (!base64) {
return;
}
const base64Image = `${PrefixJpegBase64Image}${base64}`;
var uniqueId = 'id' + new Date().getTime();
setImageId(uniqueId);
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_FORM_ELEMENT_CHANGED, {
@@ -78,8 +95,9 @@ const ImageUpload: React.FC<IImageUpload> = (props) => {
answer: uniqueId,
type: AnswerType.image,
});
await OfflineImageDAO.addImage(data, uniqueId);
await OfflineImageDAO.addImage(base64Image, uniqueId);
};
// TODO : add the validator back when firestore is fixed.
return (
<View style={[GenericStyles.mt12]}>

View File

@@ -17,7 +17,8 @@ import useIsOnline from '../../hooks/useIsOnline';
import {
getUpdatedAVCaseDetail,
getUpdatedCollectionCaseDetail,
updateCaseDetail,
setDocumentInteractionId,
updateUnsyncedCaseDetail,
} from '../../reducer/allCasesSlice';
import { deleteInteraction, deleteJourney, updateInteraction } from '../../reducer/caseReducer';
import { CaseAllocationType } from '../../screens/allCases/interface';
@@ -41,6 +42,8 @@ import { CaptureGeolocation } from './services/geoLocation.service';
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';
interface IWidget {
route: {
@@ -58,13 +61,21 @@ const Widget: React.FC<IWidget> = (props) => {
const [isSubmitting, setIsSubmitting] = useState(false);
const { params } = props.route;
const { caseId, journey } = params;
const caseType = useAppSelector(
(state) =>
state.allCases.caseDetails[caseId]?.caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE
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,
};
}
);
const name = getWidgetNameFromRoute(props.route.name, caseType);
const templateData: FormTemplateV1 = useAppSelector((state) => state.case.templateData[caseType]);
const caseData = useAppSelector((state) => state.allCases.caseDetails[caseId]);
const { sections, conditionActions: widgetConditionActions, isLeaf } = templateData.widget[name];
const sectionMap = templateData.sections;
const [error, setError] = useState();
@@ -80,7 +91,6 @@ const Widget: React.FC<IWidget> = (props) => {
setIsJourneyFirstScreen(isFirst);
}, [templateData, name]);
const dataToBeValidated = useAppSelector((state) => state.case.caseForm?.[caseId]?.[journey]);
const {
control,
handleSubmit,
@@ -127,7 +137,19 @@ const Widget: React.FC<IWidget> = (props) => {
setError(data);
};
const onSuccessfulSubmit = (data: any, nextActions?: any) => {
// Upload original doc to document service => get docRefId
const uploadOriginalDocs = (interactionId: string) => {
if (isEmpty(docsToBeUploaded)) {
return;
}
dispatch(setDocumentInteractionId({ caseId, interactionId }));
if (isOnline) {
dispatch(uploadImages(caseId, docsToBeUploaded, interactionId));
} else {
}
};
const onSuccessfulSubmit = (data: any, nextActions?: any, interactionId?: string) => {
setIsSubmitting(false);
navigateToScreen(
caseType === CaseAllocationType.COLLECTION_CASE ? 'collectionCaseDetail' : 'caseDetail',
@@ -146,6 +168,9 @@ const Widget: React.FC<IWidget> = (props) => {
nextActions,
})
);
if (interactionId) {
uploadOriginalDocs(interactionId);
}
};
async function fetchLocation(): Promise<Geolocation.GeoCoordinates | undefined> {
@@ -196,7 +221,7 @@ const Widget: React.FC<IWidget> = (props) => {
);
} else {
dispatch(
updateCaseDetail({
updateUnsyncedCaseDetail({
caseId,
updatedCaseDetail: updatedCase,
})
@@ -253,7 +278,7 @@ const Widget: React.FC<IWidget> = (props) => {
);
} else {
dispatch(
updateCaseDetail({
updateUnsyncedCaseDetail({
caseId,
updatedCaseDetail: updatedCase,
})

View File

@@ -47,6 +47,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',
}
export const API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
@@ -80,6 +82,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';
export const API_STATUS_CODE = {
OK: 200,

28
src/local-server.js Normal file
View File

@@ -0,0 +1,28 @@
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');
});

View File

@@ -1,6 +1,6 @@
import { createSlice } from '@reduxjs/toolkit';
import { toast } from '../../RN-UI-LIB/src/components/toast';
import { _map } from '../../RN-UI-LIB/src/utlis/common';
import { _map, isEmpty } from '../../RN-UI-LIB/src/utlis/common';
import { CLICKSTREAM_EVENT_NAMES, FirestoreUpdateTypes } from '../common/Constants';
import { getCurrentScreen, navigateToScreen } from '../components/utlis/navigationUtlis';
import { CaseUpdates } from '../hooks/useFirestoreUpdates';
@@ -17,9 +17,20 @@ 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';
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;
@@ -34,6 +45,8 @@ interface IAllCasesSlice {
newlyPinnedCases: number;
completedCases: number;
caseDetails: Record<string, CaseDetail>;
unsyncedCaseDetail: Record<string, CaseDetail>;
docsToBeUploaded: Record<string, IDocumentDetail>;
searchQuery: string;
isOnboarded: boolean;
visitPlansUpdating: boolean;
@@ -57,6 +70,8 @@ const initialState: IAllCasesSlice = {
newlyPinnedCases: 0,
completedCases: 0,
caseDetails: {},
unsyncedCaseDetail: {},
docsToBeUploaded: {},
searchQuery: '',
isOnboarded: false,
visitPlansUpdating: false,
@@ -382,14 +397,41 @@ const allCasesSlice = createSlice({
}
}
},
updateCaseDetail: (state, action) => {
updateUnsyncedCaseDetail: (state, action) => {
const { caseId, updatedCaseDetail } = action.payload;
let caseKey: string = caseId;
if (updatedCaseDetail.caseType === CaseAllocationType.COLLECTION_CASE) {
caseKey += '_' + Date.now();
updatedCaseDetail.offlineCaseKey = caseKey;
}
state.caseDetails[caseKey] = updatedCaseDetail;
state.unsyncedCaseDetail[caseKey] = updatedCaseDetail;
},
updateSingleCase: (state, action) => {
const { data, id, caseType, offlineCaseKey } = action.payload;
if (caseType === CaseAllocationType.COLLECTION_CASE) {
const computedKey = offlineCaseKey || id;
if (state.caseDetails?.[id]) {
state.caseDetails[id] = {
...state.caseDetails[computedKey],
isSynced: true,
};
if (offlineCaseKey) {
delete state.unsyncedCaseDetail[offlineCaseKey];
}
}
return;
}
if (data) {
state.caseDetails[id] = {
...data,
currentTask: data.tasks.find((task) => task.taskType === data.currentTask),
isSynced: true,
isApiCallMade: false,
};
} else {
state.caseDetails[id].isSynced = false;
}
},
setPinnedRank: (state, action) => {
const caseId = action.payload.caseReferenceId;
@@ -457,31 +499,7 @@ const allCasesSlice = createSlice({
state.selectedTodoListCount = 0;
state.selectedTodoListMap = {};
},
updateSingleCase: (state, action) => {
const { data, id, caseType, offlineCaseKey } = action.payload;
if (caseType === CaseAllocationType.COLLECTION_CASE) {
const computedKey = offlineCaseKey || id;
if (state.caseDetails?.[id]) {
state.caseDetails[id] = {
...state.caseDetails[computedKey],
isSynced: true,
};
delete state.caseDetails[offlineCaseKey];
}
return;
}
if (data) {
state.caseDetails[id] = {
...data,
currentTask: data.tasks.find((task) => task.taskType === data.currentTask),
isSynced: true,
isApiCallMade: false,
};
} else {
state.caseDetails[id].isSynced = false;
}
},
setFilterList: (state, action) => {
state.filterList = action.payload;
},
@@ -551,6 +569,55 @@ 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,
};
}
},
},
});
@@ -562,7 +629,7 @@ export const {
deleteIntermediateTodoListItem,
setSelectedTodoListMap,
resetSelectedTodoList,
updateCaseDetail,
updateUnsyncedCaseDetail,
updateSingleCase,
updateCaseDetailsFirestore,
toggleNewlyAddedCase,
@@ -571,6 +638,10 @@ export const {
setVisitPlansUpdating,
resetNewVisitedCases,
syncCasesByFallback,
addDocumentToUpload,
setDocumentReferenceId,
removeDocuments,
setDocumentInteractionId,
} = allCasesSlice.actions;
export default allCasesSlice.reducer;

View File

@@ -11,6 +11,7 @@ import {
import { addClickstreamEvent } from '../../services/clickstreamEventService';
import { CaseAllocationType } from '../allCases/interface';
import { CaseDetail } from './interface';
import { uploadUnsyncedImages } from '../../action/caseApiActions';
export const getUnSyncedCase = (updatedCaseDetail: CaseDetail | undefined): any => {
const caseId = updatedCaseDetail?.id;
@@ -21,7 +22,10 @@ export const getUnSyncedCase = (updatedCaseDetail: CaseDetail | undefined): any
const interactionsHandler = () => {
const dispatch = useAppDispatch();
const isOnline = useIsOnline();
const allCasesDetails = useAppSelector((state) => state.allCases.caseDetails);
const { unsyncedCasesDetails, docsToBeUploaded } = useAppSelector((state) => ({
unsyncedCasesDetails: state.allCases.unsyncedCaseDetail,
docsToBeUploaded: state.allCases.docsToBeUploaded,
}));
const { templateId } = useAppSelector(
(state) => state.case.templateData[CaseAllocationType.ADDRESS_VERIFICATION_CASE]
);
@@ -33,15 +37,16 @@ const interactionsHandler = () => {
const inProgressCaseIds = useRef<string[]>([]);
useEffect(() => {
if (!allCasesDetails) return;
if (!unsyncedCasesDetails) return;
let notSyncedCases: Array<any> = [];
_map(allCasesDetails, (el) => {
// [DISCUSS]: isApiCalled not getting true anywhere.
_map(unsyncedCasesDetails, (el) => {
if (
allCasesDetails[el]?.isSynced === false &&
allCasesDetails[el]?.isApiCalled === false &&
unsyncedCasesDetails[el]?.isSynced === false &&
unsyncedCasesDetails[el]?.isApiCalled === false &&
!inProgressCaseIds.current.includes(el)
) {
const unSyncedCase = getUnSyncedCase(allCasesDetails[el]);
const unSyncedCase = getUnSyncedCase(unsyncedCasesDetails[el]);
notSyncedCases.push(unSyncedCase);
}
});
@@ -49,6 +54,11 @@ const interactionsHandler = () => {
//TODO: use batched api call
for (const caseItem of notSyncedCases) {
if (isOnline) {
/**
* [DISCUSS]: In non-synced cases offlineCaseKey should be always there ideally.
* inProgressCaseIds not removing the processed ID,
* this will prevent processing of failed api cases again.
*/
inProgressCaseIds.current.push(caseItem.offlineCaseKey || caseItem.id);
let modifiedCaseItem: any;
if (caseItem?.caseType === CaseAllocationType.COLLECTION_CASE) {
@@ -60,7 +70,24 @@ const interactionsHandler = () => {
}
}
})();
}, [allCasesDetails, isOnline]);
}, [unsyncedCasesDetails, isOnline]);
useEffect(() => {
if (!isOnline) {
return;
}
if (!docsToBeUploaded) {
return;
}
_map(docsToBeUploaded, (caseId) => {
const interactionId = docsToBeUploaded[caseId]?.interactionId;
if (!interactionId) {
return;
}
const doc = docsToBeUploaded[caseId].documents;
dispatch(uploadUnsyncedImages(caseId, doc));
});
}, [docsToBeUploaded, isOnline]);
return null;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

BIN
uploads/file.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB