@transfergratis/react-native-sdk 0.1.24 → 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/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +12 -5
- package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
- package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +61 -59
- package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-transfergratis-react-native-sdk.jar +0 -0
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +12 -5
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/aar/transfergratis-react-native-sdk-debug.aar +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +26 -34
- package/android/src/main/AndroidManifest.xml +22 -7
- 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/AdditionalDocumentsTemplate.d.ts +12 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js +283 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js.map +1 -0
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js +212 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +216 -14
- package/build/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.js +2 -2
- package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js +120 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js +185 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.js +7 -3
- package/build/components/KYCElements/SelfieCaptureTemplate.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 +10 -0
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +7 -30
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts +12 -0
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +25 -3
- package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/config/KYCConfig.d.ts +14 -0
- package/build/config/KYCConfig.d.ts.map +1 -0
- package/build/config/KYCConfig.js +26 -0
- package/build/config/KYCConfig.js.map +1 -0
- package/build/config/allowedDomains.d.ts.map +1 -1
- package/build/config/allowedDomains.js +4 -19
- package/build/config/allowedDomains.js.map +1 -1
- package/build/hooks/useOrientationVideo.d.ts +2 -1
- package/build/hooks/useOrientationVideo.d.ts.map +1 -1
- package/build/hooks/useOrientationVideo.js +3 -3
- package/build/hooks/useOrientationVideo.js.map +1 -1
- package/build/hooks/useTemplateKYCFlow.d.ts +18 -1
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +410 -56
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/i18n/en/index.d.ts +42 -0
- package/build/i18n/en/index.d.ts.map +1 -1
- package/build/i18n/en/index.js +44 -2
- package/build/i18n/en/index.js.map +1 -1
- package/build/i18n/fr/index.d.ts +28 -0
- package/build/i18n/fr/index.d.ts.map +1 -1
- package/build/i18n/fr/index.js +30 -2
- 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/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/modules/api/CardAuthentification.d.ts +24 -3
- package/build/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/modules/api/CardAuthentification.js +90 -12
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +17 -7
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +125 -37
- package/build/modules/api/KYCService.js.map +1 -1
- package/build/modules/api/SelfieVerification.d.ts +3 -1
- package/build/modules/api/SelfieVerification.d.ts.map +1 -1
- package/build/modules/api/SelfieVerification.js +17 -1
- package/build/modules/api/SelfieVerification.js.map +1 -1
- package/build/modules/api/TemplateService.d.ts +0 -1
- package/build/modules/api/TemplateService.d.ts.map +1 -1
- package/build/modules/api/TemplateService.js +3 -3
- package/build/modules/api/TemplateService.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 +130 -5
- package/build/types/KYC.types.d.ts.map +1 -1
- package/build/types/KYC.types.js.map +1 -1
- package/build/types/env.types.d.ts +13 -0
- package/build/types/env.types.d.ts.map +1 -0
- package/build/types/env.types.js +2 -0
- package/build/types/env.types.js.map +1 -0
- 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/utils/deviceDetection.d.ts +6 -0
- package/build/utils/deviceDetection.d.ts.map +1 -0
- package/build/utils/deviceDetection.js +12 -0
- package/build/utils/deviceDetection.js.map +1 -0
- package/build/utils/platformAlert.d.ts.map +1 -1
- package/build/utils/platformAlert.js.map +1 -1
- package/build/utils/template-transformer.d.ts.map +1 -1
- package/build/utils/template-transformer.js +12 -0
- package/build/utils/template-transformer.js.map +1 -1
- package/build/web/WebKYCEntry.d.ts.map +1 -1
- package/build/web/WebKYCEntry.js +88 -38
- 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/build/withVisionCamera.js +3 -4
- package/plugin/src/index.ts +2 -1
- package/plugin/src/withRemovePermissions.js +85 -0
- package/plugin/src/withRemovePermissions.ts +83 -0
- package/plugin/src/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.ts +3 -4
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/plugin.js +6 -1
- package/src/components/EnhancedCameraView.web.tsx +76 -21
- package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
- package/src/components/KYCElements/EmailVerificationTemplate.tsx +278 -0
- package/src/components/KYCElements/IDCardCapture.tsx +253 -21
- package/src/components/KYCElements/OrientationVideoCapture.tsx +4 -1
- package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +4 -1
- package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +4 -1
- package/src/components/KYCElements/PersonalInformationTemplate.tsx +158 -0
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +253 -0
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +6 -3
- package/src/components/KYCElements/WelcomeTemplate.tsx +2 -1
- package/src/components/OverLay/type.ts +2 -0
- package/src/components/TemplateKYCExample.tsx +35 -46
- package/src/components/TemplateKYCFlowRefactored.tsx +46 -2
- package/src/config/KYCConfig.ts +34 -0
- package/src/config/allowedDomains.ts +7 -26
- package/src/hooks/useOrientationVideo.ts +5 -4
- package/src/hooks/useTemplateKYCFlow.tsx +443 -56
- package/src/i18n/en/index.ts +46 -3
- package/src/i18n/fr/index.ts +31 -2
- package/src/i18n/types.ts +2 -0
- package/src/index.ts +3 -0
- package/src/modules/api/CardAuthentification.ts +98 -12
- package/src/modules/api/KYCService.ts +158 -37
- package/src/modules/api/SelfieVerification.ts +25 -3
- package/src/modules/api/TemplateService.ts +4 -4
- package/src/modules/camera/VisionCameraModule.web.ts +30 -12
- package/src/types/KYC.types.ts +153 -6
- package/src/types/env.types.ts +13 -0
- package/src/utils/cropByObb.ts +20 -1
- package/src/utils/deviceDetection.ts +11 -0
- package/src/utils/platformAlert.ts +1 -0
- package/src/utils/template-transformer.ts +20 -8
- package/src/web/WebKYCEntry.tsx +123 -61
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert } from 'react-native';
|
|
3
|
+
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
4
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
5
|
+
import { Button } from '../ui/Button';
|
|
6
|
+
import kycService, { errorMessage } from '../../modules/api/KYCService';
|
|
7
|
+
/** RFC-style email validation: local@domain.tld */
|
|
8
|
+
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
9
|
+
const isValidEmail = (value) => EMAIL_REGEX.test((value || '').trim());
|
|
10
|
+
export const EmailVerificationTemplate = ({ component, value, onValueChange, error: propError, }) => {
|
|
11
|
+
const { actions, getLocalizedText, state, apiKey } = useTemplateKYCFlowContext();
|
|
12
|
+
const { t } = useI18n();
|
|
13
|
+
const auth = apiKey ? { apiKey } : (state.session.token ? { token: state.session.token } : undefined);
|
|
14
|
+
// const config = component.config as EmailVerificationConfig; // Keep for future use
|
|
15
|
+
// State
|
|
16
|
+
const [step, setStep] = useState('email');
|
|
17
|
+
const [email, setEmail] = useState('');
|
|
18
|
+
const [otp, setOtp] = useState('');
|
|
19
|
+
const [localError, setLocalError] = useState(null);
|
|
20
|
+
const [isSimulating, setIsSimulating] = useState(false);
|
|
21
|
+
const title = getLocalizedText(component.labels);
|
|
22
|
+
const instructions = getLocalizedText(component.instructions);
|
|
23
|
+
// Determine button text based on step
|
|
24
|
+
const verifyButtonText = getLocalizedText(component.ui.buttonText) || t('common.verify') || 'Verify';
|
|
25
|
+
const sendButtonText = t('common.sendCode') || 'Send Verification Code';
|
|
26
|
+
const buttonText = step === 'email' ? sendButtonText : verifyButtonText;
|
|
27
|
+
const handleSendCode = async () => {
|
|
28
|
+
const trimmed = email.trim();
|
|
29
|
+
if (!trimmed || !isValidEmail(trimmed)) {
|
|
30
|
+
setLocalError(t('errors.invalidEmail') || 'Please enter a valid email address');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
setLocalError(null);
|
|
34
|
+
setIsSimulating(true);
|
|
35
|
+
try {
|
|
36
|
+
await kycService.sendEmailVerificationCode(trimmed, auth);
|
|
37
|
+
setStep('otp');
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send verification code');
|
|
41
|
+
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
setIsSimulating(false);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const handleVerifyCode = async () => {
|
|
48
|
+
if (!otp || otp.length < 4) {
|
|
49
|
+
setLocalError(t('errors.invalidCode') || 'Please enter the 6-digit code');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
setLocalError(null);
|
|
53
|
+
setIsSimulating(true);
|
|
54
|
+
try {
|
|
55
|
+
await kycService.verifyEmailCode(otp.trim(), auth);
|
|
56
|
+
const data = { email, otp, verified: true };
|
|
57
|
+
onValueChange(data);
|
|
58
|
+
actions.nextComponent(data);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
const msg = errorMessage(err) ?? err?.message ?? (t('errors.wrongCode') || 'Invalid verification code');
|
|
62
|
+
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
setIsSimulating(false);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const onChangeEmail = (text) => {
|
|
69
|
+
setEmail(text);
|
|
70
|
+
if (localError)
|
|
71
|
+
setLocalError(null);
|
|
72
|
+
};
|
|
73
|
+
const onChangeOtp = (text) => {
|
|
74
|
+
setOtp(text);
|
|
75
|
+
if (localError)
|
|
76
|
+
setLocalError(null);
|
|
77
|
+
};
|
|
78
|
+
const handleBackToEmail = () => {
|
|
79
|
+
setStep('email');
|
|
80
|
+
setOtp('');
|
|
81
|
+
setLocalError(null);
|
|
82
|
+
};
|
|
83
|
+
return (<View style={styles.container}>
|
|
84
|
+
<Text style={styles.title}>{title}</Text>
|
|
85
|
+
<Text style={styles.instructions}>
|
|
86
|
+
{step === 'email' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${email}`)}
|
|
87
|
+
</Text>
|
|
88
|
+
|
|
89
|
+
<View style={styles.contentContainer}>
|
|
90
|
+
{step === 'email' ? (<View style={styles.inputContainer}>
|
|
91
|
+
<Text style={styles.label}>{t('common.email') || 'Email'}</Text>
|
|
92
|
+
<TextInput style={styles.input} placeholder="name@example.com" value={email} onChangeText={onChangeEmail} keyboardType="email-address" autoCapitalize="none" autoCorrect={false} editable={!isSimulating}/>
|
|
93
|
+
</View>) : (<View style={styles.inputContainer}>
|
|
94
|
+
<Text style={styles.label}>{t('common.verificationCode') || 'Verification Code'}</Text>
|
|
95
|
+
<TextInput style={styles.input} placeholder="123456" value={otp} onChangeText={onChangeOtp} keyboardType="number-pad" maxLength={6} editable={!isSimulating}/>
|
|
96
|
+
<TouchableOpacity onPress={handleBackToEmail} style={styles.changeEmailLink}>
|
|
97
|
+
<Text style={styles.changeEmailText}>{t('common.changeEmail') || 'Change email'}</Text>
|
|
98
|
+
</TouchableOpacity>
|
|
99
|
+
</View>)}
|
|
100
|
+
|
|
101
|
+
{(localError || propError) && (<Text style={styles.errorText}>{localError || propError}</Text>)}
|
|
102
|
+
|
|
103
|
+
<Button title={isSimulating ? (t('common.processing') || 'Processing...') : buttonText} onPress={step === 'email' ? handleSendCode : handleVerifyCode} disabled={isSimulating ||
|
|
104
|
+
(step === 'email' ? !email : !otp)}/>
|
|
105
|
+
|
|
106
|
+
{step === 'otp' && (<TouchableOpacity onPress={async () => {
|
|
107
|
+
if (isSimulating)
|
|
108
|
+
return;
|
|
109
|
+
setLocalError(null);
|
|
110
|
+
setIsSimulating(true);
|
|
111
|
+
try {
|
|
112
|
+
await kycService.sendEmailVerificationCode(email.trim(), auth);
|
|
113
|
+
Alert.alert(t('common.codeResent') || 'Code Resent', t('common.codeResentMessage', { email }) || 'Code resent to ' + email);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send code');
|
|
117
|
+
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
setIsSimulating(false);
|
|
121
|
+
}
|
|
122
|
+
}} style={styles.resendButton} disabled={isSimulating}>
|
|
123
|
+
<Text style={styles.resendText}>{t('common.resendCode') || 'Resend Code'}</Text>
|
|
124
|
+
</TouchableOpacity>)}
|
|
125
|
+
</View>
|
|
126
|
+
</View>);
|
|
127
|
+
};
|
|
128
|
+
const styles = StyleSheet.create({
|
|
129
|
+
container: {
|
|
130
|
+
padding: 24,
|
|
131
|
+
backgroundColor: 'white',
|
|
132
|
+
borderRadius: 16,
|
|
133
|
+
margin: 16,
|
|
134
|
+
shadowColor: '#000',
|
|
135
|
+
shadowOffset: { width: 0, height: 4 },
|
|
136
|
+
shadowOpacity: 0.1,
|
|
137
|
+
shadowRadius: 12,
|
|
138
|
+
elevation: 5,
|
|
139
|
+
width: '95%',
|
|
140
|
+
},
|
|
141
|
+
title: {
|
|
142
|
+
fontSize: 24,
|
|
143
|
+
fontWeight: '700',
|
|
144
|
+
marginBottom: 8,
|
|
145
|
+
color: '#1a1a1a',
|
|
146
|
+
textAlign: 'center',
|
|
147
|
+
},
|
|
148
|
+
instructions: {
|
|
149
|
+
fontSize: 16,
|
|
150
|
+
color: '#666',
|
|
151
|
+
marginBottom: 32,
|
|
152
|
+
lineHeight: 24,
|
|
153
|
+
textAlign: 'center',
|
|
154
|
+
},
|
|
155
|
+
contentContainer: {
|
|
156
|
+
// width: '100%',
|
|
157
|
+
},
|
|
158
|
+
inputContainer: {
|
|
159
|
+
marginBottom: 24,
|
|
160
|
+
},
|
|
161
|
+
label: {
|
|
162
|
+
fontSize: 14,
|
|
163
|
+
fontWeight: '600',
|
|
164
|
+
color: '#333',
|
|
165
|
+
marginBottom: 8,
|
|
166
|
+
marginLeft: 4,
|
|
167
|
+
},
|
|
168
|
+
input: {
|
|
169
|
+
borderWidth: 1,
|
|
170
|
+
borderColor: '#e0e0e0',
|
|
171
|
+
padding: 16,
|
|
172
|
+
borderRadius: 12,
|
|
173
|
+
fontSize: 16,
|
|
174
|
+
backgroundColor: '#f8f9fa',
|
|
175
|
+
color: '#333',
|
|
176
|
+
},
|
|
177
|
+
errorText: {
|
|
178
|
+
color: '#dc2626',
|
|
179
|
+
marginBottom: 16,
|
|
180
|
+
fontSize: 14,
|
|
181
|
+
textAlign: 'center',
|
|
182
|
+
backgroundColor: '#fee2e2',
|
|
183
|
+
padding: 8,
|
|
184
|
+
borderRadius: 8,
|
|
185
|
+
overflow: 'hidden',
|
|
186
|
+
},
|
|
187
|
+
button: {
|
|
188
|
+
height: 50,
|
|
189
|
+
borderRadius: 12,
|
|
190
|
+
width: "100%"
|
|
191
|
+
},
|
|
192
|
+
changeEmailLink: {
|
|
193
|
+
alignSelf: 'flex-end',
|
|
194
|
+
marginTop: 8,
|
|
195
|
+
},
|
|
196
|
+
changeEmailText: {
|
|
197
|
+
color: '#2DBD60',
|
|
198
|
+
fontSize: 14,
|
|
199
|
+
fontWeight: '500',
|
|
200
|
+
},
|
|
201
|
+
resendButton: {
|
|
202
|
+
marginTop: 16,
|
|
203
|
+
alignItems: 'center',
|
|
204
|
+
width: "100%"
|
|
205
|
+
},
|
|
206
|
+
resendText: {
|
|
207
|
+
color: '#666',
|
|
208
|
+
fontSize: 14,
|
|
209
|
+
textDecorationLine: 'underline',
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
//# sourceMappingURL=EmailVerificationTemplate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailVerificationTemplate.js","sourceRoot":"","sources":["../../../src/components/KYCElements/EmailVerificationTemplate.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useState } from 'react';\nimport { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert } from 'react-native';\nimport { TemplateComponent, LocalizedText } from '../../types/KYC.types';\nimport { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';\nimport { useI18n } from '../../hooks/useI18n';\nimport { Button } from '../ui/Button';\nimport kycService, { errorMessage } from '../../modules/api/KYCService';\n\ninterface EmailVerificationTemplateProps {\n component: TemplateComponent;\n value?: any;\n onValueChange: (data: any) => void;\n error?: string;\n language?: string;\n}\n\ntype VerificationStep = 'email' | 'otp';\n\n/** RFC-style email validation: local@domain.tld */\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nconst isValidEmail = (value: string): boolean => EMAIL_REGEX.test((value || '').trim());\n\nexport const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps> = ({\n component,\n value,\n onValueChange,\n error: propError,\n}) => {\n const { actions, getLocalizedText, state, apiKey } = useTemplateKYCFlowContext();\n const { t } = useI18n();\n\n const auth = apiKey ? { apiKey } : (state.session.token ? { token: state.session.token } : undefined);\n // const config = component.config as EmailVerificationConfig; // Keep for future use\n\n // State\n const [step, setStep] = useState<VerificationStep>('email');\n const [email, setEmail] = useState('');\n const [otp, setOtp] = useState('');\n const [localError, setLocalError] = useState<string | null>(null);\n const [isSimulating, setIsSimulating] = useState(false);\n\n const title = getLocalizedText(component.labels as LocalizedText);\n const instructions = getLocalizedText(component.instructions as LocalizedText);\n\n // Determine button text based on step\n const verifyButtonText = getLocalizedText((component.ui as any).buttonText) || t('common.verify') || 'Verify';\n const sendButtonText = t('common.sendCode') || 'Send Verification Code';\n const buttonText = step === 'email' ? sendButtonText : verifyButtonText;\n\n const handleSendCode = async () => {\n const trimmed = email.trim();\n if (!trimmed || !isValidEmail(trimmed)) {\n setLocalError(t('errors.invalidEmail') || 'Please enter a valid email address');\n return;\n }\n\n setLocalError(null);\n setIsSimulating(true);\n\n try {\n await kycService.sendEmailVerificationCode(trimmed, auth);\n setStep('otp');\n } catch (err: any) {\n const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send verification code');\n setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));\n } finally {\n setIsSimulating(false);\n }\n };\n\n const handleVerifyCode = async () => {\n if (!otp || otp.length < 4) {\n setLocalError(t('errors.invalidCode') || 'Please enter the 6-digit code');\n return;\n }\n\n setLocalError(null);\n setIsSimulating(true);\n\n try {\n await kycService.verifyEmailCode(otp.trim(), auth);\n const data = { email, otp, verified: true };\n onValueChange(data);\n actions.nextComponent(data);\n } catch (err: any) {\n const msg = errorMessage(err) ?? err?.message ?? (t('errors.wrongCode') || 'Invalid verification code');\n setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));\n } finally {\n setIsSimulating(false);\n }\n };\n\n const onChangeEmail = (text: string) => {\n setEmail(text);\n if (localError) setLocalError(null);\n };\n\n const onChangeOtp = (text: string) => {\n setOtp(text);\n if (localError) setLocalError(null);\n };\n\n const handleBackToEmail = () => {\n setStep('email');\n setOtp('');\n setLocalError(null);\n };\n\n return (\n <View style={styles.container}>\n <Text style={styles.title}>{title}</Text>\n <Text style={styles.instructions}>\n {step === 'email' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${email}`)}\n </Text>\n\n <View style={styles.contentContainer}>\n {step === 'email' ? (\n <View style={styles.inputContainer}>\n <Text style={styles.label}>{t('common.email') || 'Email'}</Text>\n <TextInput\n style={styles.input}\n placeholder=\"name@example.com\"\n value={email}\n onChangeText={onChangeEmail}\n keyboardType=\"email-address\"\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isSimulating}\n />\n </View>\n ) : (\n <View style={styles.inputContainer}>\n <Text style={styles.label}>{t('common.verificationCode') || 'Verification Code'}</Text>\n <TextInput\n style={styles.input}\n placeholder=\"123456\"\n value={otp}\n onChangeText={onChangeOtp}\n keyboardType=\"number-pad\"\n maxLength={6}\n editable={!isSimulating}\n />\n <TouchableOpacity onPress={handleBackToEmail} style={styles.changeEmailLink}>\n <Text style={styles.changeEmailText}>{t('common.changeEmail') || 'Change email'}</Text>\n </TouchableOpacity>\n </View>\n )}\n\n {(localError || propError) && (\n <Text style={styles.errorText}>{localError || propError}</Text>\n )}\n\n <Button\n title={isSimulating ? (t('common.processing') || 'Processing...') : buttonText}\n onPress={step === 'email' ? handleSendCode : handleVerifyCode}\n\n\n disabled={\n isSimulating ||\n (step === 'email' ? !email : !otp)\n }\n />\n\n {step === 'otp' && (\n <TouchableOpacity\n onPress={async () => {\n if (isSimulating) return;\n setLocalError(null);\n setIsSimulating(true);\n try {\n await kycService.sendEmailVerificationCode(email.trim(), auth);\n Alert.alert(\n t('common.codeResent') || 'Code Resent',\n t('common.codeResentMessage', { email }) || 'Code resent to ' + email\n );\n } catch (err: any) {\n const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send code');\n setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));\n } finally {\n setIsSimulating(false);\n }\n }}\n style={styles.resendButton}\n disabled={isSimulating}\n >\n <Text style={styles.resendText}>{t('common.resendCode') || 'Resend Code'}</Text>\n </TouchableOpacity>\n )}\n </View>\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {\n padding: 24,\n backgroundColor: 'white',\n borderRadius: 16,\n margin: 16,\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 4 },\n shadowOpacity: 0.1,\n shadowRadius: 12,\n elevation: 5,\n width: '95%',\n },\n title: {\n fontSize: 24,\n fontWeight: '700',\n marginBottom: 8,\n color: '#1a1a1a',\n textAlign: 'center',\n },\n instructions: {\n fontSize: 16,\n color: '#666',\n marginBottom: 32,\n lineHeight: 24,\n textAlign: 'center',\n },\n contentContainer: {\n // width: '100%',\n },\n inputContainer: {\n marginBottom: 24,\n },\n label: {\n fontSize: 14,\n fontWeight: '600',\n color: '#333',\n marginBottom: 8,\n marginLeft: 4,\n },\n input: {\n borderWidth: 1,\n borderColor: '#e0e0e0',\n padding: 16,\n borderRadius: 12,\n fontSize: 16,\n backgroundColor: '#f8f9fa',\n color: '#333',\n },\n errorText: {\n color: '#dc2626',\n marginBottom: 16,\n fontSize: 14,\n textAlign: 'center',\n backgroundColor: '#fee2e2',\n padding: 8,\n borderRadius: 8,\n overflow: 'hidden',\n },\n button: {\n height: 50,\n borderRadius: 12,\n width: \"100%\"\n },\n changeEmailLink: {\n alignSelf: 'flex-end',\n marginTop: 8,\n },\n changeEmailText: {\n color: '#2DBD60',\n fontSize: 14,\n fontWeight: '500',\n },\n resendButton: {\n marginTop: 16,\n alignItems: 'center',\n width: \"100%\"\n },\n resendText: {\n color: '#666',\n fontSize: 14,\n textDecorationLine: 'underline',\n },\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IDCardCapture.d.ts","sourceRoot":"","sources":["../../../src/components/KYCElements/IDCardCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAI5D,OAAO,EAAE,iBAAiB,EAAoI,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"IDCardCapture.d.ts","sourceRoot":"","sources":["../../../src/components/KYCElements/IDCardCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAI5D,OAAO,EAAE,iBAAiB,EAAoI,MAAM,uBAAuB,CAAC;AAe5L,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACvC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAktBtD,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import { View, Text, StyleSheet, Image, ScrollView } 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 { GovernmentDocumentTypeShorted, GovernmentDocumentTypeBackend } from '../../types/KYC.types';
|
|
@@ -11,8 +11,9 @@ import { removeDuplicates } from '../../utils/remove-duplicate';
|
|
|
11
11
|
import { backVerification, checkTemplateType, frontVerification } from '../../modules/api/CardAuthentification';
|
|
12
12
|
import { getDocumentTypeInfo } from '../../utils/get-document-type-info';
|
|
13
13
|
import pathToBase64 from '../../utils/pathToBase64';
|
|
14
|
-
import { truncateFields } from '../../modules/api/KYCService';
|
|
15
|
-
import { cropByObb, cropImageWithBBox, cropImageWithBBoxWithTolerance } from '../../utils/cropByObb';
|
|
14
|
+
import kycService, { truncateFields } from '../../modules/api/KYCService';
|
|
15
|
+
import { cropByObb, cropImageWithBBox, cropImageWithBBoxWithTolerance, getObbConfidence, OBB_CONFIDENCE_THRESHOLD } from '../../utils/cropByObb';
|
|
16
|
+
import { isMobileWeb } from '../../utils/deviceDetection';
|
|
16
17
|
import { logger } from '../../utils/logger';
|
|
17
18
|
export const IDCardCapture = ({ component, value = {}, onValueChange, error, language = 'en', }) => {
|
|
18
19
|
const { t, locale } = useI18n();
|
|
@@ -23,6 +24,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
23
24
|
// Stocker les bbox par côté pour pouvoir restaurer les images croppées
|
|
24
25
|
const [bboxBySide, setBboxBySide] = useState({});
|
|
25
26
|
const [silentCaptureResult, setSilentCaptureResult] = useState({ success: false, isAnalyzing: false });
|
|
27
|
+
const [showQRModal, setShowQRModal] = useState(false);
|
|
26
28
|
// Mapping des types de documents backend vers SDK
|
|
27
29
|
const documentTypeMapping = {
|
|
28
30
|
'nationalId': 'national_id',
|
|
@@ -32,7 +34,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
32
34
|
'healthInsuranceCard': 'health_insurance_card',
|
|
33
35
|
};
|
|
34
36
|
// const [imageNaturalSize, setImageNaturalSize] = useState<{ width: number; height: number } | null>(null);
|
|
35
|
-
const { actions, state } = useTemplateKYCFlowContext();
|
|
37
|
+
const { actions, state, env } = useTemplateKYCFlowContext();
|
|
36
38
|
const getLocalizedText = (text) => {
|
|
37
39
|
// console.log("text", text, JSON.stringify(component, null, 2));
|
|
38
40
|
if (text && typeof text[currentSide] === 'object' && text[currentSide][locale]) {
|
|
@@ -61,6 +63,33 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
61
63
|
const countryData = useMemo(() => {
|
|
62
64
|
return countrySelectionData;
|
|
63
65
|
}, [countrySelectionData]);
|
|
66
|
+
// Synchroniser capturedImages avec value quand les données sont chargées (ex: reprise de session)
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (value && Object.keys(value).length > 0) {
|
|
69
|
+
// Vérifier si les données ont changé
|
|
70
|
+
const valueChanged = JSON.stringify(value) !== JSON.stringify(capturedImages);
|
|
71
|
+
if (valueChanged) {
|
|
72
|
+
logger.log("Updating capturedImages from value:", Object.keys(value));
|
|
73
|
+
logger.log("Value data sample:", truncateFields(value));
|
|
74
|
+
const updatedImages = value;
|
|
75
|
+
setCapturedImages(updatedImages);
|
|
76
|
+
// Si on a des images chargées, mettre à jour silentCaptureResult pour l'affichage
|
|
77
|
+
Object.keys(updatedImages).forEach((side) => {
|
|
78
|
+
const imageData = updatedImages[side];
|
|
79
|
+
if (imageData?.dir) {
|
|
80
|
+
setSilentCaptureResult(prev => ({
|
|
81
|
+
...prev,
|
|
82
|
+
path: imageData.dir,
|
|
83
|
+
success: true,
|
|
84
|
+
isAnalyzing: false,
|
|
85
|
+
mrz: imageData.mrz || '',
|
|
86
|
+
templatePath: imageData.templatePath || '',
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}, [value]);
|
|
64
93
|
useEffect(() => {
|
|
65
94
|
logger.log("cropImageUri", JSON.stringify(truncateFields({ box: silentCaptureResult }), null, 2));
|
|
66
95
|
if (capturedImages[currentSide]?.dir && silentCaptureResult?.bbox) {
|
|
@@ -158,13 +187,23 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
158
187
|
countrySelectionDataDocumentType: countrySelectionData?.documentType,
|
|
159
188
|
docTypeToSend: selectedDocumentType?.type
|
|
160
189
|
});
|
|
161
|
-
const templateType = await checkTemplateType({ path: result.path || '', docType: selectedDocumentType?.type, docRegion: countryData?.code || "", postfix: currentSide });
|
|
190
|
+
const templateType = await checkTemplateType({ path: result.path || '', docType: selectedDocumentType?.type, docRegion: countryData?.code || "", postfix: currentSide }, env);
|
|
162
191
|
if (templateType.template_path) {
|
|
163
192
|
templatePath = templateType.template_path;
|
|
164
193
|
logger.log("templatePath", templatePath);
|
|
165
194
|
setSilentCaptureResult((prev) => ({ ...prev, templatePath: templatePath }));
|
|
166
195
|
}
|
|
167
196
|
if (templateType.card_obb) {
|
|
197
|
+
const obbConfidence = getObbConfidence(templateType.card_obb);
|
|
198
|
+
if (obbConfidence !== null && obbConfidence < OBB_CONFIDENCE_THRESHOLD) {
|
|
199
|
+
setSilentCaptureResult((prev) => ({
|
|
200
|
+
...prev,
|
|
201
|
+
isAnalyzing: false,
|
|
202
|
+
success: false,
|
|
203
|
+
error: t('kyc.idCardCapture.cardNotFullyInFrame'),
|
|
204
|
+
}));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
168
207
|
let bbox;
|
|
169
208
|
try {
|
|
170
209
|
const crop = await cropByObb(result?.path || '', templateType.card_obb);
|
|
@@ -206,7 +245,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
206
245
|
};
|
|
207
246
|
console.log("frontVerification params", verificationParams);
|
|
208
247
|
console.log("About to call frontVerification function");
|
|
209
|
-
const promise = frontVerification(verificationParams);
|
|
248
|
+
const promise = frontVerification(verificationParams, env);
|
|
210
249
|
console.log("frontVerification promise created", promise);
|
|
211
250
|
promise.then((mrz) => {
|
|
212
251
|
logger.log("front verification result", truncateFields(mrz));
|
|
@@ -227,8 +266,9 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
227
266
|
}).catch((e) => {
|
|
228
267
|
console.log("error front verification", e);
|
|
229
268
|
logger.log("error front verification", truncateFields(e));
|
|
230
|
-
|
|
231
|
-
|
|
269
|
+
const isCardNotFullyInFrame = e?.message?.includes('entirement') || e?.message?.includes('fully in frame');
|
|
270
|
+
const errorMessage = isCardNotFullyInFrame ? t('kyc.idCardCapture.cardNotFullyInFrame') : (e?.message || 'Erreur de détection du MRZ');
|
|
271
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, templatePath: templatePath, success: false, error: errorMessage }));
|
|
232
272
|
});
|
|
233
273
|
}
|
|
234
274
|
catch (error) {
|
|
@@ -250,7 +290,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
250
290
|
currentSide: currentSide,
|
|
251
291
|
templatePath: templatePath,
|
|
252
292
|
mrzType: getCorrespondingMrzType(templatePath, backRegionMappings.regionMapping, backRegionMappings.key || '') || '',
|
|
253
|
-
}).then((mrz) => {
|
|
293
|
+
}, env).then((mrz) => {
|
|
254
294
|
logger.log("back verification result", truncateFields(mrz));
|
|
255
295
|
const bbox = mrz?.bbox || templateBbox;
|
|
256
296
|
setSilentCaptureResult((prev) => ({
|
|
@@ -265,8 +305,9 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
265
305
|
}
|
|
266
306
|
}).catch((e) => {
|
|
267
307
|
logger.log("error back verification", truncateFields(e));
|
|
268
|
-
|
|
269
|
-
|
|
308
|
+
const isCardNotFullyInFrame = e?.message?.includes('entirement') || e?.message?.includes('fully in frame');
|
|
309
|
+
const errorMessage = isCardNotFullyInFrame ? t('kyc.idCardCapture.cardNotFullyInFrame') : (e?.message || 'Erreur de détection du MRZ');
|
|
310
|
+
setSilentCaptureResult((prev) => ({ ...prev, isAnalyzing: false, templatePath: templatePath, success: false, error: errorMessage }));
|
|
270
311
|
});
|
|
271
312
|
}
|
|
272
313
|
}
|
|
@@ -315,6 +356,73 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
315
356
|
useEffect(() => {
|
|
316
357
|
actions.showCustomStepper(!showCamera);
|
|
317
358
|
}, [showCamera]);
|
|
359
|
+
// Cross-device polling logic
|
|
360
|
+
useEffect(() => {
|
|
361
|
+
if (!showQRModal || !state.session.session_id)
|
|
362
|
+
return;
|
|
363
|
+
const pollInterval = setInterval(async () => {
|
|
364
|
+
try {
|
|
365
|
+
const result = await kycService.getVerificationResult(state.session.session_id);
|
|
366
|
+
const sessionData = result[state.session.session_id]?.data;
|
|
367
|
+
if (sessionData) {
|
|
368
|
+
// Check if verification is completed or if we have ID card data
|
|
369
|
+
// Since the requirement is "verification restarts", we might look for overall completion
|
|
370
|
+
// or we could check if user_data is populated.
|
|
371
|
+
// For now, let's assume if status is not PENDING/INITIALIZED it might be done.
|
|
372
|
+
// Or simplier: if the mobile flow completes, the session status updates.
|
|
373
|
+
logger.log('Polling result:', truncateFields(sessionData));
|
|
374
|
+
if (sessionData.verification_status === 'completed' || sessionData.verification_status === 'approved' || sessionData.verification_status === 'review') {
|
|
375
|
+
clearInterval(pollInterval);
|
|
376
|
+
setShowQRModal(false);
|
|
377
|
+
actions.submitVerification(); // Or handleComplete
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
console.error('Polling error:', error);
|
|
383
|
+
}
|
|
384
|
+
}, 5000);
|
|
385
|
+
return () => clearInterval(pollInterval);
|
|
386
|
+
}, [showQRModal, state.session.session_id, actions]);
|
|
387
|
+
const getQrCodeUrl = () => {
|
|
388
|
+
// Only available on web platform
|
|
389
|
+
if (Platform.OS !== 'web')
|
|
390
|
+
return '';
|
|
391
|
+
if (typeof window === 'undefined' || !window.location || !window.location.href)
|
|
392
|
+
return '';
|
|
393
|
+
try {
|
|
394
|
+
const currentUrl = new URL(window.location.href);
|
|
395
|
+
if (!currentUrl.searchParams.has('kyc_id') && state.session.session_id) {
|
|
396
|
+
currentUrl.searchParams.set('kyc_id', state.session.session_id);
|
|
397
|
+
}
|
|
398
|
+
currentUrl.searchParams.set('component_index', String(state.currentComponentIndex));
|
|
399
|
+
if (countrySelectionData?.code) {
|
|
400
|
+
currentUrl.searchParams.set('country', countrySelectionData.code);
|
|
401
|
+
if (countrySelectionData.documentType)
|
|
402
|
+
currentUrl.searchParams.set('document_type', countrySelectionData.documentType);
|
|
403
|
+
if (countrySelectionData.region)
|
|
404
|
+
currentUrl.searchParams.set('region', countrySelectionData.region);
|
|
405
|
+
}
|
|
406
|
+
return `https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${encodeURIComponent(currentUrl.toString())}`;
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
console.warn('Error generating QR code URL:', error);
|
|
410
|
+
return '';
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
// En reprise sur un autre appareil: afficher un chargement tant que les données de session ne sont pas restaurées
|
|
414
|
+
const isResumingSession = Boolean(state.session.session_id && state.currentComponentIndex > 0);
|
|
415
|
+
const sessionDataRestored = state.session.sessionDataRestored !== false;
|
|
416
|
+
if (isResumingSession && !sessionDataRestored && (!countrySelectionData || !selectedDocumentType)) {
|
|
417
|
+
return (<View style={styles.root}>
|
|
418
|
+
<View style={[styles.container, { justifyContent: 'center', alignItems: 'center' }]}>
|
|
419
|
+
<ActivityIndicator size="large" color="#2DBD60"/>
|
|
420
|
+
<Text style={[styles.description, { marginTop: 16 }]}>
|
|
421
|
+
{state.currentLanguage === 'en' ? 'Loading your session...' : 'Chargement de votre session...'}
|
|
422
|
+
</Text>
|
|
423
|
+
</View>
|
|
424
|
+
</View>);
|
|
425
|
+
}
|
|
318
426
|
// Vérifier si les données sont disponibles, sinon afficher un message d'erreur
|
|
319
427
|
if (!countrySelectionData || !selectedDocumentType) {
|
|
320
428
|
return (<View style={styles.root}>
|
|
@@ -331,7 +439,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
331
439
|
}
|
|
332
440
|
if (showCamera) {
|
|
333
441
|
return (<View style={styles.cameraContainer}>
|
|
334
|
-
<EnhancedCameraView showCamera={true} cameraType={cameraConfig.cameraType} style={styles.camera} onCapture={handleCapture} onError={handleError} onClose={() => setShowCamera(false)} quality="high" showCaptureButton={true} showSwitchCamera={true} onSilentCapture={handleSilentCapture} silentCaptureResult={silentCaptureResult} enableFlash={cameraConfig.flashMode === 'auto' || cameraConfig.flashMode === 'on'} overlayComponent={<IdCardOverlay xMin={cameraConfig.overlay.bbox.xMin} yMin={cameraConfig.overlay.bbox.yMin} xMax={cameraConfig.overlay.bbox.xMax} yMax={cameraConfig.overlay.bbox.yMax} instructions={cameraConfig.overlay.guideText} cornerOpacity={cameraConfig.overlay.bbox.cornerRadius || 0} isSuccess={silentCaptureResult.success} language={state.currentLanguage} stepperProps={{
|
|
442
|
+
<EnhancedCameraView showCamera={true} cameraType={cameraConfig.cameraType} style={styles.camera} onCapture={handleCapture} onError={handleError} onClose={() => setShowCamera(false)} quality="high" showCaptureButton={true} showSwitchCamera={true} onSilentCapture={handleSilentCapture} silentCaptureResult={silentCaptureResult} captureStabilizationDelayMs={3000} enableFlash={cameraConfig.flashMode === 'auto' || cameraConfig.flashMode === 'on'} overlayComponent={<IdCardOverlay xMin={cameraConfig.overlay.bbox.xMin} yMin={cameraConfig.overlay.bbox.yMin} xMax={cameraConfig.overlay.bbox.xMax} yMax={cameraConfig.overlay.bbox.yMax} instructions={cameraConfig.overlay.guideText} cornerOpacity={cameraConfig.overlay.bbox.cornerRadius || 0} isSuccess={silentCaptureResult.success} language={state.currentLanguage} stepperProps={{
|
|
335
443
|
back: () => {
|
|
336
444
|
if (currentSide === 'back') {
|
|
337
445
|
setCurrentSide('front');
|
|
@@ -404,7 +512,13 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
404
512
|
borderRadius: 12,
|
|
405
513
|
resizeMode: 'cover',
|
|
406
514
|
}}/>) : null}
|
|
407
|
-
{silentCaptureResult.path ? (<Image source={{ uri: silentCaptureResult.path }} style={{
|
|
515
|
+
{!cropImageUri && silentCaptureResult.path ? (<Image source={{ uri: silentCaptureResult.path }} style={{
|
|
516
|
+
width: '100%',
|
|
517
|
+
height: 200,
|
|
518
|
+
borderRadius: 12,
|
|
519
|
+
resizeMode: 'cover',
|
|
520
|
+
}}/>) : null}
|
|
521
|
+
{!cropImageUri && !silentCaptureResult.path && capturedImages[currentSide]?.dir ? (<Image source={{ uri: capturedImages[currentSide].dir }} style={{
|
|
408
522
|
width: '100%',
|
|
409
523
|
height: 200,
|
|
410
524
|
borderRadius: 12,
|
|
@@ -446,6 +560,32 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
|
|
|
446
560
|
|
|
447
561
|
|
|
448
562
|
{error && (<Text style={styles.errorText}>{error}</Text>)}
|
|
563
|
+
|
|
564
|
+
{/* Cross-Device / Continue on Phone Button (Web Only) */}
|
|
565
|
+
{Platform.OS === 'web' && !isMobileWeb() && !capturedImages[currentSide]?.dir && (<Button title={t('kyc.idCardCapture.continueOnPhone')} onPress={() => { setShowQRModal(true); }}/>)}
|
|
566
|
+
|
|
567
|
+
{/* QR Code Modal - Web Only */}
|
|
568
|
+
{Platform.OS === 'web' && (<Modal visible={showQRModal} transparent={true} animationType="fade" onRequestClose={() => setShowQRModal(false)}>
|
|
569
|
+
<View style={styles.modalOverlay}>
|
|
570
|
+
<View style={styles.modalContent}>
|
|
571
|
+
<Text style={styles.modalTitle}>
|
|
572
|
+
{t('kyc.idCardCapture.continueOnMobile')}
|
|
573
|
+
</Text>
|
|
574
|
+
<Text style={styles.modalDescription}>
|
|
575
|
+
{t('kyc.idCardCapture.scanQrCode')}
|
|
576
|
+
</Text>
|
|
577
|
+
|
|
578
|
+
{showQRModal && getQrCodeUrl() ? (<Image source={{ uri: getQrCodeUrl() }} style={styles.qrCodeImage}/>) : null}
|
|
579
|
+
|
|
580
|
+
<TouchableOpacity style={styles.closeButton} onPress={() => setShowQRModal(false)}>
|
|
581
|
+
<Text style={styles.closeButtonText}>
|
|
582
|
+
{t('common.close')}
|
|
583
|
+
</Text>
|
|
584
|
+
</TouchableOpacity>
|
|
585
|
+
</View>
|
|
586
|
+
</View>
|
|
587
|
+
</Modal>)}
|
|
588
|
+
|
|
449
589
|
</View>
|
|
450
590
|
</View>);
|
|
451
591
|
};
|
|
@@ -475,7 +615,7 @@ const styles = StyleSheet.create({
|
|
|
475
615
|
height: '100%',
|
|
476
616
|
},
|
|
477
617
|
previewContainer: {
|
|
478
|
-
width: '
|
|
618
|
+
width: '95%',
|
|
479
619
|
backgroundColor: 'white',
|
|
480
620
|
margin: 10,
|
|
481
621
|
borderRadius: 10,
|
|
@@ -599,5 +739,67 @@ const styles = StyleSheet.create({
|
|
|
599
739
|
marginTop: 8,
|
|
600
740
|
textAlign: 'center',
|
|
601
741
|
},
|
|
742
|
+
crossDeviceButton: {
|
|
743
|
+
marginTop: 16,
|
|
744
|
+
padding: 12,
|
|
745
|
+
alignItems: 'center',
|
|
746
|
+
borderWidth: 1,
|
|
747
|
+
borderColor: '#2DBD60',
|
|
748
|
+
borderRadius: 8,
|
|
749
|
+
backgroundColor: '#f0f9f0',
|
|
750
|
+
},
|
|
751
|
+
crossDeviceText: {
|
|
752
|
+
color: '#2DBD60',
|
|
753
|
+
fontSize: 16,
|
|
754
|
+
fontWeight: '600',
|
|
755
|
+
},
|
|
756
|
+
modalOverlay: {
|
|
757
|
+
flex: 1,
|
|
758
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
759
|
+
justifyContent: 'center',
|
|
760
|
+
alignItems: 'center',
|
|
761
|
+
},
|
|
762
|
+
modalContent: {
|
|
763
|
+
backgroundColor: 'white',
|
|
764
|
+
borderRadius: 16,
|
|
765
|
+
padding: 24,
|
|
766
|
+
alignItems: 'center',
|
|
767
|
+
width: '90%',
|
|
768
|
+
maxWidth: 340,
|
|
769
|
+
shadowColor: '#000',
|
|
770
|
+
shadowOffset: { width: 0, height: 2 },
|
|
771
|
+
shadowOpacity: 0.25,
|
|
772
|
+
shadowRadius: 4,
|
|
773
|
+
elevation: 5,
|
|
774
|
+
},
|
|
775
|
+
modalTitle: {
|
|
776
|
+
fontSize: 20,
|
|
777
|
+
fontWeight: 'bold',
|
|
778
|
+
marginBottom: 12,
|
|
779
|
+
color: '#333',
|
|
780
|
+
},
|
|
781
|
+
modalDescription: {
|
|
782
|
+
fontSize: 16,
|
|
783
|
+
color: '#666',
|
|
784
|
+
textAlign: 'center',
|
|
785
|
+
marginBottom: 20,
|
|
786
|
+
lineHeight: 22,
|
|
787
|
+
},
|
|
788
|
+
qrCodeImage: {
|
|
789
|
+
width: 200,
|
|
790
|
+
height: 200,
|
|
791
|
+
marginBottom: 20,
|
|
792
|
+
},
|
|
793
|
+
closeButton: {
|
|
794
|
+
paddingVertical: 10,
|
|
795
|
+
paddingHorizontal: 20,
|
|
796
|
+
backgroundColor: '#f5f5f5',
|
|
797
|
+
borderRadius: 8,
|
|
798
|
+
},
|
|
799
|
+
closeButtonText: {
|
|
800
|
+
fontSize: 16,
|
|
801
|
+
color: '#666',
|
|
802
|
+
fontWeight: '600',
|
|
803
|
+
},
|
|
602
804
|
});
|
|
603
805
|
//# sourceMappingURL=IDCardCapture.js.map
|