@transfergratis/react-native-sdk 0.1.23 → 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +12 -5
  2. package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
  3. package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
  4. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  5. package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
  6. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +61 -59
  7. package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-transfergratis-react-native-sdk.jar +0 -0
  8. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +12 -5
  9. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  10. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  11. package/android/build/outputs/aar/transfergratis-react-native-sdk-debug.aar +0 -0
  12. package/android/build/outputs/logs/manifest-merger-debug-report.txt +26 -34
  13. package/android/src/main/AndroidManifest.xml +13 -5
  14. package/build/components/EnhancedCameraView.d.ts.map +1 -1
  15. package/build/components/EnhancedCameraView.js +26 -3
  16. package/build/components/EnhancedCameraView.js.map +1 -1
  17. package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
  18. package/build/components/EnhancedCameraView.web.js +21 -0
  19. package/build/components/EnhancedCameraView.web.js.map +1 -1
  20. package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts +12 -0
  21. package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts.map +1 -0
  22. package/build/components/KYCElements/AdditionalDocumentsTemplate.js +283 -0
  23. package/build/components/KYCElements/AdditionalDocumentsTemplate.js.map +1 -0
  24. package/build/components/KYCElements/CameraCapture.d.ts.map +1 -1
  25. package/build/components/KYCElements/CameraCapture.js +4 -3
  26. package/build/components/KYCElements/CameraCapture.js.map +1 -1
  27. package/build/components/KYCElements/CountrySelectionTemplate.d.ts +5 -2
  28. package/build/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
  29. package/build/components/KYCElements/CountrySelectionTemplate.js +360 -101
  30. package/build/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
  31. package/build/components/KYCElements/EmailVerificationTemplate.d.ts +12 -0
  32. package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -0
  33. package/build/components/KYCElements/EmailVerificationTemplate.js +193 -0
  34. package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -0
  35. package/build/components/KYCElements/FileUpload.d.ts.map +1 -1
  36. package/build/components/KYCElements/FileUpload.js +5 -4
  37. package/build/components/KYCElements/FileUpload.js.map +1 -1
  38. package/build/components/KYCElements/FileUploadTemplate.d.ts.map +1 -1
  39. package/build/components/KYCElements/FileUploadTemplate.js +5 -4
  40. package/build/components/KYCElements/FileUploadTemplate.js.map +1 -1
  41. package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  42. package/build/components/KYCElements/IDCardCapture.js +356 -227
  43. package/build/components/KYCElements/IDCardCapture.js.map +1 -1
  44. package/build/components/KYCElements/LocationCaptureTemplate.d.ts.map +1 -1
  45. package/build/components/KYCElements/LocationCaptureTemplate.js +78 -37
  46. package/build/components/KYCElements/LocationCaptureTemplate.js.map +1 -1
  47. package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -0
  48. package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
  49. package/build/components/KYCElements/OrientationVideoCapture.js +5 -4
  50. package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
  51. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -0
  52. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
  53. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js +5 -4
  54. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
  55. package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -0
  56. package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
  57. package/build/components/KYCElements/OrientationVideoCaptureFinal.js +5 -4
  58. package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
  59. package/build/components/KYCElements/PersonalInformationTemplate.d.ts +12 -0
  60. package/build/components/KYCElements/PersonalInformationTemplate.d.ts.map +1 -0
  61. package/build/components/KYCElements/PersonalInformationTemplate.js +120 -0
  62. package/build/components/KYCElements/PersonalInformationTemplate.js.map +1 -0
  63. package/build/components/KYCElements/PhoneVerificationTemplate.d.ts +12 -0
  64. package/build/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -0
  65. package/build/components/KYCElements/PhoneVerificationTemplate.js +185 -0
  66. package/build/components/KYCElements/PhoneVerificationTemplate.js.map +1 -0
  67. package/build/components/KYCElements/SelfieCapture.d.ts.map +1 -1
  68. package/build/components/KYCElements/SelfieCapture.js +4 -3
  69. package/build/components/KYCElements/SelfieCapture.js.map +1 -1
  70. package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
  71. package/build/components/KYCElements/SelfieCaptureTemplate.js +189 -42
  72. package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
  73. package/build/components/KYCElements/WelcomeTemplate.d.ts +12 -0
  74. package/build/components/KYCElements/WelcomeTemplate.d.ts.map +1 -0
  75. package/build/components/KYCElements/WelcomeTemplate.js +243 -0
  76. package/build/components/KYCElements/WelcomeTemplate.js.map +1 -0
  77. package/build/components/TemplateKYCExample.d.ts +8 -2
  78. package/build/components/TemplateKYCExample.d.ts.map +1 -1
  79. package/build/components/TemplateKYCExample.js +10 -97
  80. package/build/components/TemplateKYCExample.js.map +1 -1
  81. package/build/components/TemplateKYCFlowRefactored.d.ts +6 -1
  82. package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
  83. package/build/components/TemplateKYCFlowRefactored.js +108 -11
  84. package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
  85. package/build/components/example/DynamicTemplateExample.d.ts +10 -0
  86. package/build/components/example/DynamicTemplateExample.d.ts.map +1 -0
  87. package/build/components/example/DynamicTemplateExample.js +241 -0
  88. package/build/components/example/DynamicTemplateExample.js.map +1 -0
  89. package/build/config/KYCConfig.d.ts +14 -0
  90. package/build/config/KYCConfig.d.ts.map +1 -0
  91. package/build/config/KYCConfig.js +26 -0
  92. package/build/config/KYCConfig.js.map +1 -0
  93. package/build/config/allowedDomains.d.ts +30 -0
  94. package/build/config/allowedDomains.d.ts.map +1 -0
  95. package/build/config/allowedDomains.js +112 -0
  96. package/build/config/allowedDomains.js.map +1 -0
  97. package/build/hooks/useOrientationVideo.d.ts +2 -1
  98. package/build/hooks/useOrientationVideo.d.ts.map +1 -1
  99. package/build/hooks/useOrientationVideo.js +3 -3
  100. package/build/hooks/useOrientationVideo.js.map +1 -1
  101. package/build/hooks/useTemplateKYCFlow.d.ts +6 -1
  102. package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  103. package/build/hooks/useTemplateKYCFlow.js +317 -34
  104. package/build/hooks/useTemplateKYCFlow.js.map +1 -1
  105. package/build/hooks/useTemplateLoader.d.ts +14 -0
  106. package/build/hooks/useTemplateLoader.d.ts.map +1 -0
  107. package/build/hooks/useTemplateLoader.js +85 -0
  108. package/build/hooks/useTemplateLoader.js.map +1 -0
  109. package/build/i18n/en/index.d.ts +49 -0
  110. package/build/i18n/en/index.d.ts.map +1 -1
  111. package/build/i18n/en/index.js +50 -1
  112. package/build/i18n/en/index.js.map +1 -1
  113. package/build/i18n/fr/index.d.ts +35 -0
  114. package/build/i18n/fr/index.d.ts.map +1 -1
  115. package/build/i18n/fr/index.js +36 -1
  116. package/build/i18n/fr/index.js.map +1 -1
  117. package/build/index.d.ts +6 -0
  118. package/build/index.d.ts.map +1 -1
  119. package/build/index.js +10 -0
  120. package/build/index.js.map +1 -1
  121. package/build/modules/api/CardAuthentification.d.ts +24 -3
  122. package/build/modules/api/CardAuthentification.d.ts.map +1 -1
  123. package/build/modules/api/CardAuthentification.js +69 -10
  124. package/build/modules/api/CardAuthentification.js.map +1 -1
  125. package/build/modules/api/KYCService.d.ts +7 -7
  126. package/build/modules/api/KYCService.d.ts.map +1 -1
  127. package/build/modules/api/KYCService.js +108 -39
  128. package/build/modules/api/KYCService.js.map +1 -1
  129. package/build/modules/api/SelfieVerification.d.ts +3 -1
  130. package/build/modules/api/SelfieVerification.d.ts.map +1 -1
  131. package/build/modules/api/SelfieVerification.js +17 -1
  132. package/build/modules/api/SelfieVerification.js.map +1 -1
  133. package/build/modules/api/TemplateService.d.ts +44 -0
  134. package/build/modules/api/TemplateService.d.ts.map +1 -0
  135. package/build/modules/api/TemplateService.js +145 -0
  136. package/build/modules/api/TemplateService.js.map +1 -0
  137. package/build/types/KYC.types.d.ts +265 -4
  138. package/build/types/KYC.types.d.ts.map +1 -1
  139. package/build/types/KYC.types.js +15 -0
  140. package/build/types/KYC.types.js.map +1 -1
  141. package/build/types/env.types.d.ts +13 -0
  142. package/build/types/env.types.d.ts.map +1 -0
  143. package/build/types/env.types.js +2 -0
  144. package/build/types/env.types.js.map +1 -0
  145. package/build/utils/cropByObb.d.ts +1 -0
  146. package/build/utils/cropByObb.d.ts.map +1 -1
  147. package/build/utils/cropByObb.js +70 -0
  148. package/build/utils/cropByObb.js.map +1 -1
  149. package/build/utils/deviceDetection.d.ts +6 -0
  150. package/build/utils/deviceDetection.d.ts.map +1 -0
  151. package/build/utils/deviceDetection.js +12 -0
  152. package/build/utils/deviceDetection.js.map +1 -0
  153. package/build/utils/platformAlert.d.ts +20 -0
  154. package/build/utils/platformAlert.d.ts.map +1 -0
  155. package/build/utils/platformAlert.js +67 -0
  156. package/build/utils/platformAlert.js.map +1 -0
  157. package/build/utils/template-transformer.d.ts +10 -0
  158. package/build/utils/template-transformer.d.ts.map +1 -0
  159. package/build/utils/template-transformer.js +365 -0
  160. package/build/utils/template-transformer.js.map +1 -0
  161. package/build/web/WebKYCEntry.d.ts.map +1 -1
  162. package/build/web/WebKYCEntry.js +158 -32
  163. package/build/web/WebKYCEntry.js.map +1 -1
  164. package/package.json +1 -1
  165. package/plugin/build/withVisionCamera.js +3 -4
  166. package/plugin/src/withVisionCamera.js +3 -4
  167. package/plugin/src/withVisionCamera.ts +3 -4
  168. package/src/components/EnhancedCameraView.tsx +31 -2
  169. package/src/components/EnhancedCameraView.web.tsx +24 -0
  170. package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
  171. package/src/components/KYCElements/CameraCapture.tsx +4 -3
  172. package/src/components/KYCElements/CountrySelectionTemplate.tsx +410 -113
  173. package/src/components/KYCElements/EmailVerificationTemplate.tsx +264 -0
  174. package/src/components/KYCElements/FileUpload.tsx +5 -4
  175. package/src/components/KYCElements/FileUploadTemplate.tsx +5 -4
  176. package/src/components/KYCElements/IDCardCapture.tsx +397 -254
  177. package/src/components/KYCElements/LocationCaptureTemplate.tsx +95 -44
  178. package/src/components/KYCElements/OrientationVideoCapture.tsx +6 -3
  179. package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +6 -3
  180. package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +6 -3
  181. package/src/components/KYCElements/PersonalInformationTemplate.tsx +158 -0
  182. package/src/components/KYCElements/PhoneVerificationTemplate.tsx +253 -0
  183. package/src/components/KYCElements/SelfieCapture.tsx +4 -3
  184. package/src/components/KYCElements/SelfieCaptureTemplate.tsx +201 -44
  185. package/src/components/KYCElements/WelcomeTemplate.tsx +289 -0
  186. package/src/components/TemplateKYCExample.tsx +37 -108
  187. package/src/components/TemplateKYCFlowRefactored.tsx +148 -12
  188. package/src/components/example/DynamicTemplateExample.tsx +289 -0
  189. package/src/config/KYCConfig.ts +34 -0
  190. package/src/config/allowedDomains.ts +133 -0
  191. package/src/hooks/useOrientationVideo.ts +5 -4
  192. package/src/hooks/useTemplateKYCFlow.tsx +347 -32
  193. package/src/hooks/useTemplateLoader.ts +102 -0
  194. package/src/i18n/en/index.ts +53 -2
  195. package/src/i18n/fr/index.ts +37 -1
  196. package/src/index.ts +14 -0
  197. package/src/modules/api/CardAuthentification.ts +76 -11
  198. package/src/modules/api/KYCService.ts +129 -45
  199. package/src/modules/api/SelfieVerification.ts +25 -3
  200. package/src/modules/api/TemplateService.ts +167 -0
  201. package/src/types/KYC.types.ts +331 -3
  202. package/src/types/env.types.ts +13 -0
  203. package/src/utils/cropByObb.ts +83 -3
  204. package/src/utils/deviceDetection.ts +11 -0
  205. package/src/utils/platformAlert.ts +86 -0
  206. package/src/utils/template-transformer.ts +445 -0
  207. package/src/web/WebKYCEntry.tsx +199 -50
@@ -6,6 +6,7 @@ import {
6
6
  OrientationVideoResult,
7
7
  OrientationType
8
8
  } from '../types/KYC.types';
9
+ import { KycEnvironment } from '../types/env.types';
9
10
  import kycService from '../modules/api/KYCService';
10
11
 
11
12
  export interface UseOrientationVideoReturn {
@@ -15,8 +16,8 @@ export interface UseOrientationVideoReturn {
15
16
  }
16
17
 
17
18
  export const useOrientationVideo = (
18
-
19
- config?: Partial<OrientationVideoConfig>
19
+ config?: Partial<OrientationVideoConfig>,
20
+ env: KycEnvironment = 'PRODUCTION'
20
21
  ): UseOrientationVideoReturn => {
21
22
  const defaultConfig: OrientationVideoConfig = {
22
23
  duration: 10,
@@ -66,7 +67,7 @@ export const useOrientationVideo = (
66
67
  setState(prev => ({ ...prev, isProcessing: true, error: null }));
67
68
 
68
69
  try {
69
- const result = await kycService.processOrientationVideo(state.recordedVideo);
70
+ const result = await kycService.processOrientationVideo(state.recordedVideo, env);
70
71
 
71
72
  if (result.success && result.data) {
72
73
  setState(prev => ({
@@ -93,7 +94,7 @@ export const useOrientationVideo = (
93
94
  }));
94
95
  throw error;
95
96
  }
96
- }, [state.recordedVideo, state.isProcessing, kycService]);
97
+ }, [state.recordedVideo, state.isProcessing, env]);
97
98
 
98
99
  const retake = useCallback(() => {
99
100
  if (state.retakeCount >= finalConfig.maxRetakes) {
@@ -1,5 +1,6 @@
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';
@@ -15,6 +16,7 @@ interface TemplateKYCFlowContextType {
15
16
  isComplete: boolean;
16
17
  getLocalizedText: (text: { en: string; fr: string;[key: string]: string }) => string;
17
18
  initializeSession: () => Promise<void>;
19
+ env: KycEnvironment;
18
20
  }
19
21
 
20
22
  const TemplateKYCFlowContext = createContext<TemplateKYCFlowContextType | undefined>(undefined);
@@ -28,6 +30,9 @@ interface TemplateKYCFlowProviderProps {
28
30
  onCancel?: () => void;
29
31
  initialLanguage?: string;
30
32
  apiKey?: string;
33
+ env?: KycEnvironment;
34
+ existingSessionId?: string;
35
+ initialStep?: number;
31
36
  }
32
37
 
33
38
  export const TemplateKYCFlowProvider: React.FC<TemplateKYCFlowProviderProps> = ({
@@ -38,8 +43,10 @@ export const TemplateKYCFlowProvider: React.FC<TemplateKYCFlowProviderProps> = (
38
43
  onCancel,
39
44
  initialLanguage = 'en',
40
45
  apiKey,
46
+ env = 'PRODUCTION',
47
+ existingSessionId,
41
48
  }) => {
42
- const hookResult = useTemplateKYCFlow(template, onComplete, onError, onCancel, initialLanguage, apiKey);
49
+ const hookResult = useTemplateKYCFlow(template, onComplete, onError, onCancel, initialLanguage, apiKey, env, existingSessionId);
43
50
 
44
51
  return (
45
52
  <TemplateKYCFlowContext.Provider value={hookResult}>
@@ -64,6 +71,9 @@ export const useTemplateKYCFlow = (
64
71
  onCancel?: () => void,
65
72
  initialLanguage: string = 'en',
66
73
  apiKey?: string,
74
+ env: KycEnvironment = 'PRODUCTION',
75
+ existingSessionId?: string,
76
+ initialStep?: number,
67
77
  ): UseTemplateReturn => {
68
78
 
69
79
  const { setLocale } = useI18n();
@@ -131,29 +141,286 @@ export const useTemplateKYCFlow = (
131
141
  const templateWithReviewAndVerification = useMemo(() => ensureVerificationProgressStep(templateWithReview), [templateWithReview, ensureVerificationProgressStep, apiKey]);
132
142
 
133
143
  // État initial du flux
134
- const buildInitialState = (): TemplateState => ({
135
- template: templateWithReviewAndVerification,
136
- currentComponentIndex: 0,
137
- completedComponents: [],
138
- componentData: {},
139
- errors: {},
140
- isProcessing: false,
141
- currentLanguage: initialLanguage,
142
- showCustomStepper: true,
143
- session: {
144
- session_id: '',
145
- token: '',
146
- isInitialized: false,
144
+ const buildInitialState = (): TemplateState => {
145
+ // Valider initialStep pour s'assurer qu'il est dans les limites du template
146
+ let validInitialStep = 0;
147
+ let completedComponents: number[] = [];
148
+
149
+ logger.log('buildInitialState called', { initialStep, existingSessionId });
150
+
151
+ if (initialStep !== undefined && initialStep >= 0) {
152
+ const maxIndex = templateWithReviewAndVerification.components.length - 1;
153
+ const requestedStep = Math.min(initialStep, maxIndex);
154
+ const requestedComponent = templateWithReviewAndVerification.components[requestedStep];
155
+
156
+ logger.log('Processing initialStep', {
157
+ initialStep,
158
+ requestedStep,
159
+ maxIndex,
160
+ componentType: requestedComponent?.type,
161
+ componentId: requestedComponent?.id
162
+ });
163
+
164
+ // Si on reprend à l'étape id_card, on peut rester à id_card si on a une session existante
165
+ // car les données de country_selection peuvent être chargées depuis la session
166
+ if (requestedComponent?.type === 'id_card') {
167
+ // Si on a une session existante, on peut rester à id_card et charger les données
168
+ if (existingSessionId) {
169
+ logger.log('id_card with existing session - staying at id_card');
170
+ validInitialStep = requestedStep;
171
+ // Marquer les composants précédents comme complétés
172
+ if (validInitialStep > 0) {
173
+ completedComponents = templateWithReviewAndVerification.components
174
+ .slice(0, validInitialStep)
175
+ .map(component => component.id);
176
+ }
177
+ } else {
178
+ // Si pas de session, revenir à country_selection pour refaire le choix
179
+ const countrySelectionIndex = templateWithReviewAndVerification.components.findIndex(
180
+ c => c.type === 'country_selection'
181
+ );
182
+
183
+ logger.log('id_card without session - going back to country_selection', { countrySelectionIndex });
184
+
185
+ if (countrySelectionIndex >= 0) {
186
+ validInitialStep = countrySelectionIndex;
187
+ // Marquer les composants avant country_selection comme complétés
188
+ if (countrySelectionIndex > 0) {
189
+ completedComponents = templateWithReviewAndVerification.components
190
+ .slice(0, countrySelectionIndex)
191
+ .map(component => component.id);
192
+ }
193
+ } else {
194
+ // Si pas de country_selection, commencer au début
195
+ validInitialStep = 0;
196
+ }
197
+ }
198
+ } else if (requestedComponent?.type === 'review_submit') {
199
+ // Si on reprend au review_submit, on ne marque pas les composants précédents
200
+ // pour permettre à l'utilisateur de revenir en arrière et vérifier/modifier les données
201
+ validInitialStep = requestedStep;
202
+ // Ne pas marquer les composants précédents comme complétés
203
+ completedComponents = [];
204
+ } else {
205
+ // Pour les autres composants (selfie, etc.), commencer directement à l'étape demandée
206
+ validInitialStep = requestedStep;
207
+
208
+ // Marquer tous les composants précédents comme complétés
209
+ // Cela permet à l'utilisateur de continuer sans refaire les étapes précédentes
210
+ if (validInitialStep > 0) {
211
+ completedComponents = templateWithReviewAndVerification.components
212
+ .slice(0, validInitialStep)
213
+ .map(component => component.id);
214
+ }
215
+ }
216
+
217
+ logger.log('Final initial state', {
218
+ validInitialStep,
219
+ completedComponentsCount: completedComponents.length,
220
+ componentAtStep: templateWithReviewAndVerification.components[validInitialStep]?.type
221
+ });
222
+ }
223
+
224
+ return {
225
+ template: templateWithReviewAndVerification,
226
+ currentComponentIndex: validInitialStep,
227
+ completedComponents: completedComponents,
228
+ componentData: {},
229
+ errors: {},
147
230
  isProcessing: false,
148
- error: null,
149
- },
150
- verification: {
151
- status: 'idle',
152
- },
153
- });
231
+ currentLanguage: initialLanguage,
232
+ showCustomStepper: true,
233
+ session: {
234
+ session_id: existingSessionId || '',
235
+ token: '',
236
+ isInitialized: false,
237
+ isProcessing: false,
238
+ error: null,
239
+ },
240
+ verification: {
241
+ status: 'idle',
242
+ },
243
+ };
244
+ };
154
245
 
155
246
  // État du flux
156
247
  const [state, setState] = useState<TemplateState>(() => buildInitialState());
248
+
249
+ // Fonction utilitaire pour convertir base64 en data URI pour l'affichage
250
+ const base64ToDataUri = useCallback((base64: string, mimeType: string = 'image/jpeg'): string => {
251
+ // Si c'est déjà une data URI, retourner tel quel
252
+ if (base64.startsWith('data:')) {
253
+ return base64;
254
+ }
255
+ // Sinon, créer une data URI
256
+ return `data:${mimeType};base64,${base64}`;
257
+ }, []);
258
+
259
+ // Charger les données de session si on reprend une session existante
260
+ useEffect(() => {
261
+ const loadSessionData = async () => {
262
+ // Ne charger que si on a une session existante
263
+ if (!existingSessionId) {
264
+ logger.log('No existingSessionId, skipping data load');
265
+ return;
266
+ }
267
+
268
+ // Si initialStep n'est pas défini ou est 0, on ne charge pas (début de session)
269
+ if (initialStep === undefined || initialStep === 0) {
270
+ logger.log('initialStep is 0 or undefined, skipping data load');
271
+ return;
272
+ }
273
+
274
+ // Attendre que la session soit initialisée
275
+ if (!state.session.isInitialized || !state.session.session_id) {
276
+ logger.log('Session not initialized yet, waiting...', {
277
+ isInitialized: state.session.isInitialized,
278
+ sessionId: state.session.session_id
279
+ });
280
+ return;
281
+ }
282
+
283
+ try {
284
+ logger.log('Loading session data for resume:', { sessionId: existingSessionId, step: initialStep });
285
+ const result = await kycService.getVerificationResult(state.session.session_id);
286
+ const sessionData = result[state.session.session_id]?.data;
287
+
288
+ if (sessionData) {
289
+ // Restaurer les données des composants depuis la session
290
+ // Utiliser 'as any' car VerificationResult peut avoir des propriétés dynamiques
291
+ const data: any = sessionData;
292
+ const restoredComponentData: Record<number, any> = {};
293
+
294
+ // Parcourir les composants jusqu'à l'étape initiale (incluse) pour restaurer leurs données
295
+ // Utiliser initialStep + 1 pour inclure le composant à l'étape initialStep
296
+ templateWithReviewAndVerification.components
297
+ .slice(0, initialStep + 1)
298
+ .forEach((component) => {
299
+ // Essayer de restaurer les données selon le type de composant
300
+ if (component.type === 'id_card' || component.type === 'file_upload') {
301
+ // Les documents peuvent être dans différentes structures
302
+ let documents: any = null;
303
+
304
+ // Chercher dans différentes structures possibles
305
+ if (data.documents) {
306
+ documents = data.documents;
307
+ } else if (data.user_data?.documents) {
308
+ documents = data.user_data.documents;
309
+ } else if (data.document_images) {
310
+ documents = data.document_images;
311
+ }
312
+
313
+ if (documents) {
314
+ // Convertir les images base64 en format utilisable
315
+ const restoredDocuments: Record<string, any> = {};
316
+
317
+ Object.keys(documents).forEach((key) => {
318
+ const doc = documents[key];
319
+ if (typeof doc === 'object' && doc !== null) {
320
+ // Si on a un fichier base64, créer une structure avec dir et file
321
+ if (doc.file || doc.base64) {
322
+ const base64Data = doc.file || doc.base64;
323
+ restoredDocuments[key] = {
324
+ dir: base64ToDataUri(base64Data), // Utiliser data URI pour l'affichage
325
+ file: base64Data, // Garder le base64 pour l'envoi
326
+ mrz: doc.mrz || '',
327
+ templatePath: doc.templatePath || '',
328
+ };
329
+ } else {
330
+ // Sinon, garder la structure originale
331
+ restoredDocuments[key] = doc;
332
+ }
333
+ } else if (typeof doc === 'string') {
334
+ // Si c'est directement une string base64
335
+ restoredDocuments[key] = {
336
+ dir: base64ToDataUri(doc),
337
+ file: doc,
338
+ mrz: '',
339
+ templatePath: '',
340
+ };
341
+ }
342
+ });
343
+
344
+ if (Object.keys(restoredDocuments).length > 0) {
345
+ restoredComponentData[component.id] = restoredDocuments;
346
+ }
347
+ }
348
+ } else if (component.type === 'selfie') {
349
+ // Les selfies peuvent être dans sessionData.selfie_info
350
+ if (data.selfie_info) {
351
+ const selfieData: Record<string, any> = {};
352
+ const selfieInfo: any = data.selfie_info;
353
+
354
+ // Si selfie_info contient une image
355
+ if (selfieInfo.image) {
356
+ const base64Image = selfieInfo.image;
357
+ selfieData['front'] = {
358
+ dir: base64ToDataUri(base64Image),
359
+ file: base64Image,
360
+ };
361
+ }
362
+
363
+ // Si on a plusieurs orientations
364
+ if (selfieInfo.orientations) {
365
+ Object.keys(selfieInfo.orientations).forEach((orientation) => {
366
+ const img = selfieInfo.orientations[orientation];
367
+ if (img) {
368
+ selfieData[orientation] = {
369
+ dir: base64ToDataUri(img),
370
+ file: img,
371
+ };
372
+ }
373
+ });
374
+ }
375
+
376
+ if (Object.keys(selfieData).length > 0) {
377
+ restoredComponentData[component.id] = selfieData;
378
+ }
379
+ }
380
+ } else if (component.type === 'country_selection') {
381
+ // Les données de sélection de pays peuvent être dans metadata
382
+ if (data.metadata || data.user_data) {
383
+ restoredComponentData[component.id] = {
384
+ ...(data.metadata || {}),
385
+ ...(data.user_data || {}),
386
+ };
387
+ }
388
+ } else if (component.type === 'location') {
389
+ // Les données de localisation peuvent être dans metadata
390
+ if (data.metadata?.location || data.user_data?.location) {
391
+ restoredComponentData[component.id] = {
392
+ ...(data.metadata?.location || {}),
393
+ ...(data.user_data?.location || {}),
394
+ };
395
+ }
396
+ }
397
+ });
398
+
399
+ // Mettre à jour l'état avec les données restaurées
400
+ if (Object.keys(restoredComponentData).length > 0) {
401
+ logger.log('Session data restored - components:', Object.keys(restoredComponentData));
402
+ logger.log('Session data restored - sample data:', truncateFields(restoredComponentData));
403
+ setState(prev => ({
404
+ ...prev,
405
+ componentData: {
406
+ ...prev.componentData,
407
+ ...restoredComponentData,
408
+ },
409
+ }));
410
+ logger.log('Component data updated in state');
411
+ } else {
412
+ logger.log('No component data to restore from session');
413
+ }
414
+ }
415
+ } catch (error) {
416
+ logger.error('Error loading session data:', truncateFields(error));
417
+ // Ne pas bloquer le flux si le chargement échoue
418
+ }
419
+ };
420
+
421
+ loadSessionData();
422
+ }, [existingSessionId, initialStep, state.session.isInitialized, state.session.session_id, templateWithReviewAndVerification.components, base64ToDataUri]);
423
+
157
424
  const mapComponentTypeToAction = useCallback((type: TemplateComponent['type']): string | null => {
158
425
  switch (type) {
159
426
  case 'id_card':
@@ -168,6 +435,9 @@ export const useTemplateKYCFlow = (
168
435
  case 'country_selection':
169
436
  // No direct backend action; pack into metadata of next actionable step
170
437
  return null;
438
+ case 'welcome':
439
+ // UI-only step, no backend action needed
440
+ return null;
171
441
  case 'initialization':
172
442
  return 'initialize_session';
173
443
  case 'verification_progress':
@@ -201,7 +471,7 @@ export const useTemplateKYCFlow = (
201
471
  const buildPayloadForComponent = useCallback((action: string | null, component: TemplateComponent, rawData: any, templateId: string, step: number) => {
202
472
  console.log('apiKey in buildPayloadForComponent', apiKey);
203
473
 
204
- const base = { template_id: null, step: component.order, permissionGranted: true } as any;
474
+ const base = { template_id: templateId || null, templateId: templateId || null, step: component.order, permissionGranted: true } as any;
205
475
  if (!action) {
206
476
  return base;
207
477
  }
@@ -230,9 +500,12 @@ export const useTemplateKYCFlow = (
230
500
  const idCardID = Object.keys(state.componentData).find((c: string) => c === "1");
231
501
  if (idCardID) {
232
502
  const _idCardData = state.componentData[idCardID];
233
- return { ...base, documents, country: _idCardData?.country || '', documentType: _idCardData?.documentType as GovernmentDocumentType || 'identity_card' };
503
+ const documentType = _idCardData?.documentType;
504
+ // Map national_id to identity_card for selfie capture
505
+ const mappedDocumentType = documentType === 'national_id' ? 'identity_card' : (documentType as GovernmentDocumentType || 'identity_card');
506
+ return { ...base, documents, country: _idCardData?.country || '', documentType: mappedDocumentType };
234
507
  }
235
- // return { ...base, documents };
508
+ return { ...base, documents };
236
509
  }
237
510
 
238
511
  if (action === 'location_permission') {
@@ -295,7 +568,18 @@ export const useTemplateKYCFlow = (
295
568
 
296
569
  const token = apiKey ? undefined : await authentification();
297
570
  console.log('token in initializeSession', { token, apiKey },);
298
- const session = await kycService.newSession({token,apiKey});
571
+
572
+ // Check if we already have a session ID from URL params (passed via state or prop)
573
+ let session;
574
+ const existingSessionId = state.session.session_id; // This might be set from initial props if we add logic for it
575
+
576
+ if (existingSessionId && existingSessionId.length > 0) {
577
+ logger.log('Resuming existing session:', existingSessionId);
578
+ // Verify existence/validity if needed, for now trust the ID and just fetch/use it
579
+ session = { session_id: existingSessionId };
580
+ } else {
581
+ session = await kycService.newSession({ token, apiKey });
582
+ }
299
583
 
300
584
  // Align backend flow from step 0 with initialize_session
301
585
  try {
@@ -371,6 +655,24 @@ export const useTemplateKYCFlow = (
371
655
 
372
656
  return componentData && componentData.code && componentData.regionMapping;
373
657
 
658
+ case 'welcome':
659
+ // Welcome is valid once user has given consent (componentData is set when they click Get Started)
660
+ return componentData && componentData.consentGiven !== false;
661
+
662
+ case 'email_verification':
663
+ return componentData && componentData.verified === true;
664
+
665
+ case 'phone_verification':
666
+ return componentData && componentData.verified === true;
667
+
668
+ case 'personal_information':
669
+ return componentData && Object.keys(componentData).length > 0;
670
+
671
+ case 'additional_documents':
672
+ // Optional by default in template config, but if required we should check based on config
673
+ // For now, return true or check length if present
674
+ return true;
675
+
374
676
  case 'review_submit':
375
677
  return true;
376
678
  default:
@@ -403,10 +705,16 @@ export const useTemplateKYCFlow = (
403
705
  const currentComp = state.template.components[state.currentComponentIndex];
404
706
  if (!currentComp) return;
405
707
 
406
- setState(prev => ({
407
- ...prev,
408
- isProcessing: true,
409
- }));
708
+ // Prevent multiple simultaneous calls
709
+ setState(prev => {
710
+ if (prev.isProcessing) {
711
+ return prev;
712
+ }
713
+ return {
714
+ ...prev,
715
+ isProcessing: true,
716
+ };
717
+ });
410
718
  // Valider le composant actuel
411
719
  if (!validateComponent(currentComp.id)) {
412
720
  setState(prev => ({
@@ -423,7 +731,13 @@ export const useTemplateKYCFlow = (
423
731
 
424
732
  try {
425
733
  const component = state.template.components.find(c => c.id === currentComp.id);
426
- if (!component) return;
734
+ if (!component) {
735
+ setState(prev => ({
736
+ ...prev,
737
+ isProcessing: false,
738
+ }));
739
+ return;
740
+ }
427
741
  if (component.type === 'review_submit') {
428
742
  // Move to verification screen and mark verification in progress
429
743
  setState(prev => ({
@@ -484,7 +798,7 @@ export const useTemplateKYCFlow = (
484
798
  session_id: state.session.session_id,
485
799
  step: step,
486
800
  data: payloadData,
487
- templateId: null,
801
+ templateId: templateId,
488
802
  token: state.session.token,
489
803
  action: action,
490
804
  apiKey: apiKey ?? "-",
@@ -504,7 +818,7 @@ export const useTemplateKYCFlow = (
504
818
  }));
505
819
 
506
820
  } catch (error) {
507
- // console.error('Error validating component:', error);
821
+ logger.error('Error in nextComponent:', error);
508
822
  setState(prev => ({
509
823
  ...prev,
510
824
  isProcessing: false,
@@ -515,7 +829,7 @@ export const useTemplateKYCFlow = (
515
829
  }));
516
830
  }
517
831
 
518
- }, [canGoNext, state.currentComponentIndex, state.template.components, validateComponent, apiKey, state.session.session_id, state.session.token]),
832
+ }, [canGoNext, state.currentComponentIndex, state.template.components, validateComponent, apiKey, state.session.session_id, state.session.token, buildPayloadForComponent, mapComponentTypeToAction, chooseTemplateId, state.currentLanguage]),
519
833
 
520
834
  // Retourner au composant précédent
521
835
  previousComponent: useCallback(() => {
@@ -638,5 +952,6 @@ export const useTemplateKYCFlow = (
638
952
  isComplete,
639
953
  getLocalizedText,
640
954
  initializeSession,
955
+ env,
641
956
  };
642
957
  };
@@ -0,0 +1,102 @@
1
+ import { useState, useCallback, useRef } from 'react';
2
+ import { KYCTemplate } from '../types/KYC.types';
3
+ import templateService from '../modules/api/TemplateService';
4
+ import { transformBackendTemplateToSDK, validateTransformedTemplate } from '../utils/template-transformer';
5
+ import { logger } from '../utils/logger';
6
+ import { authentification } from '../modules/api/KYCService';
7
+
8
+ export interface UseTemplateLoaderReturn {
9
+ template: KYCTemplate | null;
10
+ isLoading: boolean;
11
+ error: string | null;
12
+ loadTemplate: (templateId: string, apiKey?: string) => Promise<void>;
13
+ refresh: () => void;
14
+ clearError: () => void;
15
+ }
16
+
17
+ /**
18
+ * Hook to load and transform templates from the backend API
19
+ */
20
+ export function useTemplateLoader(): UseTemplateLoaderReturn {
21
+ const [template, setTemplate] = useState<KYCTemplate | null>(null);
22
+ const [isLoading, setIsLoading] = useState<boolean>(false);
23
+ const [error, setError] = useState<string | null>(null);
24
+ const currentTemplateIdRef = useRef<string | null>(null);
25
+ const currentApiKeyRef = useRef<string | undefined>(undefined);
26
+
27
+ /**
28
+ * Load a template by ID
29
+ */
30
+ const loadTemplate = useCallback(async (templateId: string, apiKey?: string) => {
31
+ // Reset state
32
+ setError(null);
33
+ setIsLoading(true);
34
+ currentTemplateIdRef.current = templateId;
35
+ currentApiKeyRef.current = apiKey;
36
+
37
+ try {
38
+ logger.log(`Loading template: ${templateId}`);
39
+
40
+ // Get token if no API key provided
41
+ let token: string | undefined;
42
+ if (!apiKey) {
43
+ try {
44
+ token = await authentification();
45
+ } catch (authError) {
46
+ logger.error('Authentication failed:', authError);
47
+ throw new Error('Failed to authenticate. Please provide a valid API key.');
48
+ }
49
+ }
50
+
51
+ // Fetch template from backend
52
+ const backendTemplate = await templateService.fetchTemplate(templateId, apiKey, token);
53
+
54
+ // Transform to SDK format
55
+ const transformedTemplate = transformBackendTemplateToSDK(backendTemplate);
56
+
57
+ // Validate transformed template
58
+ if (!validateTransformedTemplate(transformedTemplate)) {
59
+ throw new Error('Transformed template validation failed');
60
+ }
61
+
62
+ // Set the template
63
+ setTemplate(transformedTemplate);
64
+ logger.log(`Template loaded successfully: ${templateId}`);
65
+ } catch (err: any) {
66
+ const errorMessage = err.message || 'Failed to load template';
67
+ logger.error(`Error loading template ${templateId}:`, errorMessage);
68
+ setError(errorMessage);
69
+ setTemplate(null);
70
+ } finally {
71
+ setIsLoading(false);
72
+ }
73
+ }, []);
74
+
75
+ /**
76
+ * Refresh the current template
77
+ */
78
+ const refresh = useCallback(() => {
79
+ if (currentTemplateIdRef.current) {
80
+ // Clear cache for this template
81
+ templateService.clearCache(currentTemplateIdRef.current);
82
+ // Reload template
83
+ loadTemplate(currentTemplateIdRef.current, currentApiKeyRef.current);
84
+ }
85
+ }, [loadTemplate]);
86
+
87
+ /**
88
+ * Clear error state
89
+ */
90
+ const clearError = useCallback(() => {
91
+ setError(null);
92
+ }, []);
93
+
94
+ return {
95
+ template,
96
+ isLoading,
97
+ error,
98
+ loadTemplate,
99
+ refresh,
100
+ clearError,
101
+ };
102
+ }