@transfergratis/react-native-sdk 0.1.4 → 0.1.6
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 +77 -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 +137 -38
- 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 +194 -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 +4 -1
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +74 -199
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts +3 -2
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +64 -40
- 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 +6 -3
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +356 -42
- 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/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- 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 +58 -1
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +304 -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 +45 -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 +56 -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/build/web/WebKYCEntry.d.ts +9 -0
- package/build/web/WebKYCEntry.d.ts.map +1 -0
- package/build/web/WebKYCEntry.js +156 -0
- package/build/web/WebKYCEntry.js.map +1 -0
- package/build/web/index.d.ts +2 -0
- package/build/web/index.d.ts.map +1 -0
- package/build/web/index.js +2 -0
- package/build/web/index.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 +111 -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 +174 -57
- package/src/components/KYCElements/VerificationProgressTemplate.tsx +246 -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 +80 -200
- package/src/components/TemplateKYCFlowRefactored.tsx +80 -48
- 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 +407 -57
- 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/index.ts +3 -0
- package/src/modules/api/CardAuthentification.ts +114 -0
- package/src/modules/api/KYCService.ts +350 -30
- package/src/modules/api/SelfieVerification.ts +11 -0
- package/src/modules/api/backendApi.ts +8 -0
- package/src/modules/api/types.ts +51 -0
- package/src/types/KYC.types.ts +82 -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/web/WebKYCEntry.tsx +215 -0
- package/src/web/index.ts +1 -0
- package/src/types/nativewind.d.ts +0 -2
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import React, { useState, useCallback, useMemo, createContext, useContext } from 'react';
|
|
1
|
+
import React, { useState, useCallback, useMemo, createContext, useContext, useEffect } from 'react';
|
|
2
|
+
import kycService, { authentification, truncateFields } from '../modules/api/KYCService';
|
|
3
|
+
import useI18n from './useI18n';
|
|
2
4
|
const TemplateKYCFlowContext = createContext(undefined);
|
|
3
|
-
export const TemplateKYCFlowProvider = ({ children, template, onComplete, onError, initialLanguage = 'en', }) => {
|
|
4
|
-
const hookResult = useTemplateKYCFlow(template, onComplete, onError, initialLanguage);
|
|
5
|
+
export const TemplateKYCFlowProvider = ({ children, template, onComplete, onError, onCancel, initialLanguage = 'en', apiKey, }) => {
|
|
6
|
+
const hookResult = useTemplateKYCFlow(template, onComplete, onError, onCancel, initialLanguage, apiKey);
|
|
5
7
|
return (<TemplateKYCFlowContext.Provider value={hookResult}>
|
|
6
8
|
{children}
|
|
7
9
|
</TemplateKYCFlowContext.Provider>);
|
|
@@ -14,10 +16,62 @@ export const useTemplateKYCFlowContext = () => {
|
|
|
14
16
|
}
|
|
15
17
|
return context;
|
|
16
18
|
};
|
|
17
|
-
export const useTemplateKYCFlow = (template, onComplete, onError, initialLanguage = 'en') => {
|
|
19
|
+
export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, initialLanguage = 'en', apiKey) => {
|
|
20
|
+
const { setLocale } = useI18n();
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
setLocale(initialLanguage);
|
|
23
|
+
}, [initialLanguage]);
|
|
24
|
+
// Helpers to align SDK steps with backend actions/templates
|
|
25
|
+
const isUiOnlyStep = useCallback((type) => {
|
|
26
|
+
return type === 'verification_progress';
|
|
27
|
+
}, []);
|
|
28
|
+
const ensureReviewSubmitStep = useCallback((tpl) => {
|
|
29
|
+
const hasReview = tpl.components.some(c => c.type === 'review_submit');
|
|
30
|
+
if (hasReview)
|
|
31
|
+
return tpl;
|
|
32
|
+
const lastOrder = tpl.components.reduce((acc, c) => Math.max(acc, c.order ?? 0), 0);
|
|
33
|
+
const lastId = tpl.components.reduce((acc, c) => Math.max(acc, c.id), 0);
|
|
34
|
+
const reviewComponent = {
|
|
35
|
+
id: lastId + 1,
|
|
36
|
+
type: 'review_submit',
|
|
37
|
+
order: lastOrder + 1,
|
|
38
|
+
labels: { en: 'Review & Submit', fr: 'Revoir & Soumettre' },
|
|
39
|
+
instructions: { en: 'Confirm and submit', fr: 'Confirmer et soumettre' },
|
|
40
|
+
ui: { buttonText: { en: 'Complete Verification', fr: 'Terminer la vérification' } },
|
|
41
|
+
// @ts-ignore - config unused for review component
|
|
42
|
+
config: {},
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
...tpl,
|
|
46
|
+
components: [...tpl.components, reviewComponent],
|
|
47
|
+
};
|
|
48
|
+
}, []);
|
|
49
|
+
const ensureVerificationProgressStep = useCallback((tpl) => {
|
|
50
|
+
const hasVerification = tpl.components.some(c => c.type === 'verification_progress');
|
|
51
|
+
if (hasVerification)
|
|
52
|
+
return tpl;
|
|
53
|
+
const lastOrder = tpl.components.reduce((acc, c) => Math.max(acc, c.order ?? 0), 0);
|
|
54
|
+
const lastId = tpl.components.reduce((acc, c) => Math.max(acc, c.id), 0);
|
|
55
|
+
const verificationComponent = {
|
|
56
|
+
id: lastId + 2,
|
|
57
|
+
type: 'verification_progress',
|
|
58
|
+
order: lastOrder + 2,
|
|
59
|
+
labels: { en: 'Verification', fr: 'Vérification' },
|
|
60
|
+
instructions: { en: 'We\'re reviewing your documents', fr: 'Nous analysons vos documents' },
|
|
61
|
+
ui: { buttonText: { en: '', fr: '' } },
|
|
62
|
+
// @ts-ignore - config unused for progress component
|
|
63
|
+
config: {},
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
...tpl,
|
|
67
|
+
components: [...tpl.components, verificationComponent],
|
|
68
|
+
};
|
|
69
|
+
}, []);
|
|
70
|
+
const templateWithReview = useMemo(() => ensureReviewSubmitStep(template), [template, ensureReviewSubmitStep]);
|
|
71
|
+
const templateWithReviewAndVerification = useMemo(() => ensureVerificationProgressStep(templateWithReview), [templateWithReview, ensureVerificationProgressStep]);
|
|
18
72
|
// État du flux
|
|
19
73
|
const [state, setState] = useState({
|
|
20
|
-
template,
|
|
74
|
+
template: templateWithReviewAndVerification,
|
|
21
75
|
currentComponentIndex: 0,
|
|
22
76
|
completedComponents: [],
|
|
23
77
|
componentData: {},
|
|
@@ -25,35 +79,183 @@ export const useTemplateKYCFlow = (template, onComplete, onError, initialLanguag
|
|
|
25
79
|
isProcessing: false,
|
|
26
80
|
currentLanguage: initialLanguage,
|
|
27
81
|
showCustomStepper: true,
|
|
82
|
+
session: {
|
|
83
|
+
session_id: '',
|
|
84
|
+
token: '',
|
|
85
|
+
isInitialized: false,
|
|
86
|
+
isProcessing: false,
|
|
87
|
+
error: null,
|
|
88
|
+
},
|
|
89
|
+
verification: {
|
|
90
|
+
status: 'idle',
|
|
91
|
+
},
|
|
28
92
|
});
|
|
93
|
+
const mapComponentTypeToAction = useCallback((type) => {
|
|
94
|
+
switch (type) {
|
|
95
|
+
case 'id_card':
|
|
96
|
+
case 'file_upload':
|
|
97
|
+
return 'document_upload';
|
|
98
|
+
case 'selfie':
|
|
99
|
+
return 'selfie_capture';
|
|
100
|
+
case 'location':
|
|
101
|
+
return 'location_permission';
|
|
102
|
+
case 'review_submit':
|
|
103
|
+
return 'final_submit';
|
|
104
|
+
case 'country_selection':
|
|
105
|
+
// No direct backend action; pack into metadata of next actionable step
|
|
106
|
+
return null;
|
|
107
|
+
case 'initialization':
|
|
108
|
+
return 'initialize_session';
|
|
109
|
+
case 'verification_progress':
|
|
110
|
+
return null; // UI-only
|
|
111
|
+
default:
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}, []);
|
|
115
|
+
const chooseTemplateId = useCallback((tpl) => {
|
|
116
|
+
const types = tpl.components.map(c => c.type);
|
|
117
|
+
const hasLocation = types.includes('location');
|
|
118
|
+
const hasSelfie = types.includes('selfie');
|
|
119
|
+
const hasIdDoc = types.includes('id_card') || types.includes('file_upload');
|
|
120
|
+
// Simple heuristic to map to backend examples
|
|
121
|
+
if (hasLocation && hasSelfie && hasIdDoc)
|
|
122
|
+
return 'enhanced_id';
|
|
123
|
+
if (hasSelfie && hasIdDoc)
|
|
124
|
+
return 'standard_passport';
|
|
125
|
+
return 'standard_passport';
|
|
126
|
+
}, []);
|
|
127
|
+
const computeServerStepIndex = useCallback((tpl, upToIndex) => {
|
|
128
|
+
// Count actionable steps before the current component (exclude UI-only and country_selection)
|
|
129
|
+
const actionable = tpl.components
|
|
130
|
+
.slice(0, upToIndex)
|
|
131
|
+
.filter(c => !isUiOnlyStep(c.type) && mapComponentTypeToAction(c.type) !== null);
|
|
132
|
+
return actionable.length; // 0-based
|
|
133
|
+
}, [isUiOnlyStep, mapComponentTypeToAction]);
|
|
134
|
+
// Build backend-friendly payloads per action
|
|
135
|
+
const buildPayloadForComponent = useCallback((action, component, rawData, templateId, step) => {
|
|
136
|
+
const base = { template_id: null, step: component.order, permissionGranted: true };
|
|
137
|
+
if (!action) {
|
|
138
|
+
return base;
|
|
139
|
+
}
|
|
140
|
+
// Document upload expects an array of documents with base64 and metadata
|
|
141
|
+
if (action === 'document_upload') {
|
|
142
|
+
const documents = {};
|
|
143
|
+
if (rawData && typeof rawData === 'object') {
|
|
144
|
+
Object.keys(rawData).forEach((key) => {
|
|
145
|
+
documents[key] = rawData[key];
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
...base,
|
|
150
|
+
documents,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (action === 'selfie_capture') {
|
|
154
|
+
const documents = {};
|
|
155
|
+
if (rawData && typeof rawData === 'object') {
|
|
156
|
+
Object.keys(rawData).forEach((key) => {
|
|
157
|
+
documents[key] = rawData[key];
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const idCardID = Object.keys(state.componentData).find((c) => c === "1");
|
|
161
|
+
if (idCardID) {
|
|
162
|
+
const _idCardData = state.componentData[idCardID];
|
|
163
|
+
return { ...base, documents, country: _idCardData?.country || '', documentType: _idCardData?.documentType || 'identity_card' };
|
|
164
|
+
}
|
|
165
|
+
// return { ...base, documents };
|
|
166
|
+
}
|
|
167
|
+
if (action === 'location_permission') {
|
|
168
|
+
return { ...base, ...({ metadata: rawData || {} }), ...({ permissionGranted: true, }) };
|
|
169
|
+
}
|
|
170
|
+
// Default: wrap as metadata
|
|
171
|
+
return { ...base, metadata: { ...(rawData || {}) } };
|
|
172
|
+
}, [state.componentData]);
|
|
173
|
+
// Ensure the template contains a final review step
|
|
29
174
|
// Composant actuel
|
|
30
175
|
const currentComponent = useMemo(() => {
|
|
31
|
-
return template.components[state.currentComponentIndex] || null;
|
|
32
|
-
}, [template.components, state.currentComponentIndex]);
|
|
176
|
+
return state.template.components[state.currentComponentIndex] || null;
|
|
177
|
+
}, [state.template.components, state.currentComponentIndex]);
|
|
33
178
|
// Progression du flux
|
|
34
179
|
const progress = useMemo(() => {
|
|
35
|
-
return template.components.length > 0
|
|
36
|
-
? ((state.currentComponentIndex + 1) / template.components.length) * 100
|
|
180
|
+
return state.template.components.length > 0
|
|
181
|
+
? ((state.currentComponentIndex + 1) / state.template.components.length) * 100
|
|
37
182
|
: 0;
|
|
38
|
-
}, [state.currentComponentIndex, template.components.length]);
|
|
183
|
+
}, [state.currentComponentIndex, state.template.components.length]);
|
|
39
184
|
// Vérifications de navigation
|
|
40
185
|
const canGoNext = useMemo(() => {
|
|
41
|
-
return state.currentComponentIndex < template.components.length - 1;
|
|
42
|
-
}, [state.currentComponentIndex, template.components.length]);
|
|
186
|
+
return state.currentComponentIndex < state.template.components.length - 1;
|
|
187
|
+
}, [state.currentComponentIndex, state.template.components.length]);
|
|
43
188
|
const canGoPrevious = useMemo(() => {
|
|
44
189
|
return state.currentComponentIndex > 0;
|
|
45
190
|
}, [state.currentComponentIndex]);
|
|
46
191
|
const isComplete = useMemo(() => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
192
|
+
const atReview = state.template.components[state.currentComponentIndex]?.type === 'review_submit';
|
|
193
|
+
const nonReviewCount = state.template.components.filter(c => c.type !== 'review_submit').length;
|
|
194
|
+
const completedNonReview = state.completedComponents.length >= nonReviewCount;
|
|
195
|
+
return atReview && completedNonReview;
|
|
196
|
+
}, [state.currentComponentIndex, state.completedComponents.length, state.template.components]);
|
|
50
197
|
// Fonction pour obtenir le texte localisé
|
|
51
198
|
const getLocalizedText = useCallback((text) => {
|
|
52
199
|
return text[state.currentLanguage] || text.en || '';
|
|
53
200
|
}, [state.currentLanguage]);
|
|
201
|
+
const initializeSession = useCallback(async () => {
|
|
202
|
+
try {
|
|
203
|
+
setState(prev => ({
|
|
204
|
+
...prev,
|
|
205
|
+
session: {
|
|
206
|
+
...prev.session,
|
|
207
|
+
isInitialized: false,
|
|
208
|
+
isProcessing: true,
|
|
209
|
+
error: null,
|
|
210
|
+
},
|
|
211
|
+
}));
|
|
212
|
+
console.log('Initializing session');
|
|
213
|
+
const token = await authentification();
|
|
214
|
+
const session = await kycService.newSession(token);
|
|
215
|
+
// Align backend flow from step 0 with initialize_session
|
|
216
|
+
try {
|
|
217
|
+
const templateId = chooseTemplateId(templateWithReviewAndVerification);
|
|
218
|
+
await kycService.verificationSession({
|
|
219
|
+
session_id: session.session_id,
|
|
220
|
+
step: 0,
|
|
221
|
+
data: { template_id: templateId, metadata: { language: initialLanguage } },
|
|
222
|
+
templateId: templateId,
|
|
223
|
+
token: token,
|
|
224
|
+
action: 'initialize_session'
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
catch (e) {
|
|
228
|
+
console.error('Error initializing session:', JSON.stringify(e, null, 2));
|
|
229
|
+
// Non-fatal: we will surface errors via state below if needed
|
|
230
|
+
}
|
|
231
|
+
setState(prev => ({
|
|
232
|
+
...prev,
|
|
233
|
+
session: {
|
|
234
|
+
...prev.session,
|
|
235
|
+
session_id: session.session_id,
|
|
236
|
+
token: token,
|
|
237
|
+
isInitialized: true,
|
|
238
|
+
isProcessing: false,
|
|
239
|
+
error: null,
|
|
240
|
+
}
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
console.error('Error initializing session:', JSON.stringify(error, null, 2));
|
|
245
|
+
setState(prev => ({
|
|
246
|
+
...prev,
|
|
247
|
+
session: {
|
|
248
|
+
...prev.session,
|
|
249
|
+
isInitialized: false,
|
|
250
|
+
isProcessing: false,
|
|
251
|
+
error: "Erreur lors de l'initialisation de la session",
|
|
252
|
+
},
|
|
253
|
+
}));
|
|
254
|
+
}
|
|
255
|
+
}, []);
|
|
54
256
|
// Validation d'un composant
|
|
55
257
|
const validateComponent = useCallback((componentId) => {
|
|
56
|
-
const component = template.components.find(c => c.id === componentId);
|
|
258
|
+
const component = state.template.components.find(c => c.id === componentId);
|
|
57
259
|
if (!component)
|
|
58
260
|
return false;
|
|
59
261
|
const componentData = state.componentData[componentId];
|
|
@@ -74,54 +276,144 @@ export const useTemplateKYCFlow = (template, onComplete, onError, initialLanguag
|
|
|
74
276
|
return componentData && componentData.latitude && componentData.longitude;
|
|
75
277
|
case 'country_selection':
|
|
76
278
|
// Vérifier si un pays a été sélectionné
|
|
77
|
-
|
|
279
|
+
console.log("componentData", truncateFields(componentData), componentId);
|
|
280
|
+
return componentData && componentData.code && componentData.regionMapping;
|
|
281
|
+
case 'review_submit':
|
|
282
|
+
return true;
|
|
78
283
|
default:
|
|
79
284
|
return false;
|
|
80
285
|
}
|
|
81
|
-
}, [template.components, state.componentData]);
|
|
286
|
+
}, [state.template.components, state.componentData]);
|
|
82
287
|
// Actions du flux
|
|
83
288
|
const actions = {
|
|
84
289
|
// Initialiser le template
|
|
85
290
|
initializeTemplate: useCallback((newTemplate) => {
|
|
291
|
+
const withReview = ensureReviewSubmitStep(newTemplate);
|
|
292
|
+
const withVerification = ensureVerificationProgressStep(withReview);
|
|
86
293
|
setState(prev => ({
|
|
87
294
|
...prev,
|
|
88
|
-
template:
|
|
295
|
+
template: withVerification,
|
|
89
296
|
currentComponentIndex: 0,
|
|
90
297
|
completedComponents: [],
|
|
91
298
|
componentData: {},
|
|
92
299
|
errors: {},
|
|
93
300
|
isProcessing: false,
|
|
301
|
+
verification: { status: 'idle', result: undefined },
|
|
94
302
|
}));
|
|
95
|
-
}, []),
|
|
303
|
+
}, [ensureReviewSubmitStep, ensureVerificationProgressStep]),
|
|
96
304
|
// Passer au composant suivant
|
|
97
|
-
nextComponent: useCallback(() => {
|
|
305
|
+
nextComponent: useCallback(async () => {
|
|
98
306
|
if (!canGoNext)
|
|
99
307
|
return;
|
|
100
|
-
const currentComp = template.components[state.currentComponentIndex];
|
|
308
|
+
const currentComp = state.template.components[state.currentComponentIndex];
|
|
101
309
|
if (!currentComp)
|
|
102
310
|
return;
|
|
311
|
+
setState(prev => ({
|
|
312
|
+
...prev,
|
|
313
|
+
isProcessing: true,
|
|
314
|
+
}));
|
|
103
315
|
// Valider le composant actuel
|
|
104
316
|
if (!validateComponent(currentComp.id)) {
|
|
105
317
|
setState(prev => ({
|
|
106
318
|
...prev,
|
|
319
|
+
isProcessing: false,
|
|
107
320
|
errors: {
|
|
108
321
|
...prev.errors,
|
|
109
|
-
[currentComp.id]: 'Veuillez compléter cette étape avant de continuer'
|
|
322
|
+
[currentComp.id]: state.currentLanguage === "en" ? "please complete this step before move on" : " 'Veuillez compléter cette étape avant de continuer'"
|
|
110
323
|
}
|
|
111
324
|
}));
|
|
112
325
|
return;
|
|
113
326
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
327
|
+
try {
|
|
328
|
+
const component = state.template.components.find(c => c.id === currentComp.id);
|
|
329
|
+
if (!component)
|
|
330
|
+
return;
|
|
331
|
+
if (component.type === 'review_submit') {
|
|
332
|
+
// Move to verification screen and mark verification in progress
|
|
333
|
+
setState(prev => ({
|
|
334
|
+
...prev,
|
|
335
|
+
currentComponentIndex: prev.currentComponentIndex + 1,
|
|
336
|
+
completedComponents: [...prev.completedComponents, currentComp.id],
|
|
337
|
+
isProcessing: false,
|
|
338
|
+
verification: { status: 'in_progress' },
|
|
339
|
+
errors: {
|
|
340
|
+
...prev.errors,
|
|
341
|
+
[currentComp.id]: ''
|
|
342
|
+
}
|
|
343
|
+
}));
|
|
344
|
+
return;
|
|
122
345
|
}
|
|
123
|
-
|
|
124
|
-
|
|
346
|
+
// Determine backend action and step index
|
|
347
|
+
const action = mapComponentTypeToAction(component.type);
|
|
348
|
+
const templateId = chooseTemplateId(state.template);
|
|
349
|
+
const serverStep = computeServerStepIndex(state.template, state.currentComponentIndex);
|
|
350
|
+
// Optionally send initialize_session at step 0 before first actionable action
|
|
351
|
+
if (serverStep === 0) {
|
|
352
|
+
try {
|
|
353
|
+
// await kycService.verificationSession({
|
|
354
|
+
// sessionId: state.session.session_id,
|
|
355
|
+
// step: 0,
|
|
356
|
+
// data: { template_id: templateId, metadata: { language: state.currentLanguage } },
|
|
357
|
+
// templateId: templateId,
|
|
358
|
+
// token: state.session.token,
|
|
359
|
+
// action: 'initialize_session'
|
|
360
|
+
// });
|
|
361
|
+
}
|
|
362
|
+
catch (e) {
|
|
363
|
+
// if init fails, surface error below in the main call handling
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// Skip UI-only and data-only steps that have no backend action
|
|
367
|
+
if (!action) {
|
|
368
|
+
setState(prev => ({
|
|
369
|
+
...prev,
|
|
370
|
+
currentComponentIndex: prev.currentComponentIndex + 1,
|
|
371
|
+
completedComponents: [...prev.completedComponents, currentComp.id],
|
|
372
|
+
isProcessing: false,
|
|
373
|
+
errors: {
|
|
374
|
+
...prev.errors,
|
|
375
|
+
[currentComp.id]: ''
|
|
376
|
+
}
|
|
377
|
+
}));
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const step = serverStep === 0 && action !== 'initialize_session' ? 1 : serverStep;
|
|
381
|
+
// Build payload data per action
|
|
382
|
+
const payloadData = buildPayloadForComponent(action, component, state.componentData[currentComp.id], templateId, step);
|
|
383
|
+
await kycService.verificationSession({
|
|
384
|
+
session_id: state.session.session_id,
|
|
385
|
+
step: step,
|
|
386
|
+
data: payloadData,
|
|
387
|
+
templateId: null,
|
|
388
|
+
token: state.session.token,
|
|
389
|
+
action: action
|
|
390
|
+
});
|
|
391
|
+
console.log("currentComp state", truncateFields(state));
|
|
392
|
+
// Marquer comme complété et passer au suivant
|
|
393
|
+
setState(prev => ({
|
|
394
|
+
...prev,
|
|
395
|
+
currentComponentIndex: prev.currentComponentIndex + 1,
|
|
396
|
+
completedComponents: [...prev.completedComponents, currentComp.id],
|
|
397
|
+
isProcessing: false,
|
|
398
|
+
...(action === "location_permission" ? { permissionGranted: true } : {}),
|
|
399
|
+
errors: {
|
|
400
|
+
...prev.errors,
|
|
401
|
+
[currentComp.id]: ''
|
|
402
|
+
}
|
|
403
|
+
}));
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
// console.error('Error validating component:', error);
|
|
407
|
+
setState(prev => ({
|
|
408
|
+
...prev,
|
|
409
|
+
isProcessing: false,
|
|
410
|
+
errors: {
|
|
411
|
+
...prev.errors,
|
|
412
|
+
[currentComp.id]: 'Erreur lors de la validation du composant'
|
|
413
|
+
}
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
416
|
+
}, [canGoNext, state.currentComponentIndex, state.template.components, validateComponent]),
|
|
125
417
|
// Retourner au composant précédent
|
|
126
418
|
previousComponent: useCallback(() => {
|
|
127
419
|
if (!canGoPrevious)
|
|
@@ -133,16 +425,17 @@ export const useTemplateKYCFlow = (template, onComplete, onError, initialLanguag
|
|
|
133
425
|
}, [canGoPrevious]),
|
|
134
426
|
// Aller à un composant spécifique
|
|
135
427
|
goToComponent: useCallback((componentId) => {
|
|
136
|
-
const componentIndex = template.components.findIndex(c => c.id === componentId);
|
|
428
|
+
const componentIndex = state.template.components.findIndex(c => c.id === componentId);
|
|
137
429
|
if (componentIndex !== -1) {
|
|
138
430
|
setState(prev => ({
|
|
139
431
|
...prev,
|
|
140
432
|
currentComponentIndex: componentIndex,
|
|
141
433
|
}));
|
|
142
434
|
}
|
|
143
|
-
}, [template.components]),
|
|
435
|
+
}, [state.template.components]),
|
|
144
436
|
// Mettre à jour les données d'un composant
|
|
145
437
|
updateComponentData: useCallback((componentId, data) => {
|
|
438
|
+
console.log("updateComponentData", componentId, truncateFields(data));
|
|
146
439
|
setState(prev => ({
|
|
147
440
|
...prev,
|
|
148
441
|
componentData: {
|
|
@@ -159,28 +452,41 @@ export const useTemplateKYCFlow = (template, onComplete, onError, initialLanguag
|
|
|
159
452
|
validateComponent: useCallback((componentId) => {
|
|
160
453
|
return validateComponent(componentId);
|
|
161
454
|
}, [validateComponent]),
|
|
455
|
+
// complet verification
|
|
456
|
+
submitVerification: useCallback(async () => {
|
|
457
|
+
setState(prev => ({ ...prev, isProcessing: true }));
|
|
458
|
+
try {
|
|
459
|
+
onComplete?.(state.verification);
|
|
460
|
+
}
|
|
461
|
+
catch (error) {
|
|
462
|
+
setState(prev => ({ ...prev, isProcessing: false }));
|
|
463
|
+
}
|
|
464
|
+
}, [state.session.session_id, state.verification, onComplete]),
|
|
162
465
|
// Soumettre le template complet
|
|
163
466
|
submitTemplate: useCallback(async () => {
|
|
164
|
-
|
|
467
|
+
// Allow submission when on the review step and all previous steps are valid
|
|
468
|
+
const atReview = state.template.components[state.currentComponentIndex]?.type === 'review_submit';
|
|
469
|
+
const allValid = state.template.components
|
|
470
|
+
.filter(c => c.type !== 'review_submit')
|
|
471
|
+
.every(comp => validateComponent(comp.id));
|
|
472
|
+
if (!(atReview && allValid)) {
|
|
165
473
|
onError?.('Le flux KYC n\'est pas encore terminé');
|
|
166
474
|
return;
|
|
167
475
|
}
|
|
168
476
|
setState(prev => ({ ...prev, isProcessing: true }));
|
|
169
477
|
try {
|
|
170
|
-
// Vérifier que tous les composants sont validés
|
|
171
|
-
|
|
172
|
-
if (!allValid) {
|
|
478
|
+
// Vérifier que tous les composants (hors review) sont validés
|
|
479
|
+
if (!allValid)
|
|
173
480
|
throw new Error('Certaines étapes ne sont pas complètes');
|
|
174
|
-
}
|
|
175
481
|
// Appeler le callback de completion
|
|
176
|
-
onComplete?.(state.componentData);
|
|
482
|
+
// onComplete?.(state.componentData);
|
|
177
483
|
setState(prev => ({ ...prev, isProcessing: false }));
|
|
178
484
|
}
|
|
179
485
|
catch (error) {
|
|
180
486
|
setState(prev => ({ ...prev, isProcessing: false }));
|
|
181
487
|
onError?.(error instanceof Error ? error.message : 'Erreur lors de la soumission');
|
|
182
488
|
}
|
|
183
|
-
}, [
|
|
489
|
+
}, [state.template.components, state.verification, state.currentComponentIndex, validateComponent, state.componentData, onComplete, onError]),
|
|
184
490
|
// Réinitialiser le template
|
|
185
491
|
resetTemplate: useCallback(() => {
|
|
186
492
|
setState(prev => ({
|
|
@@ -190,6 +496,7 @@ export const useTemplateKYCFlow = (template, onComplete, onError, initialLanguag
|
|
|
190
496
|
componentData: {},
|
|
191
497
|
errors: {},
|
|
192
498
|
isProcessing: false,
|
|
499
|
+
verification: { status: 'idle', result: undefined },
|
|
193
500
|
}));
|
|
194
501
|
}, []),
|
|
195
502
|
// Changer la langue
|
|
@@ -206,6 +513,12 @@ export const useTemplateKYCFlow = (template, onComplete, onError, initialLanguag
|
|
|
206
513
|
showCustomStepper: show,
|
|
207
514
|
}));
|
|
208
515
|
}, []),
|
|
516
|
+
setVerificationState: useCallback((verificationState) => {
|
|
517
|
+
setState(prev => ({
|
|
518
|
+
...prev,
|
|
519
|
+
verification: verificationState,
|
|
520
|
+
}));
|
|
521
|
+
}, []),
|
|
209
522
|
};
|
|
210
523
|
return {
|
|
211
524
|
state,
|
|
@@ -216,6 +529,7 @@ export const useTemplateKYCFlow = (template, onComplete, onError, initialLanguag
|
|
|
216
529
|
canGoPrevious,
|
|
217
530
|
isComplete,
|
|
218
531
|
getLocalizedText,
|
|
532
|
+
initializeSession,
|
|
219
533
|
};
|
|
220
534
|
};
|
|
221
535
|
//# sourceMappingURL=useTemplateKYCFlow.js.map
|