@transfergratis/react-native-sdk 0.1.24 → 0.1.25
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 +10 -7
- 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 +193 -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 +180 -7
- 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/TemplateKYCExample.d.ts +4 -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 +4 -0
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +14 -2
- 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 +6 -1
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +286 -23
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/i18n/en/index.d.ts +40 -0
- package/build/i18n/en/index.d.ts.map +1 -1
- package/build/i18n/en/index.js +41 -1
- package/build/i18n/en/index.js.map +1 -1
- package/build/i18n/fr/index.d.ts +26 -0
- package/build/i18n/fr/index.d.ts.map +1 -1
- package/build/i18n/fr/index.js +27 -1
- package/build/i18n/fr/index.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 +68 -10
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +7 -7
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +101 -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/types/KYC.types.d.ts +124 -3
- 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/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 +82 -38
- package/build/web/WebKYCEntry.js.map +1 -1
- package/package.json +1 -1
- package/plugin/build/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.ts +3 -4
- package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
- package/src/components/KYCElements/EmailVerificationTemplate.tsx +264 -0
- package/src/components/KYCElements/IDCardCapture.tsx +216 -15
- 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/TemplateKYCExample.tsx +31 -46
- package/src/components/TemplateKYCFlowRefactored.tsx +27 -1
- 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 +314 -21
- package/src/i18n/en/index.ts +43 -2
- package/src/i18n/fr/index.ts +28 -1
- package/src/index.ts +3 -0
- package/src/modules/api/CardAuthentification.ts +75 -10
- package/src/modules/api/KYCService.ts +117 -37
- package/src/modules/api/SelfieVerification.ts +25 -3
- package/src/modules/api/TemplateService.ts +4 -4
- package/src/types/KYC.types.ts +146 -3
- package/src/types/env.types.ts +13 -0
- 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 +112 -61
|
@@ -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 } 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';
|
|
@@ -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';
|
|
14
|
+
import kycService, { truncateFields } from '../../modules/api/KYCService';
|
|
15
15
|
import { cropByObb, cropImageWithBBox, cropImageWithBBoxWithTolerance } from '../../utils/cropByObb';
|
|
16
|
+
import { isMobileWeb } from '../../utils/deviceDetection';
|
|
16
17
|
import { logger } from '../../utils/logger';
|
|
17
18
|
|
|
18
19
|
|
|
@@ -47,6 +48,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
47
48
|
// Stocker les bbox par côté pour pouvoir restaurer les images croppées
|
|
48
49
|
const [bboxBySide, setBboxBySide] = useState<Record<string, IBbox>>({});
|
|
49
50
|
const [silentCaptureResult, setSilentCaptureResult] = useState<ISilentCaptureResult>({ success: false, isAnalyzing: false });
|
|
51
|
+
const [showQRModal, setShowQRModal] = useState(false);
|
|
50
52
|
|
|
51
53
|
// Mapping des types de documents backend vers SDK
|
|
52
54
|
const documentTypeMapping: Record<string, GovernmentDocumentType> = {
|
|
@@ -58,7 +60,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
58
60
|
};
|
|
59
61
|
// const [imageNaturalSize, setImageNaturalSize] = useState<{ width: number; height: number } | null>(null);
|
|
60
62
|
|
|
61
|
-
const { actions, state } = useTemplateKYCFlowContext();
|
|
63
|
+
const { actions, state, env } = useTemplateKYCFlowContext();
|
|
62
64
|
|
|
63
65
|
|
|
64
66
|
|
|
@@ -96,6 +98,35 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
96
98
|
}, [countrySelectionData]);
|
|
97
99
|
|
|
98
100
|
|
|
101
|
+
// Synchroniser capturedImages avec value quand les données sont chargées (ex: reprise de session)
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (value && Object.keys(value).length > 0) {
|
|
104
|
+
// Vérifier si les données ont changé
|
|
105
|
+
const valueChanged = JSON.stringify(value) !== JSON.stringify(capturedImages);
|
|
106
|
+
if (valueChanged) {
|
|
107
|
+
logger.log("Updating capturedImages from value:", Object.keys(value));
|
|
108
|
+
logger.log("Value data sample:", truncateFields(value));
|
|
109
|
+
const updatedImages = value as Record<string, IIDCardPayload>;
|
|
110
|
+
setCapturedImages(updatedImages);
|
|
111
|
+
|
|
112
|
+
// Si on a des images chargées, mettre à jour silentCaptureResult pour l'affichage
|
|
113
|
+
Object.keys(updatedImages).forEach((side) => {
|
|
114
|
+
const imageData = updatedImages[side];
|
|
115
|
+
if (imageData?.dir) {
|
|
116
|
+
setSilentCaptureResult(prev => ({
|
|
117
|
+
...prev,
|
|
118
|
+
path: imageData.dir,
|
|
119
|
+
success: true,
|
|
120
|
+
isAnalyzing: false,
|
|
121
|
+
mrz: imageData.mrz || '',
|
|
122
|
+
templatePath: imageData.templatePath || '',
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}, [value]);
|
|
129
|
+
|
|
99
130
|
useEffect(() => {
|
|
100
131
|
logger.log("cropImageUri", JSON.stringify(truncateFields({ box: silentCaptureResult }), null, 2));
|
|
101
132
|
if (capturedImages[currentSide]?.dir && silentCaptureResult?.bbox) {
|
|
@@ -213,7 +244,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
213
244
|
countrySelectionDataDocumentType: countrySelectionData?.documentType,
|
|
214
245
|
docTypeToSend: selectedDocumentType?.type
|
|
215
246
|
});
|
|
216
|
-
const templateType = await checkTemplateType({ path: result.path || '', docType: selectedDocumentType?.type as GovernmentDocumentType, docRegion: countryData?.code || "", postfix: currentSide });
|
|
247
|
+
const templateType = await checkTemplateType({ path: result.path || '', docType: selectedDocumentType?.type as GovernmentDocumentType, docRegion: countryData?.code || "", postfix: currentSide }, env);
|
|
217
248
|
|
|
218
249
|
if (templateType.template_path) {
|
|
219
250
|
templatePath = templateType.template_path;
|
|
@@ -260,7 +291,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
260
291
|
};
|
|
261
292
|
console.log("frontVerification params", verificationParams);
|
|
262
293
|
console.log("About to call frontVerification function");
|
|
263
|
-
const promise = frontVerification(verificationParams);
|
|
294
|
+
const promise = frontVerification(verificationParams, env);
|
|
264
295
|
console.log("frontVerification promise created", promise);
|
|
265
296
|
promise.then((mrz) => {
|
|
266
297
|
logger.log("front verification result", truncateFields(mrz));
|
|
@@ -304,7 +335,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
304
335
|
currentSide: currentSide,
|
|
305
336
|
templatePath: templatePath,
|
|
306
337
|
mrzType: getCorrespondingMrzType(templatePath, backRegionMappings.regionMapping, backRegionMappings.key || '') || '',
|
|
307
|
-
}).then((mrz) => {
|
|
338
|
+
}, env).then((mrz) => {
|
|
308
339
|
logger.log("back verification result", truncateFields(mrz));
|
|
309
340
|
const bbox = (mrz as any)?.bbox || templateBbox;
|
|
310
341
|
setSilentCaptureResult((prev) => ({
|
|
@@ -380,6 +411,58 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
380
411
|
actions.showCustomStepper(!showCamera);
|
|
381
412
|
}, [showCamera]);
|
|
382
413
|
|
|
414
|
+
// Cross-device polling logic
|
|
415
|
+
useEffect(() => {
|
|
416
|
+
if (!showQRModal || !state.session.session_id) return;
|
|
417
|
+
|
|
418
|
+
const pollInterval = setInterval(async () => {
|
|
419
|
+
try {
|
|
420
|
+
const result = await kycService.getVerificationResult(state.session.session_id);
|
|
421
|
+
const sessionData = result[state.session.session_id]?.data;
|
|
422
|
+
|
|
423
|
+
if (sessionData) {
|
|
424
|
+
// Check if verification is completed or if we have ID card data
|
|
425
|
+
// Since the requirement is "verification restarts", we might look for overall completion
|
|
426
|
+
// or we could check if user_data is populated.
|
|
427
|
+
// For now, let's assume if status is not PENDING/INITIALIZED it might be done.
|
|
428
|
+
// Or simplier: if the mobile flow completes, the session status updates.
|
|
429
|
+
logger.log('Polling result:', truncateFields(sessionData));
|
|
430
|
+
|
|
431
|
+
if (sessionData.verification_status === 'completed' || sessionData.verification_status === 'approved' || sessionData.verification_status === 'review') {
|
|
432
|
+
clearInterval(pollInterval);
|
|
433
|
+
setShowQRModal(false);
|
|
434
|
+
actions.submitVerification(); // Or handleComplete
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
} catch (error) {
|
|
438
|
+
console.error('Polling error:', error);
|
|
439
|
+
}
|
|
440
|
+
}, 5000);
|
|
441
|
+
|
|
442
|
+
return () => clearInterval(pollInterval);
|
|
443
|
+
}, [showQRModal, state.session.session_id, actions]);
|
|
444
|
+
|
|
445
|
+
const getQrCodeUrl = (): string => {
|
|
446
|
+
// Only available on web platform
|
|
447
|
+
if (Platform.OS !== 'web') return '';
|
|
448
|
+
if (typeof window === 'undefined' || !window.location || !window.location.href) return '';
|
|
449
|
+
|
|
450
|
+
try {
|
|
451
|
+
const currentUrl = new URL(window.location.href);
|
|
452
|
+
if (!currentUrl.searchParams.has('kyc_id') && state.session.session_id) {
|
|
453
|
+
currentUrl.searchParams.set('kyc_id', state.session.session_id);
|
|
454
|
+
}
|
|
455
|
+
// Ajouter l'étape actuelle pour permettre à l'utilisateur de continuer au bon endroit
|
|
456
|
+
if (!currentUrl.searchParams.has('step')) {
|
|
457
|
+
currentUrl.searchParams.set('step', String(state.currentComponentIndex));
|
|
458
|
+
}
|
|
459
|
+
return `https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${encodeURIComponent(currentUrl.toString())}`;
|
|
460
|
+
} catch (error) {
|
|
461
|
+
console.warn('Error generating QR code URL:', error);
|
|
462
|
+
return '';
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
|
|
383
466
|
|
|
384
467
|
|
|
385
468
|
|
|
@@ -518,15 +601,28 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
518
601
|
}}
|
|
519
602
|
/>
|
|
520
603
|
) : null}
|
|
521
|
-
{silentCaptureResult.path ? (
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
604
|
+
{!cropImageUri && silentCaptureResult.path ? (
|
|
605
|
+
<Image
|
|
606
|
+
source={{ uri: silentCaptureResult.path }}
|
|
607
|
+
style={{
|
|
608
|
+
width: '100%',
|
|
609
|
+
height: 200,
|
|
610
|
+
borderRadius: 12,
|
|
611
|
+
resizeMode: 'cover',
|
|
612
|
+
}}
|
|
613
|
+
/>
|
|
614
|
+
) : null}
|
|
615
|
+
{!cropImageUri && !silentCaptureResult.path && capturedImages[currentSide]?.dir ? (
|
|
616
|
+
<Image
|
|
617
|
+
source={{ uri: capturedImages[currentSide].dir }}
|
|
618
|
+
style={{
|
|
619
|
+
width: '100%',
|
|
620
|
+
height: 200,
|
|
621
|
+
borderRadius: 12,
|
|
622
|
+
resizeMode: 'cover',
|
|
623
|
+
}}
|
|
624
|
+
/>
|
|
625
|
+
) : null}
|
|
530
626
|
|
|
531
627
|
</View>
|
|
532
628
|
{/* Capture button si aucune image n'a été capturée */}
|
|
@@ -582,6 +678,49 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({
|
|
|
582
678
|
{error && (
|
|
583
679
|
<Text style={styles.errorText}>{error}</Text>
|
|
584
680
|
)}
|
|
681
|
+
|
|
682
|
+
{/* Cross-Device / Continue on Phone Button (Web Only) */}
|
|
683
|
+
{Platform.OS === 'web' && !isMobileWeb() && !capturedImages[currentSide]?.dir && (
|
|
684
|
+
<Button title={t('kyc.idCardCapture.continueOnPhone')} onPress={() => { setShowQRModal(true) }} />
|
|
685
|
+
)}
|
|
686
|
+
|
|
687
|
+
{/* QR Code Modal - Web Only */}
|
|
688
|
+
{Platform.OS === 'web' && (
|
|
689
|
+
<Modal
|
|
690
|
+
visible={showQRModal}
|
|
691
|
+
transparent={true}
|
|
692
|
+
animationType="fade"
|
|
693
|
+
onRequestClose={() => setShowQRModal(false)}
|
|
694
|
+
>
|
|
695
|
+
<View style={styles.modalOverlay}>
|
|
696
|
+
<View style={styles.modalContent}>
|
|
697
|
+
<Text style={styles.modalTitle}>
|
|
698
|
+
{t('kyc.idCardCapture.continueOnMobile')}
|
|
699
|
+
</Text>
|
|
700
|
+
<Text style={styles.modalDescription}>
|
|
701
|
+
{t('kyc.idCardCapture.scanQrCode')}
|
|
702
|
+
</Text>
|
|
703
|
+
|
|
704
|
+
{showQRModal && getQrCodeUrl() ? (
|
|
705
|
+
<Image
|
|
706
|
+
source={{ uri: getQrCodeUrl() }}
|
|
707
|
+
style={styles.qrCodeImage}
|
|
708
|
+
/>
|
|
709
|
+
) : null}
|
|
710
|
+
|
|
711
|
+
<TouchableOpacity
|
|
712
|
+
style={styles.closeButton}
|
|
713
|
+
onPress={() => setShowQRModal(false)}
|
|
714
|
+
>
|
|
715
|
+
<Text style={styles.closeButtonText}>
|
|
716
|
+
{t('common.close')}
|
|
717
|
+
</Text>
|
|
718
|
+
</TouchableOpacity>
|
|
719
|
+
</View>
|
|
720
|
+
</View>
|
|
721
|
+
</Modal>
|
|
722
|
+
)}
|
|
723
|
+
|
|
585
724
|
</View>
|
|
586
725
|
</View>
|
|
587
726
|
);
|
|
@@ -738,4 +877,66 @@ const styles = StyleSheet.create({
|
|
|
738
877
|
marginTop: 8,
|
|
739
878
|
textAlign: 'center',
|
|
740
879
|
},
|
|
880
|
+
crossDeviceButton: {
|
|
881
|
+
marginTop: 16,
|
|
882
|
+
padding: 12,
|
|
883
|
+
alignItems: 'center',
|
|
884
|
+
borderWidth: 1,
|
|
885
|
+
borderColor: '#2DBD60',
|
|
886
|
+
borderRadius: 8,
|
|
887
|
+
backgroundColor: '#f0f9f0',
|
|
888
|
+
},
|
|
889
|
+
crossDeviceText: {
|
|
890
|
+
color: '#2DBD60',
|
|
891
|
+
fontSize: 16,
|
|
892
|
+
fontWeight: '600',
|
|
893
|
+
},
|
|
894
|
+
modalOverlay: {
|
|
895
|
+
flex: 1,
|
|
896
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
897
|
+
justifyContent: 'center',
|
|
898
|
+
alignItems: 'center',
|
|
899
|
+
},
|
|
900
|
+
modalContent: {
|
|
901
|
+
backgroundColor: 'white',
|
|
902
|
+
borderRadius: 16,
|
|
903
|
+
padding: 24,
|
|
904
|
+
alignItems: 'center',
|
|
905
|
+
width: '90%',
|
|
906
|
+
maxWidth: 340,
|
|
907
|
+
shadowColor: '#000',
|
|
908
|
+
shadowOffset: { width: 0, height: 2 },
|
|
909
|
+
shadowOpacity: 0.25,
|
|
910
|
+
shadowRadius: 4,
|
|
911
|
+
elevation: 5,
|
|
912
|
+
},
|
|
913
|
+
modalTitle: {
|
|
914
|
+
fontSize: 20,
|
|
915
|
+
fontWeight: 'bold',
|
|
916
|
+
marginBottom: 12,
|
|
917
|
+
color: '#333',
|
|
918
|
+
},
|
|
919
|
+
modalDescription: {
|
|
920
|
+
fontSize: 16,
|
|
921
|
+
color: '#666',
|
|
922
|
+
textAlign: 'center',
|
|
923
|
+
marginBottom: 20,
|
|
924
|
+
lineHeight: 22,
|
|
925
|
+
},
|
|
926
|
+
qrCodeImage: {
|
|
927
|
+
width: 200,
|
|
928
|
+
height: 200,
|
|
929
|
+
marginBottom: 20,
|
|
930
|
+
},
|
|
931
|
+
closeButton: {
|
|
932
|
+
paddingVertical: 10,
|
|
933
|
+
paddingHorizontal: 20,
|
|
934
|
+
backgroundColor: '#f5f5f5',
|
|
935
|
+
borderRadius: 8,
|
|
936
|
+
},
|
|
937
|
+
closeButtonText: {
|
|
938
|
+
fontSize: 16,
|
|
939
|
+
color: '#666',
|
|
940
|
+
fontWeight: '600',
|
|
941
|
+
},
|
|
741
942
|
});
|
|
@@ -11,6 +11,7 @@ import { showAlert } from '../../utils/platformAlert';
|
|
|
11
11
|
import Svg, { Rect, Path, Mask, Defs } from 'react-native-svg';
|
|
12
12
|
import { Camera, useCameraDevice } from 'react-native-vision-camera';
|
|
13
13
|
import { OrientationVideoConfig, OrientationVideoState } from '../../types/KYC.types';
|
|
14
|
+
import { KycEnvironment } from '../../types/env.types';
|
|
14
15
|
import kycService from '../../modules/api/KYCService';
|
|
15
16
|
import VisionCameraModule from '../../modules/camera/VisionCameraModule';
|
|
16
17
|
import SideSelfieIcon from '../Svgs/sideSelfieIcon';
|
|
@@ -20,6 +21,7 @@ interface OrientationVideoCaptureProps {
|
|
|
20
21
|
onComplete: (result: any) => void;
|
|
21
22
|
onError: (error: string) => void;
|
|
22
23
|
kycService: typeof kycService;
|
|
24
|
+
env?: KycEnvironment;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
const defaultConfig: OrientationVideoConfig = {
|
|
@@ -42,6 +44,7 @@ export const OrientationVideoCapture: React.FC<OrientationVideoCaptureProps> = (
|
|
|
42
44
|
onComplete,
|
|
43
45
|
onError,
|
|
44
46
|
kycService,
|
|
47
|
+
env = 'PRODUCTION',
|
|
45
48
|
}) => {
|
|
46
49
|
const finalConfig = { ...defaultConfig, ...config };
|
|
47
50
|
|
|
@@ -174,7 +177,7 @@ export const OrientationVideoCapture: React.FC<OrientationVideoCaptureProps> = (
|
|
|
174
177
|
setState(prev => ({ ...prev, isProcessing: true, error: null }));
|
|
175
178
|
|
|
176
179
|
try {
|
|
177
|
-
const result = await kycService.processOrientationVideo(videoUri);
|
|
180
|
+
const result = await kycService.processOrientationVideo(videoUri, env);
|
|
178
181
|
|
|
179
182
|
if (result.success && result.data) {
|
|
180
183
|
setState(prev => ({
|
|
@@ -12,6 +12,7 @@ import { showAlert } from '../../utils/platformAlert';
|
|
|
12
12
|
import Svg, { Rect, Path, Mask, Defs } from 'react-native-svg';
|
|
13
13
|
import { EnhancedCameraView } from '../EnhancedCameraView';
|
|
14
14
|
import { OrientationVideoConfig, OrientationVideoState } from '../../types/KYC.types';
|
|
15
|
+
import { KycEnvironment } from '../../types/env.types';
|
|
15
16
|
import kycService from '../../modules/api/KYCService';
|
|
16
17
|
import FrontSelfieIcon from '../Svgs/frontSelfieIcon';
|
|
17
18
|
import ScanningLine from '../Svgs/scanningLine';
|
|
@@ -21,6 +22,7 @@ interface OrientationVideoCaptureEnhancedProps {
|
|
|
21
22
|
onComplete: (result: any) => void;
|
|
22
23
|
onError: (error: string) => void;
|
|
23
24
|
kycService: typeof kycService;
|
|
25
|
+
env?: KycEnvironment;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
const defaultConfig: OrientationVideoConfig = {
|
|
@@ -43,6 +45,7 @@ export const OrientationVideoCaptureEnhanced: React.FC<OrientationVideoCaptureEn
|
|
|
43
45
|
onComplete,
|
|
44
46
|
onError,
|
|
45
47
|
kycService,
|
|
48
|
+
env = 'PRODUCTION',
|
|
46
49
|
}) => {
|
|
47
50
|
const finalConfig = { ...defaultConfig, ...config };
|
|
48
51
|
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
|
|
@@ -153,7 +156,7 @@ export const OrientationVideoCaptureEnhanced: React.FC<OrientationVideoCaptureEn
|
|
|
153
156
|
setState(prev => ({ ...prev, isProcessing: true, error: null }));
|
|
154
157
|
|
|
155
158
|
try {
|
|
156
|
-
const result = await kycService.processOrientationVideo(videoUri);
|
|
159
|
+
const result = await kycService.processOrientationVideo(videoUri, env);
|
|
157
160
|
|
|
158
161
|
if (result.success && result.data) {
|
|
159
162
|
setState(prev => ({
|
|
@@ -11,6 +11,7 @@ import { showAlert } from '../../utils/platformAlert';
|
|
|
11
11
|
import Svg, { Rect, Path, Mask, Defs } from 'react-native-svg';
|
|
12
12
|
import { EnhancedCameraView } from '../EnhancedCameraView';
|
|
13
13
|
import { OrientationVideoConfig, OrientationVideoState } from '../../types/KYC.types';
|
|
14
|
+
import { KycEnvironment } from '../../types/env.types';
|
|
14
15
|
import SideSelfieIcon from '../Svgs/sideSelfieIcon';
|
|
15
16
|
import kycService from '../../modules/api/KYCService';
|
|
16
17
|
|
|
@@ -19,6 +20,7 @@ interface OrientationVideoCaptureFinalProps {
|
|
|
19
20
|
onComplete: (result: any) => void;
|
|
20
21
|
onError: (error: string) => void;
|
|
21
22
|
kycService: typeof kycService;
|
|
23
|
+
env?: KycEnvironment;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const defaultConfig: OrientationVideoConfig = {
|
|
@@ -41,6 +43,7 @@ export const OrientationVideoCaptureFinal: React.FC<OrientationVideoCaptureFinal
|
|
|
41
43
|
onComplete,
|
|
42
44
|
onError,
|
|
43
45
|
kycService,
|
|
46
|
+
env = 'PRODUCTION',
|
|
44
47
|
}) => {
|
|
45
48
|
const finalConfig = { ...defaultConfig, ...config };
|
|
46
49
|
|
|
@@ -127,7 +130,7 @@ export const OrientationVideoCaptureFinal: React.FC<OrientationVideoCaptureFinal
|
|
|
127
130
|
setState(prev => ({ ...prev, isProcessing: true, error: null }));
|
|
128
131
|
|
|
129
132
|
try {
|
|
130
|
-
const result = await kycService.processOrientationVideo(videoUri);
|
|
133
|
+
const result = await kycService.processOrientationVideo(videoUri, env);
|
|
131
134
|
|
|
132
135
|
if (result.success && result.data) {
|
|
133
136
|
setState(prev => ({
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, TextInput, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
|
|
3
|
+
import { TemplateComponent, PersonalInformationConfig, LocalizedText } from '../../types/KYC.types';
|
|
4
|
+
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
5
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
6
|
+
import { Button } from '../ui/Button';
|
|
7
|
+
|
|
8
|
+
interface PersonalInformationTemplateProps {
|
|
9
|
+
component: TemplateComponent;
|
|
10
|
+
value?: any;
|
|
11
|
+
onValueChange: (data: any) => void;
|
|
12
|
+
error?: string;
|
|
13
|
+
language?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const PersonalInformationTemplate: React.FC<PersonalInformationTemplateProps> = ({
|
|
17
|
+
component,
|
|
18
|
+
value,
|
|
19
|
+
onValueChange,
|
|
20
|
+
error,
|
|
21
|
+
}) => {
|
|
22
|
+
const { actions, getLocalizedText } = useTemplateKYCFlowContext();
|
|
23
|
+
const { t } = useI18n();
|
|
24
|
+
const config = component.config as PersonalInformationConfig;
|
|
25
|
+
const [formData, setFormData] = useState<Record<string, string>>({});
|
|
26
|
+
|
|
27
|
+
const title = getLocalizedText(component.labels as LocalizedText);
|
|
28
|
+
const instructions = getLocalizedText(component.instructions as LocalizedText);
|
|
29
|
+
const buttonText = getLocalizedText((component.ui as any).buttonText) || t('common.submit');
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (value) {
|
|
33
|
+
setFormData(value);
|
|
34
|
+
}
|
|
35
|
+
}, [value]);
|
|
36
|
+
|
|
37
|
+
const handleChange = (fieldId: string, text: string) => {
|
|
38
|
+
const newData = { ...formData, [fieldId]: text };
|
|
39
|
+
setFormData(newData);
|
|
40
|
+
onValueChange(newData);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const handleCreate = () => {
|
|
44
|
+
actions.nextComponent();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const isFormValid = () => {
|
|
48
|
+
if (!config.fields) return true;
|
|
49
|
+
return config.fields.every(field => {
|
|
50
|
+
if (field.required && !formData[field.id]) return false;
|
|
51
|
+
return true;
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<KeyboardAvoidingView
|
|
57
|
+
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
58
|
+
style={styles.keyboardAvoidingView}
|
|
59
|
+
>
|
|
60
|
+
<ScrollView contentContainerStyle={styles.scrollContainer} showsVerticalScrollIndicator={false}>
|
|
61
|
+
<View style={styles.container}>
|
|
62
|
+
<Text style={styles.title}>{title}</Text>
|
|
63
|
+
<Text style={styles.instructions}>{instructions}</Text>
|
|
64
|
+
|
|
65
|
+
<View style={styles.formContainer}>
|
|
66
|
+
{config.fields && config.fields.map((field) => (
|
|
67
|
+
<View key={field.id} style={styles.fieldContainer}>
|
|
68
|
+
<Text style={styles.label}>
|
|
69
|
+
{field.label} {field.type === 'date' && field.dateFormat ? `(${field.dateFormat})` : ''} {field.required && '*'}
|
|
70
|
+
</Text>
|
|
71
|
+
<TextInput
|
|
72
|
+
style={styles.input}
|
|
73
|
+
placeholder={field.placeholder || field.label}
|
|
74
|
+
value={formData[field.id] || ''}
|
|
75
|
+
onChangeText={(text) => handleChange(field.id, text)}
|
|
76
|
+
autoCapitalize="words"
|
|
77
|
+
/>
|
|
78
|
+
</View>
|
|
79
|
+
))}
|
|
80
|
+
</View>
|
|
81
|
+
|
|
82
|
+
{error && <Text style={styles.errorText}>{error}</Text>}
|
|
83
|
+
|
|
84
|
+
<Button
|
|
85
|
+
title={buttonText}
|
|
86
|
+
onPress={handleCreate}
|
|
87
|
+
fullWidth
|
|
88
|
+
style={styles.button}
|
|
89
|
+
disabled={!isFormValid()}
|
|
90
|
+
/>
|
|
91
|
+
</View>
|
|
92
|
+
</ScrollView>
|
|
93
|
+
</KeyboardAvoidingView>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const styles = StyleSheet.create({
|
|
98
|
+
keyboardAvoidingView: {
|
|
99
|
+
flex: 1,
|
|
100
|
+
width: '100%',
|
|
101
|
+
},
|
|
102
|
+
scrollContainer: {
|
|
103
|
+
flexGrow: 1,
|
|
104
|
+
justifyContent: 'center',
|
|
105
|
+
paddingBottom: 20,
|
|
106
|
+
},
|
|
107
|
+
container: {
|
|
108
|
+
padding: 20,
|
|
109
|
+
backgroundColor: 'white',
|
|
110
|
+
borderRadius: 12,
|
|
111
|
+
margin: 16,
|
|
112
|
+
shadowColor: '#000',
|
|
113
|
+
shadowOffset: { width: 0, height: 2 },
|
|
114
|
+
shadowOpacity: 0.1,
|
|
115
|
+
shadowRadius: 4,
|
|
116
|
+
elevation: 3,
|
|
117
|
+
width: '95%',
|
|
118
|
+
},
|
|
119
|
+
title: {
|
|
120
|
+
fontSize: 22,
|
|
121
|
+
fontWeight: 'bold',
|
|
122
|
+
marginBottom: 10,
|
|
123
|
+
color: '#333',
|
|
124
|
+
},
|
|
125
|
+
instructions: {
|
|
126
|
+
fontSize: 16,
|
|
127
|
+
color: '#666',
|
|
128
|
+
marginBottom: 20,
|
|
129
|
+
lineHeight: 22,
|
|
130
|
+
},
|
|
131
|
+
formContainer: {
|
|
132
|
+
marginBottom: 20,
|
|
133
|
+
},
|
|
134
|
+
fieldContainer: {
|
|
135
|
+
marginBottom: 16,
|
|
136
|
+
},
|
|
137
|
+
label: {
|
|
138
|
+
fontSize: 14,
|
|
139
|
+
fontWeight: '600',
|
|
140
|
+
color: '#333',
|
|
141
|
+
marginBottom: 6,
|
|
142
|
+
},
|
|
143
|
+
input: {
|
|
144
|
+
borderWidth: 1,
|
|
145
|
+
borderColor: '#ddd',
|
|
146
|
+
padding: 12,
|
|
147
|
+
borderRadius: 8,
|
|
148
|
+
fontSize: 16,
|
|
149
|
+
backgroundColor: '#f9f9f9',
|
|
150
|
+
},
|
|
151
|
+
errorText: {
|
|
152
|
+
color: 'red',
|
|
153
|
+
marginBottom: 10,
|
|
154
|
+
},
|
|
155
|
+
button: {
|
|
156
|
+
marginTop: 10,
|
|
157
|
+
},
|
|
158
|
+
});
|