@sanctum-key/react-native-sdk 1.0.19 → 1.0.21

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 (34) hide show
  1. package/build/package.json +1 -1
  2. package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
  3. package/build/src/components/KYCElements/CountrySelectionTemplate.js +40 -128
  4. package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
  5. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  6. package/build/src/components/KYCElements/IDCardCapture.js +166 -129
  7. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  8. package/build/src/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
  9. package/build/src/components/KYCElements/VerificationProgressTemplate.js +62 -40
  10. package/build/src/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
  11. package/build/src/config/region_mapping.d.ts.map +1 -1
  12. package/build/src/config/region_mapping.js.map +1 -1
  13. package/build/src/hooks/useTemplateKYCFlow.js +1 -1
  14. package/build/src/hooks/useTemplateKYCFlow.js.map +1 -1
  15. package/build/src/modules/api/CardAuthentification.d.ts +5 -0
  16. package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
  17. package/build/src/modules/api/CardAuthentification.js +82 -14
  18. package/build/src/modules/api/CardAuthentification.js.map +1 -1
  19. package/build/src/modules/api/KYCService.d.ts +11 -0
  20. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  21. package/build/src/modules/api/KYCService.js +104 -29
  22. package/build/src/modules/api/KYCService.js.map +1 -1
  23. package/build/src/web/WebKYCEntry.d.ts.map +1 -1
  24. package/build/src/web/WebKYCEntry.js +34 -6
  25. package/build/src/web/WebKYCEntry.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/components/KYCElements/CountrySelectionTemplate.tsx +53 -133
  28. package/src/components/KYCElements/IDCardCapture.tsx +613 -556
  29. package/src/components/KYCElements/VerificationProgressTemplate.tsx +80 -71
  30. package/src/config/region_mapping.ts +2 -1
  31. package/src/hooks/useTemplateKYCFlow.tsx +14 -14
  32. package/src/modules/api/CardAuthentification.ts +147 -67
  33. package/src/modules/api/KYCService.ts +166 -43
  34. package/src/web/WebKYCEntry.tsx +42 -7
@@ -22,46 +22,56 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
22
22
  const [timeoutId, setTimeoutId] = useState<number | null>(null);
23
23
 
24
24
  const verification = state.verification;
25
-
26
25
  const isSuccess = verification.status === 'success';
27
26
  const isFailed = verification.status === 'failed';
28
27
 
29
- // Fonction pour récupérer le résultat de vérification avec retry
30
28
  const getVerificationResult = async (currentRetryCount = 0, maxRetries = 40) => {
31
29
  try {
32
30
  logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${maxRetries + 1})`);
31
+ const result: any = await kycService.getVerificationResult(state.session.session_id);
32
+
33
+ logger.log('getVerificationResult raw result:', JSON.stringify(result, null, 2));
34
+
35
+ if (result?.status === 'Failed.' || result?.status === 'failed' || result?.status === 'rejected') {
36
+ actions.setVerificationState({
37
+ status: 'failed',
38
+ result: {
39
+ referenceId: state.session.session_id,
40
+ issues: [result?.message || 'Verification failed. Sent for manual review.']
41
+ } as any
42
+ });
43
+ setIsRetrying(false);
44
+ return;
45
+ }
33
46
 
34
- const result = await kycService.getVerificationResult(state.session.session_id);
35
- const responseData = (result as any)?.data;
36
- const verificationResult = responseData?.[state.session.session_id]?.data;
47
+ let verificationResult = result?.data;
48
+
49
+ if (verificationResult && !verificationResult.verification_status && verificationResult[state.session.session_id]) {
50
+ const nestedData = verificationResult[state.session.session_id]?.data;
51
+ verificationResult = typeof nestedData === 'string' ? JSON.parse(nestedData) : nestedData;
52
+ }
37
53
 
38
54
  if (!verificationResult) {
39
55
  throw new Error('Verification payload missing for current session');
40
56
  }
41
57
 
42
- logger.log('getVerificationResult result', JSON.stringify({result,verificationResult}, null, 2));
58
+ const currentStatus = verificationResult.verification_status;
43
59
 
44
- // Vérifier le statut de vérification
45
- if (verificationResult.verification_status === null || verificationResult.verification_status === "processing" || verificationResult.verification_status === "pending") {
60
+ if (currentStatus === null || currentStatus === "processing" || currentStatus === "pending") {
46
61
  if (currentRetryCount < maxRetries) {
47
62
  const nextRetryCount = currentRetryCount + 1;
48
63
  setRetryCount(nextRetryCount);
49
64
  setIsRetrying(true);
50
-
51
65
  logger.log(`Verification still processing, retrying in 10s... (${nextRetryCount}/${maxRetries})`);
52
-
53
- // Nettoyer le timeout précédent s'il existe
54
- if (timeoutId) {
55
- clearTimeout(timeoutId);
56
- }
57
-
58
- // Attendre 10 secondes avant de relancer
66
+
67
+ if (timeoutId) clearTimeout(timeoutId);
68
+
59
69
  const newTimeoutId = setTimeout(() => {
60
70
  getVerificationResult(nextRetryCount, maxRetries);
61
71
  }, 10000);
62
-
63
- setTimeoutId(newTimeoutId);
64
- return; // Sortir de la fonction pour éviter de traiter le résultat
72
+
73
+ setTimeoutId(newTimeoutId as any);
74
+ return;
65
75
  } else {
66
76
  logger.error('Max retries reached, verification still processing');
67
77
  setIsRetrying(false);
@@ -69,52 +79,42 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
69
79
  }
70
80
  }
71
81
 
72
- // Traiter le résultat final (success, failed, etc.)
73
- if (verificationResult.verification_status === "completed" ||
74
- verificationResult.verification_status === "approved") {
75
- // Mettre à jour l'état avec le succès
82
+ if (currentStatus === "completed" || currentStatus === "approved") {
76
83
  actions.setVerificationState({
77
84
  status: 'success',
78
- result: result
85
+ result: {
86
+ ...result,
87
+ referenceId: verificationResult.verification_id || verificationResult.session_id
88
+ } as any
79
89
  });
80
- } else if (verificationResult.verification_status === "failed" ||
81
- verificationResult.verification_status === "rejected") {
82
- // Mettre à jour l'état avec l'échec
90
+ } else if (currentStatus === "failed" || currentStatus === "rejected") {
83
91
  actions.setVerificationState({
84
92
  status: 'failed',
85
93
  result: {
86
- referenceId: verificationResult.verification_id,
87
- issues: ['Verification failed']
94
+ referenceId: verificationResult.verification_id || state.session.session_id,
95
+ issues: ['Verification failed during processing.']
88
96
  } as any
89
97
  });
90
98
  }
91
-
99
+
92
100
  setIsRetrying(false);
93
101
 
94
102
  } catch (error: any) {
95
- logger.error(
96
- 'getVerificationResult error',
97
- JSON.stringify(errorMessage(error) || { message: error?.message || 'Unknown error' }, null, 2)
98
- );
99
-
100
- // En cas d'erreur, on peut aussi retry
103
+ logger.error('getVerificationResult error', JSON.stringify(errorMessage(error) || { message: error?.message || 'Unknown error' }, null, 2));
104
+
101
105
  if (currentRetryCount < maxRetries) {
102
106
  const nextRetryCount = currentRetryCount + 1;
103
107
  setRetryCount(nextRetryCount);
104
108
  setIsRetrying(true);
105
-
106
109
  logger.log(`getVerificationResult Error occurred, retrying in 10s... (${nextRetryCount}/${maxRetries})`);
107
-
108
- // Nettoyer le timeout précédent s'il existe
109
- if (timeoutId) {
110
- clearTimeout(timeoutId);
111
- }
112
-
110
+
111
+ if (timeoutId) clearTimeout(timeoutId);
112
+
113
113
  const newTimeoutId = setTimeout(() => {
114
114
  getVerificationResult(nextRetryCount, maxRetries);
115
115
  }, 10000);
116
-
117
- setTimeoutId(newTimeoutId);
116
+
117
+ setTimeoutId(newTimeoutId as any);
118
118
  } else {
119
119
  setIsRetrying(false);
120
120
  logger.error('Max retries reached after errors');
@@ -128,15 +128,30 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
128
128
  }
129
129
  }, [state.session.session_id]);
130
130
 
131
- // Nettoyage des timeouts lors du démontage du composant
132
131
  useEffect(() => {
133
132
  return () => {
134
- if (timeoutId) {
135
- clearTimeout(timeoutId);
136
- }
133
+ if (timeoutId) clearTimeout(timeoutId);
137
134
  };
138
135
  }, [timeoutId]);
139
136
 
137
+ // 🚨 THE FIX: Automatically trigger the webhook/completion flow on success
138
+ useEffect(() => {
139
+ let autoSubmitTimer: ReturnType<typeof setTimeout>;
140
+
141
+ if (isSuccess) {
142
+ logger.log("Verification successful. Initiating auto-submit countdown...");
143
+ // Wait 3 seconds so the user can see the "Complete" screen, then automatically push the data
144
+ autoSubmitTimer = setTimeout(() => {
145
+ actions.submitVerification();
146
+ }, 3000);
147
+ }
148
+
149
+ // Cleanup the timer if the user clicks the button manually before 3 seconds are up
150
+ return () => {
151
+ if (autoSubmitTimer) clearTimeout(autoSubmitTimer);
152
+ };
153
+ }, [isSuccess, actions]);
154
+
140
155
  if (isSuccess) {
141
156
  return (
142
157
  <View style={styles.container}>
@@ -156,19 +171,26 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
156
171
  return (
157
172
  <View style={styles.container}>
158
173
  <Text style={styles.title}>{t('kyc.verificationProgress.status.failed')}</Text>
159
- <Text style={styles.subtitle}>{t('errors.validationError')}</Text>
174
+
160
175
  <View style={styles.issuesBox}>
161
176
  <Text style={styles.issuesTitle}>{t('common.error')}</Text>
162
177
  {Array.isArray(verification.result?.issues) && verification.result.issues.map((issue: string, idx: number) => (
163
178
  <Text key={idx} style={styles.issueItem}>• {issue}</Text>
164
179
  ))}
165
180
  </View>
166
- <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.resetTemplate()}>
167
- <Text style={styles.buttonText}>{t('kyc.verificationProgress.status.retry')}</Text>
181
+
182
+ <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>
183
+ <Text style={styles.buttonText}>
184
+ {state.currentLanguage === 'en' ? 'OK / Finish' : 'Terminer'}
185
+ </Text>
168
186
  </TouchableOpacity>
169
- <TouchableOpacity style={[styles.button, styles.secondary]}>
170
- <Text style={styles.secondaryText}>{t('common.info')}</Text>
187
+
188
+ <TouchableOpacity style={[styles.button, styles.secondary]} onPress={() => actions.resetTemplate()}>
189
+ <Text style={styles.secondaryText}>
190
+ {state.currentLanguage === 'en' ? 'Start Over' : 'Recommencer'}
191
+ </Text>
171
192
  </TouchableOpacity>
193
+
172
194
  {verification.result?.referenceId ? (
173
195
  <Text style={styles.refText}>{`Reference ID: ${verification.result.referenceId}`}</Text>
174
196
  ) : null}
@@ -176,12 +198,6 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
176
198
  );
177
199
  }
178
200
 
179
-
180
-
181
-
182
-
183
-
184
-
185
201
  return (
186
202
  <View style={styles.container}>
187
203
  <Text style={styles.title}>{t('kyc.verificationProgress.title')}</Text>
@@ -191,7 +207,6 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
191
207
  : t('kyc.verificationProgress.estimatedTime')
192
208
  }
193
209
  </Text>
194
-
195
210
  <View style={styles.timeline}>
196
211
  <View style={[styles.dot, styles.done]}><Text style={styles.stepCheckmark}>✓</Text></View>
197
212
  <View style={styles.line} />
@@ -199,13 +214,11 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
199
214
  <View style={styles.line} />
200
215
  <View style={[styles.dot, styles.pending]}><Text style={styles.stepCheckmark}>3</Text></View>
201
216
  </View>
202
-
203
217
  <View style={styles.row}>
204
218
  <Text style={styles.stepLabel}>{t('kyc.verificationProgress.status.completed')}</Text>
205
219
  <Text style={styles.stepLabel}>{t('kyc.verificationProgress.steps.analyzing')}</Text>
206
220
  <Text style={styles.stepLabel}>{t('kyc.verificationProgress.steps.verifying')}</Text>
207
221
  </View>
208
-
209
222
  <View style={styles.card}>
210
223
  <Text style={styles.cardTitle}>{t('kyc.idCardCapture.title')}</Text>
211
224
  <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.extracting')}</Text>
@@ -239,17 +252,13 @@ const styles = StyleSheet.create({
239
252
  card: { backgroundColor: 'white', padding: 16, borderRadius: 16, marginTop: 24 },
240
253
  cardTitle: { fontSize: 16, color: '#6B7280', marginTop: 8 },
241
254
  cardLine: { fontSize: 18, color: '#111827', fontWeight: '600', marginTop: 2 },
242
- // Success/Failure specific
243
- button: { paddingVertical: 14, borderRadius: 10, alignItems: 'center', marginTop: 20 },
255
+ button: { paddingVertical: 14, borderRadius: 10, alignItems: 'center', marginTop: 14 },
244
256
  primary: { backgroundColor: '#2DBD60' },
245
257
  buttonText: { color: 'white', fontSize: 16, fontWeight: '600' },
246
258
  refText: { marginTop: 12, textAlign: 'center', color: '#6B7280' },
247
259
  issuesBox: { backgroundColor: '#FEF2F2', borderRadius: 16, padding: 16, marginTop: 20 },
248
260
  issuesTitle: { color: '#991B1B', fontWeight: '700', marginBottom: 8 },
249
261
  issueItem: { color: '#991B1B', marginTop: 4 },
250
- secondary: { backgroundColor: '#F3F4F6' },
251
- secondaryText: { color: '#111827', fontSize: 16, fontWeight: '600' },
252
- });
253
-
254
-
255
-
262
+ secondary: { backgroundColor: '#F3F4F6', borderWidth: 1, borderColor: '#D1D5DB' },
263
+ secondaryText: { color: '#374151', fontSize: 16, fontWeight: '600' },
264
+ });
@@ -1,6 +1,7 @@
1
1
  import { ICountryMapping } from "../types/KYC.types";
2
2
 
3
- export const countryMapping: Record<string, Record<string, Record<string, ICountryMapping[]>>> = {
3
+ export const countryMapping: Record<string, Record<string, Record<string, ICountryMapping[]>>> =
4
+ {
4
5
  "BE": {
5
6
  "passport": {
6
7
  "root": [
@@ -698,21 +698,21 @@ export const useTemplateKYCFlow = (
698
698
  const templateId = chooseTemplateId(templateWithReviewAndVerification);
699
699
 
700
700
  // This is the API call that we know succeeds
701
- await kycService.verificationSession({
702
- session_id: resolvedSessionId,
703
- step: 0,
704
- data: {
705
- template_id: templateId,
706
- metadata: {
707
- language: initialLanguage,
708
- ...(referenceId ? { reference_id: referenceId } : {}),
709
- },
701
+ await kycService.verificationSession({
702
+ session_id: resolvedSessionId,
703
+ step: 0,
704
+ data: {
705
+ template_id: templateId,
706
+ ...(referenceId ? { reference_id: referenceId } : {}),
707
+ metadata: {
708
+ language: initialLanguage,
710
709
  },
711
- templateId: templateId,
712
- token: token ?? "",
713
- action: 'initialize_session',
714
- apiKey: apiKey,
715
- });
710
+ },
711
+ templateId: templateId,
712
+ token: token ?? "",
713
+ action: 'initialize_session',
714
+ apiKey: apiKey,
715
+ });
716
716
 
717
717
 
718
718
  setState(prev => ({