@transfergratis/react-native-sdk 0.1.4 → 0.1.5
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/build/api/axios.d.ts +30 -0
- package/build/api/axios.d.ts.map +1 -0
- package/build/api/axios.js +92 -0
- package/build/api/axios.js.map +1 -0
- package/build/components/EnhancedCameraView.d.ts +1 -41
- package/build/components/EnhancedCameraView.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.js +75 -34
- package/build/components/EnhancedCameraView.js.map +1 -1
- package/build/components/EnhancedCameraView.web.d.ts +1 -41
- package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.web.js +28 -4
- package/build/components/EnhancedCameraView.web.js.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.d.ts +2 -2
- package/build/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.js +71 -114
- package/build/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/components/KYCElements/FileUploadTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/FileUploadTemplate.js +7 -3
- package/build/components/KYCElements/FileUploadTemplate.js.map +1 -1
- package/build/components/KYCElements/IDCardCapture.d.ts +7 -2
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +253 -104
- package/build/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/components/KYCElements/InitializationStep.d.ts +5 -0
- package/build/components/KYCElements/InitializationStep.d.ts.map +1 -0
- package/build/components/KYCElements/InitializationStep.js +41 -0
- package/build/components/KYCElements/InitializationStep.js.map +1 -0
- package/build/components/KYCElements/LocationCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/LocationCaptureTemplate.js +15 -13
- package/build/components/KYCElements/LocationCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -2
- package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
- package/build/components/KYCElements/ReviewSubmitTemplate.d.ts +12 -0
- package/build/components/KYCElements/ReviewSubmitTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/ReviewSubmitTemplate.js +171 -0
- package/build/components/KYCElements/ReviewSubmitTemplate.js.map +1 -0
- package/build/components/KYCElements/SelfieCaptureTemplate.d.ts +6 -2
- package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.js +105 -35
- package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/VerificationProgressTemplate.d.ts +12 -0
- package/build/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/VerificationProgressTemplate.js +93 -0
- package/build/components/KYCElements/VerificationProgressTemplate.js.map +1 -0
- package/build/components/OverLay/IdCard.d.ts +1 -1
- package/build/components/OverLay/IdCard.d.ts.map +1 -1
- package/build/components/OverLay/IdCard.js +10 -6
- package/build/components/OverLay/IdCard.js.map +1 -1
- package/build/components/OverLay/SelfieOverlay.d.ts +1 -1
- package/build/components/OverLay/SelfieOverlay.d.ts.map +1 -1
- package/build/components/OverLay/SelfieOverlay.js +5 -4
- package/build/components/OverLay/SelfieOverlay.js.map +1 -1
- package/build/components/OverLay/type.d.ts +71 -1
- package/build/components/OverLay/type.d.ts.map +1 -1
- package/build/components/OverLay/type.js.map +1 -1
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +72 -197
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +63 -39
- package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/components/example/OrientationVideoExample.d.ts.map +1 -1
- package/build/components/example/OrientationVideoExample.js +1 -5
- package/build/components/example/OrientationVideoExample.js.map +1 -1
- package/build/config/countriesData.d.ts +3 -0
- package/build/config/countriesData.d.ts.map +1 -0
- package/build/config/countriesData.js +79 -0
- package/build/config/countriesData.js.map +1 -0
- package/build/config/region_mapping.d.ts +3 -0
- package/build/config/region_mapping.d.ts.map +1 -0
- package/build/config/region_mapping.js +687 -0
- package/build/config/region_mapping.js.map +1 -0
- package/build/hooks/useI18n.d.ts +11 -0
- package/build/hooks/useI18n.d.ts.map +1 -0
- package/build/hooks/useI18n.js +37 -0
- package/build/hooks/useI18n.js.map +1 -0
- package/build/hooks/useOrientationVideo.d.ts +1 -2
- package/build/hooks/useOrientationVideo.d.ts.map +1 -1
- package/build/hooks/useOrientationVideo.js +2 -1
- package/build/hooks/useOrientationVideo.js.map +1 -1
- package/build/hooks/useRealtimeVerifier.d.ts +28 -0
- package/build/hooks/useRealtimeVerifier.d.ts.map +1 -0
- package/build/hooks/useRealtimeVerifier.js +91 -0
- package/build/hooks/useRealtimeVerifier.js.map +1 -0
- package/build/hooks/useTemplateKYCFlow.d.ts +1 -0
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +337 -38
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/i18n/en/index.d.ts +168 -0
- package/build/i18n/en/index.d.ts.map +1 -0
- package/build/i18n/en/index.js +195 -0
- package/build/i18n/en/index.js.map +1 -0
- package/build/i18n/fr/index.d.ts +168 -0
- package/build/i18n/fr/index.d.ts.map +1 -0
- package/build/i18n/fr/index.js +194 -0
- package/build/i18n/fr/index.js.map +1 -0
- package/build/i18n/index.d.ts +10 -0
- package/build/i18n/index.d.ts.map +1 -0
- package/build/i18n/index.js +56 -0
- package/build/i18n/index.js.map +1 -0
- package/build/i18n/types.d.ts +153 -0
- package/build/i18n/types.d.ts.map +1 -0
- package/build/i18n/types.js +3 -0
- package/build/i18n/types.js.map +1 -0
- package/build/i18n/usage-example.d.ts +4 -0
- package/build/i18n/usage-example.d.ts.map +1 -0
- package/build/i18n/usage-example.js +189 -0
- package/build/i18n/usage-example.js.map +1 -0
- package/build/modules/api/CardAuthentification.d.ts +22 -0
- package/build/modules/api/CardAuthentification.d.ts.map +1 -0
- package/build/modules/api/CardAuthentification.js +107 -0
- package/build/modules/api/CardAuthentification.js.map +1 -0
- package/build/modules/api/KYCService.d.ts +57 -1
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +348 -27
- package/build/modules/api/KYCService.js.map +1 -1
- package/build/modules/api/SelfieVerification.d.ts +3 -0
- package/build/modules/api/SelfieVerification.d.ts.map +1 -0
- package/build/modules/api/SelfieVerification.js +9 -0
- package/build/modules/api/SelfieVerification.js.map +1 -0
- package/build/modules/api/backendApi.d.ts +2 -0
- package/build/modules/api/backendApi.d.ts.map +1 -0
- package/build/modules/api/backendApi.js +6 -0
- package/build/modules/api/backendApi.js.map +1 -0
- package/build/modules/api/types.d.ts +20 -0
- package/build/modules/api/types.d.ts.map +1 -0
- package/build/modules/api/types.js +2 -0
- package/build/modules/api/types.js.map +1 -0
- package/build/types/KYC.types.d.ts +59 -7
- package/build/types/KYC.types.d.ts.map +1 -1
- package/build/types/KYC.types.js +9 -1
- package/build/types/KYC.types.js.map +1 -1
- package/build/utils/cropByObb.d.ts +11 -0
- package/build/utils/cropByObb.d.ts.map +1 -0
- package/build/utils/cropByObb.js +78 -0
- package/build/utils/cropByObb.js.map +1 -0
- package/build/utils/get-document-type-info.d.ts +13 -0
- package/build/utils/get-document-type-info.d.ts.map +1 -0
- package/build/utils/get-document-type-info.js +59 -0
- package/build/utils/get-document-type-info.js.map +1 -0
- package/build/utils/pathToBase64.d.ts +3 -0
- package/build/utils/pathToBase64.d.ts.map +1 -0
- package/build/utils/pathToBase64.js +47 -0
- package/build/utils/pathToBase64.js.map +1 -0
- package/build/utils/remove-duplicate.d.ts +2 -0
- package/build/utils/remove-duplicate.d.ts.map +1 -0
- package/build/utils/remove-duplicate.js +4 -0
- package/build/utils/remove-duplicate.js.map +1 -0
- package/package.json +3 -1
- package/src/api/axios.ts +144 -0
- package/src/components/EnhancedCameraView.tsx +96 -78
- package/src/components/EnhancedCameraView.web.tsx +41 -40
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +104 -136
- package/src/components/KYCElements/FileUploadTemplate.tsx +14 -8
- package/src/components/KYCElements/IDCardCapture.tsx +311 -115
- package/src/components/KYCElements/InitializationStep.tsx +53 -0
- package/src/components/KYCElements/LocationCaptureTemplate.tsx +17 -15
- package/src/components/KYCElements/OrientationVideoCapture.tsx +2 -2
- package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +2 -2
- package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +2 -2
- package/src/components/KYCElements/ReviewSubmitTemplate.tsx +201 -0
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +140 -53
- package/src/components/KYCElements/VerificationProgressTemplate.tsx +123 -0
- package/src/components/OverLay/IdCard.tsx +17 -9
- package/src/components/OverLay/SelfieOverlay.tsx +6 -5
- package/src/components/OverLay/type.ts +64 -2
- package/src/components/TemplateKYCExample.tsx +76 -197
- package/src/components/TemplateKYCFlowRefactored.tsx +74 -46
- package/src/components/example/OrientationVideoExample.tsx +3 -7
- package/src/config/countriesData.ts +84 -0
- package/src/config/region_mapping.ts +688 -0
- package/src/hooks/useI18n.ts +53 -0
- package/src/hooks/useOrientationVideo.ts +2 -2
- package/src/hooks/useRealtimeVerifier.ts +128 -0
- package/src/hooks/useTemplateKYCFlow.tsx +375 -53
- package/src/i18n/README.md +288 -0
- package/src/i18n/en/index.ts +206 -0
- package/src/i18n/fr/index.ts +205 -0
- package/src/i18n/index.ts +65 -0
- package/src/i18n/types.ts +172 -0
- package/src/i18n/usage-example.tsx +202 -0
- package/src/modules/api/CardAuthentification.ts +114 -0
- package/src/modules/api/KYCService.ts +403 -30
- package/src/modules/api/SelfieVerification.ts +11 -0
- package/src/modules/api/backendApi.ts +8 -0
- package/src/modules/api/types.ts +24 -0
- package/src/types/KYC.types.ts +83 -14
- package/src/utils/cropByObb.ts +99 -0
- package/src/utils/get-document-type-info.ts +62 -0
- package/src/utils/pathToBase64.ts +47 -0
- package/src/utils/remove-duplicate.ts +3 -0
- package/src/types/nativewind.d.ts +0 -2
|
@@ -1,15 +1,29 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import { View, Text, TouchableOpacity, StyleSheet, Image, Alert, ScrollView } from 'react-native';
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { View, Text, TouchableOpacity, StyleSheet, Image, Alert, ScrollView, Dimensions } from 'react-native';
|
|
3
3
|
import { EnhancedCameraView } from '../EnhancedCameraView';
|
|
4
|
-
import { TemplateComponent, IDCardConfig, LocalizedText, GovernmentDocumentType } from '../../types/KYC.types';
|
|
4
|
+
import { TemplateComponent, IDCardConfig, LocalizedText, GovernmentDocumentType, ISilentCaptureResult } from '../../types/KYC.types';
|
|
5
5
|
import IdCardOverlay from '../OverLay/IdCard';
|
|
6
6
|
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
7
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
7
8
|
import { Button } from '../ui/Button';
|
|
9
|
+
import { removeDuplicates } from '../../utils/remove-duplicate';
|
|
10
|
+
import { backVerification, frontVerification } from '../../modules/api/CardAuthentification';
|
|
11
|
+
import { getDocumentTypeInfo } from '../../utils/get-document-type-info';
|
|
12
|
+
import pathToBase64 from '../../utils/pathToBase64';
|
|
13
|
+
import { truncateFields } from '../../modules/api/KYCService';
|
|
14
|
+
import { cropImageWithBBox } from '../../utils/cropByObb';
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
interface IIDCardPayload {
|
|
18
|
+
dir: string;
|
|
19
|
+
file: string;
|
|
20
|
+
mrz: string;
|
|
21
|
+
}
|
|
8
22
|
|
|
9
23
|
interface IDCardCaptureProps {
|
|
10
24
|
component: TemplateComponent;
|
|
11
|
-
value?: Record<string,
|
|
12
|
-
onValueChange: (value: Record<string, string>) => void;
|
|
25
|
+
value?: Record<string, IIDCardPayload>;
|
|
26
|
+
onValueChange: (value: Record<string, IIDCardPayload | string>) => void;
|
|
13
27
|
error?: string;
|
|
14
28
|
language?: string;
|
|
15
29
|
currentSide?: string; // Nouveau prop pour spécifier le côté actuel
|
|
@@ -21,86 +35,78 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
21
35
|
onValueChange,
|
|
22
36
|
error,
|
|
23
37
|
language = 'en',
|
|
24
|
-
currentSide = 'front',
|
|
25
38
|
}) => {
|
|
39
|
+
const { t } = useI18n();
|
|
26
40
|
const [showCamera, setShowCamera] = useState(false);
|
|
27
|
-
const [capturedImages, setCapturedImages] = useState<Record<string,
|
|
28
|
-
const [
|
|
29
|
-
const [
|
|
41
|
+
const [capturedImages, setCapturedImages] = useState<Record<string, IIDCardPayload>>(value || {});
|
|
42
|
+
const [cropImageUri, setCropImageUri] = useState<string>('');
|
|
43
|
+
const [currentSide, setCurrentSide] = useState<string>('front');
|
|
44
|
+
const [selectedDocumentType, setSelectedDocumentType] = useState<{
|
|
45
|
+
type: GovernmentDocumentType;
|
|
46
|
+
region: string;
|
|
47
|
+
}>({
|
|
48
|
+
type: 'identity_card',
|
|
49
|
+
region: 'root'
|
|
50
|
+
});
|
|
51
|
+
const [showDocumentSelection, setShowDocumentSelection] = useState(
|
|
52
|
+
{
|
|
53
|
+
documentSelection: true,
|
|
54
|
+
regionSelection: false
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
const [silentCaptureResult, setSilentCaptureResult] = useState<ISilentCaptureResult>({ success: false, isAnalyzing: false });
|
|
58
|
+
// const [imageNaturalSize, setImageNaturalSize] = useState<{ width: number; height: number } | null>(null);
|
|
30
59
|
|
|
31
60
|
const { actions, state, } = useTemplateKYCFlowContext();
|
|
32
61
|
const config = component.config as IDCardConfig;
|
|
33
62
|
|
|
34
|
-
|
|
35
|
-
return text[language] || text.en || '';
|
|
36
|
-
};
|
|
63
|
+
|
|
37
64
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
name: { en: 'ID Card', fr: 'Carte d\'identité' },
|
|
43
|
-
icon: '🆔',
|
|
44
|
-
instructions: { en: 'Position your ID card within the frame', fr: 'Positionnez votre carte d\'identité dans le cadre' }
|
|
45
|
-
};
|
|
46
|
-
case 'passport':
|
|
47
|
-
return {
|
|
48
|
-
name: { en: 'Passport', fr: 'Passeport' },
|
|
49
|
-
icon: '📘',
|
|
50
|
-
instructions: { en: 'Position your passport within the frame', fr: 'Positionnez votre passeport dans le cadre' }
|
|
51
|
-
};
|
|
52
|
-
case 'drivers_license':
|
|
53
|
-
return {
|
|
54
|
-
name: { en: 'Driver\'s License', fr: 'Permis de conduire' },
|
|
55
|
-
icon: '🚗',
|
|
56
|
-
instructions: { en: 'Position your driver\'s license within the frame', fr: 'Positionnez votre permis de conduire dans le cadre' }
|
|
57
|
-
};
|
|
58
|
-
case 'residence_permit':
|
|
59
|
-
return {
|
|
60
|
-
name: { en: 'Residence Permit', fr: 'Permis de séjour' },
|
|
61
|
-
icon: '🏠',
|
|
62
|
-
instructions: { en: 'Position your residence permit within the frame', fr: 'Positionnez votre permis de séjour dans le cadre' }
|
|
63
|
-
};
|
|
64
|
-
case 'national_id':
|
|
65
|
-
return {
|
|
66
|
-
name: { en: 'National ID', fr: 'Carte nationale d\'identité' },
|
|
67
|
-
icon: '🏛️',
|
|
68
|
-
instructions: { en: 'Position your national ID within the frame', fr: 'Positionnez votre carte nationale d\'identité dans le cadre' }
|
|
69
|
-
};
|
|
70
|
-
case 'voter_id':
|
|
71
|
-
return {
|
|
72
|
-
name: { en: 'Voter ID', fr: 'Carte d\'électeur' },
|
|
73
|
-
icon: '🗳️',
|
|
74
|
-
instructions: { en: 'Position your voter ID within the frame', fr: 'Positionnez votre carte d\'électeur dans le cadre' }
|
|
75
|
-
};
|
|
76
|
-
case 'military_id':
|
|
77
|
-
return {
|
|
78
|
-
name: { en: 'Military ID', fr: 'Carte militaire' },
|
|
79
|
-
icon: '🎖️',
|
|
80
|
-
instructions: { en: 'Position your military ID within the frame', fr: 'Positionnez votre carte militaire dans le cadre' }
|
|
81
|
-
};
|
|
82
|
-
case 'student_id':
|
|
83
|
-
return {
|
|
84
|
-
name: { en: 'Student ID', fr: 'Carte d\'étudiant' },
|
|
85
|
-
icon: '🎓',
|
|
86
|
-
instructions: { en: 'Position your student ID within the frame', fr: 'Positionnez votre carte d\'étudiant dans le cadre' }
|
|
87
|
-
};
|
|
88
|
-
case 'work_permit':
|
|
89
|
-
return {
|
|
90
|
-
name: { en: 'Work Permit', fr: 'Permis de travail' },
|
|
91
|
-
icon: '💼',
|
|
92
|
-
instructions: { en: 'Position your work permit within the frame', fr: 'Positionnez votre permis de travail dans le cadre' }
|
|
93
|
-
};
|
|
94
|
-
case 'other':
|
|
95
|
-
default:
|
|
96
|
-
return {
|
|
97
|
-
name: { en: 'Government Document', fr: 'Document gouvernemental' },
|
|
98
|
-
icon: '📄',
|
|
99
|
-
instructions: { en: 'Position your document within the frame', fr: 'Positionnez votre document dans le cadre' }
|
|
100
|
-
};
|
|
65
|
+
const getLocalizedText = (text: LocalizedText | Record<string, LocalizedText>): string => {
|
|
66
|
+
// console.log("text", text, JSON.stringify(component, null, 2));
|
|
67
|
+
if (text && typeof text[currentSide] === 'object' && text[currentSide][language]) {
|
|
68
|
+
return text[currentSide][language] || '';
|
|
101
69
|
}
|
|
70
|
+
return "";
|
|
102
71
|
};
|
|
103
72
|
|
|
73
|
+
const countryData = useMemo(() => {
|
|
74
|
+
const geCountryID = Object.keys(state.componentData).find((c: string) => c === "6");
|
|
75
|
+
|
|
76
|
+
if (geCountryID) {
|
|
77
|
+
const countryMapping = state.componentData[geCountryID];
|
|
78
|
+
return countryMapping;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}, [state.componentData]);
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
const availableDocumentTypes = useMemo(() => {
|
|
85
|
+
const newconfig: GovernmentDocumentType[] = [];
|
|
86
|
+
|
|
87
|
+
if (countryData) {
|
|
88
|
+
const countryMapping = Object.keys(countryData?.regionMapping);
|
|
89
|
+
if (countryMapping && Array.isArray(countryMapping)) {
|
|
90
|
+
countryMapping.forEach((c) => {
|
|
91
|
+
newconfig.push(c as GovernmentDocumentType);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
console.log("newconfig", truncateFields(newconfig));
|
|
96
|
+
return newconfig;
|
|
97
|
+
}, []);
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
console.log("cropImageUri", JSON.stringify(truncateFields({ box: silentCaptureResult }), null, 2));
|
|
102
|
+
if (capturedImages[currentSide]?.dir && silentCaptureResult?.bbox) {
|
|
103
|
+
cropImageWithBBox(capturedImages[currentSide].dir, silentCaptureResult.bbox)?.then((uri) => {
|
|
104
|
+
setCropImageUri(uri);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}, [capturedImages[currentSide]?.dir, silentCaptureResult?.bbox])
|
|
108
|
+
|
|
109
|
+
|
|
104
110
|
|
|
105
111
|
const cameraConfig = {
|
|
106
112
|
aspectRatio: 4 / 3,
|
|
@@ -111,8 +117,8 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
111
117
|
maxRetakes: 3,
|
|
112
118
|
overlay: {
|
|
113
119
|
showGuide: true,
|
|
114
|
-
guideText: selectedDocumentType ? getDocumentTypeInfo(selectedDocumentType).instructions.en : getLocalizedText(component.instructions),
|
|
115
|
-
bbox: selectedDocumentType && config.bbox_configs[selectedDocumentType] ? config.bbox_configs[selectedDocumentType] : {
|
|
120
|
+
guideText: selectedDocumentType ? getDocumentTypeInfo(selectedDocumentType.type).instructions.en : getLocalizedText(component.instructions as Record<string, LocalizedText>),
|
|
121
|
+
bbox: selectedDocumentType && config.bbox_configs[selectedDocumentType.type] ? config.bbox_configs[selectedDocumentType.type] : {
|
|
116
122
|
xMin: 20,
|
|
117
123
|
yMin: 140,
|
|
118
124
|
xMax: 370,
|
|
@@ -128,15 +134,118 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
128
134
|
const retakePicture = (currentSide: string) => {
|
|
129
135
|
setShowCamera(true);
|
|
130
136
|
actions.showCustomStepper(false);
|
|
131
|
-
setCapturedImages({ ...capturedImages, [currentSide]: '' });
|
|
132
|
-
|
|
137
|
+
setCapturedImages({ ...capturedImages, [currentSide]: { dir: '', file: '', mrz: '' } });
|
|
138
|
+
setSilentCaptureResult((prev) => ({ path: '', success: false, isAnalyzing: false, error: '' }));
|
|
139
|
+
setCropImageUri('');
|
|
140
|
+
onValueChange({ ...value, [currentSide]: { dir: '', file: '', mrz: '' } });
|
|
133
141
|
};
|
|
134
142
|
|
|
135
|
-
const
|
|
143
|
+
const hasRegions = useCallback((documentType: GovernmentDocumentType): { hasRegions: boolean, regionMapping: string[] } => {
|
|
144
|
+
const regionMapping = countryData?.regionMapping[documentType as GovernmentDocumentType];
|
|
145
|
+
if (regionMapping && Object.keys(regionMapping).length > 1) {
|
|
146
|
+
return {
|
|
147
|
+
hasRegions: true,
|
|
148
|
+
regionMapping: Object.keys(regionMapping)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
hasRegions: false,
|
|
153
|
+
regionMapping: []
|
|
154
|
+
};
|
|
155
|
+
}, [countryData]);
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
const getCurrentSideVerification = (currentSide: string) => {
|
|
159
|
+
const regionMapping = countryData?.regionMapping[selectedDocumentType?.type as GovernmentDocumentType];
|
|
160
|
+
const authMethod: string[] = [];
|
|
161
|
+
|
|
162
|
+
const key = selectedDocumentType?.region?.trim()?.length > 0 ? selectedDocumentType?.region?.trim() : 'root';
|
|
163
|
+
// console.log("regionMapping", JSON.stringify(regionMapping, null, 2), selectedDocumentType?.region);
|
|
164
|
+
// const key = selectedDocumentType?.region as keyof typeof regionMapping;
|
|
165
|
+
|
|
166
|
+
if (regionMapping?.[key] && Array.isArray(regionMapping[key])) {
|
|
167
|
+
regionMapping[key].forEach((item: any) => {
|
|
168
|
+
if (item[currentSide as keyof typeof item]) {
|
|
169
|
+
authMethod.push(item[currentSide as keyof typeof item]);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
console.log("regionMapping", JSON.stringify(truncateFields({ regionMapping, selectedDocumentType: selectedDocumentType?.region, key }), null, 2));
|
|
175
|
+
|
|
176
|
+
return removeDuplicates(authMethod);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
const handleSilentCapture = (result: { success: boolean; path?: string; error?: string }) => {
|
|
181
|
+
if (silentCaptureResult.isAnalyzing) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
136
184
|
if (result.success && result.path) {
|
|
137
|
-
|
|
185
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: true, success: false, error: '' }));
|
|
186
|
+
if (currentSide === 'front') {
|
|
187
|
+
frontVerification(
|
|
188
|
+
{
|
|
189
|
+
path: result.path,
|
|
190
|
+
regionMapping: getCurrentSideVerification(currentSide),
|
|
191
|
+
selectedDocumentType: selectedDocumentType?.type || '',
|
|
192
|
+
code: countryData?.code || '',
|
|
193
|
+
currentSide: currentSide,
|
|
194
|
+
|
|
195
|
+
}).then((mrz) => {
|
|
196
|
+
console.log("front verification result", truncateFields(mrz));
|
|
197
|
+
setSilentCaptureResult((prev) => ({
|
|
198
|
+
...prev, path: result.path,
|
|
199
|
+
bbox: (mrz as any)?.bbox, success: true,
|
|
200
|
+
mrz: JSON.stringify(mrz), isAnalyzing: false,
|
|
201
|
+
country: countryData?.code,
|
|
202
|
+
documentType: selectedDocumentType?.type
|
|
203
|
+
}),
|
|
204
|
+
);
|
|
205
|
+
}).catch((e: any) => {
|
|
206
|
+
console.log("error front verification", truncateFields(e));
|
|
207
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: false, error: e?.message || 'Erreur de détection du MRZ' }));
|
|
208
|
+
// Alert.alert('Erreur', e?.message || 'Erreur de détection du MRZ');
|
|
209
|
+
})
|
|
210
|
+
} else {
|
|
211
|
+
backVerification({
|
|
212
|
+
path: result.path,
|
|
213
|
+
regionMapping: getCurrentSideVerification(currentSide),
|
|
214
|
+
selectedDocumentType: selectedDocumentType?.type || '',
|
|
215
|
+
code: countryData?.code || '',
|
|
216
|
+
currentSide: currentSide,
|
|
217
|
+
|
|
218
|
+
}).then((mrz) => {
|
|
219
|
+
console.log("back verification result", truncateFields(mrz));
|
|
220
|
+
setSilentCaptureResult((prev) => ({
|
|
221
|
+
...prev, path: result.path, bbox: (mrz as any)?.bbox,
|
|
222
|
+
success: true, mrz: JSON.stringify(mrz), isAnalyzing: false,
|
|
223
|
+
country: countryData?.code,
|
|
224
|
+
documentType: selectedDocumentType?.type
|
|
225
|
+
}));
|
|
226
|
+
}).catch((e: any) => {
|
|
227
|
+
console.log("error back verification", truncateFields(e));
|
|
228
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, success: false, error: e?.message || 'Erreur de détection du MRZ' }));
|
|
229
|
+
// Alert.alert('Erreur', e?.message || 'Erreur de détection du MRZ');
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Handle capture
|
|
237
|
+
const handleCapture = async (result: { success: boolean; path?: string; error?: string }) => {
|
|
238
|
+
if (silentCaptureResult.path) {
|
|
239
|
+
const base64 = await pathToBase64(silentCaptureResult.path);
|
|
240
|
+
const newImages = { ...capturedImages, [currentSide]: { dir: silentCaptureResult.path, file: base64, mrz: silentCaptureResult.mrz || "" } };
|
|
138
241
|
setCapturedImages(newImages);
|
|
139
|
-
|
|
242
|
+
if (silentCaptureResult.country && silentCaptureResult.documentType) {
|
|
243
|
+
onValueChange({
|
|
244
|
+
...newImages,
|
|
245
|
+
country: silentCaptureResult.country,
|
|
246
|
+
documentType: silentCaptureResult.documentType,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
140
249
|
setShowCamera(false);
|
|
141
250
|
actions.showCustomStepper(true);
|
|
142
251
|
} else {
|
|
@@ -150,19 +259,46 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
150
259
|
};
|
|
151
260
|
|
|
152
261
|
|
|
153
|
-
useEffect(() => {
|
|
154
262
|
|
|
155
|
-
actions.showCustomStepper(!showCamera);
|
|
156
263
|
|
|
264
|
+
|
|
265
|
+
useEffect(() => {
|
|
266
|
+
actions.showCustomStepper(!showCamera);
|
|
157
267
|
}, [showCamera]);
|
|
158
268
|
|
|
159
269
|
|
|
270
|
+
|
|
271
|
+
// const renderBboxOverlay = () => {
|
|
272
|
+
// const bbox: any = (silentCaptureResult as any)?.bbox;
|
|
273
|
+
// if (!bbox || !imageNaturalSize) return null;
|
|
274
|
+
// const containerWidth = Dimensions.get('window').width - 24 - 24; // approximate inner width accounting paddings/margins
|
|
275
|
+
// const containerHeight = 200;
|
|
276
|
+
// const scaleX = 1;
|
|
277
|
+
// const scaleY = 1;
|
|
278
|
+
// const left = Math.max(0, bbox.minX * scaleX);
|
|
279
|
+
// const top = Math.max(0, bbox.minY * scaleY);
|
|
280
|
+
// const width = Math.max(1, bbox.width * scaleX);
|
|
281
|
+
// const height = Math.max(1, bbox.height * scaleY);
|
|
282
|
+
// return (
|
|
283
|
+
// <View
|
|
284
|
+
// pointerEvents="none"
|
|
285
|
+
// style={{ position: 'absolute', left, top, width, height, borderColor: '#2DBD60', borderWidth: 2, borderStyle: 'solid', borderRadius: 6 }}
|
|
286
|
+
// />
|
|
287
|
+
// );
|
|
288
|
+
// };
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
160
293
|
const handleDocumentTypeSelection = (docType: GovernmentDocumentType) => {
|
|
161
|
-
setSelectedDocumentType(docType);
|
|
294
|
+
setSelectedDocumentType({ type: docType, region: hasRegions(docType) ? '' : 'root' });
|
|
295
|
+
};
|
|
296
|
+
const handleRegionSelection = (region: string) => {
|
|
297
|
+
setSelectedDocumentType((prev) => ({ ...prev, region: region }));
|
|
162
298
|
};
|
|
163
299
|
|
|
164
300
|
// Interface de sélection du type de document
|
|
165
|
-
if (showDocumentSelection) {
|
|
301
|
+
if (showDocumentSelection.documentSelection || showDocumentSelection.regionSelection) {
|
|
166
302
|
return (
|
|
167
303
|
<View style={styles.root}>
|
|
168
304
|
<View style={styles.container}>
|
|
@@ -171,12 +307,12 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
171
307
|
<Text style={styles.description}>{getLocalizedText(component.instructions)}</Text>
|
|
172
308
|
|
|
173
309
|
<ScrollView style={styles.documentTypesContainer} showsVerticalScrollIndicator={false}>
|
|
174
|
-
{
|
|
310
|
+
{showDocumentSelection.documentSelection ? availableDocumentTypes.map((docType) => {
|
|
175
311
|
const docInfo = getDocumentTypeInfo(docType);
|
|
176
312
|
return (
|
|
177
313
|
<TouchableOpacity
|
|
178
314
|
key={docType}
|
|
179
|
-
style={[styles.documentTypeButton, { backgroundColor: selectedDocumentType === docType ? '#2DBD6030' : '#F8F9FA', borderColor: selectedDocumentType === docType ? '#2DBD60' : '#E9ECEF', borderWidth: 2 }]}
|
|
315
|
+
style={[styles.documentTypeButton, { backgroundColor: selectedDocumentType?.type === docType ? '#2DBD6030' : '#F8F9FA', borderColor: selectedDocumentType?.type === docType ? '#2DBD60' : '#E9ECEF', borderWidth: 2 }]}
|
|
180
316
|
onPress={() => handleDocumentTypeSelection(docType)}
|
|
181
317
|
>
|
|
182
318
|
<View style={[styles.documentTypeIconContainer, { backgroundColor: 'gray', }]}>
|
|
@@ -188,21 +324,54 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
188
324
|
<Text style={styles.documentTypeArrow}>→</Text>
|
|
189
325
|
</TouchableOpacity>
|
|
190
326
|
);
|
|
191
|
-
})}
|
|
327
|
+
}) : null}
|
|
328
|
+
{showDocumentSelection.regionSelection ?
|
|
329
|
+
hasRegions(selectedDocumentType?.type || 'identity_card').regionMapping.map((region) => {
|
|
330
|
+
return (
|
|
331
|
+
<TouchableOpacity key={region} onPress={() => handleRegionSelection(region)}
|
|
332
|
+
style={[styles.documentTypeButton, { backgroundColor: selectedDocumentType?.region === region ? '#2DBD6030' : '#F8F9FA', borderColor: selectedDocumentType?.region === region ? '#2DBD60' : '#E9ECEF', borderWidth: 2 }]}
|
|
333
|
+
|
|
334
|
+
>
|
|
335
|
+
<Text>{region}</Text>
|
|
336
|
+
</TouchableOpacity>
|
|
337
|
+
);
|
|
338
|
+
}) : null}
|
|
192
339
|
</ScrollView>
|
|
193
|
-
<Button title={
|
|
340
|
+
<Button title={t('common.next')} onPress={() => {
|
|
194
341
|
if (!selectedDocumentType) {
|
|
195
|
-
Alert.alert('
|
|
342
|
+
Alert.alert(t('common.error'), t('validation.required'));
|
|
196
343
|
return;
|
|
197
344
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
345
|
+
|
|
346
|
+
if (showDocumentSelection.regionSelection) {
|
|
347
|
+
console.log("showDocumentSelection", JSON.stringify(truncateFields(showDocumentSelection), null, 2));
|
|
348
|
+
setShowDocumentSelection({
|
|
349
|
+
documentSelection: false,
|
|
350
|
+
regionSelection: false
|
|
351
|
+
});
|
|
352
|
+
setShowCamera(true);
|
|
353
|
+
actions.showCustomStepper(false);
|
|
354
|
+
return;
|
|
355
|
+
} else {
|
|
356
|
+
if (hasRegions(selectedDocumentType?.type)?.hasRegions) {
|
|
357
|
+
setShowDocumentSelection({
|
|
358
|
+
documentSelection: false,
|
|
359
|
+
regionSelection: true
|
|
360
|
+
});
|
|
361
|
+
} else {
|
|
362
|
+
setShowDocumentSelection({
|
|
363
|
+
documentSelection: false,
|
|
364
|
+
regionSelection: false
|
|
365
|
+
});
|
|
366
|
+
setShowCamera(true);
|
|
367
|
+
actions.showCustomStepper(false);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
201
371
|
}}
|
|
202
372
|
variant={selectedDocumentType ? 'primary' : "neutral"}
|
|
203
373
|
size="large"
|
|
204
374
|
fullWidth
|
|
205
|
-
// rounded
|
|
206
375
|
/>
|
|
207
376
|
|
|
208
377
|
|
|
@@ -230,6 +399,8 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
230
399
|
quality="high"
|
|
231
400
|
showCaptureButton={true}
|
|
232
401
|
showSwitchCamera={true}
|
|
402
|
+
onSilentCapture={handleSilentCapture}
|
|
403
|
+
silentCaptureResult={silentCaptureResult}
|
|
233
404
|
enableFlash={cameraConfig.flashMode === 'auto' || cameraConfig.flashMode === 'on'}
|
|
234
405
|
overlayComponent={<IdCardOverlay
|
|
235
406
|
xMin={cameraConfig.overlay.bbox.xMin}
|
|
@@ -238,12 +409,27 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
238
409
|
yMax={cameraConfig.overlay.bbox.yMax}
|
|
239
410
|
instructions={cameraConfig.overlay.guideText}
|
|
240
411
|
cornerOpacity={cameraConfig.overlay.bbox.cornerRadius || 0 as number}
|
|
412
|
+
isSuccess={silentCaptureResult.success}
|
|
413
|
+
language={state.currentLanguage}
|
|
241
414
|
stepperProps={{
|
|
242
415
|
back: () => {
|
|
243
|
-
|
|
244
|
-
|
|
416
|
+
if (currentSide === 'back') {
|
|
417
|
+
setCurrentSide('front');
|
|
418
|
+
setShowCamera(false);
|
|
419
|
+
setShowDocumentSelection({
|
|
420
|
+
documentSelection: false,
|
|
421
|
+
regionSelection: false
|
|
422
|
+
});
|
|
423
|
+
setSilentCaptureResult((prev) => ({ path: '', success: false, isAnalyzing: false, error: '' }));
|
|
424
|
+
} else {
|
|
425
|
+
setShowDocumentSelection({
|
|
426
|
+
documentSelection: true,
|
|
427
|
+
regionSelection: false
|
|
428
|
+
});
|
|
429
|
+
actions.showCustomStepper(true);
|
|
430
|
+
}
|
|
245
431
|
},
|
|
246
|
-
selectedDocumentType: getDocumentTypeInfo(selectedDocumentType ||
|
|
432
|
+
selectedDocumentType: getDocumentTypeInfo(selectedDocumentType?.type || "identity_card").name.en || '',
|
|
247
433
|
step: state.currentComponentIndex + 1,
|
|
248
434
|
totalSteps: state.template.components.length,
|
|
249
435
|
}}
|
|
@@ -254,6 +440,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
254
440
|
);
|
|
255
441
|
}
|
|
256
442
|
|
|
443
|
+
|
|
257
444
|
return (
|
|
258
445
|
<View style={styles.root}>
|
|
259
446
|
<View style={styles.previewContainer}>
|
|
@@ -266,7 +453,6 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
266
453
|
{getLocalizedText(component.instructions)}
|
|
267
454
|
</Text>
|
|
268
455
|
|
|
269
|
-
|
|
270
456
|
<View style={{ alignItems: 'center', justifyContent: 'center', flexDirection: "column", gap: 16 }}>
|
|
271
457
|
<View
|
|
272
458
|
style={{
|
|
@@ -285,29 +471,38 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
285
471
|
backgroundColor: '#fff', // Needed for shadow to show on iOS
|
|
286
472
|
}}
|
|
287
473
|
>
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
474
|
+
{cropImageUri ? (
|
|
475
|
+
<Image
|
|
476
|
+
source={{ uri: cropImageUri }}
|
|
477
|
+
style={{
|
|
478
|
+
width: '100%',
|
|
479
|
+
height: 200,
|
|
480
|
+
borderRadius: 12,
|
|
481
|
+
resizeMode: 'cover',
|
|
482
|
+
}}
|
|
483
|
+
/>
|
|
484
|
+
) : null}
|
|
485
|
+
|
|
297
486
|
</View>
|
|
298
487
|
{/* retake button */}
|
|
299
|
-
<Button title=
|
|
488
|
+
<Button title={t('kyc.idCardCapture.retakeButton')} onPress={() => {
|
|
300
489
|
retakePicture(currentSide);
|
|
301
490
|
}}
|
|
302
491
|
variant="outline"
|
|
303
492
|
size="medium"
|
|
304
493
|
fullWidth
|
|
305
|
-
|
|
306
|
-
/>
|
|
307
|
-
<Button title="Suivant" onPress={() => {
|
|
308
|
-
setShowCamera(true);
|
|
309
494
|
|
|
310
|
-
|
|
495
|
+
/>
|
|
496
|
+
<Button title={t('common.next')} onPress={() => {
|
|
497
|
+
if (currentSide === 'back' || selectedDocumentType?.type === 'passport') {
|
|
498
|
+
actions.nextComponent();
|
|
499
|
+
return;
|
|
500
|
+
} else {
|
|
501
|
+
setShowCamera(true);
|
|
502
|
+
setCurrentSide('back');
|
|
503
|
+
setSilentCaptureResult((prev) => ({ path: '', success: false, isAnalyzing: false, error: '', mrz: '' }));
|
|
504
|
+
setCropImageUri('');
|
|
505
|
+
}
|
|
311
506
|
}}
|
|
312
507
|
variant="primary"
|
|
313
508
|
size="large"
|
|
@@ -480,8 +675,9 @@ const styles = StyleSheet.create({
|
|
|
480
675
|
},
|
|
481
676
|
documentTypesContainer: {
|
|
482
677
|
// flex: 1,
|
|
483
|
-
marginBottom: 16,
|
|
678
|
+
// marginBottom: 16,
|
|
484
679
|
// paddingHorizontal: 16,
|
|
680
|
+
maxHeight: Dimensions.get('window').height - 400,
|
|
485
681
|
},
|
|
486
682
|
documentTypeButton: {
|
|
487
683
|
flexDirection: 'row',
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ActivityIndicator, Button, StyleSheet, Text, View } from "react-native"
|
|
2
|
+
import { SessionState } from "../../types/KYC.types"
|
|
3
|
+
import { useEffect } from "react"
|
|
4
|
+
import { useTemplateKYCFlowContext } from "../../hooks/useTemplateKYCFlow"
|
|
5
|
+
import { useI18n } from "../../hooks/useI18n"
|
|
6
|
+
|
|
7
|
+
export const InitializationStep = ({ session }: { session: SessionState }) => {
|
|
8
|
+
const { t } = useI18n();
|
|
9
|
+
const { initializeSession } = useTemplateKYCFlowContext()
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
initializeSession()
|
|
12
|
+
}, [])
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if (session.error) {
|
|
17
|
+
return (
|
|
18
|
+
<View style={styles.container}>
|
|
19
|
+
<Text style={styles.errorText}>{t('errors.serverError')}</Text>
|
|
20
|
+
<Button title={t('common.retry')} onPress={initializeSession} />
|
|
21
|
+
</View>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<View style={styles.container}>
|
|
27
|
+
<Text style={styles.initializingText}>{t('common.loading')}</Text>
|
|
28
|
+
{session.isProcessing && (
|
|
29
|
+
<ActivityIndicator size="large" color="#0000ff" />
|
|
30
|
+
)}
|
|
31
|
+
</View>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const styles = StyleSheet.create({
|
|
36
|
+
container: {
|
|
37
|
+
flex: 1,
|
|
38
|
+
justifyContent: 'center',
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
},
|
|
41
|
+
errorText: {
|
|
42
|
+
color: '#dc2626',
|
|
43
|
+
fontSize: 16,
|
|
44
|
+
textAlign: 'center',
|
|
45
|
+
margin: 20,
|
|
46
|
+
},
|
|
47
|
+
initializingText: {
|
|
48
|
+
color: '#0000ff',
|
|
49
|
+
fontSize: 16,
|
|
50
|
+
textAlign: 'center',
|
|
51
|
+
margin: 20,
|
|
52
|
+
},
|
|
53
|
+
})
|