@transfergratis/react-native-sdk 0.1.23 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +12 -5
- package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
- package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +61 -59
- package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-transfergratis-react-native-sdk.jar +0 -0
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +12 -5
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/aar/transfergratis-react-native-sdk-debug.aar +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +26 -34
- package/android/src/main/AndroidManifest.xml +13 -5
- package/build/components/EnhancedCameraView.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.js +26 -3
- package/build/components/EnhancedCameraView.js.map +1 -1
- package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.web.js +21 -0
- package/build/components/EnhancedCameraView.web.js.map +1 -1
- package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts +12 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js +283 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js.map +1 -0
- package/build/components/KYCElements/CameraCapture.d.ts.map +1 -1
- package/build/components/KYCElements/CameraCapture.js +4 -3
- package/build/components/KYCElements/CameraCapture.js.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.d.ts +5 -2
- package/build/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.js +360 -101
- package/build/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js +193 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/FileUpload.d.ts.map +1 -1
- package/build/components/KYCElements/FileUpload.js +5 -4
- package/build/components/KYCElements/FileUpload.js.map +1 -1
- package/build/components/KYCElements/FileUploadTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/FileUploadTemplate.js +5 -4
- package/build/components/KYCElements/FileUploadTemplate.js.map +1 -1
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +356 -227
- package/build/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/components/KYCElements/LocationCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/LocationCaptureTemplate.js +78 -37
- package/build/components/KYCElements/LocationCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.js +5 -4
- package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js +5 -4
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js +5 -4
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js +120 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js +185 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/SelfieCapture.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCapture.js +4 -3
- package/build/components/KYCElements/SelfieCapture.js.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.js +189 -42
- package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/WelcomeTemplate.d.ts +12 -0
- package/build/components/KYCElements/WelcomeTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/WelcomeTemplate.js +243 -0
- package/build/components/KYCElements/WelcomeTemplate.js.map +1 -0
- package/build/components/TemplateKYCExample.d.ts +8 -2
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +10 -97
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts +6 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +108 -11
- package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/components/example/DynamicTemplateExample.d.ts +10 -0
- package/build/components/example/DynamicTemplateExample.d.ts.map +1 -0
- package/build/components/example/DynamicTemplateExample.js +241 -0
- package/build/components/example/DynamicTemplateExample.js.map +1 -0
- package/build/config/KYCConfig.d.ts +14 -0
- package/build/config/KYCConfig.d.ts.map +1 -0
- package/build/config/KYCConfig.js +26 -0
- package/build/config/KYCConfig.js.map +1 -0
- package/build/config/allowedDomains.d.ts +30 -0
- package/build/config/allowedDomains.d.ts.map +1 -0
- package/build/config/allowedDomains.js +112 -0
- package/build/config/allowedDomains.js.map +1 -0
- package/build/hooks/useOrientationVideo.d.ts +2 -1
- package/build/hooks/useOrientationVideo.d.ts.map +1 -1
- package/build/hooks/useOrientationVideo.js +3 -3
- package/build/hooks/useOrientationVideo.js.map +1 -1
- package/build/hooks/useTemplateKYCFlow.d.ts +6 -1
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +317 -34
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/hooks/useTemplateLoader.d.ts +14 -0
- package/build/hooks/useTemplateLoader.d.ts.map +1 -0
- package/build/hooks/useTemplateLoader.js +85 -0
- package/build/hooks/useTemplateLoader.js.map +1 -0
- package/build/i18n/en/index.d.ts +49 -0
- package/build/i18n/en/index.d.ts.map +1 -1
- package/build/i18n/en/index.js +50 -1
- package/build/i18n/en/index.js.map +1 -1
- package/build/i18n/fr/index.d.ts +35 -0
- package/build/i18n/fr/index.d.ts.map +1 -1
- package/build/i18n/fr/index.js +36 -1
- package/build/i18n/fr/index.js.map +1 -1
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +10 -0
- package/build/index.js.map +1 -1
- package/build/modules/api/CardAuthentification.d.ts +24 -3
- package/build/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/modules/api/CardAuthentification.js +69 -10
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +7 -7
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +108 -39
- package/build/modules/api/KYCService.js.map +1 -1
- package/build/modules/api/SelfieVerification.d.ts +3 -1
- package/build/modules/api/SelfieVerification.d.ts.map +1 -1
- package/build/modules/api/SelfieVerification.js +17 -1
- package/build/modules/api/SelfieVerification.js.map +1 -1
- package/build/modules/api/TemplateService.d.ts +44 -0
- package/build/modules/api/TemplateService.d.ts.map +1 -0
- package/build/modules/api/TemplateService.js +145 -0
- package/build/modules/api/TemplateService.js.map +1 -0
- package/build/types/KYC.types.d.ts +265 -4
- package/build/types/KYC.types.d.ts.map +1 -1
- package/build/types/KYC.types.js +15 -0
- package/build/types/KYC.types.js.map +1 -1
- package/build/types/env.types.d.ts +13 -0
- package/build/types/env.types.d.ts.map +1 -0
- package/build/types/env.types.js +2 -0
- package/build/types/env.types.js.map +1 -0
- package/build/utils/cropByObb.d.ts +1 -0
- package/build/utils/cropByObb.d.ts.map +1 -1
- package/build/utils/cropByObb.js +70 -0
- package/build/utils/cropByObb.js.map +1 -1
- package/build/utils/deviceDetection.d.ts +6 -0
- package/build/utils/deviceDetection.d.ts.map +1 -0
- package/build/utils/deviceDetection.js +12 -0
- package/build/utils/deviceDetection.js.map +1 -0
- package/build/utils/platformAlert.d.ts +20 -0
- package/build/utils/platformAlert.d.ts.map +1 -0
- package/build/utils/platformAlert.js +67 -0
- package/build/utils/platformAlert.js.map +1 -0
- package/build/utils/template-transformer.d.ts +10 -0
- package/build/utils/template-transformer.d.ts.map +1 -0
- package/build/utils/template-transformer.js +365 -0
- package/build/utils/template-transformer.js.map +1 -0
- package/build/web/WebKYCEntry.d.ts.map +1 -1
- package/build/web/WebKYCEntry.js +158 -32
- package/build/web/WebKYCEntry.js.map +1 -1
- package/package.json +1 -1
- package/plugin/build/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.ts +3 -4
- package/src/components/EnhancedCameraView.tsx +31 -2
- package/src/components/EnhancedCameraView.web.tsx +24 -0
- package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
- package/src/components/KYCElements/CameraCapture.tsx +4 -3
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +410 -113
- package/src/components/KYCElements/EmailVerificationTemplate.tsx +264 -0
- package/src/components/KYCElements/FileUpload.tsx +5 -4
- package/src/components/KYCElements/FileUploadTemplate.tsx +5 -4
- package/src/components/KYCElements/IDCardCapture.tsx +397 -254
- package/src/components/KYCElements/LocationCaptureTemplate.tsx +95 -44
- package/src/components/KYCElements/OrientationVideoCapture.tsx +6 -3
- package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +6 -3
- package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +6 -3
- package/src/components/KYCElements/PersonalInformationTemplate.tsx +158 -0
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +253 -0
- package/src/components/KYCElements/SelfieCapture.tsx +4 -3
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +201 -44
- package/src/components/KYCElements/WelcomeTemplate.tsx +289 -0
- package/src/components/TemplateKYCExample.tsx +37 -108
- package/src/components/TemplateKYCFlowRefactored.tsx +148 -12
- package/src/components/example/DynamicTemplateExample.tsx +289 -0
- package/src/config/KYCConfig.ts +34 -0
- package/src/config/allowedDomains.ts +133 -0
- package/src/hooks/useOrientationVideo.ts +5 -4
- package/src/hooks/useTemplateKYCFlow.tsx +347 -32
- package/src/hooks/useTemplateLoader.ts +102 -0
- package/src/i18n/en/index.ts +53 -2
- package/src/i18n/fr/index.ts +37 -1
- package/src/index.ts +14 -0
- package/src/modules/api/CardAuthentification.ts +76 -11
- package/src/modules/api/KYCService.ts +129 -45
- package/src/modules/api/SelfieVerification.ts +25 -3
- package/src/modules/api/TemplateService.ts +167 -0
- package/src/types/KYC.types.ts +331 -3
- package/src/types/env.types.ts +13 -0
- package/src/utils/cropByObb.ts +83 -3
- package/src/utils/deviceDetection.ts +11 -0
- package/src/utils/platformAlert.ts +86 -0
- package/src/utils/template-transformer.ts +445 -0
- package/src/web/WebKYCEntry.tsx +199 -50
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import { View, Text,
|
|
1
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, Image, ScrollView, Platform, Modal, TouchableOpacity } from 'react-native';
|
|
3
|
+
import { showAlert } from '../../utils/platformAlert';
|
|
3
4
|
import { EnhancedCameraView } from '../EnhancedCameraView';
|
|
5
|
+
import { GovernmentDocumentTypeShorted, GovernmentDocumentTypeBackend } from '../../types/KYC.types';
|
|
4
6
|
import IdCardOverlay from '../OverLay/IdCard';
|
|
5
7
|
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
6
8
|
import { useI18n } from '../../hooks/useI18n';
|
|
@@ -9,8 +11,9 @@ import { removeDuplicates } from '../../utils/remove-duplicate';
|
|
|
9
11
|
import { backVerification, checkTemplateType, frontVerification } from '../../modules/api/CardAuthentification';
|
|
10
12
|
import { getDocumentTypeInfo } from '../../utils/get-document-type-info';
|
|
11
13
|
import pathToBase64 from '../../utils/pathToBase64';
|
|
12
|
-
import { truncateFields } from '../../modules/api/KYCService';
|
|
13
|
-
import { cropByObb, cropImageWithBBox } from '../../utils/cropByObb';
|
|
14
|
+
import kycService, { truncateFields } from '../../modules/api/KYCService';
|
|
15
|
+
import { cropByObb, cropImageWithBBox, cropImageWithBBoxWithTolerance } from '../../utils/cropByObb';
|
|
16
|
+
import { isMobileWeb } from '../../utils/deviceDetection';
|
|
14
17
|
import { logger } from '../../utils/logger';
|
|
15
18
|
export const IDCardCapture = ({ component, value = {}, onValueChange, error, language = 'en', }) => {
|
|
16
19
|
const { t, locale } = useI18n();
|
|
@@ -20,18 +23,18 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
20
23
|
const [currentSide, setCurrentSide] = useState('front');
|
|
21
24
|
// Stocker les bbox par côté pour pouvoir restaurer les images croppées
|
|
22
25
|
const [bboxBySide, setBboxBySide] = useState({});
|
|
23
|
-
const [selectedDocumentType, setSelectedDocumentType] = useState({
|
|
24
|
-
type: 'identity_card',
|
|
25
|
-
region: 'root'
|
|
26
|
-
});
|
|
27
|
-
const [showDocumentSelection, setShowDocumentSelection] = useState({
|
|
28
|
-
documentSelection: true,
|
|
29
|
-
regionSelection: false
|
|
30
|
-
});
|
|
31
26
|
const [silentCaptureResult, setSilentCaptureResult] = useState({ success: false, isAnalyzing: false });
|
|
27
|
+
const [showQRModal, setShowQRModal] = useState(false);
|
|
28
|
+
// Mapping des types de documents backend vers SDK
|
|
29
|
+
const documentTypeMapping = {
|
|
30
|
+
'nationalId': 'national_id',
|
|
31
|
+
'passport': 'passport',
|
|
32
|
+
'driversLicense': 'drivers_licence',
|
|
33
|
+
'residencePermit': 'permanent_residence',
|
|
34
|
+
'healthInsuranceCard': 'health_insurance_card',
|
|
35
|
+
};
|
|
32
36
|
// const [imageNaturalSize, setImageNaturalSize] = useState<{ width: number; height: number } | null>(null);
|
|
33
|
-
const { actions, state, } = useTemplateKYCFlowContext();
|
|
34
|
-
const config = component.config;
|
|
37
|
+
const { actions, state, env } = useTemplateKYCFlowContext();
|
|
35
38
|
const getLocalizedText = (text) => {
|
|
36
39
|
// console.log("text", text, JSON.stringify(component, null, 2));
|
|
37
40
|
if (text && typeof text[currentSide] === 'object' && text[currentSide][locale]) {
|
|
@@ -39,27 +42,54 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
39
42
|
}
|
|
40
43
|
return "";
|
|
41
44
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return
|
|
45
|
+
// Récupérer les données depuis le composant country_selection
|
|
46
|
+
const countrySelectionData = useMemo(() => {
|
|
47
|
+
const countrySelectionComponent = state.template.components.find(c => c.type === 'country_selection');
|
|
48
|
+
if (countrySelectionComponent) {
|
|
49
|
+
return state.componentData[countrySelectionComponent.id];
|
|
47
50
|
}
|
|
48
51
|
return null;
|
|
49
|
-
}, [state.componentData]);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
}, [state.template.components, state.componentData]);
|
|
53
|
+
// Extraire selectedDocumentType depuis countrySelectionData
|
|
54
|
+
const selectedDocumentType = useMemo(() => {
|
|
55
|
+
if (!countrySelectionData?.documentType)
|
|
56
|
+
return null;
|
|
57
|
+
const backendDocType = countrySelectionData.documentType;
|
|
58
|
+
const mappedType = documentTypeMapping[backendDocType] || backendDocType;
|
|
59
|
+
const region = countrySelectionData.region || 'root';
|
|
60
|
+
return { type: mappedType, region };
|
|
61
|
+
}, [countrySelectionData, documentTypeMapping]);
|
|
62
|
+
// Récupérer countryData pour compatibilité avec le code existant
|
|
63
|
+
const countryData = useMemo(() => {
|
|
64
|
+
return countrySelectionData;
|
|
65
|
+
}, [countrySelectionData]);
|
|
66
|
+
// Synchroniser capturedImages avec value quand les données sont chargées (ex: reprise de session)
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (value && Object.keys(value).length > 0) {
|
|
69
|
+
// Vérifier si les données ont changé
|
|
70
|
+
const valueChanged = JSON.stringify(value) !== JSON.stringify(capturedImages);
|
|
71
|
+
if (valueChanged) {
|
|
72
|
+
logger.log("Updating capturedImages from value:", Object.keys(value));
|
|
73
|
+
logger.log("Value data sample:", truncateFields(value));
|
|
74
|
+
const updatedImages = value;
|
|
75
|
+
setCapturedImages(updatedImages);
|
|
76
|
+
// Si on a des images chargées, mettre à jour silentCaptureResult pour l'affichage
|
|
77
|
+
Object.keys(updatedImages).forEach((side) => {
|
|
78
|
+
const imageData = updatedImages[side];
|
|
79
|
+
if (imageData?.dir) {
|
|
80
|
+
setSilentCaptureResult(prev => ({
|
|
81
|
+
...prev,
|
|
82
|
+
path: imageData.dir,
|
|
83
|
+
success: true,
|
|
84
|
+
isAnalyzing: false,
|
|
85
|
+
mrz: imageData.mrz || '',
|
|
86
|
+
templatePath: imageData.templatePath || '',
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
57
89
|
});
|
|
58
90
|
}
|
|
59
91
|
}
|
|
60
|
-
|
|
61
|
-
return newconfig;
|
|
62
|
-
}, []);
|
|
92
|
+
}, [value]);
|
|
63
93
|
useEffect(() => {
|
|
64
94
|
logger.log("cropImageUri", JSON.stringify(truncateFields({ box: silentCaptureResult }), null, 2));
|
|
65
95
|
if (capturedImages[currentSide]?.dir && silentCaptureResult?.bbox) {
|
|
@@ -68,27 +98,32 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
68
98
|
});
|
|
69
99
|
}
|
|
70
100
|
}, [capturedImages[currentSide]?.dir, silentCaptureResult?.bbox]);
|
|
71
|
-
const cameraConfig = {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
101
|
+
const cameraConfig = useMemo(() => {
|
|
102
|
+
const instructions = selectedDocumentType
|
|
103
|
+
? (locale === 'en' ? getDocumentTypeInfo(selectedDocumentType.type).instructions.en : getDocumentTypeInfo(selectedDocumentType.type).instructions.fr)
|
|
104
|
+
: getLocalizedText(component.instructions);
|
|
105
|
+
return {
|
|
106
|
+
aspectRatio: 4 / 3,
|
|
107
|
+
quality: 0.8,
|
|
108
|
+
flashMode: 'auto',
|
|
109
|
+
cameraType: 'back',
|
|
110
|
+
allowRetake: true,
|
|
111
|
+
maxRetakes: 3,
|
|
112
|
+
overlay: {
|
|
113
|
+
showGuide: true,
|
|
114
|
+
guideText: instructions,
|
|
115
|
+
bbox: {
|
|
116
|
+
xMin: 20,
|
|
117
|
+
yMin: 140,
|
|
118
|
+
xMax: 370,
|
|
119
|
+
yMax: 340,
|
|
120
|
+
borderColor: '#2DBD60',
|
|
121
|
+
borderWidth: 3,
|
|
122
|
+
cornerRadius: 8
|
|
123
|
+
}
|
|
89
124
|
}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
125
|
+
};
|
|
126
|
+
}, [selectedDocumentType, locale, component.instructions]);
|
|
92
127
|
const retakePicture = (currentSide) => {
|
|
93
128
|
setShowCamera(true);
|
|
94
129
|
actions.showCustomStepper(false);
|
|
@@ -97,26 +132,14 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
97
132
|
setCropImageUri('');
|
|
98
133
|
onValueChange({ ...value, [currentSide]: { dir: '', file: '', mrz: '' } });
|
|
99
134
|
};
|
|
100
|
-
const hasRegions = useCallback((documentType) => {
|
|
101
|
-
const regionMapping = countryData?.regionMapping[documentType];
|
|
102
|
-
if (regionMapping && Object.keys(regionMapping).length > 1) {
|
|
103
|
-
return {
|
|
104
|
-
hasRegions: true,
|
|
105
|
-
regionMapping: Object.keys(regionMapping)
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
hasRegions: false,
|
|
110
|
-
regionMapping: []
|
|
111
|
-
};
|
|
112
|
-
}, [countryData]);
|
|
113
135
|
const getCurrentSideVerification = (currentSide) => {
|
|
114
|
-
|
|
136
|
+
if (!selectedDocumentType || !countryData?.regionMapping) {
|
|
137
|
+
return { authMethod: [], mrzTypes: [], regionMapping: null, key: 'root' };
|
|
138
|
+
}
|
|
139
|
+
const regionMapping = countryData.regionMapping[selectedDocumentType.type];
|
|
115
140
|
const authMethod = [];
|
|
116
141
|
const mrzTypes = [];
|
|
117
|
-
const key = selectedDocumentType
|
|
118
|
-
// console.log("regionMapping", JSON.stringify(regionMapping, null, 2), selectedDocumentType?.region);
|
|
119
|
-
// const key = selectedDocumentType?.region as keyof typeof regionMapping;
|
|
142
|
+
const key = selectedDocumentType.region?.trim()?.length > 0 ? selectedDocumentType.region.trim() : 'root';
|
|
120
143
|
if (regionMapping?.[key] && Array.isArray(regionMapping[key])) {
|
|
121
144
|
regionMapping[key].forEach((item) => {
|
|
122
145
|
if (item[currentSide]) {
|
|
@@ -127,11 +150,11 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
127
150
|
}
|
|
128
151
|
});
|
|
129
152
|
}
|
|
130
|
-
logger.log("regionMapping", JSON.stringify(truncateFields({ regionMapping, selectedDocumentType: selectedDocumentType
|
|
153
|
+
logger.log("regionMapping", JSON.stringify(truncateFields({ regionMapping, selectedDocumentType: selectedDocumentType.region, key }), null, 2));
|
|
131
154
|
return { authMethod: removeDuplicates(authMethod), mrzTypes: removeDuplicates(mrzTypes), regionMapping: regionMapping, key: key };
|
|
132
155
|
};
|
|
133
156
|
const getCorrespondingMrzType = (templatePath, mapping, selectedDocumentType = "root") => {
|
|
134
|
-
if (!mapping[selectedDocumentType])
|
|
157
|
+
if (!mapping || !mapping[selectedDocumentType])
|
|
135
158
|
return null;
|
|
136
159
|
// Extraire le nom du fichier depuis le template_path
|
|
137
160
|
const fileName = templatePath.split("/").pop()?.replace(".jpg", "").replace(".png", "");
|
|
@@ -151,11 +174,20 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
151
174
|
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: true, success: false, error: '' }));
|
|
152
175
|
let templatePath = silentCaptureResult.templatePath || '';
|
|
153
176
|
let templateBbox;
|
|
177
|
+
if (!selectedDocumentType) {
|
|
178
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: false, error: 'Document type not selected' }));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
154
181
|
const regionMappings = getCurrentSideVerification(currentSide);
|
|
155
182
|
// logger.log("regionMappings", JSON.stringify(truncateFields({regionMappings, templatePath}), null, 2));
|
|
156
183
|
if (templatePath.length === 0) {
|
|
157
184
|
try {
|
|
158
|
-
|
|
185
|
+
logger.log("checkTemplateType - BEFORE call", {
|
|
186
|
+
selectedDocumentTypeType: selectedDocumentType?.type,
|
|
187
|
+
countrySelectionDataDocumentType: countrySelectionData?.documentType,
|
|
188
|
+
docTypeToSend: selectedDocumentType?.type
|
|
189
|
+
});
|
|
190
|
+
const templateType = await checkTemplateType({ path: result.path || '', docType: selectedDocumentType?.type, docRegion: countryData?.code || "", postfix: currentSide }, env);
|
|
159
191
|
if (templateType.template_path) {
|
|
160
192
|
templatePath = templateType.template_path;
|
|
161
193
|
logger.log("templatePath", templatePath);
|
|
@@ -174,57 +206,87 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
174
206
|
catch (e) {
|
|
175
207
|
logger.log("error checking template type", truncateFields(e));
|
|
176
208
|
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: false, error: e?.message || 'Erreur de vérification du template' }));
|
|
209
|
+
return; // Return early if checkTemplateType fails
|
|
177
210
|
}
|
|
178
211
|
}
|
|
179
|
-
logger.log("templatePath before
|
|
212
|
+
logger.log("templatePath before verification", templatePath, "currentSide", currentSide);
|
|
180
213
|
if (currentSide === 'front') {
|
|
181
|
-
frontVerification
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
setSilentCaptureResult((prev) => ({
|
|
193
|
-
...prev,
|
|
214
|
+
logger.log("frontVerification - BEFORE call", {
|
|
215
|
+
selectedDocumentTypeType: selectedDocumentType?.type,
|
|
216
|
+
countrySelectionDataDocumentType: countrySelectionData?.documentType,
|
|
217
|
+
docTypeToSend: selectedDocumentType?.type
|
|
218
|
+
});
|
|
219
|
+
logger.log("Calling frontVerification", { templatePath, selectedDocumentType: selectedDocumentType?.type, regionMappings });
|
|
220
|
+
console.log("About to call frontVerification", typeof frontVerification);
|
|
221
|
+
try {
|
|
222
|
+
const mrzType = getCorrespondingMrzType(templatePath, regionMappings.regionMapping, regionMappings.key || '') || '';
|
|
223
|
+
console.log("mrzType calculated", mrzType);
|
|
224
|
+
const verificationParams = {
|
|
194
225
|
path: result.path,
|
|
226
|
+
regionMapping: {
|
|
227
|
+
authMethod: regionMappings.authMethod,
|
|
228
|
+
mrzTypes: regionMappings.mrzTypes,
|
|
229
|
+
},
|
|
230
|
+
selectedDocumentType: GovernmentDocumentTypeShorted[selectedDocumentType?.type] || '',
|
|
231
|
+
code: countryData?.code || '',
|
|
232
|
+
currentSide: currentSide,
|
|
195
233
|
templatePath: templatePath,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
234
|
+
mrzType: mrzType,
|
|
235
|
+
};
|
|
236
|
+
console.log("frontVerification params", verificationParams);
|
|
237
|
+
console.log("About to call frontVerification function");
|
|
238
|
+
const promise = frontVerification(verificationParams, env);
|
|
239
|
+
console.log("frontVerification promise created", promise);
|
|
240
|
+
promise.then((mrz) => {
|
|
241
|
+
logger.log("front verification result", truncateFields(mrz));
|
|
242
|
+
const bbox = mrz?.bbox || templateBbox;
|
|
243
|
+
setSilentCaptureResult((prev) => ({
|
|
244
|
+
...prev,
|
|
245
|
+
path: result.path,
|
|
246
|
+
templatePath: templatePath,
|
|
247
|
+
bbox: bbox, success: true,
|
|
248
|
+
mrz: JSON.stringify(mrz), isAnalyzing: false,
|
|
249
|
+
country: countryData?.code,
|
|
250
|
+
documentType: selectedDocumentType.type,
|
|
251
|
+
}));
|
|
252
|
+
// Stocker le bbox pour ce côté
|
|
253
|
+
if (bbox && typeof bbox === 'object') {
|
|
254
|
+
setBboxBySide((prev) => ({ ...prev, [currentSide]: bbox }));
|
|
255
|
+
}
|
|
256
|
+
}).catch((e) => {
|
|
257
|
+
console.log("error front verification", e);
|
|
258
|
+
logger.log("error front verification", truncateFields(e));
|
|
259
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, templatePath: templatePath, success: false, error: e?.message || 'Erreur de détection du MRZ' }));
|
|
260
|
+
// showAlert('Erreur', e?.message || 'Erreur de détection du MRZ');
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
console.log("Error setting up frontVerification call", error);
|
|
265
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: false, error: error?.message || 'Erreur lors de la configuration de la vérification' }));
|
|
266
|
+
}
|
|
210
267
|
}
|
|
211
268
|
else {
|
|
269
|
+
const backRegionMappings = getCurrentSideVerification(currentSide);
|
|
270
|
+
logger.log("Calling backVerification", { templatePath, selectedDocumentType: selectedDocumentType.type, backRegionMappings });
|
|
212
271
|
backVerification({
|
|
213
272
|
path: result.path,
|
|
214
|
-
regionMapping:
|
|
215
|
-
|
|
273
|
+
regionMapping: {
|
|
274
|
+
authMethod: backRegionMappings.authMethod,
|
|
275
|
+
mrzTypes: backRegionMappings.mrzTypes,
|
|
276
|
+
},
|
|
277
|
+
selectedDocumentType: GovernmentDocumentTypeShorted[selectedDocumentType.type] || '',
|
|
216
278
|
code: countryData?.code || '',
|
|
217
279
|
currentSide: currentSide,
|
|
218
280
|
templatePath: templatePath,
|
|
219
|
-
mrzType: getCorrespondingMrzType(templatePath,
|
|
220
|
-
}).then((mrz) => {
|
|
281
|
+
mrzType: getCorrespondingMrzType(templatePath, backRegionMappings.regionMapping, backRegionMappings.key || '') || '',
|
|
282
|
+
}, env).then((mrz) => {
|
|
221
283
|
logger.log("back verification result", truncateFields(mrz));
|
|
222
284
|
const bbox = mrz?.bbox || templateBbox;
|
|
223
285
|
setSilentCaptureResult((prev) => ({
|
|
224
286
|
...prev, path: result.path, bbox: bbox,
|
|
225
287
|
success: true, mrz: JSON.stringify(mrz), isAnalyzing: false,
|
|
226
288
|
country: countryData?.code,
|
|
227
|
-
documentType: selectedDocumentType
|
|
289
|
+
documentType: selectedDocumentType.type,
|
|
228
290
|
}));
|
|
229
291
|
// Stocker le bbox pour ce côté
|
|
230
292
|
if (bbox && typeof bbox === 'object') {
|
|
@@ -233,109 +295,115 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
233
295
|
}).catch((e) => {
|
|
234
296
|
logger.log("error back verification", truncateFields(e));
|
|
235
297
|
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, templatePath: templatePath, success: false, error: e?.message || 'Erreur de détection du MRZ' }));
|
|
236
|
-
//
|
|
298
|
+
// showAlert('Erreur', e?.message || 'Erreur de détection du MRZ');
|
|
237
299
|
});
|
|
238
300
|
}
|
|
239
301
|
}
|
|
240
302
|
};
|
|
241
303
|
// Handle capture
|
|
242
304
|
const handleCapture = async (result) => {
|
|
305
|
+
console.log("handleCapture", JSON.stringify(truncateFields({ result, silentCaptureResult }), null, 2));
|
|
243
306
|
if (silentCaptureResult.path) {
|
|
244
|
-
|
|
307
|
+
// Créer une image rognée avec tolérance de 10% pour l'envoi
|
|
308
|
+
let imagePathForUpload = silentCaptureResult.path;
|
|
309
|
+
if (silentCaptureResult.bbox) {
|
|
310
|
+
try {
|
|
311
|
+
logger.log("Début du rognage avec tolérance, URI original:", silentCaptureResult.path);
|
|
312
|
+
imagePathForUpload = await cropImageWithBBoxWithTolerance(silentCaptureResult.path, silentCaptureResult.bbox, 0.05);
|
|
313
|
+
logger.log("Image rognée avec tolérance créée pour l'envoi, URI final:", imagePathForUpload);
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
logger.log("Erreur lors du rognage avec tolérance, utilisation de l'image originale:", truncateFields(error));
|
|
317
|
+
// En cas d'erreur, on utilise l'image originale
|
|
318
|
+
imagePathForUpload = silentCaptureResult.path;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const base64 = await pathToBase64(imagePathForUpload);
|
|
245
322
|
logger.log("silentCaptureResult captured", JSON.stringify(truncateFields(silentCaptureResult), null, 2));
|
|
323
|
+
// Utiliser l'image originale pour l'affichage (dir) mais l'image rognée avec tolérance pour l'envoi (file)
|
|
246
324
|
const newImages = { ...capturedImages, [currentSide]: { dir: silentCaptureResult.path, file: base64, mrz: silentCaptureResult.mrz || "", templatePath: silentCaptureResult.templatePath } };
|
|
247
325
|
setCapturedImages(newImages);
|
|
248
326
|
if (silentCaptureResult.country && silentCaptureResult.documentType) {
|
|
249
327
|
onValueChange({
|
|
250
328
|
...newImages,
|
|
251
329
|
country: silentCaptureResult.country,
|
|
252
|
-
documentType: silentCaptureResult.documentType,
|
|
330
|
+
documentType: GovernmentDocumentTypeBackend[silentCaptureResult.documentType] || '',
|
|
253
331
|
});
|
|
254
332
|
}
|
|
255
333
|
setShowCamera(false);
|
|
256
334
|
actions.showCustomStepper(true);
|
|
257
335
|
}
|
|
258
336
|
else {
|
|
259
|
-
|
|
337
|
+
showAlert('Erreur', result.error || 'Impossible de prendre la photo');
|
|
260
338
|
}
|
|
261
339
|
};
|
|
262
340
|
const handleError = (event) => {
|
|
263
|
-
|
|
341
|
+
showAlert('Erreur', event.message);
|
|
264
342
|
setShowCamera(false);
|
|
265
343
|
};
|
|
266
344
|
useEffect(() => {
|
|
267
345
|
actions.showCustomStepper(!showCamera);
|
|
268
346
|
}, [showCamera]);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
347
|
+
// Cross-device polling logic
|
|
348
|
+
useEffect(() => {
|
|
349
|
+
if (!showQRModal || !state.session.session_id)
|
|
350
|
+
return;
|
|
351
|
+
const pollInterval = setInterval(async () => {
|
|
352
|
+
try {
|
|
353
|
+
const result = await kycService.getVerificationResult(state.session.session_id);
|
|
354
|
+
const sessionData = result[state.session.session_id]?.data;
|
|
355
|
+
if (sessionData) {
|
|
356
|
+
// Check if verification is completed or if we have ID card data
|
|
357
|
+
// Since the requirement is "verification restarts", we might look for overall completion
|
|
358
|
+
// or we could check if user_data is populated.
|
|
359
|
+
// For now, let's assume if status is not PENDING/INITIALIZED it might be done.
|
|
360
|
+
// Or simplier: if the mobile flow completes, the session status updates.
|
|
361
|
+
logger.log('Polling result:', truncateFields(sessionData));
|
|
362
|
+
if (sessionData.verification_status === 'completed' || sessionData.verification_status === 'approved' || sessionData.verification_status === 'review') {
|
|
363
|
+
clearInterval(pollInterval);
|
|
364
|
+
setShowQRModal(false);
|
|
365
|
+
actions.submitVerification(); // Or handleComplete
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
console.error('Polling error:', error);
|
|
371
|
+
}
|
|
372
|
+
}, 5000);
|
|
373
|
+
return () => clearInterval(pollInterval);
|
|
374
|
+
}, [showQRModal, state.session.session_id, actions]);
|
|
375
|
+
const getQrCodeUrl = () => {
|
|
376
|
+
// Only available on web platform
|
|
377
|
+
if (Platform.OS !== 'web')
|
|
378
|
+
return '';
|
|
379
|
+
if (typeof window === 'undefined' || !window.location || !window.location.href)
|
|
380
|
+
return '';
|
|
381
|
+
try {
|
|
382
|
+
const currentUrl = new URL(window.location.href);
|
|
383
|
+
if (!currentUrl.searchParams.has('kyc_id') && state.session.session_id) {
|
|
384
|
+
currentUrl.searchParams.set('kyc_id', state.session.session_id);
|
|
385
|
+
}
|
|
386
|
+
// Ajouter l'étape actuelle pour permettre à l'utilisateur de continuer au bon endroit
|
|
387
|
+
if (!currentUrl.searchParams.has('step')) {
|
|
388
|
+
currentUrl.searchParams.set('step', String(state.currentComponentIndex));
|
|
389
|
+
}
|
|
390
|
+
return `https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${encodeURIComponent(currentUrl.toString())}`;
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
console.warn('Error generating QR code URL:', error);
|
|
394
|
+
return '';
|
|
395
|
+
}
|
|
276
396
|
};
|
|
277
|
-
//
|
|
278
|
-
if (
|
|
397
|
+
// Vérifier si les données sont disponibles, sinon afficher un message d'erreur
|
|
398
|
+
if (!countrySelectionData || !selectedDocumentType) {
|
|
279
399
|
return (<View style={styles.root}>
|
|
280
400
|
<View style={styles.container}>
|
|
281
|
-
|
|
282
401
|
<Text style={styles.title}>{getLocalizedText(component.labels)}</Text>
|
|
283
|
-
<Text style={styles.description}>
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
return (<TouchableOpacity key={docType} style={[styles.documentTypeButton, { backgroundColor: selectedDocumentType?.type === docType ? '#2DBD6030' : '#F8F9FA', borderColor: selectedDocumentType?.type === docType ? '#2DBD60' : '#E9ECEF', borderWidth: 2 }]} onPress={() => handleDocumentTypeSelection(docType)}>
|
|
289
|
-
<View style={[styles.documentTypeIconContainer, { backgroundColor: 'gray', }]}>
|
|
290
|
-
<Text style={styles.documentTypeIcon}>{docInfo.icon}</Text>
|
|
291
|
-
</View>
|
|
292
|
-
<Text style={styles.documentTypeName}>
|
|
293
|
-
{docInfo.name[language] || docInfo.name.en}
|
|
294
|
-
</Text>
|
|
295
|
-
<Text style={styles.documentTypeArrow}>→</Text>
|
|
296
|
-
</TouchableOpacity>);
|
|
297
|
-
}) : null}
|
|
298
|
-
{showDocumentSelection.regionSelection ?
|
|
299
|
-
hasRegions(selectedDocumentType?.type || 'identity_card').regionMapping.map((region) => {
|
|
300
|
-
return (<TouchableOpacity key={region} onPress={() => handleRegionSelection(region)} style={[styles.documentTypeButton, { backgroundColor: selectedDocumentType?.region === region ? '#2DBD6030' : '#F8F9FA', borderColor: selectedDocumentType?.region === region ? '#2DBD60' : '#E9ECEF', borderWidth: 2 }]}>
|
|
301
|
-
<Text>{region}</Text>
|
|
302
|
-
</TouchableOpacity>);
|
|
303
|
-
}) : null}
|
|
304
|
-
</ScrollView>
|
|
305
|
-
<Button title={t('common.next')} onPress={() => {
|
|
306
|
-
if (!selectedDocumentType) {
|
|
307
|
-
Alert.alert(t('common.error'), t('validation.required'));
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
if (showDocumentSelection.regionSelection) {
|
|
311
|
-
logger.log("showDocumentSelection", JSON.stringify(truncateFields(showDocumentSelection), null, 2));
|
|
312
|
-
setShowDocumentSelection({
|
|
313
|
-
documentSelection: false,
|
|
314
|
-
regionSelection: false
|
|
315
|
-
});
|
|
316
|
-
setShowCamera(true);
|
|
317
|
-
actions.showCustomStepper(false);
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
321
|
-
if (hasRegions(selectedDocumentType?.type)?.hasRegions) {
|
|
322
|
-
setShowDocumentSelection({
|
|
323
|
-
documentSelection: false,
|
|
324
|
-
regionSelection: true
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
else {
|
|
328
|
-
setShowDocumentSelection({
|
|
329
|
-
documentSelection: false,
|
|
330
|
-
regionSelection: false
|
|
331
|
-
});
|
|
332
|
-
setShowCamera(true);
|
|
333
|
-
actions.showCustomStepper(false);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}} variant={selectedDocumentType ? 'primary' : "neutral"} size="large" fullWidth/>
|
|
337
|
-
|
|
338
|
-
|
|
402
|
+
<Text style={styles.description}>
|
|
403
|
+
{state.currentLanguage === "en"
|
|
404
|
+
? "Please complete the country and document selection first."
|
|
405
|
+
: "Veuillez d'abord compléter la sélection du pays et du document."}
|
|
406
|
+
</Text>
|
|
339
407
|
{error && (<Text style={styles.errorText}>{error}</Text>)}
|
|
340
408
|
</View>
|
|
341
409
|
</View>);
|
|
@@ -347,10 +415,6 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
347
415
|
if (currentSide === 'back') {
|
|
348
416
|
setCurrentSide('front');
|
|
349
417
|
setShowCamera(false);
|
|
350
|
-
setShowDocumentSelection({
|
|
351
|
-
documentSelection: false,
|
|
352
|
-
regionSelection: false
|
|
353
|
-
});
|
|
354
418
|
// Si une image front existe, on la restaure pour l'afficher
|
|
355
419
|
if (capturedImages['front']?.dir) {
|
|
356
420
|
// Restaurer l'état de capture du front pour afficher l'image
|
|
@@ -375,14 +439,11 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
375
439
|
}
|
|
376
440
|
}
|
|
377
441
|
else {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
regionSelection: false
|
|
381
|
-
});
|
|
382
|
-
actions.showCustomStepper(true);
|
|
442
|
+
// Retour au composant précédent (country_selection)
|
|
443
|
+
actions.previousComponent();
|
|
383
444
|
}
|
|
384
445
|
},
|
|
385
|
-
selectedDocumentType: locale === 'en' ? getDocumentTypeInfo(selectedDocumentType
|
|
446
|
+
selectedDocumentType: selectedDocumentType ? (locale === 'en' ? getDocumentTypeInfo(selectedDocumentType.type).name.en : getDocumentTypeInfo(selectedDocumentType.type).name.fr) : '',
|
|
386
447
|
step: state.currentComponentIndex + 1,
|
|
387
448
|
totalSteps: state.template.components.length,
|
|
388
449
|
side: currentSide,
|
|
@@ -422,7 +483,13 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
422
483
|
borderRadius: 12,
|
|
423
484
|
resizeMode: 'cover',
|
|
424
485
|
}}/>) : null}
|
|
425
|
-
{silentCaptureResult.path ? (<Image source={{ uri: silentCaptureResult.path }} style={{
|
|
486
|
+
{!cropImageUri && silentCaptureResult.path ? (<Image source={{ uri: silentCaptureResult.path }} style={{
|
|
487
|
+
width: '100%',
|
|
488
|
+
height: 200,
|
|
489
|
+
borderRadius: 12,
|
|
490
|
+
resizeMode: 'cover',
|
|
491
|
+
}}/>) : null}
|
|
492
|
+
{!cropImageUri && !silentCaptureResult.path && capturedImages[currentSide]?.dir ? (<Image source={{ uri: capturedImages[currentSide].dir }} style={{
|
|
426
493
|
width: '100%',
|
|
427
494
|
height: 200,
|
|
428
495
|
borderRadius: 12,
|
|
@@ -430,22 +497,33 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
430
497
|
}}/>) : null}
|
|
431
498
|
|
|
432
499
|
</View>
|
|
433
|
-
{/*
|
|
434
|
-
<Button title={
|
|
435
|
-
retakePicture(currentSide);
|
|
436
|
-
}} variant="outline" size="medium" fullWidth/>
|
|
437
|
-
<Button title={t('common.next')} onPress={() => {
|
|
438
|
-
if (currentSide === 'back' || selectedDocumentType?.type === 'passport') {
|
|
439
|
-
actions.nextComponent();
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
else {
|
|
500
|
+
{/* Capture button si aucune image n'a été capturée */}
|
|
501
|
+
{!capturedImages[currentSide]?.dir && (<Button title={state.currentLanguage === "en" ? "Take Photo" : "Prendre une photo"} onPress={() => {
|
|
443
502
|
setShowCamera(true);
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
503
|
+
actions.showCustomStepper(false);
|
|
504
|
+
}} variant="primary" size="large" fullWidth/>)}
|
|
505
|
+
{/* retake button si une image a été capturée */}
|
|
506
|
+
{capturedImages[currentSide]?.dir && (<>
|
|
507
|
+
<Button title={t('kyc.idCardCapture.retakeButton')} onPress={() => {
|
|
508
|
+
retakePicture(currentSide);
|
|
509
|
+
}} variant="outline" size="medium" fullWidth/>
|
|
510
|
+
<Button title={t('common.next')} onPress={() => {
|
|
511
|
+
if (!selectedDocumentType) {
|
|
512
|
+
showAlert('Error', 'Document type not selected');
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
if (currentSide === 'back' || selectedDocumentType.type === 'passport') {
|
|
516
|
+
actions.nextComponent();
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
setShowCamera(true);
|
|
521
|
+
setCurrentSide('back');
|
|
522
|
+
setSilentCaptureResult((prev) => ({ path: '', success: false, isAnalyzing: false, error: '', mrz: '', templatePath: '' }));
|
|
523
|
+
setCropImageUri('');
|
|
524
|
+
}
|
|
525
|
+
}} variant="primary" size="large" fullWidth/>
|
|
526
|
+
</>)}
|
|
449
527
|
</View>
|
|
450
528
|
</View>
|
|
451
529
|
</ScrollView>
|
|
@@ -453,6 +531,32 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
453
531
|
|
|
454
532
|
|
|
455
533
|
{error && (<Text style={styles.errorText}>{error}</Text>)}
|
|
534
|
+
|
|
535
|
+
{/* Cross-Device / Continue on Phone Button (Web Only) */}
|
|
536
|
+
{Platform.OS === 'web' && !isMobileWeb() && !capturedImages[currentSide]?.dir && (<Button title={t('kyc.idCardCapture.continueOnPhone')} onPress={() => { setShowQRModal(true); }}/>)}
|
|
537
|
+
|
|
538
|
+
{/* QR Code Modal - Web Only */}
|
|
539
|
+
{Platform.OS === 'web' && (<Modal visible={showQRModal} transparent={true} animationType="fade" onRequestClose={() => setShowQRModal(false)}>
|
|
540
|
+
<View style={styles.modalOverlay}>
|
|
541
|
+
<View style={styles.modalContent}>
|
|
542
|
+
<Text style={styles.modalTitle}>
|
|
543
|
+
{t('kyc.idCardCapture.continueOnMobile')}
|
|
544
|
+
</Text>
|
|
545
|
+
<Text style={styles.modalDescription}>
|
|
546
|
+
{t('kyc.idCardCapture.scanQrCode')}
|
|
547
|
+
</Text>
|
|
548
|
+
|
|
549
|
+
{showQRModal && getQrCodeUrl() ? (<Image source={{ uri: getQrCodeUrl() }} style={styles.qrCodeImage}/>) : null}
|
|
550
|
+
|
|
551
|
+
<TouchableOpacity style={styles.closeButton} onPress={() => setShowQRModal(false)}>
|
|
552
|
+
<Text style={styles.closeButtonText}>
|
|
553
|
+
{t('common.close')}
|
|
554
|
+
</Text>
|
|
555
|
+
</TouchableOpacity>
|
|
556
|
+
</View>
|
|
557
|
+
</View>
|
|
558
|
+
</Modal>)}
|
|
559
|
+
|
|
456
560
|
</View>
|
|
457
561
|
</View>);
|
|
458
562
|
};
|
|
@@ -606,42 +710,67 @@ const styles = StyleSheet.create({
|
|
|
606
710
|
marginTop: 8,
|
|
607
711
|
textAlign: 'center',
|
|
608
712
|
},
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
// paddingHorizontal: 16,
|
|
613
|
-
maxHeight: Dimensions.get('window').height - 400,
|
|
614
|
-
},
|
|
615
|
-
documentTypeButton: {
|
|
616
|
-
flexDirection: 'row',
|
|
713
|
+
crossDeviceButton: {
|
|
714
|
+
marginTop: 16,
|
|
715
|
+
padding: 12,
|
|
617
716
|
alignItems: 'center',
|
|
618
|
-
backgroundColor: '#F8F9FA',
|
|
619
|
-
padding: 16,
|
|
620
|
-
marginBottom: 12,
|
|
621
|
-
borderRadius: 12,
|
|
622
717
|
borderWidth: 1,
|
|
623
|
-
borderColor: '#
|
|
718
|
+
borderColor: '#2DBD60',
|
|
719
|
+
borderRadius: 8,
|
|
720
|
+
backgroundColor: '#f0f9f0',
|
|
624
721
|
},
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
722
|
+
crossDeviceText: {
|
|
723
|
+
color: '#2DBD60',
|
|
724
|
+
fontSize: 16,
|
|
725
|
+
fontWeight: '600',
|
|
726
|
+
},
|
|
727
|
+
modalOverlay: {
|
|
728
|
+
flex: 1,
|
|
729
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
629
730
|
justifyContent: 'center',
|
|
630
|
-
|
|
731
|
+
alignItems: 'center',
|
|
631
732
|
},
|
|
632
|
-
|
|
633
|
-
|
|
733
|
+
modalContent: {
|
|
734
|
+
backgroundColor: 'white',
|
|
735
|
+
borderRadius: 16,
|
|
736
|
+
padding: 24,
|
|
737
|
+
alignItems: 'center',
|
|
738
|
+
width: '90%',
|
|
739
|
+
maxWidth: 340,
|
|
740
|
+
shadowColor: '#000',
|
|
741
|
+
shadowOffset: { width: 0, height: 2 },
|
|
742
|
+
shadowOpacity: 0.25,
|
|
743
|
+
shadowRadius: 4,
|
|
744
|
+
elevation: 5,
|
|
634
745
|
},
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
746
|
+
modalTitle: {
|
|
747
|
+
fontSize: 20,
|
|
748
|
+
fontWeight: 'bold',
|
|
749
|
+
marginBottom: 12,
|
|
639
750
|
color: '#333',
|
|
640
751
|
},
|
|
641
|
-
|
|
642
|
-
fontSize:
|
|
752
|
+
modalDescription: {
|
|
753
|
+
fontSize: 16,
|
|
643
754
|
color: '#666',
|
|
644
|
-
|
|
755
|
+
textAlign: 'center',
|
|
756
|
+
marginBottom: 20,
|
|
757
|
+
lineHeight: 22,
|
|
758
|
+
},
|
|
759
|
+
qrCodeImage: {
|
|
760
|
+
width: 200,
|
|
761
|
+
height: 200,
|
|
762
|
+
marginBottom: 20,
|
|
763
|
+
},
|
|
764
|
+
closeButton: {
|
|
765
|
+
paddingVertical: 10,
|
|
766
|
+
paddingHorizontal: 20,
|
|
767
|
+
backgroundColor: '#f5f5f5',
|
|
768
|
+
borderRadius: 8,
|
|
769
|
+
},
|
|
770
|
+
closeButtonText: {
|
|
771
|
+
fontSize: 16,
|
|
772
|
+
color: '#666',
|
|
773
|
+
fontWeight: '600',
|
|
645
774
|
},
|
|
646
775
|
});
|
|
647
776
|
//# sourceMappingURL=IDCardCapture.js.map
|