From 330eb8e1d3191518fba40c27fcf8a7d359262c00 Mon Sep 17 00:00:00 2001 From: yashmantri Date: Wed, 13 Sep 2023 14:13:20 +0530 Subject: [PATCH] TP-38645 | Show Documents On Customer Profile Screen --- App.tsx | 7 +- android/app/build.gradle | 14 ++ .../main/java/com/avapp/MainApplication.java | 1 + .../com/avapp/ScreenshotBlockerModule.java | 59 +++++ .../avapp/ScreenshotBlockerModulePackage.java | 28 +++ package.json | 1 + src/components/utlis/ScreenshotBlocker.ts | 5 + src/screens/auth/ProtectedRouter.tsx | 11 + .../caseDetails/CollectionCaseDetail.tsx | 6 + src/screens/caseDetails/CustomerProfile.tsx | 206 ++++++------------ src/screens/caseDetails/DocumentDetails.tsx | 131 +++++++++++ .../caseDetails/DocumentImageComponent.tsx | 116 ++++++++++ src/screens/caseDetails/PDFFullScreen.tsx | 74 +++++++ src/screens/caseDetails/interface.ts | 11 + .../caseDetails/utils/documentUtils.tsx | 90 ++++++++ yarn.lock | 38 +++- 16 files changed, 652 insertions(+), 146 deletions(-) create mode 100644 android/app/src/main/java/com/avapp/ScreenshotBlockerModule.java create mode 100644 android/app/src/main/java/com/avapp/ScreenshotBlockerModulePackage.java create mode 100644 src/components/utlis/ScreenshotBlocker.ts create mode 100644 src/screens/caseDetails/DocumentDetails.tsx create mode 100644 src/screens/caseDetails/DocumentImageComponent.tsx create mode 100644 src/screens/caseDetails/PDFFullScreen.tsx create mode 100644 src/screens/caseDetails/utils/documentUtils.tsx diff --git a/App.tsx b/App.tsx index 07a85922..42d56e9b 100644 --- a/App.tsx +++ b/App.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { AppState, LogBox, @@ -38,6 +38,7 @@ import { import usePolling from './src/hooks/usePolling'; import { MILLISECONDS_IN_A_SECOND } from './RN-UI-LIB/src/utlis/common'; import analytics from '@react-native-firebase/analytics'; +import ScreenshotBlocker from './src/components/utlis/ScreenshotBlocker'; initSentry(); @@ -112,6 +113,10 @@ function App() { active: true, }); + useEffect(() => { + ScreenshotBlocker.unblockScreenshots(); + }, []); + React.useEffect(() => { askForPermissions(); const appStateChange = AppState.addEventListener('change', async (change) => { diff --git a/android/app/build.gradle b/android/app/build.gradle index 848437fe..d69d2728 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -135,6 +135,12 @@ def VERSION_CODE = 83 def VERSION_NAME = "2.3.10" android { + packagingOptions { + pickFirst 'lib/x86/libc++_shared.so' + pickFirst 'lib/x86_64/libc++_shared.so' + pickFirst 'lib/armeabi-v7a/libc++_shared.so' + pickFirst 'lib/arm64-v8a/libc++_shared.so' + } ndkVersion rootProject.ext.ndkVersion compileSdkVersion rootProject.ext.compileSdkVersion @@ -217,10 +223,18 @@ android { } signingConfigs { debug { + if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) { + storeFile file(MYAPP_UPLOAD_STORE_FILE) + storePassword MYAPP_UPLOAD_STORE_PASSWORD + keyAlias MYAPP_UPLOAD_KEY_ALIAS + keyPassword MYAPP_UPLOAD_KEY_PASSWORD + } + else { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' + } } release { if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) { diff --git a/android/app/src/main/java/com/avapp/MainApplication.java b/android/app/src/main/java/com/avapp/MainApplication.java index 809273f1..d051ff98 100644 --- a/android/app/src/main/java/com/avapp/MainApplication.java +++ b/android/app/src/main/java/com/avapp/MainApplication.java @@ -37,6 +37,7 @@ public class MainApplication extends Application implements ReactApplication { List packages = new PackageList(this).getPackages(); // Packages that cannot be autolinked yet can be added manually here, for example: packages.add(new DeviceUtilsModulePackage()); + packages.add(new ScreenshotBlockerModulePackage()); return packages; } diff --git a/android/app/src/main/java/com/avapp/ScreenshotBlockerModule.java b/android/app/src/main/java/com/avapp/ScreenshotBlockerModule.java new file mode 100644 index 00000000..62280baa --- /dev/null +++ b/android/app/src/main/java/com/avapp/ScreenshotBlockerModule.java @@ -0,0 +1,59 @@ +package com.avapp; + +import android.app.Activity; +import android.view.WindowManager; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.modules.core.DeviceEventManagerModule; + +import android.os.Handler; +import android.os.Looper; + +public class ScreenshotBlockerModule extends ReactContextBaseJavaModule { + private ReactApplicationContext reactContext; + + public ScreenshotBlockerModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } + + @Override + public String getName() { + return "ScreenshotBlocker"; + } + + @ReactMethod + public void blockScreenshots() { + new Handler(Looper.getMainLooper()).post(new Runnable() { + Activity activity = getCurrentActivity(); + + @Override + public void run() { + if (activity != null) { + activity.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_SECURE, + WindowManager.LayoutParams.FLAG_SECURE + ); + } + } + }); + } + + @ReactMethod + public void unblockScreenshots() { + new Handler(Looper.getMainLooper()).post(new Runnable() { + Activity activity = getCurrentActivity(); + + @Override + public void run() { + if (activity != null) { + activity.getWindow().clearFlags( + WindowManager.LayoutParams.FLAG_SECURE + ); + } + } + }); + } + +} \ No newline at end of file diff --git a/android/app/src/main/java/com/avapp/ScreenshotBlockerModulePackage.java b/android/app/src/main/java/com/avapp/ScreenshotBlockerModulePackage.java new file mode 100644 index 00000000..f16bdd35 --- /dev/null +++ b/android/app/src/main/java/com/avapp/ScreenshotBlockerModulePackage.java @@ -0,0 +1,28 @@ +package com.avapp; + + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ScreenshotBlockerModulePackage implements ReactPackage { + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + + @Override + public List createNativeModules( + ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + + modules.add(new ScreenshotBlockerModule(reactContext)); + + return modules; + } +} \ No newline at end of file diff --git a/package.json b/package.json index 54c608a2..6f3226bf 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "react-native-gzip": "1.0.0", "react-native-image-picker": "4.10.2", "react-native-pager-view": "6.1.2", + "react-native-pdf": "^6.7.1", "react-native-permissions": "3.6.1", "react-native-qrcode-svg": "^6.2.0", "react-native-safe-area-context": "4.4.1", diff --git a/src/components/utlis/ScreenshotBlocker.ts b/src/components/utlis/ScreenshotBlocker.ts new file mode 100644 index 00000000..d0269405 --- /dev/null +++ b/src/components/utlis/ScreenshotBlocker.ts @@ -0,0 +1,5 @@ +import { NativeModules } from 'react-native'; + +const { ScreenshotBlocker } = NativeModules; + +export default ScreenshotBlocker; diff --git a/src/screens/auth/ProtectedRouter.tsx b/src/screens/auth/ProtectedRouter.tsx index e7d4f679..fa0cd8fc 100644 --- a/src/screens/auth/ProtectedRouter.tsx +++ b/src/screens/auth/ProtectedRouter.tsx @@ -32,6 +32,7 @@ import Notifications from '../notifications'; import RegisterPayments from '../registerPayements/RegisterPayments'; import TodoList from '../todoList/TodoList'; import UngroupedAddressContainer from '../addressGeolocation/UngroupedAddressContainer'; +import PDFFullScreen from '../caseDetails/PDFFullScreen'; const Stack = createNativeStackNavigator(); @@ -170,6 +171,16 @@ const ProtectedRouter = () => { }} listeners={getScreenFocusListenerObj} /> + null, + animationDuration: SCREEN_ANIMATION_DURATION, + animation: 'none', + }} + listeners={getScreenFocusListenerObj} + /> = (props) => { }); }; + useFocusEffect(() => { + ScreenshotBlocker.unblockScreenshots(); + }); + return ( diff --git a/src/screens/caseDetails/CustomerProfile.tsx b/src/screens/caseDetails/CustomerProfile.tsx index de202b40..c3376099 100644 --- a/src/screens/caseDetails/CustomerProfile.tsx +++ b/src/screens/caseDetails/CustomerProfile.tsx @@ -1,25 +1,25 @@ -import { ActivityIndicator, Pressable, ScrollView, StyleSheet, View } from 'react-native'; +import { ScrollView, StyleSheet, View } from 'react-native'; import React, { useEffect, useState } from 'react'; import { SafeAreaView } from 'react-native-safe-area-context'; import { GenericStyles, SCREEN_WIDTH } from '../../../RN-UI-LIB/src/styles'; import { COLORS } from '../../../RN-UI-LIB/src/styles/colors'; -import RNFastImage from '../../../RN-UI-LIB/src/components/FastImage'; import NavigationHeader, { Icon } from '../../../RN-UI-LIB/src/components/NavigationHeader'; -import { CaseDetail, DOCUMENT_TYPE, IDocument } from './interface'; +import { CaseDetail, DocumentDetail, DOCUMENT_TYPE, IDocument } from './interface'; import useIsOnline from '../../hooks/useIsOnline'; import useFetchDocument from '../../hooks/useFetchDocument'; import { RELATIVE_PATH_PREFIX, - checkS3Url, findDocumentByDocumentType, getDocumentList, } from '../../components/utlis/commonFunctions'; -import { goBack, navigateToScreen } from '../../components/utlis/navigationUtlis'; -import Text from '../../../RN-UI-LIB/src/components/Text'; -import { ISignedRequest, getSignedApi } from '../../action/dataActions'; -import { useTimeout } from 'react-native-toast-message/lib/src/hooks'; -import { DELAY_FOR_PAINTING_IMAGE } from '../../common/Constants'; -import { isNullOrEmptyString } from '../../../RN-UI-LIB/src/utlis/common'; +import { goBack } from '../../components/utlis/navigationUtlis'; +import SuspenseLoader from '../../../RN-UI-LIB/src/components/suspense_loader/SuspenseLoader'; +import LineLoader from '../../../RN-UI-LIB/src/components/suspense_loader/LineLoader'; +import ScreenshotBlocker from '../../components/utlis/ScreenshotBlocker'; +import { useFocusEffect } from '@react-navigation/native'; +import DocumentImageComponent from './DocumentImageComponent'; +import DocumentDetails from './DocumentDetails'; +import { getDocumentDetails } from './utils/documentUtils'; interface ICustomerProfile { route: { @@ -35,12 +35,9 @@ const CustomerProfile: React.FC = (props) => { params: { caseDetail }, }, } = props; - const [errorModalImage, setErrorModalImage] = useState(false); - const [loading, setLoading] = useState(true); - const { startTimer, isActive, clearTimer } = useTimeout(() => { - setLoading(false); - }, DELAY_FOR_PAINTING_IMAGE); const isOnline = useIsOnline(); + const [isDocumentsLoading, setIsDocumentsLoading] = useState(false); + const { documentObj, setRetryForUnsignedDocuments } = useFetchDocument( { caseId: caseDetail?.id, @@ -51,45 +48,7 @@ const CustomerProfile: React.FC = (props) => { false, false ); - const [vkycUri, setVkycUri] = useState(); - const [showVkyc, setShowVkyc] = useState(false); - - const updateVkycVideo = (uri: string) => { - setVkycUri(uri); - }; - - useEffect(() => { - if (caseDetail) { - const docList: IDocument[] = getDocumentList(caseDetail) || []; - const vkycDoc = findDocumentByDocumentType(docList, DOCUMENT_TYPE.VKYC_VIDEO); - if (!vkycDoc?.referenceId) { - return; - } - setShowVkyc(true); - const vkycUri = vkycDoc?.uri; - async function checkUrl(url: string) { - const result = await checkS3Url(url); - if (result) { - setVkycUri(url); - } else { - const imageReferenceId = vkycDoc?.referenceId!!; - const signedRequestPayload: ISignedRequest = [ - { - documentReferenceId: imageReferenceId, - caseId: caseDetail.id, - caseType: caseDetail.caseType, - }, - ]; - const response = await getSignedApi(signedRequestPayload); - const url = response?.imageUrl || ''; - setVkycUri(url); - } - } - if (vkycUri) { - checkUrl(vkycUri); - } - } - }, [caseDetail]); + const [documentData, setDocumentData] = useState>([]); const getImageURI = () => { if (!isOnline) { @@ -106,72 +65,75 @@ const CustomerProfile: React.FC = (props) => { ); }; - const handleVkycPress = () => { - navigateToScreen('vkycFull', { - vkycUri, - }); - }; + useEffect(() => { + if (caseDetail) { + const docList: IDocument[] = getDocumentList(caseDetail) || []; + const docPromises: Promise[] = []; + // TODO: Add Driver License Enum + const updatedDocList = [ + DOCUMENT_TYPE.VKYC_VIDEO, + DOCUMENT_TYPE.AADHAR, + DOCUMENT_TYPE.PAN, + DOCUMENT_TYPE.AADHAR_PHOTO, + ]; + updatedDocList.forEach((documentType) => { + const document = findDocumentByDocumentType(docList, documentType); + if (document) { + const docPromise = getDocumentDetails(document, caseDetail.id, caseDetail.caseType); + if (docPromise) docPromises.push(docPromise); + } + }); - const onLoadStart = () => { - setLoading(true); - setErrorModalImage(false); - }; - const onLoadEnd = () => { - // added this to show loader for the image is getting painted on screen - startTimer(); - }; + setIsDocumentsLoading(true); + Promise.all(docPromises) + .then((docs: Array) => { + const documents = docs?.filter( + (document: DocumentDetail | null) => document + ) as Array; + setDocumentData(documents); + setIsDocumentsLoading(false); + }) + .catch(() => { + setIsDocumentsLoading(false); + }); + } + }, [caseDetail]); - const onLoad = () => { - clearTimer(); - setLoading(false); - setErrorModalImage(false); - }; + useFocusEffect(() => { + ScreenshotBlocker.blockScreenshots(); + }); const imageUri = getImageURI(); + return ( goBack()} icon={Icon.close} /> - { - setRetryForUnsignedDocuments([DOCUMENT_TYPE.SELFIE]); - setErrorModalImage(true); - }} - onLoadStart={onLoadStart} - onLoad={onLoad} - onLoadEnd={onLoadEnd} + - {loading ? ( - - {!isNullOrEmptyString(imageUri) ? 'Loading Image...' : 'No Image Found'} - - ) : errorModalImage ? ( - - Error loading image - - ) : null} - {showVkyc ? ( - - - VKYC video - - {vkycUri ? ( - - Open video - - ) : ( - - )} - - ) : null} - {/* } /> */} + + {[...Array(4).keys()].map(() => ( + + ))} + + } + > + + ); @@ -190,37 +152,7 @@ const styles = StyleSheet.create({ borderWidth: 1, borderColor: COLORS.BORDER.GREY, }, - imageStyle: { - height: '100%', - }, container: { position: 'relative', }, - errorText: { - position: 'absolute', - top: '50%', - textAlign: 'center', - width: '100%', - color: COLORS.TEXT.RED, - }, - loadingText: { - position: 'absolute', - top: '50%', - textAlign: 'center', - width: '100%', - }, - vkyc: { - marginHorizontal: 16, - paddingHorizontal: 12, - paddingVertical: 18, - borderRadius: 4, - borderWidth: 1, - borderColor: COLORS.BORDER.GREY, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - }, - openVideoTxt: { - color: COLORS.TEXT.BLUE, - }, }); diff --git a/src/screens/caseDetails/DocumentDetails.tsx b/src/screens/caseDetails/DocumentDetails.tsx new file mode 100644 index 00000000..6a590b46 --- /dev/null +++ b/src/screens/caseDetails/DocumentDetails.tsx @@ -0,0 +1,131 @@ +import React, { useState } from 'react'; +import { Pressable, StyleSheet, View } from 'react-native'; +import WebView from 'react-native-webview'; +import Accordion from '../../../RN-UI-LIB/src/components/accordian/Accordian'; +import Text from '../../../RN-UI-LIB/src/components/Text'; +import ArrowSolidDownIcon from '../../../RN-UI-LIB/src/Icons/ArrowSolidDownIcon'; +import { GenericStyles, getShadowStyle } from '../../../RN-UI-LIB/src/styles'; +import { COLORS } from '../../../RN-UI-LIB/src/styles/colors'; +import { navigateToScreen } from '../../components/utlis/navigationUtlis'; +import DocumentImageComponent from './DocumentImageComponent'; +import { DocumentDetail } from './interface'; +import { vkycHtml } from './vkycTemplate'; + +interface DocumentDetails { + documentData: Array; +} + +const DocumentDetails = (props: DocumentDetails) => { + const { documentData } = props; + const [isExpanded, setIsExpanded] = useState(false); + + const handleOpenPdfPress = (url: string) => { + // TODO: Dynamic Url + navigateToScreen('pdfFull', { + pdfUri: 'https://www.africau.edu/images/default/sample.pdf', + }); + }; + + return ( + + {documentData.map((item: any) => + item.docContentType !== 'pdf' ? ( + + {item?.icon} + {item?.title} + + } + customExpandUi={{ + whenCollapsed: ( + + + + ), + whenExpanded: ( + + + + ), + }} + onExpanded={(value) => { + setIsExpanded(value); + }} + > + + {item.docContentType === 'video' ? ( + + ) : ( + + )} + + + ) : ( + + + {item?.icon} + {item?.title} + + handleOpenPdfPress(item.url)}> + Open PDF + + + ) + )} + + ); +}; + +const styles = StyleSheet.create({ + openPdfTxt: { + color: COLORS.TEXT.BLUE, + }, + accordionExpandBtn: { + fontSize: 13, + marginTop: 8, + fontWeight: '500', + lineHeight: 20, + color: COLORS.TEXT.BLUE, + paddingRight: 16, + }, + accordionContentWrapper: { + backgroundColor: '#F7F7F7', + borderBottomLeftRadius: 8, + borderBottomRightRadius: 8, + height: 250, + padding: 16, + }, + rotateBtn: { transform: [{ rotateX: '180deg' }], marginTop: 0 }, + headerWrapper: { + ...GenericStyles.alignCenter, + ...GenericStyles.row, + ...GenericStyles.ph16, + ...GenericStyles.mb12, + }, + accordionStyles: { + ...GenericStyles.pt12, + ...GenericStyles.br8, + ...getShadowStyle(4), + paddingHorizontal: 0, + marginBottom: 16, + }, +}); + +export default DocumentDetails; diff --git a/src/screens/caseDetails/DocumentImageComponent.tsx b/src/screens/caseDetails/DocumentImageComponent.tsx new file mode 100644 index 00000000..43ec0fc6 --- /dev/null +++ b/src/screens/caseDetails/DocumentImageComponent.tsx @@ -0,0 +1,116 @@ +import React, { useState } from 'react'; +import { StyleSheet } from 'react-native'; +import { useTimeout } from 'react-native-toast-message/lib/src/hooks'; +import RNFastImage from '../../../RN-UI-LIB/src/components/FastImage'; +import Text from '../../../RN-UI-LIB/src/components/Text'; +import { GenericStyles } from '../../../RN-UI-LIB/src/styles'; +import { COLORS } from '../../../RN-UI-LIB/src/styles/colors'; +import { isNullOrEmptyString } from '../../../RN-UI-LIB/src/utlis/common'; +import { DELAY_FOR_PAINTING_IMAGE } from '../../common/Constants'; +import { DOCUMENT_TYPE } from './interface'; + +interface DocumentImageComponentProps { + docType: DOCUMENT_TYPE; + url: string; + setRetryForUnsignedDocuments?: React.Dispatch>; +} + +const DocumentImageComponent = (props: DocumentImageComponentProps) => { + const { docType, url, setRetryForUnsignedDocuments } = props; + const [errorModalImage, setErrorModalImage] = useState({ + [DOCUMENT_TYPE.SELFIE]: false, + [DOCUMENT_TYPE.AADHAR]: false, + [DOCUMENT_TYPE.PAN]: false, + }); + + const [loading, setLoading] = useState({ + [DOCUMENT_TYPE.SELFIE]: true, + [DOCUMENT_TYPE.AADHAR]: true, + [DOCUMENT_TYPE.PAN]: true, + }); + + const { startTimer, isActive, clearTimer } = useTimeout(() => { + setLoading({ + [DOCUMENT_TYPE.SELFIE]: false, + [DOCUMENT_TYPE.AADHAR]: false, + [DOCUMENT_TYPE.PAN]: false, + }); + }, DELAY_FOR_PAINTING_IMAGE); + + const onLoadStart = (docType: DOCUMENT_TYPE) => { + setLoading({ + ...loading, + [docType]: true, + }); + setErrorModalImage({ + ...errorModalImage, + [docType]: false, + }); + }; + const onLoadEnd = () => { + // added this to show loader for the image is getting painted on screen + startTimer(); + }; + + const onLoad = (docType: DOCUMENT_TYPE) => { + clearTimer(); + setLoading({ + ...loading, + [docType]: false, + }); + setErrorModalImage({ + ...errorModalImage, + [docType]: false, + }); + }; + + return ( + <> + { + setRetryForUnsignedDocuments?.([docType]); + setErrorModalImage({ + ...errorModalImage, + [docType]: true, + }); + }} + onLoadStart={() => onLoadStart(docType)} + onLoad={() => onLoad(docType)} + onLoadEnd={onLoadEnd} + /> + {loading[docType] ? ( + + {!isNullOrEmptyString(url) ? 'Loading Image...' : 'No Image Found'} + + ) : errorModalImage[docType] ? ( + + Error loading image + + ) : null} + + ); +}; + +const styles = StyleSheet.create({ + imageStyle: { + height: '100%', + }, + errorText: { + ...GenericStyles.absolute, + top: '50%', + textAlign: 'center', + width: '100%', + color: COLORS.TEXT.RED, + }, + loadingText: { + ...GenericStyles.absolute, + top: '50%', + textAlign: 'center', + width: '100%', + }, +}); + +export default DocumentImageComponent; diff --git a/src/screens/caseDetails/PDFFullScreen.tsx b/src/screens/caseDetails/PDFFullScreen.tsx new file mode 100644 index 00000000..64cb58f8 --- /dev/null +++ b/src/screens/caseDetails/PDFFullScreen.tsx @@ -0,0 +1,74 @@ +import { Dimensions, StyleSheet, View } from 'react-native'; +import React, { useState } from 'react'; +import { GenericStyles } from '../../../RN-UI-LIB/src/styles'; +import NavigationHeader, { Icon } from '../../../RN-UI-LIB/src/components/NavigationHeader'; +import { goBack } from '../../components/utlis/navigationUtlis'; +import Pdf from 'react-native-pdf'; +import Text from '../../../RN-UI-LIB/src/components/Text'; +import { COLORS } from '../../../RN-UI-LIB/src/styles/colors'; + +interface ICustomerProfile { + route: { + params: { + pdfUri: string; + }; + }; +} + +const PDFFullScreen: React.FC = (props) => { + const { + route: { + params: { pdfUri }, + }, + } = props; + + const [error, setError] = useState(false); + + return ( + + + + { + return !error ? ( + Loading... + ) : ( + + Error loading pdf + + ); + }} + onError={() => { + setError(true); + }} + style={styles.pdf} + /> + + + ); +}; + +export default PDFFullScreen; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'flex-start', + alignItems: 'center', + margin: 12, + }, + pdf: { + flex: 1, + width: Dimensions.get('window').width, + height: Dimensions.get('window').height, + }, + errorText: { + ...GenericStyles.absolute, + top: '50%', + textAlign: 'center', + width: '100%', + color: COLORS.TEXT.RED, + }, +}); diff --git a/src/screens/caseDetails/interface.ts b/src/screens/caseDetails/interface.ts index 3acea768..bb7b0c6a 100644 --- a/src/screens/caseDetails/interface.ts +++ b/src/screens/caseDetails/interface.ts @@ -139,6 +139,9 @@ export enum DOCUMENT_TYPE { SELFIE = 'SELFIE', OPTIMIZED_SELFIE = 'OPTIMIZED_SELFIE', VKYC_VIDEO = 'VKYC_VIDEO', + PAN = 'PAN', + AADHAR = 'AADHAR', + AADHAR_PHOTO = 'aadhar_photo', } export type TDocumentObj = { @@ -151,6 +154,14 @@ export interface IDocument { type: DOCUMENT_TYPE; } +export interface DocumentDetail { + icon: React.ReactNode; + title: string; + docType: DOCUMENT_TYPE; + docContentType: string; + url: string; +} + export enum FeedbackStatus { ATTEMPTED = 'ATTEMPTED', NOT_ATTEMPTED = 'NOT_ATTEMPTED', diff --git a/src/screens/caseDetails/utils/documentUtils.tsx b/src/screens/caseDetails/utils/documentUtils.tsx new file mode 100644 index 00000000..1051cadc --- /dev/null +++ b/src/screens/caseDetails/utils/documentUtils.tsx @@ -0,0 +1,90 @@ +import ImageIcon from '../../../../RN-UI-LIB/src/Icons/ImageIcon'; +import PdfIcon from '../../../../RN-UI-LIB/src/Icons/PdfIcon'; +import VideoIcon from '../../../../RN-UI-LIB/src/Icons/VideoIcon'; +import { getSignedApi, ISignedRequest } from '../../../action/dataActions'; +import { checkS3Url } from '../../../components/utlis/commonFunctions'; +import { CaseAllocationType } from '../../allCases/interface'; +import { DOCUMENT_TYPE, IDocument } from '../interface'; + +async function checkUrlData( + url: string, + referenceId: string, + caseId: string, + caseType: CaseAllocationType +) { + const result = await checkS3Url(url); + if (result) { + return url; + } else { + const signedRequestPayload: ISignedRequest = [ + { + documentReferenceId: referenceId!!, + caseId: caseId, + caseType: caseType, + }, + ]; + const response = await getSignedApi(signedRequestPayload); + const url = response?.imageUrl || ''; + return url; + } +} + +export const getDocumentDetails = async ( + document: IDocument, + caseId: string, + caseType: CaseAllocationType +) => { + if (!document.referenceId) { + return null; + } + if (document?.uri) { + try { + const imageUrl = await checkUrlData(document.uri, document.referenceId, caseId, caseType); + if (!imageUrl) return null; + // TODO: Make Dynamic Based on Content type from firestore and add DL Case + switch (document.type) { + case DOCUMENT_TYPE.VKYC_VIDEO: + return { + icon: , + title: 'VKYC video', + docType: DOCUMENT_TYPE.VKYC_VIDEO, + docContentType: 'video', + url: imageUrl, + }; + + case DOCUMENT_TYPE.PAN: + return { + icon: , + title: 'Pan details', + docType: DOCUMENT_TYPE.PAN, + docContentType: 'image', + url: imageUrl, + }; + + case DOCUMENT_TYPE.AADHAR: + return { + icon: , + title: 'Aadhar details', + docType: DOCUMENT_TYPE.AADHAR, + docContentType: 'pdf', + url: imageUrl, + }; + + case DOCUMENT_TYPE.AADHAR_PHOTO: + return { + icon: , + title: 'Aadhar photo', + docType: DOCUMENT_TYPE.AADHAR_PHOTO, + docContentType: 'image', + url: imageUrl, + }; + + default: + break; + } + } catch (error) { + return null; + } + } + return null; +}; diff --git a/yarn.lock b/yarn.lock index 20dab82a..d477678d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1658,16 +1658,16 @@ resolved "https://registry.yarnpkg.com/@react-native/assets/-/assets-1.0.0.tgz#c6f9bf63d274bafc8e970628de24986b30a55c8e" integrity sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ== +"@react-native/normalize-color@*", "@react-native/normalize-color@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91" + integrity sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA== + "@react-native/normalize-color@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.0.0.tgz#da955909432474a9a0fe1cbffc66576a0447f567" integrity sha512-Wip/xsc5lw8vsBlmY2MO/gFLp3MvuZ2baBZjDeTjjndMgM0h5sxz7AZR62RDPGgstp8Np7JzjvVqVT7tpFZqsw== -"@react-native/normalize-color@^2.0.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91" - integrity sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA== - "@react-native/polyfills@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa" @@ -3339,6 +3339,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypto-js@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.3.0.tgz#846dd1cce2f68aacfa156c8578f926a609b7976b" + integrity sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q== + css-select@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" @@ -3404,7 +3409,7 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -dayjs@^1.11.9: +dayjs@1.11.9: version "1.11.9" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a" integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA== @@ -3551,6 +3556,15 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +deprecated-react-native-prop-types@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz#c10c6ee75ff2b6de94bb127f142b814e6e08d9ab" + integrity sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA== + dependencies: + "@react-native/normalize-color" "*" + invariant "*" + prop-types "*" + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -5045,7 +5059,7 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" -invariant@2.2.4, invariant@^2.2.2, invariant@^2.2.4: +invariant@*, invariant@2.2.4, invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -7528,7 +7542,7 @@ prompts@^2.0.1, prompts@^2.4.0: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@15.8.1, prop-types@^15.7.2, prop-types@^15.8.0, prop-types@^15.8.1: +prop-types@*, 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== @@ -7762,6 +7776,14 @@ react-native-pager-view@6.1.2: resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.1.2.tgz#3522079b9a9d6634ca5e8d153bc0b4d660254552" integrity sha512-qs2KSFc+7N7B+UZ6SG2sTvCkppagm5fVyRclv1KFKc7lDtrhXLzN59tXJw575LDP/dRJoXsNwqUAhZJdws6ABQ== +react-native-pdf@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/react-native-pdf/-/react-native-pdf-6.7.1.tgz#198b8ec3e8f1025ceb43ddfc6bc5b422521c4411" + integrity sha512-zszQygtNBYoUfEtP/fV7zhzGeohDlUksh2p3OzshLrxdY9mw7Tm5VXAxYq4d8HsomRJUbFlJ7rHaTU9AQL800g== + dependencies: + crypto-js "^3.2.0" + deprecated-react-native-prop-types "^2.3.0" + react-native-permissions@3.6.1: version "3.6.1" resolved "https://registry.yarnpkg.com/react-native-permissions/-/react-native-permissions-3.6.1.tgz#73adcc1cef8cd57a9ef167b4507405f4ff5749c4"