@transfergratis/react-native-sdk 0.1.24 → 0.1.26
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 +22 -7
- package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.web.js +76 -21
- 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/EmailVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js +212 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +216 -14
- package/build/components/KYCElements/IDCardCapture.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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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/SelfieCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.js +7 -3
- package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/WelcomeTemplate.js +2 -1
- package/build/components/KYCElements/WelcomeTemplate.js.map +1 -1
- package/build/components/OverLay/type.d.ts +2 -0
- 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 +10 -0
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +7 -30
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts +12 -0
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +25 -3
- package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
- 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.map +1 -1
- package/build/config/allowedDomains.js +4 -19
- package/build/config/allowedDomains.js.map +1 -1
- 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 +18 -1
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +410 -56
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/i18n/en/index.d.ts +42 -0
- package/build/i18n/en/index.d.ts.map +1 -1
- package/build/i18n/en/index.js +44 -2
- package/build/i18n/en/index.js.map +1 -1
- package/build/i18n/fr/index.d.ts +28 -0
- package/build/i18n/fr/index.d.ts.map +1 -1
- package/build/i18n/fr/index.js +30 -2
- package/build/i18n/fr/index.js.map +1 -1
- package/build/i18n/types.d.ts +2 -0
- package/build/i18n/types.d.ts.map +1 -1
- package/build/i18n/types.js.map +1 -1
- 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 +24 -3
- package/build/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/modules/api/CardAuthentification.js +90 -12
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +17 -7
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +125 -37
- 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 +0 -1
- package/build/modules/api/TemplateService.d.ts.map +1 -1
- package/build/modules/api/TemplateService.js +3 -3
- package/build/modules/api/TemplateService.js.map +1 -1
- package/build/modules/camera/VisionCameraModule.web.d.ts.map +1 -1
- package/build/modules/camera/VisionCameraModule.web.js +27 -8
- package/build/modules/camera/VisionCameraModule.web.js.map +1 -1
- package/build/types/KYC.types.d.ts +130 -5
- package/build/types/KYC.types.d.ts.map +1 -1
- 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 +7 -0
- package/build/utils/cropByObb.d.ts.map +1 -1
- package/build/utils/cropByObb.js +20 -1
- 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.map +1 -1
- package/build/utils/platformAlert.js.map +1 -1
- package/build/utils/template-transformer.d.ts.map +1 -1
- package/build/utils/template-transformer.js +12 -0
- package/build/utils/template-transformer.js.map +1 -1
- package/build/web/WebKYCEntry.d.ts.map +1 -1
- package/build/web/WebKYCEntry.js +88 -38
- package/build/web/WebKYCEntry.js.map +1 -1
- package/package.json +1 -1
- package/plugin/build/index.d.ts +1 -0
- package/plugin/build/index.js +3 -1
- package/plugin/build/withRemovePermissions.d.ts +3 -0
- package/plugin/build/withRemovePermissions.js +67 -0
- package/plugin/build/withVisionCamera.js +3 -4
- package/plugin/src/index.ts +2 -1
- package/plugin/src/withRemovePermissions.js +85 -0
- package/plugin/src/withRemovePermissions.ts +83 -0
- package/plugin/src/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.ts +3 -4
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/plugin.js +6 -1
- package/src/components/EnhancedCameraView.web.tsx +76 -21
- package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
- package/src/components/KYCElements/EmailVerificationTemplate.tsx +278 -0
- package/src/components/KYCElements/IDCardCapture.tsx +253 -21
- package/src/components/KYCElements/OrientationVideoCapture.tsx +4 -1
- package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +4 -1
- package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +4 -1
- package/src/components/KYCElements/PersonalInformationTemplate.tsx +158 -0
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +253 -0
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +6 -3
- package/src/components/KYCElements/WelcomeTemplate.tsx +2 -1
- package/src/components/OverLay/type.ts +2 -0
- package/src/components/TemplateKYCExample.tsx +35 -46
- package/src/components/TemplateKYCFlowRefactored.tsx +46 -2
- package/src/config/KYCConfig.ts +34 -0
- package/src/config/allowedDomains.ts +7 -26
- package/src/hooks/useOrientationVideo.ts +5 -4
- package/src/hooks/useTemplateKYCFlow.tsx +443 -56
- package/src/i18n/en/index.ts +46 -3
- package/src/i18n/fr/index.ts +31 -2
- package/src/i18n/types.ts +2 -0
- package/src/index.ts +3 -0
- package/src/modules/api/CardAuthentification.ts +98 -12
- package/src/modules/api/KYCService.ts +158 -37
- package/src/modules/api/SelfieVerification.ts +25 -3
- package/src/modules/api/TemplateService.ts +4 -4
- package/src/modules/camera/VisionCameraModule.web.ts +30 -12
- package/src/types/KYC.types.ts +153 -6
- package/src/types/env.types.ts +13 -0
- package/src/utils/cropByObb.ts +20 -1
- package/src/utils/deviceDetection.ts +11 -0
- package/src/utils/platformAlert.ts +1 -0
- package/src/utils/template-transformer.ts +20 -8
- package/src/web/WebKYCEntry.tsx +123 -61
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React, { useState, useCallback, useMemo, createContext, useContext, ReactNode, useEffect } from 'react';
|
|
2
2
|
import { KYCTemplate, TemplateState, TemplateActions, UseTemplateReturn, TemplateComponent, GovernmentDocumentType, VerificationState } from '../types/KYC.types';
|
|
3
|
+
import { KycEnvironment } from '../types/env.types';
|
|
3
4
|
import kycService, { authentification, truncateFields } from '../modules/api/KYCService';
|
|
4
5
|
import useI18n from './useI18n';
|
|
5
6
|
import { logger } from '../utils/logger';
|
|
7
|
+
import { countryMapping } from '../config/region_mapping';
|
|
8
|
+
import { countryData } from '../config/countriesData';
|
|
6
9
|
|
|
7
10
|
// Context pour le provider
|
|
8
11
|
interface TemplateKYCFlowContextType {
|
|
@@ -15,6 +18,8 @@ interface TemplateKYCFlowContextType {
|
|
|
15
18
|
isComplete: boolean;
|
|
16
19
|
getLocalizedText: (text: { en: string; fr: string;[key: string]: string }) => string;
|
|
17
20
|
initializeSession: () => Promise<void>;
|
|
21
|
+
env: KycEnvironment;
|
|
22
|
+
apiKey?: string;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
const TemplateKYCFlowContext = createContext<TemplateKYCFlowContextType | undefined>(undefined);
|
|
@@ -28,6 +33,12 @@ interface TemplateKYCFlowProviderProps {
|
|
|
28
33
|
onCancel?: () => void;
|
|
29
34
|
initialLanguage?: string;
|
|
30
35
|
apiKey?: string;
|
|
36
|
+
env?: KycEnvironment;
|
|
37
|
+
existingSessionId?: string;
|
|
38
|
+
/** Index in template.components where to resume (0-based). Simple to store in template table. */
|
|
39
|
+
initialComponentIndex?: number;
|
|
40
|
+
/** Pays / type de document depuis l'URL de reprise — évite de dépendre du backend pour afficher les pays. */
|
|
41
|
+
initialCountryResume?: { code: string; documentType: string; region?: string };
|
|
31
42
|
}
|
|
32
43
|
|
|
33
44
|
export const TemplateKYCFlowProvider: React.FC<TemplateKYCFlowProviderProps> = ({
|
|
@@ -38,8 +49,12 @@ export const TemplateKYCFlowProvider: React.FC<TemplateKYCFlowProviderProps> = (
|
|
|
38
49
|
onCancel,
|
|
39
50
|
initialLanguage = 'en',
|
|
40
51
|
apiKey,
|
|
52
|
+
env = 'PRODUCTION',
|
|
53
|
+
existingSessionId,
|
|
54
|
+
initialComponentIndex,
|
|
55
|
+
initialCountryResume,
|
|
41
56
|
}) => {
|
|
42
|
-
const hookResult = useTemplateKYCFlow(template, onComplete, onError, onCancel, initialLanguage, apiKey);
|
|
57
|
+
const hookResult = useTemplateKYCFlow(template, onComplete, onError, onCancel, initialLanguage, apiKey, env, existingSessionId, initialComponentIndex, initialCountryResume);
|
|
43
58
|
|
|
44
59
|
return (
|
|
45
60
|
<TemplateKYCFlowContext.Provider value={hookResult}>
|
|
@@ -64,6 +79,10 @@ export const useTemplateKYCFlow = (
|
|
|
64
79
|
onCancel?: () => void,
|
|
65
80
|
initialLanguage: string = 'en',
|
|
66
81
|
apiKey?: string,
|
|
82
|
+
env: KycEnvironment = 'PRODUCTION',
|
|
83
|
+
existingSessionId?: string,
|
|
84
|
+
initialComponentIndex?: number,
|
|
85
|
+
initialCountryResume?: { code: string; documentType: string; region?: string },
|
|
67
86
|
): UseTemplateReturn => {
|
|
68
87
|
|
|
69
88
|
const { setLocale } = useI18n();
|
|
@@ -130,30 +149,348 @@ export const useTemplateKYCFlow = (
|
|
|
130
149
|
const templateWithReview = useMemo(() => ensureReviewSubmitStep(template), [template, ensureReviewSubmitStep, apiKey]);
|
|
131
150
|
const templateWithReviewAndVerification = useMemo(() => ensureVerificationProgressStep(templateWithReview), [templateWithReview, ensureVerificationProgressStep, apiKey]);
|
|
132
151
|
|
|
133
|
-
// État initial du flux
|
|
134
|
-
const buildInitialState = (): TemplateState =>
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
152
|
+
// État initial du flux (initialComponentIndex = index dans template.components pour reprendre au bon composant)
|
|
153
|
+
const buildInitialState = (): TemplateState => {
|
|
154
|
+
let resumeAtIndex = 0;
|
|
155
|
+
let completedComponents: number[] = [];
|
|
156
|
+
let initialComponentData: Record<number, unknown> = {};
|
|
157
|
+
|
|
158
|
+
logger.log('buildInitialState called', { initialComponentIndex, existingSessionId, initialCountryResume });
|
|
159
|
+
|
|
160
|
+
if (initialComponentIndex !== undefined && initialComponentIndex >= 0) {
|
|
161
|
+
const maxIndex = templateWithReviewAndVerification.components.length - 1;
|
|
162
|
+
const requestedIndex = Math.min(initialComponentIndex, maxIndex);
|
|
163
|
+
const requestedComponent = templateWithReviewAndVerification.components[requestedIndex];
|
|
164
|
+
|
|
165
|
+
logger.log('Processing initialComponentIndex (component in template)', {
|
|
166
|
+
initialComponentIndex,
|
|
167
|
+
requestedIndex,
|
|
168
|
+
maxIndex,
|
|
169
|
+
componentType: requestedComponent?.type,
|
|
170
|
+
componentId: requestedComponent?.id,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Reprendre au composant en cours (id_card, selfie, etc.)
|
|
174
|
+
if (requestedComponent?.type === 'id_card') {
|
|
175
|
+
if (existingSessionId) {
|
|
176
|
+
logger.log('id_card with existing session - staying at id_card');
|
|
177
|
+
resumeAtIndex = requestedIndex;
|
|
178
|
+
if (resumeAtIndex > 0) {
|
|
179
|
+
completedComponents = templateWithReviewAndVerification.components
|
|
180
|
+
.slice(0, resumeAtIndex)
|
|
181
|
+
.map(component => component.id);
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
const countrySelectionIndex = templateWithReviewAndVerification.components.findIndex(
|
|
185
|
+
c => c.type === 'country_selection'
|
|
186
|
+
);
|
|
187
|
+
logger.log('id_card without session - going back to country_selection', { countrySelectionIndex });
|
|
188
|
+
if (countrySelectionIndex >= 0) {
|
|
189
|
+
resumeAtIndex = countrySelectionIndex;
|
|
190
|
+
if (countrySelectionIndex > 0) {
|
|
191
|
+
completedComponents = templateWithReviewAndVerification.components
|
|
192
|
+
.slice(0, countrySelectionIndex)
|
|
193
|
+
.map(component => component.id);
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
resumeAtIndex = 0;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} else if (requestedComponent?.type === 'review_submit') {
|
|
200
|
+
resumeAtIndex = requestedIndex;
|
|
201
|
+
completedComponents = [];
|
|
202
|
+
} else {
|
|
203
|
+
resumeAtIndex = requestedIndex;
|
|
204
|
+
if (resumeAtIndex > 0) {
|
|
205
|
+
completedComponents = templateWithReviewAndVerification.components
|
|
206
|
+
.slice(0, resumeAtIndex)
|
|
207
|
+
.map(component => component.id);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
logger.log('Final initial state (resume at component index)', {
|
|
212
|
+
resumeAtIndex,
|
|
213
|
+
completedComponentsCount: completedComponents.length,
|
|
214
|
+
componentAtResume: templateWithReviewAndVerification.components[resumeAtIndex]?.type,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (initialCountryResume?.code && initialCountryResume?.documentType) {
|
|
219
|
+
const countrySel = templateWithReviewAndVerification.components.find(c => c.type === 'country_selection');
|
|
220
|
+
if (countrySel && countryData[initialCountryResume.code]) {
|
|
221
|
+
initialComponentData[countrySel.id] = {
|
|
222
|
+
code: initialCountryResume.code,
|
|
223
|
+
documentType: initialCountryResume.documentType,
|
|
224
|
+
region: initialCountryResume.region || 'root',
|
|
225
|
+
...countryData[initialCountryResume.code],
|
|
226
|
+
};
|
|
227
|
+
logger.log('Prefilled country_selection from URL', { code: initialCountryResume.code, documentType: initialCountryResume.documentType });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
template: templateWithReviewAndVerification,
|
|
233
|
+
currentComponentIndex: resumeAtIndex,
|
|
234
|
+
completedComponents: completedComponents,
|
|
235
|
+
componentData: initialComponentData,
|
|
236
|
+
errors: {},
|
|
147
237
|
isProcessing: false,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
238
|
+
currentLanguage: initialLanguage,
|
|
239
|
+
showCustomStepper: true,
|
|
240
|
+
session: {
|
|
241
|
+
session_id: existingSessionId || '',
|
|
242
|
+
token: '',
|
|
243
|
+
isInitialized: false,
|
|
244
|
+
isProcessing: false,
|
|
245
|
+
error: null,
|
|
246
|
+
sessionDataRestored: !existingSessionId || Boolean(initialCountryResume?.code && initialCountryResume?.documentType),
|
|
247
|
+
},
|
|
248
|
+
verification: {
|
|
249
|
+
status: 'idle',
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
};
|
|
154
253
|
|
|
155
254
|
// État du flux
|
|
156
255
|
const [state, setState] = useState<TemplateState>(() => buildInitialState());
|
|
256
|
+
|
|
257
|
+
// Fonction utilitaire pour convertir base64 en data URI pour l'affichage
|
|
258
|
+
const base64ToDataUri = useCallback((base64: string, mimeType: string = 'image/jpeg'): string => {
|
|
259
|
+
// Si c'est déjà une data URI, retourner tel quel
|
|
260
|
+
if (base64.startsWith('data:')) {
|
|
261
|
+
return base64;
|
|
262
|
+
}
|
|
263
|
+
// Sinon, créer une data URI
|
|
264
|
+
return `data:${mimeType};base64,${base64}`;
|
|
265
|
+
}, []);
|
|
266
|
+
|
|
267
|
+
// Charger les données de session si on reprend une session existante
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
const loadSessionData = async () => {
|
|
270
|
+
// Ne charger que si on a une session existante
|
|
271
|
+
if (!existingSessionId) {
|
|
272
|
+
logger.log('No existingSessionId, skipping data load');
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Si initialComponentIndex n'est pas défini ou est 0, on ne charge pas (début de session)
|
|
277
|
+
if (initialComponentIndex === undefined || initialComponentIndex === 0) {
|
|
278
|
+
logger.log('initialComponentIndex is 0 or undefined, skipping data load');
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Attendre que la session soit initialisée
|
|
283
|
+
if (!state.session.isInitialized || !state.session.session_id) {
|
|
284
|
+
logger.log('Session not initialized yet, waiting...', {
|
|
285
|
+
isInitialized: state.session.isInitialized,
|
|
286
|
+
sessionId: state.session.session_id
|
|
287
|
+
});
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
logger.log('Loading session data for resume:', { sessionId: existingSessionId, componentIndex: initialComponentIndex });
|
|
293
|
+
const result = await kycService.getVerificationResult(state.session.session_id);
|
|
294
|
+
const sessionData = result[state.session.session_id]?.data;
|
|
295
|
+
|
|
296
|
+
if (sessionData) {
|
|
297
|
+
// Restaurer les données des composants depuis la session
|
|
298
|
+
// Utiliser 'as any' car VerificationResult peut avoir des propriétés dynamiques
|
|
299
|
+
const data: any = sessionData;
|
|
300
|
+
const restoredComponentData: Record<number, any> = {};
|
|
301
|
+
|
|
302
|
+
// Parcourir les composants jusqu'au composant de reprise (inclu) pour restaurer leurs données
|
|
303
|
+
templateWithReviewAndVerification.components
|
|
304
|
+
.slice(0, initialComponentIndex + 1)
|
|
305
|
+
.forEach((component) => {
|
|
306
|
+
// Essayer de restaurer les données selon le type de composant
|
|
307
|
+
if (component.type === 'id_card' || component.type === 'file_upload') {
|
|
308
|
+
// Les documents peuvent être dans différentes structures
|
|
309
|
+
let documents: any = null;
|
|
310
|
+
|
|
311
|
+
// Chercher dans différentes structures possibles
|
|
312
|
+
if (data.documents) {
|
|
313
|
+
documents = data.documents;
|
|
314
|
+
} else if (data.user_data?.documents) {
|
|
315
|
+
documents = data.user_data.documents;
|
|
316
|
+
} else if (data.document_images) {
|
|
317
|
+
documents = data.document_images;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (documents) {
|
|
321
|
+
// Convertir les images base64 en format utilisable
|
|
322
|
+
const restoredDocuments: Record<string, any> = {};
|
|
323
|
+
|
|
324
|
+
Object.keys(documents).forEach((key) => {
|
|
325
|
+
const doc = documents[key];
|
|
326
|
+
if (typeof doc === 'object' && doc !== null) {
|
|
327
|
+
// Si on a un fichier base64, créer une structure avec dir et file
|
|
328
|
+
if (doc.file || doc.base64) {
|
|
329
|
+
const base64Data = doc.file || doc.base64;
|
|
330
|
+
restoredDocuments[key] = {
|
|
331
|
+
dir: base64ToDataUri(base64Data), // Utiliser data URI pour l'affichage
|
|
332
|
+
file: base64Data, // Garder le base64 pour l'envoi
|
|
333
|
+
mrz: doc.mrz || '',
|
|
334
|
+
templatePath: doc.templatePath || '',
|
|
335
|
+
};
|
|
336
|
+
} else {
|
|
337
|
+
// Sinon, garder la structure originale
|
|
338
|
+
restoredDocuments[key] = doc;
|
|
339
|
+
}
|
|
340
|
+
} else if (typeof doc === 'string') {
|
|
341
|
+
// Si c'est directement une string base64
|
|
342
|
+
restoredDocuments[key] = {
|
|
343
|
+
dir: base64ToDataUri(doc),
|
|
344
|
+
file: doc,
|
|
345
|
+
mrz: '',
|
|
346
|
+
templatePath: '',
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
if (Object.keys(restoredDocuments).length > 0) {
|
|
352
|
+
restoredComponentData[component.id] = restoredDocuments;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
} else if (component.type === 'selfie') {
|
|
356
|
+
// Les selfies peuvent être dans sessionData.selfie_info
|
|
357
|
+
if (data.selfie_info) {
|
|
358
|
+
const selfieData: Record<string, any> = {};
|
|
359
|
+
const selfieInfo: any = data.selfie_info;
|
|
360
|
+
|
|
361
|
+
// Si selfie_info contient une image
|
|
362
|
+
if (selfieInfo.image) {
|
|
363
|
+
const base64Image = selfieInfo.image;
|
|
364
|
+
selfieData['front'] = {
|
|
365
|
+
dir: base64ToDataUri(base64Image),
|
|
366
|
+
file: base64Image,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Si on a plusieurs orientations
|
|
371
|
+
if (selfieInfo.orientations) {
|
|
372
|
+
Object.keys(selfieInfo.orientations).forEach((orientation) => {
|
|
373
|
+
const img = selfieInfo.orientations[orientation];
|
|
374
|
+
if (img) {
|
|
375
|
+
selfieData[orientation] = {
|
|
376
|
+
dir: base64ToDataUri(img),
|
|
377
|
+
file: img,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (Object.keys(selfieData).length > 0) {
|
|
384
|
+
restoredComponentData[component.id] = selfieData;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
} else if (component.type === 'country_selection') {
|
|
388
|
+
// Reconstruire country_selection au format attendu par IDCardCapture / CountrySelectionTemplate (code, documentType, region, regionMapping)
|
|
389
|
+
const meta = data.metadata || data.user_data || data;
|
|
390
|
+
const code = meta.country || meta.country_code || meta.code;
|
|
391
|
+
const documentType = meta.document_type || meta.documentType;
|
|
392
|
+
const region = meta.region;
|
|
393
|
+
if (code && documentType != null) {
|
|
394
|
+
const country = countryData[code];
|
|
395
|
+
const mapping = countryMapping[code as keyof typeof countryMapping];
|
|
396
|
+
if (country) {
|
|
397
|
+
restoredComponentData[component.id] = {
|
|
398
|
+
code,
|
|
399
|
+
...country,
|
|
400
|
+
documentType,
|
|
401
|
+
region: region || undefined,
|
|
402
|
+
regionMapping: mapping || undefined,
|
|
403
|
+
};
|
|
404
|
+
logger.log('Restored country_selection for resume', { code, documentType, region });
|
|
405
|
+
} else {
|
|
406
|
+
restoredComponentData[component.id] = { code, documentType, region: region || undefined, regionMapping: mapping || undefined };
|
|
407
|
+
}
|
|
408
|
+
} else if (data.metadata || data.user_data) {
|
|
409
|
+
restoredComponentData[component.id] = {
|
|
410
|
+
...(data.metadata || {}),
|
|
411
|
+
...(data.user_data || {}),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
} else if (component.type === 'location') {
|
|
415
|
+
// Les données de localisation peuvent être dans metadata
|
|
416
|
+
if (data.metadata?.location || data.user_data?.location) {
|
|
417
|
+
restoredComponentData[component.id] = {
|
|
418
|
+
...(data.metadata?.location || {}),
|
|
419
|
+
...(data.user_data?.location || {}),
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// Fallback: si pas de country_selection restauré mais on a des documents avec templatePath, déduire code/documentType (ex. "templates/national_id_CM_front.jpg")
|
|
426
|
+
const countrySelectionComponent = templateWithReviewAndVerification.components.find(c => c.type === 'country_selection');
|
|
427
|
+
if (countrySelectionComponent && !restoredComponentData[countrySelectionComponent.id] && data.documents) {
|
|
428
|
+
const docs = data.documents as Record<string, { templatePath?: string }>;
|
|
429
|
+
const firstDoc = Object.values(docs).find(d => d?.templatePath);
|
|
430
|
+
const path = firstDoc?.templatePath || '';
|
|
431
|
+
const match = path.match(/([a-z_]+)_([A-Z]{2})(?:_|$)/i) || path.match(/([A-Z]{2})/);
|
|
432
|
+
const code = match ? (match[2] || match[1]).toUpperCase().slice(0, 2) : null;
|
|
433
|
+
const docTypeFromPath = path.match(/(national_id|identity_card|passport|passport_card)/i)?.[1]?.toLowerCase().replace('identity_card', 'national_id') || null;
|
|
434
|
+
if (code && countryData[code]) {
|
|
435
|
+
const documentType = docTypeFromPath || 'national_id';
|
|
436
|
+
const mapping = countryMapping[code as keyof typeof countryMapping];
|
|
437
|
+
const country = countryData[code];
|
|
438
|
+
restoredComponentData[countrySelectionComponent.id] = {
|
|
439
|
+
code,
|
|
440
|
+
...country,
|
|
441
|
+
documentType,
|
|
442
|
+
region: undefined,
|
|
443
|
+
regionMapping: mapping || undefined,
|
|
444
|
+
};
|
|
445
|
+
logger.log('Restored country_selection from document templatePath', { code, documentType, path });
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Mettre à jour l'état avec les données restaurées
|
|
450
|
+
if (Object.keys(restoredComponentData).length > 0) {
|
|
451
|
+
logger.log('Session data restored - components:', Object.keys(restoredComponentData));
|
|
452
|
+
logger.log('Session data restored - sample data:', truncateFields(restoredComponentData));
|
|
453
|
+
setState(prev => ({
|
|
454
|
+
...prev,
|
|
455
|
+
componentData: {
|
|
456
|
+
...prev.componentData,
|
|
457
|
+
...restoredComponentData,
|
|
458
|
+
},
|
|
459
|
+
session: { ...prev.session, sessionDataRestored: true },
|
|
460
|
+
}));
|
|
461
|
+
logger.log('Component data updated in state');
|
|
462
|
+
} else {
|
|
463
|
+
logger.log('No component data to restore from session');
|
|
464
|
+
setState(prev => ({ ...prev, session: { ...prev.session, sessionDataRestored: true } }));
|
|
465
|
+
}
|
|
466
|
+
} else {
|
|
467
|
+
setState(prev => ({ ...prev, session: { ...prev.session, sessionDataRestored: true } }));
|
|
468
|
+
}
|
|
469
|
+
} catch (error) {
|
|
470
|
+
logger.error('Error loading session data:', truncateFields(error));
|
|
471
|
+
setState(prev => ({ ...prev, session: { ...prev.session, sessionDataRestored: true } }));
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
loadSessionData();
|
|
476
|
+
}, [existingSessionId, initialComponentIndex, state.session.isInitialized, state.session.session_id, templateWithReviewAndVerification.components, base64ToDataUri]);
|
|
477
|
+
|
|
478
|
+
// Si l'index pointe vers Review alors que des étapes ne sont pas complétées, ramener à la première étape incomplète
|
|
479
|
+
useEffect(() => {
|
|
480
|
+
const comp = state.template.components[state.currentComponentIndex];
|
|
481
|
+
if (!comp || comp.type !== 'review_submit') return;
|
|
482
|
+
const nonReview = state.template.components.filter(
|
|
483
|
+
c => c.type !== 'review_submit' && c.type !== 'verification_progress'
|
|
484
|
+
);
|
|
485
|
+
if (nonReview.every(c => state.completedComponents.includes(c.id))) return;
|
|
486
|
+
const firstIncomplete = nonReview.find(c => !state.completedComponents.includes(c.id));
|
|
487
|
+
if (!firstIncomplete) return;
|
|
488
|
+
const targetIndex = state.template.components.findIndex(c => c.id === firstIncomplete.id);
|
|
489
|
+
if (targetIndex >= 0 && targetIndex !== state.currentComponentIndex) {
|
|
490
|
+
setState(prev => ({ ...prev, currentComponentIndex: targetIndex }));
|
|
491
|
+
}
|
|
492
|
+
}, [state.currentComponentIndex, state.completedComponents, state.template.components]);
|
|
493
|
+
|
|
157
494
|
const mapComponentTypeToAction = useCallback((type: TemplateComponent['type']): string | null => {
|
|
158
495
|
switch (type) {
|
|
159
496
|
case 'id_card':
|
|
@@ -208,7 +545,7 @@ export const useTemplateKYCFlow = (
|
|
|
208
545
|
if (!action) {
|
|
209
546
|
return base;
|
|
210
547
|
}
|
|
211
|
-
// Document upload expects
|
|
548
|
+
// Document upload expects documents; include country_selection in metadata so resume can restore it
|
|
212
549
|
if (action === 'document_upload') {
|
|
213
550
|
const documents: Record<string, any> = {};
|
|
214
551
|
if (rawData && typeof rawData === 'object') {
|
|
@@ -216,9 +553,18 @@ export const useTemplateKYCFlow = (
|
|
|
216
553
|
documents[key] = rawData[key];
|
|
217
554
|
});
|
|
218
555
|
}
|
|
556
|
+
const countryComp = state.template.components.find(c => c.type === 'country_selection');
|
|
557
|
+
const countryDataForPayload = countryComp ? state.componentData[countryComp.id] : null;
|
|
558
|
+
const metadata: Record<string, unknown> = {};
|
|
559
|
+
if (countryDataForPayload?.code) {
|
|
560
|
+
metadata.country = countryDataForPayload.code;
|
|
561
|
+
metadata.document_type = countryDataForPayload.documentType;
|
|
562
|
+
if (countryDataForPayload.region != null) metadata.region = countryDataForPayload.region;
|
|
563
|
+
}
|
|
219
564
|
return {
|
|
220
565
|
...base,
|
|
221
566
|
documents,
|
|
567
|
+
...(Object.keys(metadata).length > 0 ? { metadata } : {}),
|
|
222
568
|
};
|
|
223
569
|
}
|
|
224
570
|
|
|
@@ -253,17 +599,29 @@ export const useTemplateKYCFlow = (
|
|
|
253
599
|
// console.log('apiKey in useTemplateKYCFlow', apiKey);
|
|
254
600
|
|
|
255
601
|
|
|
256
|
-
// Composant actuel
|
|
602
|
+
// Composant actuel (peut être redirigé si on pointe vers Review alors que le flux n'est pas terminé)
|
|
257
603
|
const currentComponent = useMemo(() => {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
604
|
+
const comp = state.template.components[state.currentComponentIndex] || null;
|
|
605
|
+
if (!comp || comp.type !== 'review_submit') return comp;
|
|
606
|
+
const nonReview = state.template.components.filter(
|
|
607
|
+
c => c.type !== 'review_submit' && c.type !== 'verification_progress'
|
|
608
|
+
);
|
|
609
|
+
const allDone = nonReview.every(c => state.completedComponents.includes(c.id));
|
|
610
|
+
if (allDone) return comp;
|
|
611
|
+
const firstIncomplete = nonReview.find(c => !state.completedComponents.includes(c.id));
|
|
612
|
+
return firstIncomplete || comp;
|
|
613
|
+
}, [state.template.components, state.currentComponentIndex, state.completedComponents, apiKey]);
|
|
614
|
+
|
|
615
|
+
// Progression du flux (basée sur le composant effectivement affiché)
|
|
262
616
|
const progress = useMemo(() => {
|
|
617
|
+
const idx = currentComponent
|
|
618
|
+
? state.template.components.findIndex(c => c.id === currentComponent.id)
|
|
619
|
+
: state.currentComponentIndex;
|
|
620
|
+
const i = idx >= 0 ? idx : state.currentComponentIndex;
|
|
263
621
|
return state.template.components.length > 0
|
|
264
|
-
? ((
|
|
622
|
+
? ((i + 1) / state.template.components.length) * 100
|
|
265
623
|
: 0;
|
|
266
|
-
}, [
|
|
624
|
+
}, [currentComponent, state.template.components, state.currentComponentIndex, apiKey]);
|
|
267
625
|
|
|
268
626
|
// Vérifications de navigation
|
|
269
627
|
const canGoNext = useMemo(() => {
|
|
@@ -301,7 +659,18 @@ export const useTemplateKYCFlow = (
|
|
|
301
659
|
|
|
302
660
|
const token = apiKey ? undefined : await authentification();
|
|
303
661
|
console.log('token in initializeSession', { token, apiKey },);
|
|
304
|
-
|
|
662
|
+
|
|
663
|
+
// Check if we already have a session ID from URL params (passed via state or prop)
|
|
664
|
+
let session;
|
|
665
|
+
const existingSessionId = state.session.session_id; // This might be set from initial props if we add logic for it
|
|
666
|
+
|
|
667
|
+
if (existingSessionId && existingSessionId.length > 0) {
|
|
668
|
+
logger.log('Resuming existing session:', existingSessionId);
|
|
669
|
+
// Verify existence/validity if needed, for now trust the ID and just fetch/use it
|
|
670
|
+
session = { session_id: existingSessionId };
|
|
671
|
+
} else {
|
|
672
|
+
session = await kycService.newSession({ token, apiKey });
|
|
673
|
+
}
|
|
305
674
|
|
|
306
675
|
// Align backend flow from step 0 with initialize_session
|
|
307
676
|
try {
|
|
@@ -345,12 +714,21 @@ export const useTemplateKYCFlow = (
|
|
|
345
714
|
}));
|
|
346
715
|
}
|
|
347
716
|
}, [apiKey]);
|
|
348
|
-
|
|
349
|
-
|
|
717
|
+
|
|
718
|
+
// When user switches device: resume with existingSessionId + initialStep — ensure session is initialized so loadSessionData runs
|
|
719
|
+
useEffect(() => {
|
|
720
|
+
if (!existingSessionId || state.session.isInitialized) return;
|
|
721
|
+
if (state.session.session_id !== existingSessionId) return;
|
|
722
|
+
logger.log('Resuming on new device: initializing session so data can load', { existingSessionId, initialComponentIndex });
|
|
723
|
+
initializeSession();
|
|
724
|
+
}, [existingSessionId, state.session.session_id, state.session.isInitialized, initializeSession]);
|
|
725
|
+
|
|
726
|
+
// Validation d'un composant (dataOverride permet de valider sans attendre la mise à jour du state)
|
|
727
|
+
const validateComponent = useCallback((componentId: number, dataOverride?: any): boolean => {
|
|
350
728
|
const component = state.template.components.find(c => c.id === componentId);
|
|
351
729
|
if (!component) return false;
|
|
352
730
|
|
|
353
|
-
const componentData = state.componentData[componentId];
|
|
731
|
+
const componentData = dataOverride !== undefined ? dataOverride : state.componentData[componentId];
|
|
354
732
|
|
|
355
733
|
switch (component.type) {
|
|
356
734
|
case 'id_card':
|
|
@@ -381,6 +759,20 @@ export const useTemplateKYCFlow = (
|
|
|
381
759
|
// Welcome is valid once user has given consent (componentData is set when they click Get Started)
|
|
382
760
|
return componentData && componentData.consentGiven !== false;
|
|
383
761
|
|
|
762
|
+
case 'email_verification':
|
|
763
|
+
return componentData && componentData.verified === true;
|
|
764
|
+
|
|
765
|
+
case 'phone_verification':
|
|
766
|
+
return componentData && componentData.verified === true;
|
|
767
|
+
|
|
768
|
+
case 'personal_information':
|
|
769
|
+
return componentData && Object.keys(componentData).length > 0;
|
|
770
|
+
|
|
771
|
+
case 'additional_documents':
|
|
772
|
+
// Optional by default in template config, but if required we should check based on config
|
|
773
|
+
// For now, return true or check length if present
|
|
774
|
+
return true;
|
|
775
|
+
|
|
384
776
|
case 'review_submit':
|
|
385
777
|
return true;
|
|
386
778
|
default:
|
|
@@ -406,8 +798,8 @@ export const useTemplateKYCFlow = (
|
|
|
406
798
|
}));
|
|
407
799
|
}, [ensureReviewSubmitStep, ensureVerificationProgressStep, apiKey]),
|
|
408
800
|
|
|
409
|
-
// Passer au composant suivant
|
|
410
|
-
nextComponent: useCallback(async () => {
|
|
801
|
+
// Passer au composant suivant (overrideData = données du step courant si déjà connues, évite un double clic)
|
|
802
|
+
nextComponent: useCallback(async (overrideData?: any) => {
|
|
411
803
|
if (!canGoNext) return;
|
|
412
804
|
|
|
413
805
|
const currentComp = state.template.components[state.currentComponentIndex];
|
|
@@ -423,8 +815,8 @@ export const useTemplateKYCFlow = (
|
|
|
423
815
|
isProcessing: true,
|
|
424
816
|
};
|
|
425
817
|
});
|
|
426
|
-
// Valider
|
|
427
|
-
if (!validateComponent(currentComp.id)) {
|
|
818
|
+
// Valider avec override ou state
|
|
819
|
+
if (!validateComponent(currentComp.id, overrideData)) {
|
|
428
820
|
setState(prev => ({
|
|
429
821
|
...prev,
|
|
430
822
|
isProcessing: false,
|
|
@@ -446,18 +838,16 @@ export const useTemplateKYCFlow = (
|
|
|
446
838
|
}));
|
|
447
839
|
return;
|
|
448
840
|
}
|
|
841
|
+
|
|
449
842
|
if (component.type === 'review_submit') {
|
|
450
|
-
// Move to verification screen and mark verification in progress
|
|
451
843
|
setState(prev => ({
|
|
452
844
|
...prev,
|
|
453
845
|
currentComponentIndex: prev.currentComponentIndex + 1,
|
|
454
846
|
completedComponents: [...prev.completedComponents, currentComp.id],
|
|
847
|
+
componentData: overrideData !== undefined ? { ...prev.componentData, [currentComp.id]: overrideData } : prev.componentData,
|
|
455
848
|
isProcessing: false,
|
|
456
849
|
verification: { status: 'in_progress' },
|
|
457
|
-
errors: {
|
|
458
|
-
...prev.errors,
|
|
459
|
-
[currentComp.id]: ''
|
|
460
|
-
}
|
|
850
|
+
errors: { ...prev.errors, [currentComp.id]: '' }
|
|
461
851
|
}));
|
|
462
852
|
return;
|
|
463
853
|
}
|
|
@@ -488,18 +878,16 @@ export const useTemplateKYCFlow = (
|
|
|
488
878
|
...prev,
|
|
489
879
|
currentComponentIndex: prev.currentComponentIndex + 1,
|
|
490
880
|
completedComponents: [...prev.completedComponents, currentComp.id],
|
|
881
|
+
componentData: overrideData !== undefined ? { ...prev.componentData, [currentComp.id]: overrideData } : prev.componentData,
|
|
491
882
|
isProcessing: false,
|
|
492
|
-
errors: {
|
|
493
|
-
...prev.errors,
|
|
494
|
-
[currentComp.id]: ''
|
|
495
|
-
}
|
|
883
|
+
errors: { ...prev.errors, [currentComp.id]: '' }
|
|
496
884
|
}));
|
|
497
885
|
return;
|
|
498
886
|
}
|
|
499
887
|
|
|
500
888
|
const step = serverStep === 0 && action !== 'initialize_session' ? 1 : serverStep;
|
|
501
|
-
|
|
502
|
-
const payloadData = buildPayloadForComponent(action, component,
|
|
889
|
+
const currentStepData = overrideData !== undefined ? overrideData : state.componentData[currentComp.id];
|
|
890
|
+
const payloadData = buildPayloadForComponent(action, component, currentStepData, templateId, step);
|
|
503
891
|
console.log('payloadData', action, apiKey);
|
|
504
892
|
|
|
505
893
|
await kycService.verificationSession({
|
|
@@ -512,17 +900,14 @@ export const useTemplateKYCFlow = (
|
|
|
512
900
|
apiKey: apiKey ?? "-",
|
|
513
901
|
});
|
|
514
902
|
logger.log("currentComp state", truncateFields(state));
|
|
515
|
-
// Marquer comme complété et passer au suivant
|
|
516
903
|
setState(prev => ({
|
|
517
904
|
...prev,
|
|
518
905
|
currentComponentIndex: prev.currentComponentIndex + 1,
|
|
519
906
|
completedComponents: [...prev.completedComponents, currentComp.id],
|
|
907
|
+
componentData: overrideData !== undefined ? { ...prev.componentData, [currentComp.id]: overrideData } : prev.componentData,
|
|
520
908
|
isProcessing: false,
|
|
521
909
|
...(action === "location_permission" ? { permissionGranted: true } : {}),
|
|
522
|
-
errors: {
|
|
523
|
-
...prev.errors,
|
|
524
|
-
[currentComp.id]: ''
|
|
525
|
-
}
|
|
910
|
+
errors: { ...prev.errors, [currentComp.id]: '' }
|
|
526
911
|
}));
|
|
527
912
|
|
|
528
913
|
} catch (error) {
|
|
@@ -579,8 +964,8 @@ export const useTemplateKYCFlow = (
|
|
|
579
964
|
}, [apiKey]),
|
|
580
965
|
|
|
581
966
|
// Valider un composant
|
|
582
|
-
validateComponent: useCallback((componentId: number) => {
|
|
583
|
-
return validateComponent(componentId);
|
|
967
|
+
validateComponent: useCallback((componentId: number, dataOverride?: any) => {
|
|
968
|
+
return validateComponent(componentId, dataOverride);
|
|
584
969
|
}, [validateComponent, apiKey]),
|
|
585
970
|
// complet verification
|
|
586
971
|
submitVerification: useCallback(async () => {
|
|
@@ -660,5 +1045,7 @@ export const useTemplateKYCFlow = (
|
|
|
660
1045
|
isComplete,
|
|
661
1046
|
getLocalizedText,
|
|
662
1047
|
initializeSession,
|
|
663
|
-
|
|
1048
|
+
env,
|
|
1049
|
+
apiKey,
|
|
1050
|
+
} as UseTemplateReturn;
|
|
664
1051
|
};
|