@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,5 +1,6 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
2
|
import { KYCTemplate, TemplateState, TemplateActions, UseTemplateReturn, VerificationState } from '../types/KYC.types';
|
|
3
|
+
import { KycEnvironment } from '../types/env.types';
|
|
3
4
|
interface TemplateKYCFlowContextType {
|
|
4
5
|
state: TemplateState;
|
|
5
6
|
actions: TemplateActions;
|
|
@@ -14,6 +15,8 @@ interface TemplateKYCFlowContextType {
|
|
|
14
15
|
[key: string]: string;
|
|
15
16
|
}) => string;
|
|
16
17
|
initializeSession: () => Promise<void>;
|
|
18
|
+
env: KycEnvironment;
|
|
19
|
+
apiKey?: string;
|
|
17
20
|
}
|
|
18
21
|
interface TemplateKYCFlowProviderProps {
|
|
19
22
|
children: ReactNode;
|
|
@@ -23,9 +26,23 @@ interface TemplateKYCFlowProviderProps {
|
|
|
23
26
|
onCancel?: () => void;
|
|
24
27
|
initialLanguage?: string;
|
|
25
28
|
apiKey?: string;
|
|
29
|
+
env?: KycEnvironment;
|
|
30
|
+
existingSessionId?: string;
|
|
31
|
+
/** Index in template.components where to resume (0-based). Simple to store in template table. */
|
|
32
|
+
initialComponentIndex?: number;
|
|
33
|
+
/** Pays / type de document depuis l'URL de reprise — évite de dépendre du backend pour afficher les pays. */
|
|
34
|
+
initialCountryResume?: {
|
|
35
|
+
code: string;
|
|
36
|
+
documentType: string;
|
|
37
|
+
region?: string;
|
|
38
|
+
};
|
|
26
39
|
}
|
|
27
40
|
export declare const TemplateKYCFlowProvider: React.FC<TemplateKYCFlowProviderProps>;
|
|
28
41
|
export declare const useTemplateKYCFlowContext: () => TemplateKYCFlowContextType;
|
|
29
|
-
export declare const useTemplateKYCFlow: (template: KYCTemplate, onComplete?: (data: VerificationState) => void, onError?: (error: string) => void, onCancel?: () => void, initialLanguage?: string, apiKey?: string
|
|
42
|
+
export declare const useTemplateKYCFlow: (template: KYCTemplate, onComplete?: (data: VerificationState) => void, onError?: (error: string) => void, onCancel?: () => void, initialLanguage?: string, apiKey?: string, env?: KycEnvironment, existingSessionId?: string, initialComponentIndex?: number, initialCountryResume?: {
|
|
43
|
+
code: string;
|
|
44
|
+
documentType: string;
|
|
45
|
+
region?: string;
|
|
46
|
+
}) => UseTemplateReturn;
|
|
30
47
|
export {};
|
|
31
48
|
//# sourceMappingURL=useTemplateKYCFlow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTemplateKYCFlow.d.ts","sourceRoot":"","sources":["../../src/hooks/useTemplateKYCFlow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAA6D,SAAS,EAAa,MAAM,OAAO,CAAC;AAC/G,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAA6C,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"useTemplateKYCFlow.d.ts","sourceRoot":"","sources":["../../src/hooks/useTemplateKYCFlow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAA6D,SAAS,EAAa,MAAM,OAAO,CAAC;AAC/G,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAA6C,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAClK,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAQpD,UAAU,0BAA0B;IAClC,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,eAAe,CAAC;IACzB,gBAAgB,EAAE,GAAG,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAA,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;IACrF,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,UAAU,4BAA4B;IACpC,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC/C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iGAAiG;IACjG,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,6GAA6G;IAC7G,oBAAoB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAChF;AAED,eAAO,MAAM,uBAAuB,EAAE,KAAK,CAAC,EAAE,CAAC,4BAA4B,CAoB1E,CAAC;AAGF,eAAO,MAAM,yBAAyB,QAAO,0BAM5C,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,UAAU,WAAW,EACrB,aAAa,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,EAC9C,UAAU,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EACjC,WAAW,MAAM,IAAI,EACrB,kBAAiB,MAAa,EAC9B,SAAS,MAAM,EACf,MAAK,cAA6B,EAClC,oBAAoB,MAAM,EAC1B,wBAAwB,MAAM,EAC9B,uBAAuB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAC7E,iBAq8BF,CAAC"}
|
|
@@ -2,9 +2,11 @@ import React, { useState, useCallback, useMemo, createContext, useContext, useEf
|
|
|
2
2
|
import kycService, { authentification, truncateFields } from '../modules/api/KYCService';
|
|
3
3
|
import useI18n from './useI18n';
|
|
4
4
|
import { logger } from '../utils/logger';
|
|
5
|
+
import { countryMapping } from '../config/region_mapping';
|
|
6
|
+
import { countryData } from '../config/countriesData';
|
|
5
7
|
const TemplateKYCFlowContext = createContext(undefined);
|
|
6
|
-
export const TemplateKYCFlowProvider = ({ children, template, onComplete, onError, onCancel, initialLanguage = 'en', apiKey, }) => {
|
|
7
|
-
const hookResult = useTemplateKYCFlow(template, onComplete, onError, onCancel, initialLanguage, apiKey);
|
|
8
|
+
export const TemplateKYCFlowProvider = ({ children, template, onComplete, onError, onCancel, initialLanguage = 'en', apiKey, env = 'PRODUCTION', existingSessionId, initialComponentIndex, initialCountryResume, }) => {
|
|
9
|
+
const hookResult = useTemplateKYCFlow(template, onComplete, onError, onCancel, initialLanguage, apiKey, env, existingSessionId, initialComponentIndex, initialCountryResume);
|
|
8
10
|
return (<TemplateKYCFlowContext.Provider value={hookResult}>
|
|
9
11
|
{children}
|
|
10
12
|
</TemplateKYCFlowContext.Provider>);
|
|
@@ -17,7 +19,7 @@ export const useTemplateKYCFlowContext = () => {
|
|
|
17
19
|
}
|
|
18
20
|
return context;
|
|
19
21
|
};
|
|
20
|
-
export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, initialLanguage = 'en', apiKey) => {
|
|
22
|
+
export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, initialLanguage = 'en', apiKey, env = 'PRODUCTION', existingSessionId, initialComponentIndex, initialCountryResume) => {
|
|
21
23
|
const { setLocale } = useI18n();
|
|
22
24
|
useEffect(() => {
|
|
23
25
|
setLocale(initialLanguage);
|
|
@@ -70,29 +72,336 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
70
72
|
}, [apiKey]);
|
|
71
73
|
const templateWithReview = useMemo(() => ensureReviewSubmitStep(template), [template, ensureReviewSubmitStep, apiKey]);
|
|
72
74
|
const templateWithReviewAndVerification = useMemo(() => ensureVerificationProgressStep(templateWithReview), [templateWithReview, ensureVerificationProgressStep, apiKey]);
|
|
73
|
-
// État initial du flux
|
|
74
|
-
const buildInitialState = () =>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
75
|
+
// État initial du flux (initialComponentIndex = index dans template.components pour reprendre au bon composant)
|
|
76
|
+
const buildInitialState = () => {
|
|
77
|
+
let resumeAtIndex = 0;
|
|
78
|
+
let completedComponents = [];
|
|
79
|
+
let initialComponentData = {};
|
|
80
|
+
logger.log('buildInitialState called', { initialComponentIndex, existingSessionId, initialCountryResume });
|
|
81
|
+
if (initialComponentIndex !== undefined && initialComponentIndex >= 0) {
|
|
82
|
+
const maxIndex = templateWithReviewAndVerification.components.length - 1;
|
|
83
|
+
const requestedIndex = Math.min(initialComponentIndex, maxIndex);
|
|
84
|
+
const requestedComponent = templateWithReviewAndVerification.components[requestedIndex];
|
|
85
|
+
logger.log('Processing initialComponentIndex (component in template)', {
|
|
86
|
+
initialComponentIndex,
|
|
87
|
+
requestedIndex,
|
|
88
|
+
maxIndex,
|
|
89
|
+
componentType: requestedComponent?.type,
|
|
90
|
+
componentId: requestedComponent?.id,
|
|
91
|
+
});
|
|
92
|
+
// Reprendre au composant en cours (id_card, selfie, etc.)
|
|
93
|
+
if (requestedComponent?.type === 'id_card') {
|
|
94
|
+
if (existingSessionId) {
|
|
95
|
+
logger.log('id_card with existing session - staying at id_card');
|
|
96
|
+
resumeAtIndex = requestedIndex;
|
|
97
|
+
if (resumeAtIndex > 0) {
|
|
98
|
+
completedComponents = templateWithReviewAndVerification.components
|
|
99
|
+
.slice(0, resumeAtIndex)
|
|
100
|
+
.map(component => component.id);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const countrySelectionIndex = templateWithReviewAndVerification.components.findIndex(c => c.type === 'country_selection');
|
|
105
|
+
logger.log('id_card without session - going back to country_selection', { countrySelectionIndex });
|
|
106
|
+
if (countrySelectionIndex >= 0) {
|
|
107
|
+
resumeAtIndex = countrySelectionIndex;
|
|
108
|
+
if (countrySelectionIndex > 0) {
|
|
109
|
+
completedComponents = templateWithReviewAndVerification.components
|
|
110
|
+
.slice(0, countrySelectionIndex)
|
|
111
|
+
.map(component => component.id);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
resumeAtIndex = 0;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (requestedComponent?.type === 'review_submit') {
|
|
120
|
+
resumeAtIndex = requestedIndex;
|
|
121
|
+
completedComponents = [];
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
resumeAtIndex = requestedIndex;
|
|
125
|
+
if (resumeAtIndex > 0) {
|
|
126
|
+
completedComponents = templateWithReviewAndVerification.components
|
|
127
|
+
.slice(0, resumeAtIndex)
|
|
128
|
+
.map(component => component.id);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
logger.log('Final initial state (resume at component index)', {
|
|
132
|
+
resumeAtIndex,
|
|
133
|
+
completedComponentsCount: completedComponents.length,
|
|
134
|
+
componentAtResume: templateWithReviewAndVerification.components[resumeAtIndex]?.type,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (initialCountryResume?.code && initialCountryResume?.documentType) {
|
|
138
|
+
const countrySel = templateWithReviewAndVerification.components.find(c => c.type === 'country_selection');
|
|
139
|
+
if (countrySel && countryData[initialCountryResume.code]) {
|
|
140
|
+
initialComponentData[countrySel.id] = {
|
|
141
|
+
code: initialCountryResume.code,
|
|
142
|
+
documentType: initialCountryResume.documentType,
|
|
143
|
+
region: initialCountryResume.region || 'root',
|
|
144
|
+
...countryData[initialCountryResume.code],
|
|
145
|
+
};
|
|
146
|
+
logger.log('Prefilled country_selection from URL', { code: initialCountryResume.code, documentType: initialCountryResume.documentType });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
template: templateWithReviewAndVerification,
|
|
151
|
+
currentComponentIndex: resumeAtIndex,
|
|
152
|
+
completedComponents: completedComponents,
|
|
153
|
+
componentData: initialComponentData,
|
|
154
|
+
errors: {},
|
|
87
155
|
isProcessing: false,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
156
|
+
currentLanguage: initialLanguage,
|
|
157
|
+
showCustomStepper: true,
|
|
158
|
+
session: {
|
|
159
|
+
session_id: existingSessionId || '',
|
|
160
|
+
token: '',
|
|
161
|
+
isInitialized: false,
|
|
162
|
+
isProcessing: false,
|
|
163
|
+
error: null,
|
|
164
|
+
sessionDataRestored: !existingSessionId || Boolean(initialCountryResume?.code && initialCountryResume?.documentType),
|
|
165
|
+
},
|
|
166
|
+
verification: {
|
|
167
|
+
status: 'idle',
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
};
|
|
94
171
|
// État du flux
|
|
95
172
|
const [state, setState] = useState(() => buildInitialState());
|
|
173
|
+
// Fonction utilitaire pour convertir base64 en data URI pour l'affichage
|
|
174
|
+
const base64ToDataUri = useCallback((base64, mimeType = 'image/jpeg') => {
|
|
175
|
+
// Si c'est déjà une data URI, retourner tel quel
|
|
176
|
+
if (base64.startsWith('data:')) {
|
|
177
|
+
return base64;
|
|
178
|
+
}
|
|
179
|
+
// Sinon, créer une data URI
|
|
180
|
+
return `data:${mimeType};base64,${base64}`;
|
|
181
|
+
}, []);
|
|
182
|
+
// Charger les données de session si on reprend une session existante
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
const loadSessionData = async () => {
|
|
185
|
+
// Ne charger que si on a une session existante
|
|
186
|
+
if (!existingSessionId) {
|
|
187
|
+
logger.log('No existingSessionId, skipping data load');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// Si initialComponentIndex n'est pas défini ou est 0, on ne charge pas (début de session)
|
|
191
|
+
if (initialComponentIndex === undefined || initialComponentIndex === 0) {
|
|
192
|
+
logger.log('initialComponentIndex is 0 or undefined, skipping data load');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
// Attendre que la session soit initialisée
|
|
196
|
+
if (!state.session.isInitialized || !state.session.session_id) {
|
|
197
|
+
logger.log('Session not initialized yet, waiting...', {
|
|
198
|
+
isInitialized: state.session.isInitialized,
|
|
199
|
+
sessionId: state.session.session_id
|
|
200
|
+
});
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
logger.log('Loading session data for resume:', { sessionId: existingSessionId, componentIndex: initialComponentIndex });
|
|
205
|
+
const result = await kycService.getVerificationResult(state.session.session_id);
|
|
206
|
+
const sessionData = result[state.session.session_id]?.data;
|
|
207
|
+
if (sessionData) {
|
|
208
|
+
// Restaurer les données des composants depuis la session
|
|
209
|
+
// Utiliser 'as any' car VerificationResult peut avoir des propriétés dynamiques
|
|
210
|
+
const data = sessionData;
|
|
211
|
+
const restoredComponentData = {};
|
|
212
|
+
// Parcourir les composants jusqu'au composant de reprise (inclu) pour restaurer leurs données
|
|
213
|
+
templateWithReviewAndVerification.components
|
|
214
|
+
.slice(0, initialComponentIndex + 1)
|
|
215
|
+
.forEach((component) => {
|
|
216
|
+
// Essayer de restaurer les données selon le type de composant
|
|
217
|
+
if (component.type === 'id_card' || component.type === 'file_upload') {
|
|
218
|
+
// Les documents peuvent être dans différentes structures
|
|
219
|
+
let documents = null;
|
|
220
|
+
// Chercher dans différentes structures possibles
|
|
221
|
+
if (data.documents) {
|
|
222
|
+
documents = data.documents;
|
|
223
|
+
}
|
|
224
|
+
else if (data.user_data?.documents) {
|
|
225
|
+
documents = data.user_data.documents;
|
|
226
|
+
}
|
|
227
|
+
else if (data.document_images) {
|
|
228
|
+
documents = data.document_images;
|
|
229
|
+
}
|
|
230
|
+
if (documents) {
|
|
231
|
+
// Convertir les images base64 en format utilisable
|
|
232
|
+
const restoredDocuments = {};
|
|
233
|
+
Object.keys(documents).forEach((key) => {
|
|
234
|
+
const doc = documents[key];
|
|
235
|
+
if (typeof doc === 'object' && doc !== null) {
|
|
236
|
+
// Si on a un fichier base64, créer une structure avec dir et file
|
|
237
|
+
if (doc.file || doc.base64) {
|
|
238
|
+
const base64Data = doc.file || doc.base64;
|
|
239
|
+
restoredDocuments[key] = {
|
|
240
|
+
dir: base64ToDataUri(base64Data), // Utiliser data URI pour l'affichage
|
|
241
|
+
file: base64Data, // Garder le base64 pour l'envoi
|
|
242
|
+
mrz: doc.mrz || '',
|
|
243
|
+
templatePath: doc.templatePath || '',
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
// Sinon, garder la structure originale
|
|
248
|
+
restoredDocuments[key] = doc;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else if (typeof doc === 'string') {
|
|
252
|
+
// Si c'est directement une string base64
|
|
253
|
+
restoredDocuments[key] = {
|
|
254
|
+
dir: base64ToDataUri(doc),
|
|
255
|
+
file: doc,
|
|
256
|
+
mrz: '',
|
|
257
|
+
templatePath: '',
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
if (Object.keys(restoredDocuments).length > 0) {
|
|
262
|
+
restoredComponentData[component.id] = restoredDocuments;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else if (component.type === 'selfie') {
|
|
267
|
+
// Les selfies peuvent être dans sessionData.selfie_info
|
|
268
|
+
if (data.selfie_info) {
|
|
269
|
+
const selfieData = {};
|
|
270
|
+
const selfieInfo = data.selfie_info;
|
|
271
|
+
// Si selfie_info contient une image
|
|
272
|
+
if (selfieInfo.image) {
|
|
273
|
+
const base64Image = selfieInfo.image;
|
|
274
|
+
selfieData['front'] = {
|
|
275
|
+
dir: base64ToDataUri(base64Image),
|
|
276
|
+
file: base64Image,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// Si on a plusieurs orientations
|
|
280
|
+
if (selfieInfo.orientations) {
|
|
281
|
+
Object.keys(selfieInfo.orientations).forEach((orientation) => {
|
|
282
|
+
const img = selfieInfo.orientations[orientation];
|
|
283
|
+
if (img) {
|
|
284
|
+
selfieData[orientation] = {
|
|
285
|
+
dir: base64ToDataUri(img),
|
|
286
|
+
file: img,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
if (Object.keys(selfieData).length > 0) {
|
|
292
|
+
restoredComponentData[component.id] = selfieData;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else if (component.type === 'country_selection') {
|
|
297
|
+
// Reconstruire country_selection au format attendu par IDCardCapture / CountrySelectionTemplate (code, documentType, region, regionMapping)
|
|
298
|
+
const meta = data.metadata || data.user_data || data;
|
|
299
|
+
const code = meta.country || meta.country_code || meta.code;
|
|
300
|
+
const documentType = meta.document_type || meta.documentType;
|
|
301
|
+
const region = meta.region;
|
|
302
|
+
if (code && documentType != null) {
|
|
303
|
+
const country = countryData[code];
|
|
304
|
+
const mapping = countryMapping[code];
|
|
305
|
+
if (country) {
|
|
306
|
+
restoredComponentData[component.id] = {
|
|
307
|
+
code,
|
|
308
|
+
...country,
|
|
309
|
+
documentType,
|
|
310
|
+
region: region || undefined,
|
|
311
|
+
regionMapping: mapping || undefined,
|
|
312
|
+
};
|
|
313
|
+
logger.log('Restored country_selection for resume', { code, documentType, region });
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
restoredComponentData[component.id] = { code, documentType, region: region || undefined, regionMapping: mapping || undefined };
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
else if (data.metadata || data.user_data) {
|
|
320
|
+
restoredComponentData[component.id] = {
|
|
321
|
+
...(data.metadata || {}),
|
|
322
|
+
...(data.user_data || {}),
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
else if (component.type === 'location') {
|
|
327
|
+
// Les données de localisation peuvent être dans metadata
|
|
328
|
+
if (data.metadata?.location || data.user_data?.location) {
|
|
329
|
+
restoredComponentData[component.id] = {
|
|
330
|
+
...(data.metadata?.location || {}),
|
|
331
|
+
...(data.user_data?.location || {}),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
// 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")
|
|
337
|
+
const countrySelectionComponent = templateWithReviewAndVerification.components.find(c => c.type === 'country_selection');
|
|
338
|
+
if (countrySelectionComponent && !restoredComponentData[countrySelectionComponent.id] && data.documents) {
|
|
339
|
+
const docs = data.documents;
|
|
340
|
+
const firstDoc = Object.values(docs).find(d => d?.templatePath);
|
|
341
|
+
const path = firstDoc?.templatePath || '';
|
|
342
|
+
const match = path.match(/([a-z_]+)_([A-Z]{2})(?:_|$)/i) || path.match(/([A-Z]{2})/);
|
|
343
|
+
const code = match ? (match[2] || match[1]).toUpperCase().slice(0, 2) : null;
|
|
344
|
+
const docTypeFromPath = path.match(/(national_id|identity_card|passport|passport_card)/i)?.[1]?.toLowerCase().replace('identity_card', 'national_id') || null;
|
|
345
|
+
if (code && countryData[code]) {
|
|
346
|
+
const documentType = docTypeFromPath || 'national_id';
|
|
347
|
+
const mapping = countryMapping[code];
|
|
348
|
+
const country = countryData[code];
|
|
349
|
+
restoredComponentData[countrySelectionComponent.id] = {
|
|
350
|
+
code,
|
|
351
|
+
...country,
|
|
352
|
+
documentType,
|
|
353
|
+
region: undefined,
|
|
354
|
+
regionMapping: mapping || undefined,
|
|
355
|
+
};
|
|
356
|
+
logger.log('Restored country_selection from document templatePath', { code, documentType, path });
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// Mettre à jour l'état avec les données restaurées
|
|
360
|
+
if (Object.keys(restoredComponentData).length > 0) {
|
|
361
|
+
logger.log('Session data restored - components:', Object.keys(restoredComponentData));
|
|
362
|
+
logger.log('Session data restored - sample data:', truncateFields(restoredComponentData));
|
|
363
|
+
setState(prev => ({
|
|
364
|
+
...prev,
|
|
365
|
+
componentData: {
|
|
366
|
+
...prev.componentData,
|
|
367
|
+
...restoredComponentData,
|
|
368
|
+
},
|
|
369
|
+
session: { ...prev.session, sessionDataRestored: true },
|
|
370
|
+
}));
|
|
371
|
+
logger.log('Component data updated in state');
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
logger.log('No component data to restore from session');
|
|
375
|
+
setState(prev => ({ ...prev, session: { ...prev.session, sessionDataRestored: true } }));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
setState(prev => ({ ...prev, session: { ...prev.session, sessionDataRestored: true } }));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
logger.error('Error loading session data:', truncateFields(error));
|
|
384
|
+
setState(prev => ({ ...prev, session: { ...prev.session, sessionDataRestored: true } }));
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
loadSessionData();
|
|
388
|
+
}, [existingSessionId, initialComponentIndex, state.session.isInitialized, state.session.session_id, templateWithReviewAndVerification.components, base64ToDataUri]);
|
|
389
|
+
// Si l'index pointe vers Review alors que des étapes ne sont pas complétées, ramener à la première étape incomplète
|
|
390
|
+
useEffect(() => {
|
|
391
|
+
const comp = state.template.components[state.currentComponentIndex];
|
|
392
|
+
if (!comp || comp.type !== 'review_submit')
|
|
393
|
+
return;
|
|
394
|
+
const nonReview = state.template.components.filter(c => c.type !== 'review_submit' && c.type !== 'verification_progress');
|
|
395
|
+
if (nonReview.every(c => state.completedComponents.includes(c.id)))
|
|
396
|
+
return;
|
|
397
|
+
const firstIncomplete = nonReview.find(c => !state.completedComponents.includes(c.id));
|
|
398
|
+
if (!firstIncomplete)
|
|
399
|
+
return;
|
|
400
|
+
const targetIndex = state.template.components.findIndex(c => c.id === firstIncomplete.id);
|
|
401
|
+
if (targetIndex >= 0 && targetIndex !== state.currentComponentIndex) {
|
|
402
|
+
setState(prev => ({ ...prev, currentComponentIndex: targetIndex }));
|
|
403
|
+
}
|
|
404
|
+
}, [state.currentComponentIndex, state.completedComponents, state.template.components]);
|
|
96
405
|
const mapComponentTypeToAction = useCallback((type) => {
|
|
97
406
|
switch (type) {
|
|
98
407
|
case 'id_card':
|
|
@@ -144,7 +453,7 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
144
453
|
if (!action) {
|
|
145
454
|
return base;
|
|
146
455
|
}
|
|
147
|
-
// Document upload expects
|
|
456
|
+
// Document upload expects documents; include country_selection in metadata so resume can restore it
|
|
148
457
|
if (action === 'document_upload') {
|
|
149
458
|
const documents = {};
|
|
150
459
|
if (rawData && typeof rawData === 'object') {
|
|
@@ -152,9 +461,19 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
152
461
|
documents[key] = rawData[key];
|
|
153
462
|
});
|
|
154
463
|
}
|
|
464
|
+
const countryComp = state.template.components.find(c => c.type === 'country_selection');
|
|
465
|
+
const countryDataForPayload = countryComp ? state.componentData[countryComp.id] : null;
|
|
466
|
+
const metadata = {};
|
|
467
|
+
if (countryDataForPayload?.code) {
|
|
468
|
+
metadata.country = countryDataForPayload.code;
|
|
469
|
+
metadata.document_type = countryDataForPayload.documentType;
|
|
470
|
+
if (countryDataForPayload.region != null)
|
|
471
|
+
metadata.region = countryDataForPayload.region;
|
|
472
|
+
}
|
|
155
473
|
return {
|
|
156
474
|
...base,
|
|
157
475
|
documents,
|
|
476
|
+
...(Object.keys(metadata).length > 0 ? { metadata } : {}),
|
|
158
477
|
};
|
|
159
478
|
}
|
|
160
479
|
if (action === 'selfie_capture') {
|
|
@@ -182,16 +501,28 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
182
501
|
}, [state.componentData, apiKey]);
|
|
183
502
|
// Ensure the template contains a final review step
|
|
184
503
|
// console.log('apiKey in useTemplateKYCFlow', apiKey);
|
|
185
|
-
// Composant actuel
|
|
504
|
+
// Composant actuel (peut être redirigé si on pointe vers Review alors que le flux n'est pas terminé)
|
|
186
505
|
const currentComponent = useMemo(() => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
506
|
+
const comp = state.template.components[state.currentComponentIndex] || null;
|
|
507
|
+
if (!comp || comp.type !== 'review_submit')
|
|
508
|
+
return comp;
|
|
509
|
+
const nonReview = state.template.components.filter(c => c.type !== 'review_submit' && c.type !== 'verification_progress');
|
|
510
|
+
const allDone = nonReview.every(c => state.completedComponents.includes(c.id));
|
|
511
|
+
if (allDone)
|
|
512
|
+
return comp;
|
|
513
|
+
const firstIncomplete = nonReview.find(c => !state.completedComponents.includes(c.id));
|
|
514
|
+
return firstIncomplete || comp;
|
|
515
|
+
}, [state.template.components, state.currentComponentIndex, state.completedComponents, apiKey]);
|
|
516
|
+
// Progression du flux (basée sur le composant effectivement affiché)
|
|
190
517
|
const progress = useMemo(() => {
|
|
518
|
+
const idx = currentComponent
|
|
519
|
+
? state.template.components.findIndex(c => c.id === currentComponent.id)
|
|
520
|
+
: state.currentComponentIndex;
|
|
521
|
+
const i = idx >= 0 ? idx : state.currentComponentIndex;
|
|
191
522
|
return state.template.components.length > 0
|
|
192
|
-
? ((
|
|
523
|
+
? ((i + 1) / state.template.components.length) * 100
|
|
193
524
|
: 0;
|
|
194
|
-
}, [
|
|
525
|
+
}, [currentComponent, state.template.components, state.currentComponentIndex, apiKey]);
|
|
195
526
|
// Vérifications de navigation
|
|
196
527
|
const canGoNext = useMemo(() => {
|
|
197
528
|
return state.currentComponentIndex < state.template.components.length - 1;
|
|
@@ -223,7 +554,17 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
223
554
|
logger.log('Initializing session');
|
|
224
555
|
const token = apiKey ? undefined : await authentification();
|
|
225
556
|
console.log('token in initializeSession', { token, apiKey });
|
|
226
|
-
|
|
557
|
+
// Check if we already have a session ID from URL params (passed via state or prop)
|
|
558
|
+
let session;
|
|
559
|
+
const existingSessionId = state.session.session_id; // This might be set from initial props if we add logic for it
|
|
560
|
+
if (existingSessionId && existingSessionId.length > 0) {
|
|
561
|
+
logger.log('Resuming existing session:', existingSessionId);
|
|
562
|
+
// Verify existence/validity if needed, for now trust the ID and just fetch/use it
|
|
563
|
+
session = { session_id: existingSessionId };
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
session = await kycService.newSession({ token, apiKey });
|
|
567
|
+
}
|
|
227
568
|
// Align backend flow from step 0 with initialize_session
|
|
228
569
|
try {
|
|
229
570
|
const templateId = chooseTemplateId(templateWithReviewAndVerification);
|
|
@@ -266,12 +607,21 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
266
607
|
}));
|
|
267
608
|
}
|
|
268
609
|
}, [apiKey]);
|
|
269
|
-
//
|
|
270
|
-
|
|
610
|
+
// When user switches device: resume with existingSessionId + initialStep — ensure session is initialized so loadSessionData runs
|
|
611
|
+
useEffect(() => {
|
|
612
|
+
if (!existingSessionId || state.session.isInitialized)
|
|
613
|
+
return;
|
|
614
|
+
if (state.session.session_id !== existingSessionId)
|
|
615
|
+
return;
|
|
616
|
+
logger.log('Resuming on new device: initializing session so data can load', { existingSessionId, initialComponentIndex });
|
|
617
|
+
initializeSession();
|
|
618
|
+
}, [existingSessionId, state.session.session_id, state.session.isInitialized, initializeSession]);
|
|
619
|
+
// Validation d'un composant (dataOverride permet de valider sans attendre la mise à jour du state)
|
|
620
|
+
const validateComponent = useCallback((componentId, dataOverride) => {
|
|
271
621
|
const component = state.template.components.find(c => c.id === componentId);
|
|
272
622
|
if (!component)
|
|
273
623
|
return false;
|
|
274
|
-
const componentData = state.componentData[componentId];
|
|
624
|
+
const componentData = dataOverride !== undefined ? dataOverride : state.componentData[componentId];
|
|
275
625
|
switch (component.type) {
|
|
276
626
|
case 'id_card':
|
|
277
627
|
// Vérifier si au moins un côté a été capturé
|
|
@@ -294,6 +644,16 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
294
644
|
case 'welcome':
|
|
295
645
|
// Welcome is valid once user has given consent (componentData is set when they click Get Started)
|
|
296
646
|
return componentData && componentData.consentGiven !== false;
|
|
647
|
+
case 'email_verification':
|
|
648
|
+
return componentData && componentData.verified === true;
|
|
649
|
+
case 'phone_verification':
|
|
650
|
+
return componentData && componentData.verified === true;
|
|
651
|
+
case 'personal_information':
|
|
652
|
+
return componentData && Object.keys(componentData).length > 0;
|
|
653
|
+
case 'additional_documents':
|
|
654
|
+
// Optional by default in template config, but if required we should check based on config
|
|
655
|
+
// For now, return true or check length if present
|
|
656
|
+
return true;
|
|
297
657
|
case 'review_submit':
|
|
298
658
|
return true;
|
|
299
659
|
default:
|
|
@@ -317,8 +677,8 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
317
677
|
verification: { status: 'idle', result: undefined },
|
|
318
678
|
}));
|
|
319
679
|
}, [ensureReviewSubmitStep, ensureVerificationProgressStep, apiKey]),
|
|
320
|
-
// Passer au composant suivant
|
|
321
|
-
nextComponent: useCallback(async () => {
|
|
680
|
+
// Passer au composant suivant (overrideData = données du step courant si déjà connues, évite un double clic)
|
|
681
|
+
nextComponent: useCallback(async (overrideData) => {
|
|
322
682
|
if (!canGoNext)
|
|
323
683
|
return;
|
|
324
684
|
const currentComp = state.template.components[state.currentComponentIndex];
|
|
@@ -334,8 +694,8 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
334
694
|
isProcessing: true,
|
|
335
695
|
};
|
|
336
696
|
});
|
|
337
|
-
// Valider
|
|
338
|
-
if (!validateComponent(currentComp.id)) {
|
|
697
|
+
// Valider avec override ou state
|
|
698
|
+
if (!validateComponent(currentComp.id, overrideData)) {
|
|
339
699
|
setState(prev => ({
|
|
340
700
|
...prev,
|
|
341
701
|
isProcessing: false,
|
|
@@ -356,17 +716,14 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
356
716
|
return;
|
|
357
717
|
}
|
|
358
718
|
if (component.type === 'review_submit') {
|
|
359
|
-
// Move to verification screen and mark verification in progress
|
|
360
719
|
setState(prev => ({
|
|
361
720
|
...prev,
|
|
362
721
|
currentComponentIndex: prev.currentComponentIndex + 1,
|
|
363
722
|
completedComponents: [...prev.completedComponents, currentComp.id],
|
|
723
|
+
componentData: overrideData !== undefined ? { ...prev.componentData, [currentComp.id]: overrideData } : prev.componentData,
|
|
364
724
|
isProcessing: false,
|
|
365
725
|
verification: { status: 'in_progress' },
|
|
366
|
-
errors: {
|
|
367
|
-
...prev.errors,
|
|
368
|
-
[currentComp.id]: ''
|
|
369
|
-
}
|
|
726
|
+
errors: { ...prev.errors, [currentComp.id]: '' }
|
|
370
727
|
}));
|
|
371
728
|
return;
|
|
372
729
|
}
|
|
@@ -396,17 +753,15 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
396
753
|
...prev,
|
|
397
754
|
currentComponentIndex: prev.currentComponentIndex + 1,
|
|
398
755
|
completedComponents: [...prev.completedComponents, currentComp.id],
|
|
756
|
+
componentData: overrideData !== undefined ? { ...prev.componentData, [currentComp.id]: overrideData } : prev.componentData,
|
|
399
757
|
isProcessing: false,
|
|
400
|
-
errors: {
|
|
401
|
-
...prev.errors,
|
|
402
|
-
[currentComp.id]: ''
|
|
403
|
-
}
|
|
758
|
+
errors: { ...prev.errors, [currentComp.id]: '' }
|
|
404
759
|
}));
|
|
405
760
|
return;
|
|
406
761
|
}
|
|
407
762
|
const step = serverStep === 0 && action !== 'initialize_session' ? 1 : serverStep;
|
|
408
|
-
|
|
409
|
-
const payloadData = buildPayloadForComponent(action, component,
|
|
763
|
+
const currentStepData = overrideData !== undefined ? overrideData : state.componentData[currentComp.id];
|
|
764
|
+
const payloadData = buildPayloadForComponent(action, component, currentStepData, templateId, step);
|
|
410
765
|
console.log('payloadData', action, apiKey);
|
|
411
766
|
await kycService.verificationSession({
|
|
412
767
|
session_id: state.session.session_id,
|
|
@@ -418,17 +773,14 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
418
773
|
apiKey: apiKey ?? "-",
|
|
419
774
|
});
|
|
420
775
|
logger.log("currentComp state", truncateFields(state));
|
|
421
|
-
// Marquer comme complété et passer au suivant
|
|
422
776
|
setState(prev => ({
|
|
423
777
|
...prev,
|
|
424
778
|
currentComponentIndex: prev.currentComponentIndex + 1,
|
|
425
779
|
completedComponents: [...prev.completedComponents, currentComp.id],
|
|
780
|
+
componentData: overrideData !== undefined ? { ...prev.componentData, [currentComp.id]: overrideData } : prev.componentData,
|
|
426
781
|
isProcessing: false,
|
|
427
782
|
...(action === "location_permission" ? { permissionGranted: true } : {}),
|
|
428
|
-
errors: {
|
|
429
|
-
...prev.errors,
|
|
430
|
-
[currentComp.id]: ''
|
|
431
|
-
}
|
|
783
|
+
errors: { ...prev.errors, [currentComp.id]: '' }
|
|
432
784
|
}));
|
|
433
785
|
}
|
|
434
786
|
catch (error) {
|
|
@@ -478,8 +830,8 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
478
830
|
}));
|
|
479
831
|
}, [apiKey]),
|
|
480
832
|
// Valider un composant
|
|
481
|
-
validateComponent: useCallback((componentId) => {
|
|
482
|
-
return validateComponent(componentId);
|
|
833
|
+
validateComponent: useCallback((componentId, dataOverride) => {
|
|
834
|
+
return validateComponent(componentId, dataOverride);
|
|
483
835
|
}, [validateComponent, apiKey]),
|
|
484
836
|
// complet verification
|
|
485
837
|
submitVerification: useCallback(async () => {
|
|
@@ -551,6 +903,8 @@ export const useTemplateKYCFlow = (template, onComplete, onError, onCancel, init
|
|
|
551
903
|
isComplete,
|
|
552
904
|
getLocalizedText,
|
|
553
905
|
initializeSession,
|
|
906
|
+
env,
|
|
907
|
+
apiKey,
|
|
554
908
|
};
|
|
555
909
|
};
|
|
556
910
|
//# sourceMappingURL=useTemplateKYCFlow.js.map
|