@transfergratis/react-native-sdk 0.1.25 → 0.1.26
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/android/src/main/AndroidManifest.xml +12 -0
- package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.web.js +76 -21
- package/build/components/EnhancedCameraView.web.js.map +1 -1
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/EmailVerificationTemplate.js +48 -29
- package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -1
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +40 -11
- package/build/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/components/KYCElements/WelcomeTemplate.js +2 -1
- package/build/components/KYCElements/WelcomeTemplate.js.map +1 -1
- package/build/components/OverLay/type.d.ts +2 -0
- package/build/components/OverLay/type.d.ts.map +1 -1
- package/build/components/OverLay/type.js.map +1 -1
- package/build/components/TemplateKYCExample.d.ts +8 -2
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +2 -2
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts +10 -2
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +13 -3
- package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/config/KYCConfig.js +1 -1
- package/build/config/KYCConfig.js.map +1 -1
- package/build/hooks/useTemplateKYCFlow.d.ts +14 -2
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +175 -84
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/i18n/en/index.d.ts +2 -0
- package/build/i18n/en/index.d.ts.map +1 -1
- package/build/i18n/en/index.js +3 -1
- package/build/i18n/en/index.js.map +1 -1
- package/build/i18n/fr/index.d.ts +2 -0
- package/build/i18n/fr/index.d.ts.map +1 -1
- package/build/i18n/fr/index.js +3 -1
- package/build/i18n/fr/index.js.map +1 -1
- package/build/i18n/types.d.ts +2 -0
- package/build/i18n/types.d.ts.map +1 -1
- package/build/i18n/types.js.map +1 -1
- package/build/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/modules/api/CardAuthentification.js +22 -2
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +10 -0
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +24 -0
- package/build/modules/api/KYCService.js.map +1 -1
- package/build/modules/camera/VisionCameraModule.web.d.ts.map +1 -1
- package/build/modules/camera/VisionCameraModule.web.js +27 -8
- package/build/modules/camera/VisionCameraModule.web.js.map +1 -1
- package/build/types/KYC.types.d.ts +6 -2
- package/build/types/KYC.types.d.ts.map +1 -1
- package/build/types/KYC.types.js.map +1 -1
- package/build/utils/cropByObb.d.ts +7 -0
- package/build/utils/cropByObb.d.ts.map +1 -1
- package/build/utils/cropByObb.js +20 -1
- package/build/utils/cropByObb.js.map +1 -1
- package/build/web/WebKYCEntry.d.ts.map +1 -1
- package/build/web/WebKYCEntry.js +11 -5
- package/build/web/WebKYCEntry.js.map +1 -1
- package/package.json +1 -1
- package/plugin/build/index.d.ts +1 -0
- package/plugin/build/index.js +3 -1
- package/plugin/build/withRemovePermissions.d.ts +3 -0
- package/plugin/build/withRemovePermissions.js +67 -0
- package/plugin/src/index.ts +2 -1
- package/plugin/src/withRemovePermissions.js +85 -0
- package/plugin/src/withRemovePermissions.ts +83 -0
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/plugin.js +6 -1
- package/src/components/EnhancedCameraView.web.tsx +76 -21
- package/src/components/KYCElements/EmailVerificationTemplate.tsx +47 -33
- package/src/components/KYCElements/IDCardCapture.tsx +41 -10
- package/src/components/KYCElements/WelcomeTemplate.tsx +2 -1
- package/src/components/OverLay/type.ts +2 -0
- package/src/components/TemplateKYCExample.tsx +9 -5
- package/src/components/TemplateKYCFlowRefactored.tsx +24 -6
- package/src/config/KYCConfig.ts +1 -1
- package/src/hooks/useTemplateKYCFlow.tsx +189 -95
- package/src/i18n/en/index.ts +3 -1
- package/src/i18n/fr/index.ts +3 -1
- package/src/i18n/types.ts +2 -0
- package/src/modules/api/CardAuthentification.ts +23 -2
- package/src/modules/api/KYCService.ts +41 -0
- package/src/modules/camera/VisionCameraModule.web.ts +30 -12
- package/src/types/KYC.types.ts +7 -3
- package/src/utils/cropByObb.ts +20 -1
- package/src/web/WebKYCEntry.tsx +17 -6
|
@@ -4,6 +4,7 @@ import { TemplateComponent, LocalizedText } from '../../types/KYC.types';
|
|
|
4
4
|
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
5
5
|
import { useI18n } from '../../hooks/useI18n';
|
|
6
6
|
import { Button } from '../ui/Button';
|
|
7
|
+
import kycService, { errorMessage } from '../../modules/api/KYCService';
|
|
7
8
|
|
|
8
9
|
interface EmailVerificationTemplateProps {
|
|
9
10
|
component: TemplateComponent;
|
|
@@ -15,14 +16,21 @@ interface EmailVerificationTemplateProps {
|
|
|
15
16
|
|
|
16
17
|
type VerificationStep = 'email' | 'otp';
|
|
17
18
|
|
|
19
|
+
/** RFC-style email validation: local@domain.tld */
|
|
20
|
+
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
21
|
+
|
|
22
|
+
const isValidEmail = (value: string): boolean => EMAIL_REGEX.test((value || '').trim());
|
|
23
|
+
|
|
18
24
|
export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps> = ({
|
|
19
25
|
component,
|
|
20
26
|
value,
|
|
21
27
|
onValueChange,
|
|
22
28
|
error: propError,
|
|
23
29
|
}) => {
|
|
24
|
-
const { actions, getLocalizedText } = useTemplateKYCFlowContext();
|
|
30
|
+
const { actions, getLocalizedText, state, apiKey } = useTemplateKYCFlowContext();
|
|
25
31
|
const { t } = useI18n();
|
|
32
|
+
|
|
33
|
+
const auth = apiKey ? { apiKey } : (state.session.token ? { token: state.session.token } : undefined);
|
|
26
34
|
// const config = component.config as EmailVerificationConfig; // Keep for future use
|
|
27
35
|
|
|
28
36
|
// State
|
|
@@ -40,8 +48,9 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
|
|
|
40
48
|
const sendButtonText = t('common.sendCode') || 'Send Verification Code';
|
|
41
49
|
const buttonText = step === 'email' ? sendButtonText : verifyButtonText;
|
|
42
50
|
|
|
43
|
-
const handleSendCode = () => {
|
|
44
|
-
|
|
51
|
+
const handleSendCode = async () => {
|
|
52
|
+
const trimmed = email.trim();
|
|
53
|
+
if (!trimmed || !isValidEmail(trimmed)) {
|
|
45
54
|
setLocalError(t('errors.invalidEmail') || 'Please enter a valid email address');
|
|
46
55
|
return;
|
|
47
56
|
}
|
|
@@ -49,16 +58,18 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
|
|
|
49
58
|
setLocalError(null);
|
|
50
59
|
setIsSimulating(true);
|
|
51
60
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
setIsSimulating(false);
|
|
61
|
+
try {
|
|
62
|
+
await kycService.sendEmailVerificationCode(trimmed, auth);
|
|
55
63
|
setStep('otp');
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
} catch (err: any) {
|
|
65
|
+
const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send verification code');
|
|
66
|
+
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
67
|
+
} finally {
|
|
68
|
+
setIsSimulating(false);
|
|
69
|
+
}
|
|
59
70
|
};
|
|
60
71
|
|
|
61
|
-
const handleVerifyCode = () => {
|
|
72
|
+
const handleVerifyCode = async () => {
|
|
62
73
|
if (!otp || otp.length < 4) {
|
|
63
74
|
setLocalError(t('errors.invalidCode') || 'Please enter the 6-digit code');
|
|
64
75
|
return;
|
|
@@ -67,24 +78,17 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
|
|
|
67
78
|
setLocalError(null);
|
|
68
79
|
setIsSimulating(true);
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
try {
|
|
82
|
+
await kycService.verifyEmailCode(otp.trim(), auth);
|
|
83
|
+
const data = { email, otp, verified: true };
|
|
84
|
+
onValueChange(data);
|
|
85
|
+
actions.nextComponent(data);
|
|
86
|
+
} catch (err: any) {
|
|
87
|
+
const msg = errorMessage(err) ?? err?.message ?? (t('errors.wrongCode') || 'Invalid verification code');
|
|
88
|
+
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
89
|
+
} finally {
|
|
72
90
|
setIsSimulating(false);
|
|
73
|
-
|
|
74
|
-
// Mock validation logic
|
|
75
|
-
// Let's accept '123456' as the correct code or any code for testing if strictly requested?
|
|
76
|
-
// User said "verify with error message" implying we should support failure.
|
|
77
|
-
// Let's say if code is "000000" it fails, otherwise success, OR hardcode a success one.
|
|
78
|
-
// User said "verify with error message and next component if is a good one"
|
|
79
|
-
// Let's make "123456" the good one for clarity.
|
|
80
|
-
|
|
81
|
-
if (otp === '123456') {
|
|
82
|
-
onValueChange({ email, otp, verified: true });
|
|
83
|
-
actions.nextComponent();
|
|
84
|
-
} else {
|
|
85
|
-
setLocalError(t('errors.wrongCode') || 'Invalid verification code. Try 123456');
|
|
86
|
-
}
|
|
87
|
-
}, 1500);
|
|
91
|
+
}
|
|
88
92
|
};
|
|
89
93
|
|
|
90
94
|
const onChangeEmail = (text: string) => {
|
|
@@ -160,12 +164,22 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
|
|
|
160
164
|
|
|
161
165
|
{step === 'otp' && (
|
|
162
166
|
<TouchableOpacity
|
|
163
|
-
onPress={() => {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
onPress={async () => {
|
|
168
|
+
if (isSimulating) return;
|
|
169
|
+
setLocalError(null);
|
|
170
|
+
setIsSimulating(true);
|
|
171
|
+
try {
|
|
172
|
+
await kycService.sendEmailVerificationCode(email.trim(), auth);
|
|
173
|
+
Alert.alert(
|
|
174
|
+
t('common.codeResent') || 'Code Resent',
|
|
175
|
+
t('common.codeResentMessage', { email }) || 'Code resent to ' + email
|
|
176
|
+
);
|
|
177
|
+
} catch (err: any) {
|
|
178
|
+
const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send code');
|
|
179
|
+
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
180
|
+
} finally {
|
|
181
|
+
setIsSimulating(false);
|
|
182
|
+
}
|
|
169
183
|
}}
|
|
170
184
|
style={styles.resendButton}
|
|
171
185
|
disabled={isSimulating}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import { View, Text, StyleSheet, Image, ScrollView, Platform, Modal, TouchableOpacity } from 'react-native';
|
|
2
|
+
import { View, Text, StyleSheet, Image, ScrollView, Platform, Modal, TouchableOpacity, ActivityIndicator } from 'react-native';
|
|
3
3
|
import { showAlert } from '../../utils/platformAlert';
|
|
4
4
|
import { EnhancedCameraView } from '../EnhancedCameraView';
|
|
5
5
|
import { TemplateComponent, LocalizedText, GovernmentDocumentType, ISilentCaptureResult, IBbox, GovernmentDocumentTypeShorted, GovernmentDocumentTypeBackend } from '../../types/KYC.types';
|
|
@@ -12,7 +12,7 @@ import { backVerification, checkTemplateType, frontVerification } from '../../mo
|
|
|
12
12
|
import { getDocumentTypeInfo } from '../../utils/get-document-type-info';
|
|
13
13
|
import pathToBase64 from '../../utils/pathToBase64';
|
|
14
14
|
import kycService, { truncateFields } from '../../modules/api/KYCService';
|
|
15
|
-
import { cropByObb, cropImageWithBBox, cropImageWithBBoxWithTolerance } from '../../utils/cropByObb';
|
|
15
|
+
import { cropByObb, cropImageWithBBox, cropImageWithBBoxWithTolerance, getObbConfidence, OBB_CONFIDENCE_THRESHOLD } from '../../utils/cropByObb';
|
|
16
16
|
import { isMobileWeb } from '../../utils/deviceDetection';
|
|
17
17
|
import { logger } from '../../utils/logger';
|
|
18
18
|
|
|
@@ -252,6 +252,16 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
252
252
|
setSilentCaptureResult((prev) => ({ ...prev, templatePath: templatePath }));
|
|
253
253
|
}
|
|
254
254
|
if (templateType.card_obb) {
|
|
255
|
+
const obbConfidence = getObbConfidence((templateType as any).card_obb);
|
|
256
|
+
if (obbConfidence !== null && obbConfidence < OBB_CONFIDENCE_THRESHOLD) {
|
|
257
|
+
setSilentCaptureResult((prev) => ({
|
|
258
|
+
...prev,
|
|
259
|
+
isAnalyzing: false,
|
|
260
|
+
success: false,
|
|
261
|
+
error: t('kyc.idCardCapture.cardNotFullyInFrame'),
|
|
262
|
+
}));
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
255
265
|
let bbox: IBbox | undefined;
|
|
256
266
|
try {
|
|
257
267
|
const crop = await cropByObb(result?.path || '', (templateType as any).card_obb);
|
|
@@ -314,8 +324,9 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
314
324
|
}).catch((e: any) => {
|
|
315
325
|
console.log("error front verification", e);
|
|
316
326
|
logger.log("error front verification", truncateFields(e));
|
|
317
|
-
|
|
318
|
-
|
|
327
|
+
const isCardNotFullyInFrame = e?.message?.includes('entirement') || e?.message?.includes('fully in frame');
|
|
328
|
+
const errorMessage = isCardNotFullyInFrame ? t('kyc.idCardCapture.cardNotFullyInFrame') : (e?.message || 'Erreur de détection du MRZ');
|
|
329
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, templatePath: templatePath, success: false, error: errorMessage }));
|
|
319
330
|
});
|
|
320
331
|
} catch (error: any) {
|
|
321
332
|
console.log("Error setting up frontVerification call", error);
|
|
@@ -351,8 +362,9 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
351
362
|
}
|
|
352
363
|
}).catch((e: any) => {
|
|
353
364
|
logger.log("error back verification", truncateFields(e));
|
|
354
|
-
|
|
355
|
-
|
|
365
|
+
const isCardNotFullyInFrame = e?.message?.includes('entirement') || e?.message?.includes('fully in frame');
|
|
366
|
+
const errorMessage = isCardNotFullyInFrame ? t('kyc.idCardCapture.cardNotFullyInFrame') : (e?.message || 'Erreur de détection du MRZ');
|
|
367
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, templatePath: templatePath, success: false, error: errorMessage }));
|
|
356
368
|
})
|
|
357
369
|
}
|
|
358
370
|
|
|
@@ -452,9 +464,11 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
452
464
|
if (!currentUrl.searchParams.has('kyc_id') && state.session.session_id) {
|
|
453
465
|
currentUrl.searchParams.set('kyc_id', state.session.session_id);
|
|
454
466
|
}
|
|
455
|
-
|
|
456
|
-
if (
|
|
457
|
-
currentUrl.searchParams.set('
|
|
467
|
+
currentUrl.searchParams.set('component_index', String(state.currentComponentIndex));
|
|
468
|
+
if (countrySelectionData?.code) {
|
|
469
|
+
currentUrl.searchParams.set('country', countrySelectionData.code);
|
|
470
|
+
if (countrySelectionData.documentType) currentUrl.searchParams.set('document_type', countrySelectionData.documentType);
|
|
471
|
+
if (countrySelectionData.region) currentUrl.searchParams.set('region', countrySelectionData.region);
|
|
458
472
|
}
|
|
459
473
|
return `https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${encodeURIComponent(currentUrl.toString())}`;
|
|
460
474
|
} catch (error) {
|
|
@@ -469,6 +483,22 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
469
483
|
|
|
470
484
|
|
|
471
485
|
|
|
486
|
+
// En reprise sur un autre appareil: afficher un chargement tant que les données de session ne sont pas restaurées
|
|
487
|
+
const isResumingSession = Boolean(state.session.session_id && state.currentComponentIndex > 0);
|
|
488
|
+
const sessionDataRestored = state.session.sessionDataRestored !== false;
|
|
489
|
+
if (isResumingSession && !sessionDataRestored && (!countrySelectionData || !selectedDocumentType)) {
|
|
490
|
+
return (
|
|
491
|
+
<View style={styles.root}>
|
|
492
|
+
<View style={[styles.container, { justifyContent: 'center', alignItems: 'center' }]}>
|
|
493
|
+
<ActivityIndicator size="large" color="#2DBD60" />
|
|
494
|
+
<Text style={[styles.description, { marginTop: 16 }]}>
|
|
495
|
+
{state.currentLanguage === 'en' ? 'Loading your session...' : 'Chargement de votre session...'}
|
|
496
|
+
</Text>
|
|
497
|
+
</View>
|
|
498
|
+
</View>
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
|
|
472
502
|
// Vérifier si les données sont disponibles, sinon afficher un message d'erreur
|
|
473
503
|
if (!countrySelectionData || !selectedDocumentType) {
|
|
474
504
|
return (
|
|
@@ -506,6 +536,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
506
536
|
showSwitchCamera={true}
|
|
507
537
|
onSilentCapture={handleSilentCapture}
|
|
508
538
|
silentCaptureResult={silentCaptureResult}
|
|
539
|
+
captureStabilizationDelayMs={3000}
|
|
509
540
|
enableFlash={cameraConfig.flashMode === 'auto' || cameraConfig.flashMode === 'on'}
|
|
510
541
|
overlayComponent={<IdCardOverlay
|
|
511
542
|
xMin={cameraConfig.overlay.bbox.xMin}
|
|
@@ -752,7 +783,7 @@ const styles = StyleSheet.create({
|
|
|
752
783
|
height: '100%',
|
|
753
784
|
},
|
|
754
785
|
previewContainer: {
|
|
755
|
-
width: '
|
|
786
|
+
width: '95%',
|
|
756
787
|
backgroundColor: 'white',
|
|
757
788
|
margin: 10,
|
|
758
789
|
borderRadius: 10,
|
|
@@ -150,7 +150,7 @@ export const WelcomeTemplate: React.FC<WelcomeTemplateProps> = ({
|
|
|
150
150
|
|
|
151
151
|
{/* Get Started Button */}
|
|
152
152
|
<Button
|
|
153
|
-
title={buttonText}
|
|
153
|
+
title={buttonText?.length === 0 ? t('kyc.welcome.getStarted') || 'Get Started' : buttonText}
|
|
154
154
|
fullWidth
|
|
155
155
|
onPress={handleGetStarted}
|
|
156
156
|
style={{ paddingVertical: 20, marginTop: 36 }}
|
|
@@ -175,6 +175,7 @@ const styles = StyleSheet.create({
|
|
|
175
175
|
shadowRadius: 1.84,
|
|
176
176
|
elevation: 3,
|
|
177
177
|
maxWidth: 760,
|
|
178
|
+
width: '94%',
|
|
178
179
|
},
|
|
179
180
|
title: {
|
|
180
181
|
fontSize: 24,
|
|
@@ -81,6 +81,8 @@ export interface EnhancedCameraViewProps {
|
|
|
81
81
|
onVideoRecordingStart?: () => void;
|
|
82
82
|
onVideoRecordingStop?: (result: { success: boolean; path?: string; error?: string }) => void;
|
|
83
83
|
videoDuration?: number;
|
|
84
|
+
/** Delay in ms before first auto-capture (lets camera focus and user position document). Recommended 2500–3000 for ID/document capture. */
|
|
85
|
+
captureStabilizationDelayMs?: number;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
export interface CheckTemplateTypeResponse {
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { View, SafeAreaView } from 'react-native';
|
|
3
3
|
import { TemplateKYCFlow } from './TemplateKYCFlowRefactored';
|
|
4
4
|
import { KYCTemplate, VerificationState } from '../types/KYC.types';
|
|
5
|
-
import { KycEnvironment } from '../types/env.types';
|
|
5
|
+
import { KycEnvironment, BackendEnvironment } from '../types/env.types';
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
@@ -144,10 +144,12 @@ export const TemplateKYCExample: React.FC<{
|
|
|
144
144
|
API_KEY?: string;
|
|
145
145
|
templateId?: string;
|
|
146
146
|
template?: KYCTemplate;
|
|
147
|
-
env?: KycEnvironment;
|
|
147
|
+
env?: KycEnvironment; // Flow execution: PRODUCTION (full AI) or SANDBOX (skip AI)
|
|
148
|
+
serverEnv?: BackendEnvironment; // Backend to call: PRODUCTION or TEST (API URL)
|
|
148
149
|
existingSessionId?: string;
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
initialComponentIndex?: number;
|
|
151
|
+
initialCountryResume?: { code: string; documentType: string; region?: string };
|
|
152
|
+
}> = ({ onComplete, onCancel, onError, language, API_KEY, templateId, template, env = 'PRODUCTION', serverEnv, existingSessionId, initialComponentIndex, initialCountryResume }) => {
|
|
151
153
|
const handleComplete = (data: VerificationState) => {
|
|
152
154
|
console.log('KYC Template completed with data:', data);
|
|
153
155
|
onComplete(data);
|
|
@@ -180,8 +182,10 @@ export const TemplateKYCExample: React.FC<{
|
|
|
180
182
|
language={language} // ou "en" pour l'anglais
|
|
181
183
|
API_KEY={API_KEY}
|
|
182
184
|
env={env}
|
|
185
|
+
serverEnv={serverEnv}
|
|
183
186
|
existingSessionId={existingSessionId}
|
|
184
|
-
|
|
187
|
+
initialComponentIndex={initialComponentIndex}
|
|
188
|
+
initialCountryResume={initialCountryResume}
|
|
185
189
|
/>
|
|
186
190
|
</View>
|
|
187
191
|
</SafeAreaView>
|
|
@@ -18,7 +18,8 @@ import { EmailVerificationTemplate } from './KYCElements/EmailVerificationTempla
|
|
|
18
18
|
import { PhoneVerificationTemplate } from './KYCElements/PhoneVerificationTemplate';
|
|
19
19
|
import { PersonalInformationTemplate } from './KYCElements/PersonalInformationTemplate';
|
|
20
20
|
import { AdditionalDocumentsTemplate } from './KYCElements/AdditionalDocumentsTemplate';
|
|
21
|
-
import { KycEnvironment } from '../types/env.types';
|
|
21
|
+
import { KycEnvironment, BackendEnvironment } from '../types/env.types';
|
|
22
|
+
import KYCConfig from '../config/KYCConfig';
|
|
22
23
|
|
|
23
24
|
interface TemplateKYCFlowProps {
|
|
24
25
|
template?: KYCTemplate; // Format SDK direct (existing, now optional)
|
|
@@ -28,9 +29,13 @@ interface TemplateKYCFlowProps {
|
|
|
28
29
|
language?: string;
|
|
29
30
|
onCancel?: () => void;
|
|
30
31
|
API_KEY?: string; // Required if templateId is used
|
|
31
|
-
env?: KycEnvironment; //
|
|
32
|
+
env?: KycEnvironment; // Flow execution: PRODUCTION (full AI) or SANDBOX (skip AI)
|
|
33
|
+
serverEnv?: BackendEnvironment; // Backend to call: PRODUCTION or TEST (API URL)
|
|
32
34
|
existingSessionId?: string;
|
|
33
|
-
|
|
35
|
+
/** Index in template.components (0-based) to resume at — e.g. from URL component_index or template table */
|
|
36
|
+
initialComponentIndex?: number;
|
|
37
|
+
/** Pays / type de document depuis l'URL de reprise (reprise multi-appareil) */
|
|
38
|
+
initialCountryResume?: { code: string; documentType: string; region?: string };
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
export const TemplateKYCFlow: React.FC<TemplateKYCFlowProps> = ({
|
|
@@ -42,12 +47,21 @@ export const TemplateKYCFlow: React.FC<TemplateKYCFlowProps> = ({
|
|
|
42
47
|
onCancel,
|
|
43
48
|
API_KEY,
|
|
44
49
|
env = 'PRODUCTION',
|
|
50
|
+
serverEnv,
|
|
45
51
|
existingSessionId,
|
|
46
|
-
|
|
52
|
+
initialComponentIndex,
|
|
53
|
+
initialCountryResume,
|
|
47
54
|
}) => {
|
|
48
55
|
const { t } = useI18n();
|
|
49
56
|
const { template: loadedTemplate, isLoading, error, loadTemplate } = useTemplateLoader();
|
|
50
57
|
|
|
58
|
+
// Which backend URL to call (independent from flow env)
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (serverEnv !== undefined) {
|
|
61
|
+
KYCConfig.setBackendEnvironment(serverEnv);
|
|
62
|
+
}
|
|
63
|
+
}, [serverEnv]);
|
|
64
|
+
|
|
51
65
|
// Validate props
|
|
52
66
|
useEffect(() => {
|
|
53
67
|
if (!providedTemplate && !templateId) {
|
|
@@ -136,7 +150,8 @@ export const TemplateKYCFlow: React.FC<TemplateKYCFlowProps> = ({
|
|
|
136
150
|
apiKey={API_KEY}
|
|
137
151
|
env={env}
|
|
138
152
|
existingSessionId={existingSessionId}
|
|
139
|
-
|
|
153
|
+
initialComponentIndex={initialComponentIndex}
|
|
154
|
+
initialCountryResume={initialCountryResume}
|
|
140
155
|
>
|
|
141
156
|
<TemplateKYCFlowContent onCancel={OnCancel} />
|
|
142
157
|
</TemplateKYCFlowProvider>
|
|
@@ -241,7 +256,10 @@ const TemplateKYCFlowContent: React.FC<{ onCancel?: () => void }> = ({ onCancel
|
|
|
241
256
|
{(state.showCustomStepper && state.session.isInitialized) ? (
|
|
242
257
|
<View style={styles.header}>
|
|
243
258
|
<Text style={styles.progressText}>
|
|
244
|
-
{t('kyc.step', {
|
|
259
|
+
{t('kyc.step', {
|
|
260
|
+
current: (state.template.components.findIndex(c => c.id === currentComponent.id) + 1) || (state.currentComponentIndex + 1),
|
|
261
|
+
total: state.template.components.length,
|
|
262
|
+
})}
|
|
245
263
|
</Text>
|
|
246
264
|
<View style={styles.progressContainer}>
|
|
247
265
|
<View style={styles.progressBar}>
|
package/src/config/KYCConfig.ts
CHANGED
|
@@ -6,7 +6,7 @@ class KYCConfig {
|
|
|
6
6
|
|
|
7
7
|
private backendUrls: Record<BackendEnvironment, string> = {
|
|
8
8
|
PRODUCTION: 'https://service.sanctumkey.com/api/v1',
|
|
9
|
-
TEST: 'https://
|
|
9
|
+
TEST: 'https://kyc-backend.transfergratis.net/api/v1', // Placeholder URL
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
private constructor() { }
|