diff --git a/android/app/src/main/java/com/avapp/MainApplication.java b/android/app/src/main/java/com/avapp/MainApplication.java index 6e98e5d8..d7fc5b84 100644 --- a/android/app/src/main/java/com/avapp/MainApplication.java +++ b/android/app/src/main/java/com/avapp/MainApplication.java @@ -124,7 +124,7 @@ public class MainApplication extends Application implements ReactApplication { try { Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize"); field.setAccessible(true); - field.set(null, 20 * 1024 * 1024); // 20MB + field.set(null, 40 * 1024 * 1024); // 40MB } catch (Exception e) { if (BuildConfig.DEBUG) { e.printStackTrace(); diff --git a/src/action/dataActions.ts b/src/action/dataActions.ts index 4ab0f11d..7fdb53a3 100644 --- a/src/action/dataActions.ts +++ b/src/action/dataActions.ts @@ -6,7 +6,6 @@ import axiosInstance, { isAxiosError, } from '../components/utlis/apiHelper'; import { navigateToScreen } from '../components/utlis/navigationUtlis'; -import OfflineImageDAO from '../wmDB/dao/OfflineImageDAO'; import { resetSelectedTodoList, resetTodoList, @@ -105,7 +104,6 @@ export const syncCaseDetail = offlineCaseKey: payload.data.offlineCaseKey, }) ); - OfflineImageDAO.deleteImages(offlineImageIdList); toast({ type: 'success', text1: ToastMessages.FEEDBACK_SUCCESSFUL, @@ -117,6 +115,7 @@ export const syncCaseDetail = .catch((errObj) => { const statusCode = errObj?.response?.status; const errorCode = errObj?.response?.data?.error_code; + if (isAxiosError(errObj) && statusCode !== API_STATUS_CODE.UNPROCESSABLE_CONTENT) { toast({ type: 'error', @@ -186,11 +185,11 @@ export const getSignedApi = async ( return new Promise((res) => { if (shouldBatch) { batchSignedApiRequest(signedRequestPayload, (results: any) => { - res({ imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || '' }); + res({ imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || '' }); }, skipFirebaseUpdate); } else { makeBulkSignedApiRequest(signedRequestPayload, (results: any) => { - res({ imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || '' }); + res({ imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || '' }); }, skipFirebaseUpdate); } }); diff --git a/src/common/Constants.ts b/src/common/Constants.ts index 496d473b..d91ed9a4 100644 --- a/src/common/Constants.ts +++ b/src/common/Constants.ts @@ -1294,6 +1294,14 @@ export const CLICKSTREAM_EVENT_NAMES = { description: 'Feedback nudge closed' }, + FA_FEEDBACK_IMAGE_NOT_FOUND: { + name: 'FA_FEEDBACK_IMAGE_NOT_FOUND', + description: 'Feedback image not found' + }, + FA_UNSYNC_FEEDBACK_CAPTURED: { + name: 'FA_UNSYNC_FEEDBACK_CAPTURED', + description: 'Unsync feedback captured' + }, } as const; export enum MimeType { diff --git a/src/components/form/components/AddressSelection.tsx b/src/components/form/components/AddressSelection.tsx index 25723745..c6e3826e 100644 --- a/src/components/form/components/AddressSelection.tsx +++ b/src/components/form/components/AddressSelection.tsx @@ -62,7 +62,7 @@ const AddressSelection: React.FC = (props) => { ); const caseType = currentCase?.caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE; const template = useAppSelector((state) => state.case.templateData[caseType]); - const question = template.questions[questionId]; + const question = template?.questions?.[questionId]; const dispatch = useAppDispatch(); diff --git a/src/components/form/components/ImageUpload.tsx b/src/components/form/components/ImageUpload.tsx deleted file mode 100644 index 34e2eba0..00000000 --- a/src/components/form/components/ImageUpload.tsx +++ /dev/null @@ -1,290 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Control, Controller } from 'react-hook-form'; -import { - ActivityIndicator, - ImageBackground, - StyleSheet, - TouchableOpacity, - View, -} from 'react-native'; -import PhotoUpload, { - IImageDetails, - LAUNCH_REQUEST, -} 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 { useAppDispatch, useAppSelector } from '../../../hooks'; -import { RootState } from '../../../store/store'; -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, - getPrefixBase64Image, -} from '../../../common/Constants'; -import { addClickstreamEvent } from '../../../services/clickstreamEventService'; -import { isQuestionMandatory, validateInput } from '../services/validation.service'; -import { CaseAllocationType } from '../../../screens/allCases/interface'; -import { - addIntermediateDocument, - deleteIntermediateDocument, -} from '../../../reducer/feedbackImagesSlice'; - -interface IOfflineImage { - idx: string; - imageData: string; - originalImageUri: string; -} - -interface IImageUpload { - questionType: string; - questionId: string; - widgetId: string; - journeyId: string; - caseId: string; - sectionId: string; - control: Control; - error: any; - offlineImages: IOfflineImage[]; -} - -const getImageUri = (imageList: IOfflineImage[], imageId: string) => { - const image = imageList?.find((image) => image?.idx === imageId); - let uri = ''; - if (image) { - const { originalImageUri, imageData } = image || {}; - uri = originalImageUri || imageData || ''; - } - return uri; -}; - -const ImageUpload: React.FC = (props) => { - const { questionId, error, sectionId, caseId, journeyId, widgetId, questionType } = props; - const [imageId, setImageId] = useState(''); - const [loading, setImageLoading] = useState(false); - const caseType = useAppSelector( - (state) => - state.allCases.caseDetails[caseId]?.caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE - ); - const template = useAppSelector((state) => state.case.templateData[caseType]); - const question = template.questions[questionId as keyof typeof template.questions]; - const dataFromRedux = useSelector( - (state: RootState) => - state.case.caseForm?.[caseId]?.[journeyId]?.widgetContext?.[widgetId]?.sectionContext?.[ - sectionId - ]?.questionContext?.[questionId]?.answer - ); - - const dispatch = useAppDispatch(); - - useEffect(() => { - if (dataFromRedux) { - setImageId(dataFromRedux); - } - }, [dataFromRedux]); - - if (!question) { - return null; - } - - const addOriginalFileUriToDocs = (caseId: string, fileUri: string, questionKey: string) => { - if (!fileUri) { - return; - } - dispatch(addIntermediateDocument({ caseId, fileUri, questionKey })); - }; - - const addImageUploadSuccessClickstream = (openRequest: LAUNCH_REQUEST) => { - if (openRequest === LAUNCH_REQUEST.CAMERA) { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FEEDBACK_PHOTO_CAPTURED_SUCCESSFULLY, { - caseId, - questionType, - questionId, - sectionId, - widgetId, - }); - } else if (openRequest === LAUNCH_REQUEST.IMAGE_LIBRARY) { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FEEDBACK_PHOTO_UPLOADED_SUCCESSFULLY, { - caseId, - questionType, - questionId, - sectionId, - widgetId, - }); - } - }; - - const handleChange = async (clickedImage: IImageDetails, onChange: (...event: any[]) => void) => { - const { base64 = '', uri = '', openRequest } = clickedImage; - addImageUploadSuccessClickstream(openRequest); - 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, { - caseId, - questionType, - value: uniqueId, - questionId, - error, - sectionId, - widgetId, - }); - onChange({ - answer: uniqueId, - type: AnswerType.image, - }); - await OfflineImageDAO.addImage(base64Image, uri, uniqueId); - }; - - const handleImageDelete = () => { - setImageId(''); - dispatch(deleteIntermediateDocument({ caseId, questionKey: questionId })); - }; - - const handleError = (error: string) => { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_PHOTO_UPLOAD_ERROR, { - caseId, - questionType, - questionId, - error, - sectionId, - widgetId, - }); - }; - - const handlePictureAction = (openRequest: LAUNCH_REQUEST) => { - if (openRequest === LAUNCH_REQUEST.CAMERA) { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FEEDBACK_CLICKED_TAKE_PHOTO, { - caseId, - questionType, - questionId, - sectionId, - widgetId, - }); - } else if (openRequest === LAUNCH_REQUEST.IMAGE_LIBRARY) { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_FEEDBACK_CLICKED_UPLOAD_PHOTO, { - caseId, - questionType, - questionId, - sectionId, - widgetId, - }); - } - }; - - // TODO : add the validator back when firestore is fixed. - return ( - - - {question.text}{' '} - {isQuestionMandatory(question) && *} - - {!imageId ? ( - validateInput(data, question.metadata.validators) }} - render={({ field: { onChange } }) => ( - handleChange(clickedImage, onChange)} - showUploadFromGalleryOption={true} - containerStyle={[GenericStyles.containerStyle, loading ? styles.displayNone : null]} - imageLoading={setImageLoading} - onError={handleError} - /> - )} - name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`} - /> - ) : ( - - handleError('Error in image rendering')} - // onLoadStart={() => setImageLoading(true)} - // onLoadEnd={() => setImageLoading(false)} - > - - - - {loading ? ( - - ) : null} - - - )} - - - - - - ); -}; - -const styles = StyleSheet.create({ - image: { - width: '100%', - height: 350, - resizeMode: 'contain', - }, - deleteButton: { - position: 'absolute', - right: 8, - top: 8, - backgroundColor: COLORS.BACKGROUND.PRIMARY, - height: 28, - width: 28, - borderRadius: 14, - justifyContent: 'center', - alignItems: 'center', - borderWidth: 1, - borderColor: COLORS.BORDER.PRIMARY, - }, - br8: { - borderRadius: 8, - }, - displayNone: { - display: 'none', - }, - loadingState: { - justifyContent: 'center', - backgroundColor: COLORS.BACKGROUND.PRIMARY, - alignItems: 'center', - borderRadius: 8, - }, - centerAllign: { - position: 'absolute', - top: '50%', - left: '50%', - }, -}); -const enhance = withObservables([], () => ({ - offlineImages: OfflineImageDAO.observeOfflineImage(), -})); - -export default enhance(ImageUpload); diff --git a/src/components/form/components/imageUpload/ImageUploadV2.tsx b/src/components/form/components/imageUpload/ImageUploadV2.tsx index fc4d1e05..8f7c02fc 100644 --- a/src/components/form/components/imageUpload/ImageUploadV2.tsx +++ b/src/components/form/components/imageUpload/ImageUploadV2.tsx @@ -10,7 +10,6 @@ import { useAppDispatch, useAppSelector } from '../../../../hooks'; import { RootState } from '../../../../store/store'; import { AnswerType } from '../../interface'; import ErrorMessage from '../ErrorMessage'; -import OfflineImageDAO from '../../../../wmDB/dao/OfflineImageDAO'; import { CLICKSTREAM_EVENT_NAMES, PrefixJpegBase64Image } from '../../../../common/Constants'; import { addClickstreamEvent, ClickstreamDesc } from '../../../../services/clickstreamEventService'; import { isQuestionMandatory, validateInput } from '../../services/validation.service'; @@ -205,7 +204,6 @@ const ImageUploadV2: React.FC = (props) => { answer: uniqueId, type: AnswerType.image, }); - await OfflineImageDAO.addImage(base64Image, uri, uniqueId, imageWidth, imageHeight); toast({ type: 'success', text1: 'Geolocation & Timestamp added successfully' }); setImageLoading(false); addOriginalFileUriToDocs(caseId, uri, questionId, imageWidth, imageHeight); @@ -221,11 +219,7 @@ const ImageUploadV2: React.FC = (props) => { } }; - const { - fileUri, - imageHeight = 350, - imageWidth = 350 - } = imageDoc || {}; + const { fileUri, imageHeight = 350, imageWidth = 350 } = imageDoc || {}; const imageHeightWrtAspectRatio = getImageHeightWrtAspectRatio( imageWidth, @@ -242,13 +236,12 @@ const ImageUploadV2: React.FC = (props) => { ) => { setImageLoading(false); const { base64 = '', uri = '', openRequest } = clickedImage; + const uniqueId = 'id' + new Date().getTime(); addImageUploadSuccessClickstream(openRequest); - 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, { caseId, @@ -263,7 +256,7 @@ const ImageUploadV2: React.FC = (props) => { answer: uniqueId, type: AnswerType.image, }); - await OfflineImageDAO.addImage(base64Image, uri, uniqueId); + addOriginalFileUriToDocs(caseId, uri, questionId, imageWidth, imageHeight); }; const handleImageUpload = async (onChange: (...event: any[]) => void) => { diff --git a/src/components/form/index.tsx b/src/components/form/index.tsx index 1bd14684..a8e46e27 100644 --- a/src/components/form/index.tsx +++ b/src/components/form/index.tsx @@ -307,6 +307,14 @@ const Widget: React.FC = (props) => { unSyncedCase, nudgeBottomSheetDetails?.showNudgeBottomSheet ); + if(!transformedPayload?.data?.answers) { + toast({ + type: 'error', + text1: ToastMessages.FEEDBACK_IMAGE_NOT_FOUND, + }); + onErrorSubmit({}, transformedPayload) + return; + } dispatch( syncCaseDetail(transformedPayload, { onSuccessCB: (apiCaseData, interactionId: string) => diff --git a/src/components/form/services/formComponents.ts b/src/components/form/services/formComponents.ts index 5fe57997..553c17f1 100644 --- a/src/components/form/services/formComponents.ts +++ b/src/components/form/services/formComponents.ts @@ -10,7 +10,6 @@ import AddressSelection from '../components/AddressSelection'; import PhoneNumberSelection from '../components/PhoneNumberSelection'; import DateInput from '../components/DateInput'; import TimeInput from '../components/TimeInput'; -import ImageUpload from '../components/ImageUpload'; export const FormComponentList = { TextInput, diff --git a/src/components/form/services/geoLocation.service.ts b/src/components/form/services/geoLocation.service.ts index ba62682f..3bbbad6b 100644 --- a/src/components/form/services/geoLocation.service.ts +++ b/src/components/form/services/geoLocation.service.ts @@ -49,10 +49,6 @@ export class CaptureGeolocation { if (cachedLocation && Date.now() - (cachedLocation?.location?.timestamp || 0) < cacheTTL) { return resolve(cachedLocation?.location?.coords); } - if (cachedLocation && cachedLocation?.isCapturing) { - console.info('Capture already in progress. Returning'); - resolve(undefined); - } CaptureGeolocation.setCapturing(resourceId, true); const isLocationOn = await PermissionsAndroid.check( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION diff --git a/src/screens/allCases/constants.ts b/src/screens/allCases/constants.ts index 5e226b94..be787421 100644 --- a/src/screens/allCases/constants.ts +++ b/src/screens/allCases/constants.ts @@ -64,6 +64,7 @@ export const ToastMessages = { SUCCESS_COPYING_EMPLOYER_NAME: 'Employer Name Copied Successfully!!', FEEDBACK_SUCCESSFUL: 'Feedback submitted successfully!', FEEDBACK_FAILED: 'Feedback submission failed', + FEEDBACK_IMAGE_NOT_FOUND: 'Feedback submission failed. Please try uploading image again', FIRESTORE_SIGNIN_FAILED: 'Error signing in to Firestore', PAYMENT_LINK_ERROR: 'Payment link could not be shared', PAYMENT_LINK_SUCCESS: 'Link has been generated and shared with customer', diff --git a/src/screens/caseDetails/interactionsHandler.tsx b/src/screens/caseDetails/interactionsHandler.tsx index ee00eada..5669f1bc 100644 --- a/src/screens/caseDetails/interactionsHandler.tsx +++ b/src/screens/caseDetails/interactionsHandler.tsx @@ -4,10 +4,7 @@ import { syncCaseDetail } from '../../action/dataActions'; import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants'; import { useAppDispatch, useAppSelector } from '../../hooks'; import useIsOnline from '../../hooks/useIsOnline'; -import { - getTransformedAvCase, - getTransformedCollectionCaseItem, -} from '../../services/casePayload.transformer'; +import { getTransformedCollectionCaseItem } from '../../services/casePayload.transformer'; import { addClickstreamEvent } from '../../services/clickstreamEventService'; import { CaseAllocationType } from '../allCases/interface'; import { CaseDetail } from './interface'; @@ -64,12 +61,16 @@ const interactionsHandler = () => { for (const caseItem of notSyncedCases) { if (isOnline) { const caseKey = caseItem.offlineCaseKey || caseItem.id; + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_UNSYNC_FEEDBACK_CAPTURED, { + caseId: caseKey, + }); inProgressCaseIds.current.push(caseKey); let modifiedCaseItem: any; if (caseItem?.caseType === CaseAllocationType.COLLECTION_CASE) { modifiedCaseItem = await getTransformedCollectionCaseItem(caseItem, true); - } else { - modifiedCaseItem = await getTransformedAvCase(caseItem, templateId); + } + if (!modifiedCaseItem?.data?.answers) { + return; } dispatch( syncCaseDetail(modifiedCaseItem, { diff --git a/src/services/casePayload.transformer.ts b/src/services/casePayload.transformer.ts index 4bf17836..39511b2c 100644 --- a/src/services/casePayload.transformer.ts +++ b/src/services/casePayload.transformer.ts @@ -1,16 +1,12 @@ -import { CONTEXT_TASK_STATUSES, CaseDetail } from './../screens/caseDetails/interface'; +import { CaseDetail } from './../screens/caseDetails/interface'; import { AnswerType } from '../components/form/interface'; -import OfflineImageDAO from '../wmDB/dao/OfflineImageDAO'; -import { - CaseAllocationType, - IAvCasePayload, - IAvTaskFeedbackItem, - IQuestionContextOutput, - TaskTitle, -} from '../screens/allCases/interface'; +import { IQuestionContextOutput } from '../screens/allCases/interface'; import Geolocation from 'react-native-geolocation-service'; - -const AV_TEMPLATE_VERSION_NUMBER = 3; +import store from '@store'; +import RNFS from 'react-native-fs'; +import { addClickstreamEvent } from './clickstreamEventService'; +import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants'; +import ImageResizer from '@bam.tech/react-native-image-resizer'; interface QuestionContext { answer: string; @@ -36,8 +32,18 @@ interface Answer { allocationReferenceId: string; } -export const extractQuestionContext = async (answer: Answer): Promise => { +const IMAGE_QUALITY = 50; +const MAX_WIDTH = 500; +const MAX_HEIGHT = 500; + +export const extractQuestionContext = async ( + answer: Answer, + caseReferenceId: string +): Promise => { const questionContexts: IQuestionContextOutput[] = []; + let isBase64ImageAvailable = true; + const docsData = + store?.getState()?.feedbackImages?.intermediateDocsToBeUploaded?.[caseReferenceId]?.documents; const { widgetContext } = answer; for (const widgetKey in widgetContext) { @@ -64,12 +70,27 @@ export const extractQuestionContext = async (answer: Answer): Promise { - let imageList = await OfflineImageDAO.getImage(imageId); - // returns the latest image in the database - return imageList?.[0]; -} - -export const getImageHeightWrtAspectRatio = (imageWidth: number, imageHeight: number, requiredImageWidth: number) => { +export const getImageHeightWrtAspectRatio = ( + imageWidth: number, + imageHeight: number, + requiredImageWidth: number +) => { if (!imageWidth || !imageHeight) { return 0; } @@ -96,16 +116,6 @@ export const getImageHeightWrtAspectRatio = (imageWidth: number, imageHeight: nu return requiredImageWidth * aspectRatio; }; -export const getBase64ImageFromOfflineDb = async (imageId: string) => { - let imageList = await OfflineImageDAO.getImage(imageId); - return imageList?.[0]?.imageData; -}; - -export const getOriginalImageFromOfflineDb = async (imageId: string) => { - let imageList = await OfflineImageDAO.getImage(imageId); - return imageList?.[0]?.originalImageUri; -}; - export interface IGetTransformedCaseItem extends CaseDetail { answer: any; caseId: string; @@ -118,7 +128,10 @@ export const getTransformedCollectionCaseItem = async ( forceSubmit = false ) => { let cloneCaseItem = { ...caseItem }; - let answerContextArray = await extractQuestionContext(cloneCaseItem?.answer); + let answerContextArray = await extractQuestionContext( + cloneCaseItem?.answer, + caseItem?.caseReferenceId + ); let data = { caseReferenceId: caseItem.caseReferenceId, answers: answerContextArray, @@ -129,42 +142,3 @@ export const getTransformedCollectionCaseItem = async ( }; return { caseType: caseItem.caseType, data, forceSubmit }; }; - -export const getTransformedAvCase = async ( - caseItem: IGetTransformedCaseItem, - templateId: string -) => { - const { caseType, allocationReferenceId, caseId, coords } = caseItem; - const transformedAvCase: IAvCasePayload = { - caseType: caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE, - data: { - version: AV_TEMPLATE_VERSION_NUMBER, - templateId, - allocationReferenceId: allocationReferenceId as string, - taskFeedbacks: [], - }, - }; - const taskContext = caseItem?.context?.taskContext; - for (let taskId in taskContext) { - const taskItems: any[] = taskContext[taskId]; - for (const taskItem of taskItems) { - const { taskStatus, createdAt } = taskItem; - if (taskId !== TaskTitle.CALLING_TASK && taskStatus === CONTEXT_TASK_STATUSES.OPEN) continue; - - let taskFeedbackItem: IAvTaskFeedbackItem = { - taskType: taskId as TaskTitle, - location: coords, - answers: [], - taskStatus, - capturedAt: createdAt || new Date().getTime(), - }; - - const answersList = await extractQuestionContext(taskItem); - if (!answersList.length) continue; - - taskFeedbackItem.answers = answersList; - transformedAvCase.data.taskFeedbacks.push(taskFeedbackItem); - } - } - return transformedAvCase; -}; diff --git a/src/services/clickstreamEventService.ts b/src/services/clickstreamEventService.ts index a3a39d70..75f7a0f6 100644 --- a/src/services/clickstreamEventService.ts +++ b/src/services/clickstreamEventService.ts @@ -1,15 +1,11 @@ -import { ApiKeys, API_URLS } from './../components/utlis/apiHelper'; +import { API_URLS } from './../components/utlis/apiHelper'; import { getAppVersion, getEventNameFromAPIKey, getKeyByValue, - getParamsObject, } from './../components/utlis/commonFunctions'; -import React from 'react'; import axiosInstance from '../components/utlis/apiHelper'; -import { getNetInfo } from '../components/utlis/commonFunctions'; import { GLOBAL } from '../constants/Global'; -import ClickStreamEventsDAO, { IClickstreamEvent } from '../wmDB/dao/ClickStreamEventsDAO'; import { NetInfoCellularGeneration, NetInfoState, @@ -23,8 +19,20 @@ import { SCREEN_HEIGHT, SCREEN_WIDTH } from '@rn-ui-lib/styles'; export type ClickstreamDesc = { name: string; description: string }; +export interface IClickstreamEvent { + event_name: string; + description: string; + timestamp: number; + agentId: string; + deviceId: string; + attributes?: unknown; + networkStatus: string; + appVersion: string; + isOnline: boolean; + batteryLevel: string; +} + const MAX_BUFFER_SIZE_FOR_API = 10; -const MAX_BUFFER_SIZE_FOR_DB_WRITE = 20; let eventsList: IClickstreamEvent[] = []; let bufferEventsList: IClickstreamEvent[] = []; @@ -48,9 +56,6 @@ const addEvent = async (networkStatus: string) => { if (eventsList.length > MAX_BUFFER_SIZE_FOR_API) { if (networkStatus !== 'offline') { fireClickstreamEvents(); - } else if (eventsList.length > MAX_BUFFER_SIZE_FOR_DB_WRITE) { - await ClickStreamEventsDAO.addEventsBulk(eventsList); - eventsList = []; } } }; @@ -122,40 +127,9 @@ const fireClickstreamEvents = async () => { const url = JANUS_SERVICE_URL; bufferEventsList = [...eventsList]; eventsList = []; + const payload = await getPayload(bufferEventsList); - const clickstreamEventsFromDB = await ClickStreamEventsDAO.getAllEvents(); - - const events = clickstreamEventsFromDB - .map((item: IClickstreamEvent) => { - const { - deviceId, - agentId, - event_name, - attributes, - timestamp, - networkStatus, - appVersion, - isOnline, - batteryLevel, - } = item; - return { - deviceId, - agentId, - event_name, - attributes, - timestamp, - networkStatus, - appVersion, - isOnline, - batteryLevel, - }; - }) - .concat(bufferEventsList); - const payload = await getPayload(events); - - axiosInstance - .post(url, payload, { headers: { donotHandleError: true } }) - .then(() => ClickStreamEventsDAO.deleteAllEvents()); + axiosInstance.post(url, payload, { headers: { donotHandleError: true } }); }; export const sendApiToClickstreamEvent = ( @@ -171,7 +145,7 @@ export const sendApiToClickstreamEvent = ( const eventName = getEventNameFromAPIKey(apiKey, isSuccess); addClickstreamEvent( { name: eventName, description: eventName }, - { timeTaken: milliseconds, statusCode, response: statusCode === 400 ? response : '' } + { timeTaken: milliseconds, statusCode, response: statusCode === 400 ? response : '' } ); } } diff --git a/src/wmDB/const.ts b/src/wmDB/const.ts deleted file mode 100644 index 87ba9fff..00000000 --- a/src/wmDB/const.ts +++ /dev/null @@ -1,9 +0,0 @@ -export enum TableName { - OFFLINE_IMAGES = 'offline_image', - CUSTOMER_IMAGE = 'customer_image', - CLICKSTREAM_EVENTS = 'clickstream_events', -} - -export const DB_VERSION = 6; - -export const DB_NAME = 'AVAPP'; diff --git a/src/wmDB/dao/ClickStreamEventsDAO.ts b/src/wmDB/dao/ClickStreamEventsDAO.ts deleted file mode 100644 index a7a5c9e9..00000000 --- a/src/wmDB/dao/ClickStreamEventsDAO.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { database } from '../db'; -import { Q } from '@nozbe/watermelondb'; -import { TableName } from '../const'; -import { logError } from '../../components/utlis/errorUtils'; - -const clickStreamEvents = database.get(TableName.CLICKSTREAM_EVENTS); - -export interface IClickstreamEvent { - event_name: string; - description: string; - timestamp: number; - agentId: string; - deviceId: string; - attributes?: unknown; - networkStatus: string; - appVersion: string; - isOnline: boolean; - batteryLevel: string; -} - -export default { - observeOfflineImage: () => clickStreamEvents.query().observe(), - addEvent: async ( - event_name: string, - timestamp: number, - description: string, - agentId: string, - deviceId: string, - attributes: any, - networkStatus: string, - appVersion: string, - isOnline: boolean, - batteryLevel: string - ) => { - try { - return await database.action(async () => { - return await clickStreamEvents.create((event: any) => { - event.event_name = event_name; - event.description = description; - event.timestamp = timestamp; - event.deviceId = deviceId; - event.agentId = agentId; - event.attributes = attributes; - event.networkStatus = networkStatus; - event.appVersion = appVersion; - event.isOnline = isOnline; - event.batteryLevel = batteryLevel; - }); - }); - } catch (e) { - console.log(e); - } - }, - addEventsBulk: async (events: Array) => { - function prepareInsertion(events: Array) { - return events.map((clickStreamEvent) => { - const { - event_name, - deviceId, - attributes, - agentId, - timestamp, - description, - networkStatus, - isOnline, - appVersion, - batteryLevel, - } = clickStreamEvent; - try { - return clickStreamEvents.prepareCreate((event: any) => { - event.event_name = event_name; - event.description = description; - event.timestamp = timestamp; - event.deviceId = deviceId; - event.agentId = agentId; - event.attributes = attributes; - event.networkStatus = networkStatus; - event.isOnline = isOnline; - event.appVersion = appVersion; - event.batteryLevel = batteryLevel; - }); - } catch (e) { - logError(e as Error, 'WM DB'); - } - }); - } - try { - return await database.action(async () => { - const allRecords = prepareInsertion(events); - await database.batch(...allRecords); - }); - } catch (e) { - logError(e as Error, 'WM DB'); - } - }, - getAllEvents: async () => { - try { - return await database.action(async () => { - return await clickStreamEvents.query().fetch(); - }); - } catch (e) { - console.log(e); - return; - } - }, - deleteAllEvents: async () => { - try { - return await database.action(async () => { - await clickStreamEvents.query().destroyAllPermanently(); - }); - } catch (e) { - console.log(e); - return; - } - }, -}; diff --git a/src/wmDB/dao/CustomerImageDAO.ts b/src/wmDB/dao/CustomerImageDAO.ts deleted file mode 100644 index 2087002e..00000000 --- a/src/wmDB/dao/CustomerImageDAO.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { database } from '../db'; -import { Q } from '@nozbe/watermelondb'; -import { TableName } from '../const'; -import { logError } from '../../components/utlis/errorUtils'; - -const customerImage = database.get(TableName.CUSTOMER_IMAGE); - -interface ICustomerOfflineImage { - caseId: string; - imageURL: string; - image64: string; -} - -export default { - observeOfflineImage: () => customerImage.query().observe(), - addBulkCustomerImage: async (customerImageList: ICustomerOfflineImage[]) => { - function prepareInsertion(customerImageList: ICustomerOfflineImage[]) { - return customerImageList.map((customerImageItem) => { - try { - return customerImage.prepareCreate((imageRow: any) => { - imageRow.caseId = customerImageItem.caseId; - imageRow.imageURL = customerImageItem.imageURL; - imageRow.image64 = customerImageItem.image64; - }); - } catch (e) { - logError(e as Error, 'WM DB'); - } - }); - } - try { - return await database.action(async () => { - const allRecords = prepareInsertion(customerImageList); - await database.batch(...allRecords); - }); - } catch (e) { - logError(e as Error, 'WM DB'); - } - }, - addCustomerImage: async (customerImageItem: ICustomerOfflineImage) => { - try { - return await database.action(async () => { - return await customerImage.create((imageRow: any) => { - imageRow.caseId = customerImageItem.caseId; - imageRow.imageURL = customerImageItem.imageURL; - imageRow.image64 = customerImageItem.image64; - }); - }); - } catch (e) { - logError(e as Error, 'WM DB'); - } - }, - getImageByURL: async (imageURL: string) => { - try { - return await database.action(async () => { - return await customerImage.query(Q.where('image_url', imageURL), Q.take(1)).fetch(); - }); - } catch (e) { - logError(e as Error, 'WM DB'); - return; - } - }, - getImageByCase: async (caseId: string) => { - try { - return await database.action(async () => { - return await customerImage.query(Q.where('case_id', caseId), Q.take(1)).fetch(); - }); - } catch (e) { - logError(e as Error, 'WM DB'); - return; - } - }, - deleteImages: async (caseIds: Array | string) => { - let tCaseIds = Array.isArray(caseIds) ? caseIds : [caseIds]; - try { - return await database.action(async () => { - await customerImage.query(Q.where('case_id', Q.oneOf(tCaseIds))).destroyAllPermanently(); - }); - } catch (e) { - logError(e as Error, 'WM DB'); - return; - } - }, - deleteAll: async () => { - try { - return await database.action(async () => { - await customerImage.query().destroyAllPermanently(); - }); - } catch (e) { - logError(e as Error, 'WM DB'); - return; - } - }, -}; diff --git a/src/wmDB/dao/OfflineImageDAO.ts b/src/wmDB/dao/OfflineImageDAO.ts deleted file mode 100644 index 1a23f7ea..00000000 --- a/src/wmDB/dao/OfflineImageDAO.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { database } from '../db'; -import { Q } from '@nozbe/watermelondb'; -import { TableName } from '../const'; - -const offlineImage = database.get(TableName.OFFLINE_IMAGES); - -export default { - observeOfflineImage: () => offlineImage.query().observe(), - addImage: async ( - imageData: string, - originalImageUri: string, - imageIdx: string, - imageWidth: number, - imageHeight: number - ) => { - try { - return await database.action(async () => { - return await offlineImage.create((image: any) => { - image.idx = imageIdx; - image.imageData = imageData; - image.originalImageUri = originalImageUri; - image.imageWidth = imageWidth; - image.imageHeight = imageHeight; - }); - }); - } catch (e) { - console.log(e); - } - }, - getImage: async (imageId: string) => { - try { - return await database.action(async () => { - return await offlineImage.query(Q.where('idx', imageId), Q.take(1)).fetch(); - }); - } catch (e) { - console.log(e); - return; - } - }, - deleteImages: async (imageIdList: Array) => { - try { - return await database.action(async () => { - await offlineImage.query(Q.where('idx', Q.oneOf(imageIdList))).destroyAllPermanently(); - }); - } catch (e) { - console.log(e); - return; - } - }, - deleteAll: async () => { - try { - return await database.action(async () => { - await offlineImage.query().destroyAllPermanently(); - }); - } catch (e) { - console.log(e); - return; - } - }, -}; diff --git a/src/wmDB/db.ts b/src/wmDB/db.ts deleted file mode 100644 index c863ebb4..00000000 --- a/src/wmDB/db.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Database } from '@nozbe/watermelondb'; -import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite'; -import { DB_NAME } from './const'; -import ClickstreamEvents from './model/ClickstreamEvents'; -import CustomerImage from './model/CustomerImage'; -import OfflineImage from './model/OfflineImage'; - -import schema from './schema'; - -const adapter = new SQLiteAdapter({ - dbName: DB_NAME, - schema, -}); - -const database = new Database({ - adapter, - modelClasses: [OfflineImage, CustomerImage, ClickstreamEvents], -}); - -export { database }; diff --git a/src/wmDB/index.ts b/src/wmDB/index.ts deleted file mode 100644 index 676f39b2..00000000 --- a/src/wmDB/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import PostDAO from './dao/OfflineImageDAO'; -import CustomerImageDAO from './dao/CustomerImageDAO'; -import ClickstreamDAO from './dao/ClickStreamEventsDAO'; - -export { database } from './db'; -export { PostDAO, CustomerImageDAO, ClickstreamDAO }; diff --git a/src/wmDB/model/ClickstreamEvents.ts b/src/wmDB/model/ClickstreamEvents.ts deleted file mode 100644 index 24aaf137..00000000 --- a/src/wmDB/model/ClickstreamEvents.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Model } from '@nozbe/watermelondb'; -import { field, json } from '@nozbe/watermelondb/decorators'; -import { TableName } from '../const'; - -const sanitizeAttributes = (json: any) => json; - -export default class ClickstreamEvents extends Model { - static table = TableName.CLICKSTREAM_EVENTS; - - @field('event_name') event_name!: string; - @field('description') description!: string; - @field('agent_id') agentId!: string; - @field('device_id') deviceId!: string; - @field('network_status') networkStatus!: string; - @field('timestamp') timestamp!: number; - @json('attributes', sanitizeAttributes) attributes: any; - @field('app_version') appVersion!: string; - @field('is_online') isOnline!: boolean; - @field('battery_level') batteryLevel!: string; -} diff --git a/src/wmDB/model/CustomerImage.ts b/src/wmDB/model/CustomerImage.ts deleted file mode 100644 index ccde7cc7..00000000 --- a/src/wmDB/model/CustomerImage.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Model } from '@nozbe/watermelondb'; -import { field, readonly, date } from '@nozbe/watermelondb/decorators'; -import { TableName } from '../const'; - -export default class CustomerImage extends Model { - static table = TableName.CUSTOMER_IMAGE; - - @field('case_id') caseId!: string; - @field('image_url') imageURL!: string; - @field('image_64') image64!: string; - @readonly @date('created_at') createdAt!: any; - @readonly @date('updated_at') updatedAt!: any; -} diff --git a/src/wmDB/model/OfflineImage.ts b/src/wmDB/model/OfflineImage.ts deleted file mode 100644 index d3726c5f..00000000 --- a/src/wmDB/model/OfflineImage.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Model } from '@nozbe/watermelondb'; -import { field, readonly, date } from '@nozbe/watermelondb/decorators'; -import { TableName } from '../const'; - -export default class OfflineImage extends Model { - static table = TableName.OFFLINE_IMAGES; - - @field('idx') idx!: string; - @field('image_data') imageData!: string; - @field('original_image_uri') originalImageUri!: string; - @field('image_width') imageWidth!: string; - @field('image_height') imageHeight!: string; - @readonly @date('created_at') createdAt!: any; - @readonly @date('updated_at') updatedAt!: any; -} diff --git a/src/wmDB/schema.ts b/src/wmDB/schema.ts deleted file mode 100644 index ded3a4d7..00000000 --- a/src/wmDB/schema.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { appSchema, tableSchema } from '@nozbe/watermelondb'; -import { DB_VERSION, TableName } from './const'; - -export default appSchema({ - version: DB_VERSION, - tables: [ - tableSchema({ - name: TableName.OFFLINE_IMAGES, - columns: [ - { name: 'idx', type: 'string' }, - { name: 'image_data', type: 'string' }, - { name: 'original_image_uri', type: 'string' }, - { name: 'image_width', type: 'string' }, - { name: 'image_height', type: 'string' }, - ], - }), - tableSchema({ - name: TableName.CUSTOMER_IMAGE, - columns: [ - { name: 'case_id', type: 'string' }, - { name: 'image_url', type: 'string' }, - { name: 'image_64', type: 'string' }, - ], - }), - tableSchema({ - name: TableName.CLICKSTREAM_EVENTS, - columns: [ - { name: 'event_name', type: 'string' }, - { name: 'description', type: 'string' }, - { name: 'agent_id', type: 'string' }, - { name: 'device_id', type: 'string' }, - { name: 'attributes', type: 'string' }, - { name: 'network_status', type: 'string' }, - { name: 'timestamp', type: 'number' }, - ], - }), - ], -});