@sanctum-key/react-native-sdk 1.0.48 → 1.0.50

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 (58) hide show
  1. package/build/package.json +1 -1
  2. package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
  3. package/build/src/components/KYCElements/CountrySelection.js +33 -108
  4. package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
  5. package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
  6. package/build/src/components/KYCElements/CountrySelectionTemplate.js +50 -164
  7. package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
  8. package/build/src/components/KYCElements/DocumentTypeSelection.d.ts.map +1 -1
  9. package/build/src/components/KYCElements/DocumentTypeSelection.js +32 -109
  10. package/build/src/components/KYCElements/DocumentTypeSelection.js.map +1 -1
  11. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  12. package/build/src/components/KYCElements/IDCardCapture.js +58 -25
  13. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  14. package/build/src/components/KYCElements/InitializationStep.d.ts.map +1 -1
  15. package/build/src/components/KYCElements/InitializationStep.js +13 -1
  16. package/build/src/components/KYCElements/InitializationStep.js.map +1 -1
  17. package/build/src/components/KYCElements/LocationCaptureTemplate.d.ts.map +1 -1
  18. package/build/src/components/KYCElements/LocationCaptureTemplate.js +46 -157
  19. package/build/src/components/KYCElements/LocationCaptureTemplate.js.map +1 -1
  20. package/build/src/components/KYCElements/SelfieCapture.d.ts.map +1 -1
  21. package/build/src/components/KYCElements/SelfieCapture.js +28 -24
  22. package/build/src/components/KYCElements/SelfieCapture.js.map +1 -1
  23. package/build/src/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
  24. package/build/src/components/KYCElements/VerificationProgressTemplate.js +31 -40
  25. package/build/src/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
  26. package/build/src/components/SelfieCapture.d.ts.map +1 -1
  27. package/build/src/components/SelfieCapture.js +33 -90
  28. package/build/src/components/SelfieCapture.js.map +1 -1
  29. package/build/src/components/TemplateKYCExample.d.ts.map +1 -1
  30. package/build/src/components/TemplateKYCExample.js +69 -120
  31. package/build/src/components/TemplateKYCExample.js.map +1 -1
  32. package/build/src/components/TemplateKYCFlowRefactored.d.ts +0 -2
  33. package/build/src/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
  34. package/build/src/components/TemplateKYCFlowRefactored.js +95 -210
  35. package/build/src/components/TemplateKYCFlowRefactored.js.map +1 -1
  36. package/build/src/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  37. package/build/src/hooks/useTemplateKYCFlow.js.map +1 -1
  38. package/build/src/types/KYC.types.d.ts.map +1 -1
  39. package/build/src/types/KYC.types.js.map +1 -1
  40. package/build/src/utils/logger.d.ts +12 -4
  41. package/build/src/utils/logger.d.ts.map +1 -1
  42. package/build/src/utils/logger.js +156 -28
  43. package/build/src/utils/logger.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/components/KYCElements/CountrySelection.tsx +36 -109
  46. package/src/components/KYCElements/CountrySelectionTemplate.tsx +67 -266
  47. package/src/components/KYCElements/DocumentTypeSelection.tsx +34 -110
  48. package/src/components/KYCElements/IDCardCapture.tsx +93 -39
  49. package/src/components/KYCElements/InitializationStep.tsx +17 -2
  50. package/src/components/KYCElements/LocationCaptureTemplate.tsx +53 -170
  51. package/src/components/KYCElements/SelfieCapture.tsx +50 -58
  52. package/src/components/KYCElements/VerificationProgressTemplate.tsx +38 -45
  53. package/src/components/SelfieCapture.tsx +44 -100
  54. package/src/components/TemplateKYCExample.tsx +94 -145
  55. package/src/components/TemplateKYCFlowRefactored.tsx +105 -239
  56. package/src/hooks/useTemplateKYCFlow.tsx +1 -0
  57. package/src/types/KYC.types.ts +0 -1
  58. package/src/utils/logger.ts +182 -29
@@ -37,8 +37,10 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
37
37
  logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${MAX_RETRIES})...`);
38
38
  const result: any = await kycService.getVerificationResult(state.session.session_id);
39
39
 
40
- const rootStatus = (result?.status || '').toLowerCase();
41
- if (rootStatus === 'failed.' || rootStatus === 'failed' || rootStatus === 'rejected' || rootStatus === 'error') {
40
+ const rootStatus = (result?.status || '').toLowerCase().trim().replace(/\.$/, '');
41
+
42
+ // FAILED CONDITION
43
+ if (rootStatus === 'failed' || rootStatus === 'rejected' || rootStatus === 'error') {
42
44
  actions.setVerificationState({
43
45
  status: 'failed',
44
46
  result: {
@@ -68,50 +70,15 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
68
70
  throw new Error('Verification payload missing or invalid for current session');
69
71
  }
70
72
 
71
- const vStatus = (vData.verification_status || vData.status || vData.state || '').toLowerCase();
73
+ const vStatus = (vData.verification_status || vData.status || vData.state || '').toLowerCase().replace(/\.$/, '');
72
74
  const vDecision = (vData.decision || vData.outcome || vData.result || '').toLowerCase();
73
75
 
74
- logger.log(`Parsed Status: [${vStatus}], Decision: [${vDecision}]`);
75
-
76
- // SUCCESS CONDITION
77
- if (
78
- vStatus === 'approved' ||
79
- vStatus === 'verified' ||
80
- vStatus === 'success' ||
81
- vStatus === 'completed' ||
82
- vDecision === 'approved' ||
83
- vDecision === 'passed' ||
84
- vDecision === 'clear'
85
- ) {
86
- const hasActualData = vData && Object.keys(vData).length > 0;
87
-
88
- if (!hasActualData) {
89
- actions.setVerificationState({
90
- status: 'failed',
91
- result: {
92
- referenceId: state.session.session_id,
93
- issues: ['Document text could not be read clearly. Please retake the photo in better lighting.']
94
- } as any
95
- });
96
- isPollingRef.current = false;
97
- return;
98
- }
99
-
100
- actions.setVerificationState({
101
- status: 'success',
102
- result: { ...result, referenceId: vData.verification_id || vData.session_id || state.session.session_id } as any
103
- });
104
- isPollingRef.current = false;
105
- return;
106
- }
76
+ logger.log(`Parsed Root Status: [${rootStatus}], Inner Status: [${vStatus}], Decision: [${vDecision}]`);
107
77
 
108
- // PENDING/PROCESSING CONDITION - RE-INTRODUCING POLLING
78
+
109
79
  if (
110
- vStatus === 'processing' ||
111
- vStatus === 'pending' ||
112
- vStatus === 'in_progress' ||
113
- vStatus === 'initiated' ||
114
- !vStatus
80
+ rootStatus === 'pending' || rootStatus === 'processing' || rootStatus === 'in_progress' ||
81
+ vStatus === 'processing' || vStatus === 'pending' || vStatus === 'in_progress' || vStatus === 'initiated' || !vStatus
115
82
  ) {
116
83
  if (currentRetryCount < MAX_RETRIES) {
117
84
  const nextCount = currentRetryCount + 1;
@@ -139,8 +106,36 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
139
106
  return;
140
107
  }
141
108
 
109
+ // SUCCESS CONDITION (Only runs if we are absolutely sure it is no longer pending)
110
+ if (
111
+ rootStatus === 'success' || rootStatus === 'approved' || rootStatus === 'verified' ||
112
+ vStatus === 'approved' || vStatus === 'verified' || vStatus === 'success' || vStatus === 'completed' ||
113
+ vDecision === 'approved' || vDecision === 'passed' || vDecision === 'clear'
114
+ ) {
115
+ const hasActualData = vData && Object.keys(vData).length > 0;
116
+
117
+ if (!hasActualData) {
118
+ actions.setVerificationState({
119
+ status: 'failed',
120
+ result: {
121
+ referenceId: state.session.session_id,
122
+ issues: ['Document text could not be read clearly. Please retake the photo in better lighting.']
123
+ } as any
124
+ });
125
+ isPollingRef.current = false;
126
+ return;
127
+ }
128
+
129
+ actions.setVerificationState({
130
+ status: 'success',
131
+ result: { ...result, referenceId: vData.verification_id || vData.session_id || state.session.session_id } as any
132
+ });
133
+ isPollingRef.current = false;
134
+ return;
135
+ }
136
+
142
137
  // UNKNOWN FALLBACK
143
- logger.warn(`Unknown verification status received: ${vStatus}`);
138
+ logger.warn(`Unknown verification status received: Root: ${rootStatus}, Inner: ${vStatus}`);
144
139
  actions.setVerificationState({
145
140
  status: 'failed',
146
141
  result: {
@@ -153,7 +148,6 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
153
148
  } catch (error: any) {
154
149
  logger.error('getVerificationResult error', JSON.stringify(errorMessage(error) || { message: error?.message || 'Unknown error' }, null, 2));
155
150
 
156
- // If network fails temporarily, we should also retry instead of instantly failing
157
151
  if (currentRetryCount < MAX_RETRIES) {
158
152
  const nextCount = currentRetryCount + 1;
159
153
  if (isMountedRef.current) setRetryCount(nextCount);
@@ -204,7 +198,6 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
204
198
  };
205
199
  }, [isSuccess, actions]);
206
200
 
207
- // --- RENDER LOGIC ---
208
201
 
209
202
  if (isSuccess) {
210
203
  return (
@@ -3,6 +3,7 @@ import { View, Text, TouchableOpacity, Image, Alert, StyleSheet } from 'react-na
3
3
  import { useKYCStore } from '../stores/kycStore';
4
4
  import VisionCameraModule from '../modules/camera/VisionCameraModule';
5
5
  import { EnhancedCameraView } from './EnhancedCameraView';
6
+ import { sdkLogger } from '../utils/logger';
6
7
 
7
8
  export const SelfieCapture: React.FC = () => {
8
9
  const [capturedSelfie, setCapturedSelfie] = useState<string | null>(null);
@@ -13,10 +14,12 @@ export const SelfieCapture: React.FC = () => {
13
14
  const instructions = "Placez votre visage dans le cadre et souriez naturellement. Assurez-vous que votre visage est bien éclairé et centré.";
14
15
 
15
16
  useEffect(() => {
16
- // Check camera availability on component mount
17
+ sdkLogger.info("User started Selfie Capture step");
18
+
17
19
  const checkCameraAvailability = async () => {
18
20
  const isAvailable = await VisionCameraModule.isCameraAvailable();
19
21
  if (!isAvailable) {
22
+ sdkLogger.error("Selfie camera check failed: Camera not available on this platform");
20
23
  Alert.alert('Erreur', 'Caméra non disponible sur cette plateforme');
21
24
  }
22
25
  };
@@ -26,19 +29,23 @@ export const SelfieCapture: React.FC = () => {
26
29
 
27
30
  const handleCapture = async () => {
28
31
  try {
32
+ sdkLogger.info("Requesting permissions to start selfie camera");
29
33
  setIsCapturing(true);
30
34
  setProcessing(true);
31
-
35
+
32
36
  const hasPermissions = await VisionCameraModule.requestAllPermissions();
33
37
  if (!hasPermissions) {
38
+ sdkLogger.warn("User denied camera/microphone permissions for selfie");
34
39
  Alert.alert('Permission refusée', 'Nous avons besoin de l\'accès à la caméra et au microphone');
35
40
  setIsCapturing(false);
36
41
  setProcessing(false);
37
42
  return;
38
43
  }
39
-
44
+
45
+ sdkLogger.info("Selfie camera permissions granted, mounting camera");
40
46
  setShowCamera(true);
41
- } catch (error) {
47
+ } catch (error: any) {
48
+ sdkLogger.error("Failed to open selfie camera", { error: error?.message });
42
49
  Alert.alert('Erreur', 'Impossible d\'ouvrir la caméra');
43
50
  setIsCapturing(false);
44
51
  setProcessing(false);
@@ -46,6 +53,7 @@ export const SelfieCapture: React.FC = () => {
46
53
  };
47
54
 
48
55
  const handleCaptureSuccess = (imagePath: string) => {
56
+ sdkLogger.info("User successfully captured selfie image");
49
57
  setCapturedSelfie(imagePath);
50
58
  setSelfie(imagePath);
51
59
  setShowCamera(false);
@@ -54,6 +62,7 @@ export const SelfieCapture: React.FC = () => {
54
62
  };
55
63
 
56
64
  const handleRetake = () => {
65
+ sdkLogger.info("User chose to retake selfie");
57
66
  setCapturedSelfie(null);
58
67
  setShowCamera(false);
59
68
  };
@@ -62,6 +71,7 @@ export const SelfieCapture: React.FC = () => {
62
71
  if (result.success && result.path) {
63
72
  handleCaptureSuccess(result.path);
64
73
  } else {
74
+ sdkLogger.warn("Selfie capture action failed", { error: result.error }); // 🚨 LOG
65
75
  Alert.alert('Erreur', result.error || 'Échec de la capture');
66
76
  setIsCapturing(false);
67
77
  setProcessing(false);
@@ -69,6 +79,7 @@ export const SelfieCapture: React.FC = () => {
69
79
  };
70
80
 
71
81
  const handleCameraError = (event: { message: string }) => {
82
+ sdkLogger.error("Selfie camera hardware/software error", { error: event.message }); // 🚨 LOG
72
83
  Alert.alert('Erreur', event.message || 'Une erreur est survenue');
73
84
  setShowCamera(false);
74
85
  setIsCapturing(false);
@@ -76,6 +87,7 @@ export const SelfieCapture: React.FC = () => {
76
87
  };
77
88
 
78
89
  const handleCloseCamera = () => {
90
+ sdkLogger.info("User manually closed the selfie camera without capturing"); // 🚨 LOG
79
91
  setShowCamera(false);
80
92
  setIsCapturing(false);
81
93
  setProcessing(false);
@@ -115,18 +127,21 @@ export const SelfieCapture: React.FC = () => {
115
127
  resizeMode="cover"
116
128
  />
117
129
  </View>
118
-
130
+
119
131
  <View style={styles.buttonContainer}>
120
- <TouchableOpacity
121
- style={[styles.button, styles.retakeButton]}
132
+ <TouchableOpacity
133
+ style={[styles.button, styles.retakeButton]}
122
134
  onPress={handleRetake}
123
135
  >
124
136
  <Text style={styles.buttonText}>Reprendre</Text>
125
137
  </TouchableOpacity>
126
-
127
- <TouchableOpacity
128
- style={[styles.button, styles.validateButton]}
129
- onPress={() => {/* Navigation vers l'étape suivante */}}
138
+
139
+ <TouchableOpacity
140
+ style={[styles.button, styles.validateButton]}
141
+ onPress={() => {
142
+ sdkLogger.info("User validated selfie capture, proceeding to next step"); // 🚨 LOG
143
+ /* Navigation vers l'étape suivante */
144
+ }}
130
145
  >
131
146
  <Text style={styles.buttonText}>Valider</Text>
132
147
  </TouchableOpacity>
@@ -139,8 +154,8 @@ export const SelfieCapture: React.FC = () => {
139
154
  {instructions}
140
155
  </Text>
141
156
 
142
- <TouchableOpacity
143
- style={[styles.button, styles.captureButton]}
157
+ <TouchableOpacity
158
+ style={[styles.button, styles.captureButton]}
144
159
  onPress={handleCapture}
145
160
  disabled={isCapturing}
146
161
  >
@@ -155,90 +170,19 @@ export const SelfieCapture: React.FC = () => {
155
170
  };
156
171
 
157
172
  const styles = StyleSheet.create({
158
- container: {
159
- flex: 1,
160
- backgroundColor: '#f5f5f5',
161
- },
162
- captureContainer: {
163
- flex: 1,
164
- justifyContent: 'center',
165
- alignItems: 'center',
166
- padding: 20,
167
- },
168
- title: {
169
- fontSize: 24,
170
- fontWeight: 'bold',
171
- color: '#333',
172
- marginBottom: 20,
173
- textAlign: 'center',
174
- },
175
- instructions: {
176
- fontSize: 16,
177
- color: '#666',
178
- textAlign: 'center',
179
- marginBottom: 40,
180
- lineHeight: 24,
181
- },
182
- previewContainer: {
183
- flex: 1,
184
- padding: 20,
185
- },
186
- imageContainer: {
187
- flex: 1,
188
- justifyContent: 'center',
189
- alignItems: 'center',
190
- marginBottom: 20,
191
- },
192
- previewImage: {
193
- width: 250,
194
- height: 250,
195
- borderRadius: 125,
196
- borderWidth: 3,
197
- borderColor: '#4CAF50',
198
- },
199
- buttonContainer: {
200
- flexDirection: 'row',
201
- justifyContent: 'space-between',
202
- gap: 15,
203
- },
204
- button: {
205
- flex: 1,
206
- paddingVertical: 15,
207
- paddingHorizontal: 20,
208
- borderRadius: 10,
209
- alignItems: 'center',
210
- justifyContent: 'center',
211
- },
212
- captureButton: {
213
- backgroundColor: '#4CAF50',
214
- },
215
- retakeButton: {
216
- backgroundColor: '#FF9800',
217
- },
218
- validateButton: {
219
- backgroundColor: '#2196F3',
220
- },
221
- buttonText: {
222
- color: 'white',
223
- fontSize: 16,
224
- fontWeight: '600',
225
- },
226
- selfieOverlay: {
227
- position: 'absolute',
228
- top: 0,
229
- left: 0,
230
- right: 0,
231
- bottom: 0,
232
- justifyContent: 'center',
233
- alignItems: 'center',
234
- pointerEvents: 'none',
235
- },
236
- faceFrame: {
237
- width: 250,
238
- height: 300,
239
- borderWidth: 3,
240
- borderColor: '#4CAF50',
241
- borderRadius: 125,
242
- backgroundColor: 'transparent',
243
- },
244
- });
173
+ container: { flex: 1, backgroundColor: '#f5f5f5', },
174
+ captureContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, },
175
+ title: { fontSize: 24, fontWeight: 'bold', color: '#333', marginBottom: 20, textAlign: 'center', },
176
+ instructions: { fontSize: 16, color: '#666', textAlign: 'center', marginBottom: 40, lineHeight: 24, },
177
+ previewContainer: { flex: 1, padding: 20, },
178
+ imageContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', marginBottom: 20, },
179
+ previewImage: { width: 250, height: 250, borderRadius: 125, borderWidth: 3, borderColor: '#4CAF50', },
180
+ buttonContainer: { flexDirection: 'row', justifyContent: 'space-between', gap: 15, },
181
+ button: { flex: 1, paddingVertical: 15, paddingHorizontal: 20, borderRadius: 10, alignItems: 'center', justifyContent: 'center', },
182
+ captureButton: { backgroundColor: '#4CAF50', },
183
+ retakeButton: { backgroundColor: '#FF9800', },
184
+ validateButton: { backgroundColor: '#2196F3', },
185
+ buttonText: { color: 'white', fontSize: 16, fontWeight: '600', },
186
+ selfieOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center', pointerEvents: 'none', },
187
+ faceFrame: { width: 250, height: 300, borderWidth: 3, borderColor: '#4CAF50', borderRadius: 125, backgroundColor: 'transparent', },
188
+ });
@@ -3,140 +3,45 @@ import { View, SafeAreaView } from 'react-native';
3
3
  import { TemplateKYCFlow } from './TemplateKYCFlowRefactored';
4
4
  import { KYCTemplate, VerificationState } from '../types/KYC.types';
5
5
  import { KycEnvironment, BackendEnvironment } from '../types/env.types';
6
-
7
-
8
-
6
+ import { sdkLogger } from '../utils/logger'; // 🚨 IMPORT SDK LOGGER
9
7
 
10
8
  const advancedVerificationTemplate: KYCTemplate = {
11
9
  id: 1,
12
- name: {
13
- en: "Advanced Verification",
14
- fr: "Vérification Avancée"
15
- },
16
- description: {
17
- en: "Extended identity verification flow",
18
- fr: "Processus de vérification d'identité étendu"
19
- },
10
+ name: { en: "Advanced Verification", fr: "Vérification Avancée" },
11
+ description: { en: "Extended identity verification flow", fr: "Processus de vérification d'identité étendu" },
20
12
  version: "1.1.0",
21
13
  components: [
22
14
  {
23
- id: 5,
24
- type: "location" as const,
25
- order: 1,
26
- labels: {
27
- en: "Enable your location",
28
- fr: "Activez votre localisation"
29
- },
30
- instructions: {
31
- en: "We need your GPS location for compliance purposes.",
32
- fr: "Nous avons besoin de votre localisation GPS pour des raisons réglementaires."
33
- },
34
- ui: {
35
- icon: "location-icon.png",
36
- themeColor: "#2DBD60",
37
- buttonText: { en: "Enable Location", fr: "Activer la localisation" }
38
- },
39
- config: {
40
- accuracy: "high",
41
- required: true
42
- } as const
15
+ id: 5, type: "location" as const, order: 1,
16
+ labels: { en: "Enable your location", fr: "Activez votre localisation" },
17
+ instructions: { en: "We need your GPS location for compliance purposes.", fr: "Nous avons besoin de votre localisation GPS pour des raisons réglementaires." },
18
+ ui: { icon: "location-icon.png", themeColor: "#2DBD60", buttonText: { en: "Enable Location", fr: "Activer la localisation" } },
19
+ config: { accuracy: "high", required: true } as const
43
20
  },
44
21
  {
45
- id: 6,
46
- type: "country_selection" as const,
47
- order: 2,
48
- labels: {
49
- en: "Select your country",
50
- fr: "Sélectionnez votre pays"
51
- },
52
- instructions: {
53
- en: "Choose your country of residence.",
54
- fr: "Choisissez votre pays de résidence."
55
- },
56
- ui: {
57
- icon: "country-icon.png",
58
- themeColor: "#2DBD60",
59
- buttonText: { en: "Confirm", fr: "Confirmer" }
60
- },
61
- config: {
62
- allowed_countries: ["CM", "NG", "CI", "KE", "GH"],
63
- default_country: "CM",
64
- required: true
65
- } as const
22
+ id: 6, type: "country_selection" as const, order: 2,
23
+ labels: { en: "Select your country", fr: "Sélectionnez votre pays" },
24
+ instructions: { en: "Choose your country of residence.", fr: "Choisissez votre pays de résidence." },
25
+ ui: { icon: "country-icon.png", themeColor: "#2DBD60", buttonText: { en: "Confirm", fr: "Confirmer" } },
26
+ config: { allowed_countries: ["CM", "NG", "CI", "KE", "GH"], default_country: "CM", required: true } as const
66
27
  },
67
28
  {
68
- id: 1,
69
- type: "id_card" as const,
70
- order: 3,
71
- templateId: 1,
72
- labels: {
73
- front: {
74
- en: "Upload front of ID card",
75
- fr: "Téléversez le recto de votre carte d'identité"
76
- },
77
- back: {
78
- en: "Upload back of ID card",
79
- fr: "Téléversez le verso de votre carte d'identité"
80
- },
81
- },
82
- instructions: {
83
- front: {
84
- en: "Take a clear photo of the front of your ID.",
85
- fr: "Prenez une photo nette du recto de votre pièce."
86
- },
87
- back: {
88
- en: "Take a clear photo of the back of your ID.",
89
- fr: "Prenez une photo nette du verso de votre pièce."
90
- },
91
- },
92
- ui: {
93
- front: {
94
- icon: "id-card-icon.png",
95
- themeColor: "#2DBD60",
96
- buttonText: { en: "Next", fr: "Suivant" }
97
- },
98
- back: {
99
- icon: "id-card-icon.png",
100
- themeColor: "#2DBD60",
101
- buttonText: { en: "Next", fr: "Suivant" }
102
- },
103
- },
104
- config: {
105
- sides: ["front", "back"],
106
- allowed_formats: ["jpg", "png"],
107
- max_size_mb: 5,
108
- document_types: ["drivers_licence", "passport", "drivers_licence", "national_id"],
109
-
110
- } as const
29
+ id: 1, type: "id_card" as const, order: 3, templateId: 1,
30
+ labels: { front: { en: "Upload front of ID card", fr: "Téléversez le recto de votre carte d'identité" }, back: { en: "Upload back of ID card", fr: "Téléversez le verso de votre carte d'identité" }, },
31
+ instructions: { front: { en: "Take a clear photo of the front of your ID.", fr: "Prenez une photo nette du recto de votre pièce." }, back: { en: "Take a clear photo of the back of your ID.", fr: "Prenez une photo nette du verso de votre pièce." }, },
32
+ ui: { front: { icon: "id-card-icon.png", themeColor: "#2DBD60", buttonText: { en: "Next", fr: "Suivant" } }, back: { icon: "id-card-icon.png", themeColor: "#2DBD60", buttonText: { en: "Next", fr: "Suivant" } }, },
33
+ config: { sides: ["front", "back"], allowed_formats: ["jpg", "png"], max_size_mb: 5, document_types: ["drivers_licence", "passport", "drivers_licence", "national_id"], } as const
111
34
  },
112
35
  {
113
- id: 3,
114
- type: "selfie" as const,
115
- order: 5,
116
- templateId: 1,
117
- labels: {
118
- en: "Take selfies from different angles",
119
- fr: "Prenez des selfies sous différents angles"
120
- },
121
- instructions: {
122
- en: "Take selfies from front, left, and right angles.",
123
- fr: "Prenez des selfies de face, profil gauche et profil droit."
124
- },
125
- ui: {
126
- icon: "selfie-icon.png",
127
- themeColor: "#2DBD60",
128
- buttonText: { en: "Next", fr: "Suivant" }
129
- },
130
- config: {
131
- liveness_check: true,
132
- max_attempts: 3,
133
- orientations: ["center", "left", "right"]
134
- } as const
36
+ id: 3, type: "selfie" as const, order: 5, templateId: 1,
37
+ labels: { en: "Take selfies from different angles", fr: "Prenez des selfies sous différents angles" },
38
+ instructions: { en: "Take selfies from front, left, and right angles.", fr: "Prenez des selfies de face, profil gauche et profil droit." },
39
+ ui: { icon: "selfie-icon.png", themeColor: "#2DBD60", buttonText: { en: "Next", fr: "Suivant" } },
40
+ config: { liveness_check: true, max_attempts: 3, orientations: ["center", "left", "right"] } as const
135
41
  },
136
42
  ]
137
43
  };
138
44
 
139
-
140
45
  export interface TemplateKYCExampleProps {
141
46
  onComplete: (data: VerificationState) => void;
142
47
  onCancel: () => void;
@@ -145,8 +50,8 @@ export interface TemplateKYCExampleProps {
145
50
  API_KEY?: string;
146
51
  templateId?: string;
147
52
  template?: KYCTemplate;
148
- env?: KycEnvironment;
149
- serverEnv?: BackendEnvironment;
53
+ env?: KycEnvironment;
54
+ serverEnv?: BackendEnvironment;
150
55
  existingSessionId?: string;
151
56
  initialComponentIndex?: number;
152
57
  initialCountryResume?: { code: string; documentType: string; region?: string };
@@ -155,28 +60,76 @@ export interface TemplateKYCExampleProps {
155
60
  kyc_session_id?: string;
156
61
  }
157
62
 
158
- export function TemplateKYCExample({
159
- onComplete,
160
- onCancel,
161
- onError,
162
- language,
163
- API_KEY,
164
- templateId,
165
- template,
166
- env = 'PRODUCTION',
167
- serverEnv,
168
- existingSessionId,
169
- initialComponentIndex,
170
- initialCountryResume,
171
- referenceId,
63
+ export function TemplateKYCExample({
64
+ onComplete,
65
+ onCancel,
66
+ onError,
67
+ language,
68
+ API_KEY,
69
+ templateId,
70
+ template,
71
+ env = 'PRODUCTION',
72
+ serverEnv,
73
+ existingSessionId,
74
+ initialComponentIndex,
75
+ initialCountryResume,
76
+ referenceId,
172
77
  onSessionSave,
173
- kyc_session_id
174
- }: TemplateKYCExampleProps): JSX.Element { // <--- Explicit Return Type
78
+ kyc_session_id
79
+ }: TemplateKYCExampleProps): JSX.Element {
175
80
 
176
81
  const handleComplete = (data: VerificationState) => {
177
- console.log('KYC Template completed with data:', data);
178
- onComplete(data);
179
- // Ici vous pouvez envoyer les données à votre API
82
+ console.log('KYC Template completed with raw data:', data);
83
+
84
+ let finalPayload: any = data; // Fallback to raw data if mapping fails
85
+
86
+ if ((data.status === 'success' || data.status === 'in_progress') && data.result) {
87
+ // 1. Extract the dynamic root key (e.g., 'national_id', 'passport')
88
+ const docKey = Object.keys(data.result)[0];
89
+
90
+ if (docKey && data.result[docKey]) {
91
+ const backendData = data.result[docKey].data;
92
+ const personalInfo = backendData?.user_data?.personal_information || {};
93
+
94
+ // Ensure we capture the session ID from whichever prop was provided
95
+ const activeSessionId = kyc_session_id || existingSessionId || "";
96
+
97
+ // 2. Strict mapping to your expected format
98
+ finalPayload = {
99
+ data: {
100
+ verification_id: backendData?.verification_id,
101
+ verification_status: backendData?.verification_status,
102
+ session_id: activeSessionId,
103
+ user_data: {
104
+ personal_information: {
105
+ first_name: personalInfo.first_name || undefined,
106
+ given_name: personalInfo.given_name || undefined,
107
+ last_name: personalInfo.last_name || undefined,
108
+ surname: personalInfo.last_name || undefined, // fallback
109
+ address: personalInfo.address || undefined,
110
+ city: personalInfo.city || undefined,
111
+ postal_code: personalInfo.postal_code || undefined,
112
+ expiry_date: personalInfo.expiry_date || undefined,
113
+ issue_date: personalInfo.issue_date || undefined,
114
+ date_of_birth: personalInfo.date_of_birth || undefined,
115
+ birth_date: personalInfo.date_of_birth || undefined, // fallback
116
+ country: personalInfo.country || undefined,
117
+ document_number: (personalInfo as any).document_number || undefined,
118
+ nationality: (personalInfo as any).nationality || undefined,
119
+ }
120
+ }
121
+ }
122
+ };
123
+
124
+ sdkLogger.info("Wrapper formatted completion payload successfully", {
125
+ verification_id: finalPayload.data.verification_id
126
+ });
127
+ }
128
+ } else {
129
+ sdkLogger.warn("Wrapper received completion without a success result object", { status: data.status });
130
+ }
131
+
132
+ onComplete(finalPayload as any);
180
133
  };
181
134
 
182
135
  const handleCancel = () => {
@@ -189,8 +142,6 @@ export function TemplateKYCExample({
189
142
  onError(error);
190
143
  };
191
144
 
192
- // Transform backend template to SDK format
193
- // Determine which template to use: prefer templateId for dynamic loading, then template prop, then fallback to hardcoded
194
145
  const templateToUse = templateId ? undefined : (template || advancedVerificationTemplate);
195
146
 
196
147
  return (
@@ -202,7 +153,7 @@ export function TemplateKYCExample({
202
153
  onComplete={handleComplete}
203
154
  onError={handleError}
204
155
  onCancel={handleCancel}
205
- language={language} // ou "en" pour l'anglais
156
+ language={language}
206
157
  API_KEY={API_KEY}
207
158
  env={env}
208
159
  serverEnv={serverEnv}
@@ -212,10 +163,8 @@ export function TemplateKYCExample({
212
163
  referenceId={referenceId}
213
164
  onSessionSave={onSessionSave}
214
165
  kyc_session_id={kyc_session_id}
215
-
216
166
  />
217
167
  </View>
218
168
  </SafeAreaView>
219
169
  );
220
- }
221
-
170
+ }