NTP-58799 | Persist original image (#1157)

This commit is contained in:
Mantri Ramkishor
2025-05-06 14:50:40 +05:30
committed by GitHub
parent d4764af421
commit be25274085
4 changed files with 101 additions and 44 deletions

View File

@@ -270,7 +270,6 @@ public class PhotoModule extends ReactContextBaseJavaModule {
String longitude = attributes.getString("longitude");
exif.setAttribute(ExifInterface.TAG_IMAGE_DESCRIPTION, json.toString());
exif.setAttribute(ExifInterface.TAG_ARTIST, "Aman Chaturvedi (1932)");
String currentDateTime = getCurrentFormattedDateTime();
exif.setAttribute(ExifInterface.TAG_DATETIME, currentDateTime);

View File

@@ -10,6 +10,8 @@ import { type IDocument, removeDocumentByQuestionKey } from '../reducer/feedback
import { addClickstreamEvent } from '@services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
import { PAST_FEEDBACK_PAGE_SIZE } from '@screens/caseDetails/feedback/pastFeedbackCommon';
import RNBlobUtil from 'react-native-blob-util';
import logger from '@components/utlis/logger';
export const getRepaymentsData = (loanAccountNumber: string, caseId: string, caseBusinessVertical: string) => (dispatch: AppDispatch) => {
dispatch(setRepaymentsLoading({ loanAccountNumber, isLoading: true }));
@@ -119,54 +121,93 @@ export const getFeedbackHistory = (loanAccountNumber: string) => (dispatch: AppD
export const uploadImages =
(caseKey: string, documents: Record<string, IDocument>, interactionReferenceId: string) =>
(dispatch: AppDispatch) => {
async (dispatch: AppDispatch) => {
if (!documents || !interactionReferenceId) {
return;
}
_map(documents, (questionKey, index) => {
for (const questionKey of Object.keys(documents)) {
const fileDoc = documents[questionKey];
if (!fileDoc) {
return;
if (!fileDoc || !fileDoc.fileUri) {
continue;
}
const { fileUri } = fileDoc;
const formData = new FormData();
formData.append(
'originalImageData',
JSON.stringify({
interactionReferenceId,
questionKey,
})
);
formData.append('image', {
uri: fileUri,
name: `image_${interactionReferenceId}_${index}`,
type: 'image/jpeg',
} as any);
const url = getApiUrl(ApiKeys.UPLOAD_FEEDBACK_IMAGES);
axiosInstance
.put(url, formData, {
headers: {
'Content-Type': 'multipart/form-data',
donotHandleError: true,
const mimeType = 'image/jpeg';
try {
// Get pre-signed URL
const presignRes = await axiosInstance.post(
getApiUrl(ApiKeys.GET_PRE_SIGNED_URL_FOR_FEEDBACK_IMAGE),
{
interactionReferenceId,
questionKey,
mimeType,
},
timeout: 5 * MILLISECONDS_IN_A_MINUTE,
})
.then((res) => {
dispatch(removeDocumentByQuestionKey({ caseKey, questionKey }));
})
.catch((err) => {
if (err?.response?.status === API_STATUS_CODE.NOT_FOUND) {
dispatch(removeDocumentByQuestionKey({ caseKey, questionKey }));
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_WRONG_QUESTION_KEY, {
error: err,
questionKey,
interactionReferenceId,
});
{
headers: { doNotHandleError: true },
}
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_PERSIST_ORIGINAL_IMAGE_FAILURE, {
payload: formData,
});
logError(err as Error, 'Error uploading image to document service');
);
if (!presignRes?.data?.presignedUrl || !presignRes?.data?.id) {
throw new Error('Failed to get presigned URL');
}
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_PERSIST_ORIGINAL_IMAGE_PRESIGNED_SUCCESS, {
payload: {
questionKey,
interactionReferenceId,
},
});
});
// Upload image to pre-signed URL
const fileStats = await RNBlobUtil.fs.stat(fileDoc.fileUri);
await RNBlobUtil.fetch(
'PUT',
presignRes?.data?.presignedUrl,
{
'Content-Type': mimeType,
},
RNBlobUtil.wrap(fileStats.path)
);
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_PERSIST_ORIGINAL_IMAGE_S3_SUCCESS, {
payload: {
questionKey,
interactionReferenceId,
},
});
// Acknowledge
await axiosInstance.post(
getApiUrl(ApiKeys.FEEDBACK_ORIGINAL_IMAGE_ACK),
{},
{
params: { id: presignRes?.data?.id },
headers: { doNotHandleError: true },
}
);
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_PERSIST_ORIGINAL_IMAGE_ACKNOWLEDGE_SUCCESS, {
payload: {
questionKey,
interactionReferenceId,
},
});
// Remove document from redux
dispatch(removeDocumentByQuestionKey({ caseKey, questionKey }));
} catch (err) {
logger({
msg: `Image upload failed`,
type: 'error',
extras: {
error: err,
questionKey,
interactionReferenceId,
},
});
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_PERSIST_ORIGINAL_IMAGE_FAILURE, {
payload: {
questionKey,
interactionReferenceId,
},
});
continue;
}
}
};

View File

@@ -1433,6 +1433,19 @@ export const CLICKSTREAM_EVENT_NAMES = {
description: 'Failed to persist original image',
},
FA_PERSIST_ORIGINAL_IMAGE_PRESIGNED_SUCCESS: {
name: 'FA_PERSIST_ORIGINAL_IMAGE_PRESIGNED_SUCCESS',
description: 'Successfully presigned generated for original image',
},
FA_PERSIST_ORIGINAL_IMAGE_S3_SUCCESS: {
name: 'FA_PERSIST_ORIGINAL_IMAGE_S3_SUCCESS',
description: 'Successfully persisted original image to S3',
},
FA_PERSIST_ORIGINAL_IMAGE_ACKNOWLEDGE_SUCCESS: {
name: 'FA_PERSIST_ORIGINAL_IMAGE_ACKNOWLEDGE_SUCCESS',
description: 'Successfully acknowledged original image',
},
// Filter coachmarks
FA_FILTER_COACHMARKS_LOADED: {
name: 'FA_FILTER_COACHMARKS_LOADED',

View File

@@ -120,7 +120,9 @@ export enum ApiKeys {
GET_TRAINING_MATERIAL_LIST = 'GET_TRAINING_MATERIAL_LIST',
GET_TRAINING_MATERIAL_DETAILS = 'GET_TRAINING_MATERIAL_DETAILS',
SELF_CALL_ACK= '/api/v1/self-call',
GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION = "GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION"
GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION = "GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION",
GET_PRE_SIGNED_URL_FOR_FEEDBACK_IMAGE = 'GET_PRE_SIGNED_URL_FOR_FEEDBACK_IMAGE',
FEEDBACK_ORIGINAL_IMAGE_ACK = 'FEEDBACK_ORIGINAL_IMAGE_ACK',
}
export const API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
@@ -230,6 +232,8 @@ API_URLS[ApiKeys.SELF_CALL_ACK] = '/sync-data/self-call-metadata';
API_URLS[ApiKeys.GET_TOP_ADDRESSES] = '/collection-cases/unified-locations';
API_URLS[ApiKeys.GET_FEEDBACK_ADDRESSES] = '/collection-cases/unified-locations/lite';
API_URLS[ApiKeys.GET_CASES_GEOLOCATION_DISTANCE_FROM_AGENT_LOCATION] = '/geolocation-distance/single-source'
API_URLS[ApiKeys.GET_PRE_SIGNED_URL_FOR_FEEDBACK_IMAGE] = '/file-upload/presigned-url';
API_URLS[ApiKeys.FEEDBACK_ORIGINAL_IMAGE_ACK] = '/file-upload/acknowledge';
export const API_STATUS_CODE = {
OK: 200,