@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.
- package/build/package.json +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.js +40 -128
- package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.js +166 -129
- package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/src/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/VerificationProgressTemplate.js +62 -40
- package/build/src/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
- package/build/src/config/region_mapping.d.ts.map +1 -1
- package/build/src/config/region_mapping.js.map +1 -1
- package/build/src/hooks/useTemplateKYCFlow.js +1 -1
- package/build/src/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/src/modules/api/CardAuthentification.d.ts +5 -0
- package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/src/modules/api/CardAuthentification.js +82 -14
- package/build/src/modules/api/CardAuthentification.js.map +1 -1
- package/build/src/modules/api/KYCService.d.ts +11 -0
- package/build/src/modules/api/KYCService.d.ts.map +1 -1
- package/build/src/modules/api/KYCService.js +104 -29
- package/build/src/modules/api/KYCService.js.map +1 -1
- package/build/src/web/WebKYCEntry.d.ts.map +1 -1
- package/build/src/web/WebKYCEntry.js +34 -6
- package/build/src/web/WebKYCEntry.js.map +1 -1
- package/package.json +1 -1
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +53 -133
- package/src/components/KYCElements/IDCardCapture.tsx +613 -556
- package/src/components/KYCElements/VerificationProgressTemplate.tsx +80 -71
- package/src/config/region_mapping.ts +2 -1
- package/src/hooks/useTemplateKYCFlow.tsx +14 -14
- package/src/modules/api/CardAuthentification.ts +147 -67
- package/src/modules/api/KYCService.ts +166 -43
- 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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
58
|
+
const currentStatus = verificationResult.verification_status;
|
|
43
59
|
|
|
44
|
-
|
|
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
|
-
|
|
54
|
-
|
|
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;
|
|
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
|
-
|
|
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:
|
|
85
|
+
result: {
|
|
86
|
+
...result,
|
|
87
|
+
referenceId: verificationResult.verification_id || verificationResult.session_id
|
|
88
|
+
} as any
|
|
79
89
|
});
|
|
80
|
-
} else if (
|
|
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
|
-
|
|
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
|
-
|
|
109
|
-
|
|
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
|
-
|
|
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
|
-
|
|
167
|
-
|
|
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
|
-
|
|
170
|
-
|
|
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
|
-
|
|
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: '#
|
|
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
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
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
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
710
|
+
},
|
|
711
|
+
templateId: templateId,
|
|
712
|
+
token: token ?? "",
|
|
713
|
+
action: 'initialize_session',
|
|
714
|
+
apiKey: apiKey,
|
|
715
|
+
});
|
|
716
716
|
|
|
717
717
|
|
|
718
718
|
setState(prev => ({
|