@sanctum-key/react-native-sdk 1.0.19 → 1.0.20
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 +38 -33
- package/build/src/components/KYCElements/VerificationProgressTemplate.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 +67 -13
- package/build/src/modules/api/CardAuthentification.js.map +1 -1
- package/build/src/modules/api/KYCService.d.ts +10 -0
- package/build/src/modules/api/KYCService.d.ts.map +1 -1
- package/build/src/modules/api/KYCService.js +94 -25
- 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 +54 -66
- package/src/hooks/useTemplateKYCFlow.tsx +14 -14
- package/src/modules/api/CardAuthentification.ts +133 -66
- package/src/modules/api/KYCService.ts +142 -38
- package/src/web/WebKYCEntry.tsx +42 -7
|
@@ -22,7 +22,6 @@ 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
|
|
|
@@ -30,38 +29,47 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
|
|
|
30
29
|
const getVerificationResult = async (currentRetryCount = 0, maxRetries = 40) => {
|
|
31
30
|
try {
|
|
32
31
|
logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${maxRetries + 1})`);
|
|
32
|
+
const result: any = await kycService.getVerificationResult(state.session.session_id);
|
|
33
|
+
|
|
34
|
+
logger.log('getVerificationResult raw result:', JSON.stringify(result, null, 2));
|
|
35
|
+
|
|
36
|
+
if (result?.status === 'Failed.' || result?.status === 'failed' || result?.status === 'rejected') {
|
|
37
|
+
actions.setVerificationState({
|
|
38
|
+
status: 'failed',
|
|
39
|
+
result: {
|
|
40
|
+
referenceId: state.session.session_id,
|
|
41
|
+
issues: [result?.message || 'Verification failed. Sent for manual review.']
|
|
42
|
+
} as any
|
|
43
|
+
});
|
|
44
|
+
setIsRetrying(false);
|
|
45
|
+
return; // Break out of the function so it DOES NOT RETRY
|
|
46
|
+
}
|
|
33
47
|
|
|
34
|
-
|
|
35
|
-
const responseData =
|
|
48
|
+
// Check standard nested payload format
|
|
49
|
+
const responseData = result?.data;
|
|
36
50
|
const verificationResult = responseData?.[state.session.session_id]?.data;
|
|
37
51
|
|
|
38
52
|
if (!verificationResult) {
|
|
53
|
+
// If we still didn't get data and the status wasn't failed, throw to trigger a retry
|
|
39
54
|
throw new Error('Verification payload missing for current session');
|
|
40
55
|
}
|
|
41
56
|
|
|
42
|
-
logger.log('getVerificationResult result', JSON.stringify({result,verificationResult}, null, 2));
|
|
43
|
-
|
|
44
57
|
// Vérifier le statut de vérification
|
|
45
58
|
if (verificationResult.verification_status === null || verificationResult.verification_status === "processing" || verificationResult.verification_status === "pending") {
|
|
46
59
|
if (currentRetryCount < maxRetries) {
|
|
47
60
|
const nextRetryCount = currentRetryCount + 1;
|
|
48
61
|
setRetryCount(nextRetryCount);
|
|
49
62
|
setIsRetrying(true);
|
|
50
|
-
|
|
51
63
|
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
|
|
64
|
+
|
|
65
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
66
|
+
|
|
59
67
|
const newTimeoutId = setTimeout(() => {
|
|
60
68
|
getVerificationResult(nextRetryCount, maxRetries);
|
|
61
69
|
}, 10000);
|
|
62
|
-
|
|
63
|
-
setTimeoutId(newTimeoutId);
|
|
64
|
-
return;
|
|
70
|
+
|
|
71
|
+
setTimeoutId(newTimeoutId as any);
|
|
72
|
+
return;
|
|
65
73
|
} else {
|
|
66
74
|
logger.error('Max retries reached, verification still processing');
|
|
67
75
|
setIsRetrying(false);
|
|
@@ -70,51 +78,39 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
|
|
|
70
78
|
}
|
|
71
79
|
|
|
72
80
|
// 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
|
|
81
|
+
if (verificationResult.verification_status === "completed" || verificationResult.verification_status === "approved") {
|
|
76
82
|
actions.setVerificationState({
|
|
77
83
|
status: 'success',
|
|
78
84
|
result: result
|
|
79
85
|
});
|
|
80
|
-
} else if (verificationResult.verification_status === "failed" ||
|
|
81
|
-
verificationResult.verification_status === "rejected") {
|
|
82
|
-
// Mettre à jour l'état avec l'échec
|
|
86
|
+
} else if (verificationResult.verification_status === "failed" || verificationResult.verification_status === "rejected") {
|
|
83
87
|
actions.setVerificationState({
|
|
84
88
|
status: 'failed',
|
|
85
89
|
result: {
|
|
86
|
-
referenceId: verificationResult.verification_id,
|
|
87
|
-
issues: ['Verification failed']
|
|
90
|
+
referenceId: verificationResult.verification_id || state.session.session_id,
|
|
91
|
+
issues: ['Verification failed during processing.']
|
|
88
92
|
} as any
|
|
89
93
|
});
|
|
90
94
|
}
|
|
91
|
-
|
|
95
|
+
|
|
92
96
|
setIsRetrying(false);
|
|
93
97
|
|
|
94
98
|
} 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
|
|
99
|
+
logger.error('getVerificationResult error', JSON.stringify(errorMessage(error) || { message: error?.message || 'Unknown error' }, null, 2));
|
|
100
|
+
|
|
101
101
|
if (currentRetryCount < maxRetries) {
|
|
102
102
|
const nextRetryCount = currentRetryCount + 1;
|
|
103
103
|
setRetryCount(nextRetryCount);
|
|
104
104
|
setIsRetrying(true);
|
|
105
|
-
|
|
106
105
|
logger.log(`getVerificationResult Error occurred, retrying in 10s... (${nextRetryCount}/${maxRetries})`);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
clearTimeout(timeoutId);
|
|
111
|
-
}
|
|
112
|
-
|
|
106
|
+
|
|
107
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
108
|
+
|
|
113
109
|
const newTimeoutId = setTimeout(() => {
|
|
114
110
|
getVerificationResult(nextRetryCount, maxRetries);
|
|
115
111
|
}, 10000);
|
|
116
|
-
|
|
117
|
-
setTimeoutId(newTimeoutId);
|
|
112
|
+
|
|
113
|
+
setTimeoutId(newTimeoutId as any);
|
|
118
114
|
} else {
|
|
119
115
|
setIsRetrying(false);
|
|
120
116
|
logger.error('Max retries reached after errors');
|
|
@@ -128,12 +124,9 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
|
|
|
128
124
|
}
|
|
129
125
|
}, [state.session.session_id]);
|
|
130
126
|
|
|
131
|
-
// Nettoyage des timeouts lors du démontage du composant
|
|
132
127
|
useEffect(() => {
|
|
133
128
|
return () => {
|
|
134
|
-
if (timeoutId)
|
|
135
|
-
clearTimeout(timeoutId);
|
|
136
|
-
}
|
|
129
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
137
130
|
};
|
|
138
131
|
}, [timeoutId]);
|
|
139
132
|
|
|
@@ -156,19 +149,27 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
|
|
|
156
149
|
return (
|
|
157
150
|
<View style={styles.container}>
|
|
158
151
|
<Text style={styles.title}>{t('kyc.verificationProgress.status.failed')}</Text>
|
|
159
|
-
|
|
152
|
+
|
|
160
153
|
<View style={styles.issuesBox}>
|
|
161
154
|
<Text style={styles.issuesTitle}>{t('common.error')}</Text>
|
|
162
155
|
{Array.isArray(verification.result?.issues) && verification.result.issues.map((issue: string, idx: number) => (
|
|
163
156
|
<Text key={idx} style={styles.issueItem}>• {issue}</Text>
|
|
164
157
|
))}
|
|
165
158
|
</View>
|
|
166
|
-
|
|
167
|
-
|
|
159
|
+
|
|
160
|
+
{/* 🚨 FIX 2: Give the user actionable options to End or Restart */}
|
|
161
|
+
<TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>
|
|
162
|
+
<Text style={styles.buttonText}>
|
|
163
|
+
{state.currentLanguage === 'en' ? 'OK / Finish' : 'Terminer'}
|
|
164
|
+
</Text>
|
|
168
165
|
</TouchableOpacity>
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
|
|
167
|
+
<TouchableOpacity style={[styles.button, styles.secondary]} onPress={() => actions.resetTemplate()}>
|
|
168
|
+
<Text style={styles.secondaryText}>
|
|
169
|
+
{state.currentLanguage === 'en' ? 'Start Over' : 'Recommencer'}
|
|
170
|
+
</Text>
|
|
171
171
|
</TouchableOpacity>
|
|
172
|
+
|
|
172
173
|
{verification.result?.referenceId ? (
|
|
173
174
|
<Text style={styles.refText}>{`Reference ID: ${verification.result.referenceId}`}</Text>
|
|
174
175
|
) : null}
|
|
@@ -176,12 +177,6 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
|
|
|
176
177
|
);
|
|
177
178
|
}
|
|
178
179
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
180
|
return (
|
|
186
181
|
<View style={styles.container}>
|
|
187
182
|
<Text style={styles.title}>{t('kyc.verificationProgress.title')}</Text>
|
|
@@ -191,7 +186,6 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
|
|
|
191
186
|
: t('kyc.verificationProgress.estimatedTime')
|
|
192
187
|
}
|
|
193
188
|
</Text>
|
|
194
|
-
|
|
195
189
|
<View style={styles.timeline}>
|
|
196
190
|
<View style={[styles.dot, styles.done]}><Text style={styles.stepCheckmark}>✓</Text></View>
|
|
197
191
|
<View style={styles.line} />
|
|
@@ -199,13 +193,11 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
|
|
|
199
193
|
<View style={styles.line} />
|
|
200
194
|
<View style={[styles.dot, styles.pending]}><Text style={styles.stepCheckmark}>3</Text></View>
|
|
201
195
|
</View>
|
|
202
|
-
|
|
203
196
|
<View style={styles.row}>
|
|
204
197
|
<Text style={styles.stepLabel}>{t('kyc.verificationProgress.status.completed')}</Text>
|
|
205
198
|
<Text style={styles.stepLabel}>{t('kyc.verificationProgress.steps.analyzing')}</Text>
|
|
206
199
|
<Text style={styles.stepLabel}>{t('kyc.verificationProgress.steps.verifying')}</Text>
|
|
207
200
|
</View>
|
|
208
|
-
|
|
209
201
|
<View style={styles.card}>
|
|
210
202
|
<Text style={styles.cardTitle}>{t('kyc.idCardCapture.title')}</Text>
|
|
211
203
|
<Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.extracting')}</Text>
|
|
@@ -239,17 +231,13 @@ const styles = StyleSheet.create({
|
|
|
239
231
|
card: { backgroundColor: 'white', padding: 16, borderRadius: 16, marginTop: 24 },
|
|
240
232
|
cardTitle: { fontSize: 16, color: '#6B7280', marginTop: 8 },
|
|
241
233
|
cardLine: { fontSize: 18, color: '#111827', fontWeight: '600', marginTop: 2 },
|
|
242
|
-
|
|
243
|
-
button: { paddingVertical: 14, borderRadius: 10, alignItems: 'center', marginTop: 20 },
|
|
234
|
+
button: { paddingVertical: 14, borderRadius: 10, alignItems: 'center', marginTop: 14 },
|
|
244
235
|
primary: { backgroundColor: '#2DBD60' },
|
|
245
236
|
buttonText: { color: 'white', fontSize: 16, fontWeight: '600' },
|
|
246
237
|
refText: { marginTop: 12, textAlign: 'center', color: '#6B7280' },
|
|
247
238
|
issuesBox: { backgroundColor: '#FEF2F2', borderRadius: 16, padding: 16, marginTop: 20 },
|
|
248
239
|
issuesTitle: { color: '#991B1B', fontWeight: '700', marginBottom: 8 },
|
|
249
240
|
issueItem: { color: '#991B1B', marginTop: 4 },
|
|
250
|
-
secondary: { backgroundColor: '#F3F4F6' },
|
|
251
|
-
secondaryText: { color: '#
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
241
|
+
secondary: { backgroundColor: '#F3F4F6', borderWidth: 1, borderColor: '#D1D5DB' },
|
|
242
|
+
secondaryText: { color: '#374151', fontSize: 16, fontWeight: '600' },
|
|
243
|
+
});
|
|
@@ -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 => ({
|