@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.
Files changed (149) hide show
  1. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +12 -5
  2. package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
  3. package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
  4. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  5. package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
  6. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +61 -59
  7. package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-transfergratis-react-native-sdk.jar +0 -0
  8. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +12 -5
  9. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  10. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  11. package/android/build/outputs/aar/transfergratis-react-native-sdk-debug.aar +0 -0
  12. package/android/build/outputs/logs/manifest-merger-debug-report.txt +26 -34
  13. package/android/src/main/AndroidManifest.xml +10 -7
  14. package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts +12 -0
  15. package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts.map +1 -0
  16. package/build/components/KYCElements/AdditionalDocumentsTemplate.js +283 -0
  17. package/build/components/KYCElements/AdditionalDocumentsTemplate.js.map +1 -0
  18. package/build/components/KYCElements/EmailVerificationTemplate.d.ts +12 -0
  19. package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -0
  20. package/build/components/KYCElements/EmailVerificationTemplate.js +193 -0
  21. package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -0
  22. package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  23. package/build/components/KYCElements/IDCardCapture.js +180 -7
  24. package/build/components/KYCElements/IDCardCapture.js.map +1 -1
  25. package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -0
  26. package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
  27. package/build/components/KYCElements/OrientationVideoCapture.js +2 -2
  28. package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
  29. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -0
  30. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
  31. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js +2 -2
  32. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
  33. package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -0
  34. package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
  35. package/build/components/KYCElements/OrientationVideoCaptureFinal.js +2 -2
  36. package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
  37. package/build/components/KYCElements/PersonalInformationTemplate.d.ts +12 -0
  38. package/build/components/KYCElements/PersonalInformationTemplate.d.ts.map +1 -0
  39. package/build/components/KYCElements/PersonalInformationTemplate.js +120 -0
  40. package/build/components/KYCElements/PersonalInformationTemplate.js.map +1 -0
  41. package/build/components/KYCElements/PhoneVerificationTemplate.d.ts +12 -0
  42. package/build/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -0
  43. package/build/components/KYCElements/PhoneVerificationTemplate.js +185 -0
  44. package/build/components/KYCElements/PhoneVerificationTemplate.js.map +1 -0
  45. package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
  46. package/build/components/KYCElements/SelfieCaptureTemplate.js +7 -3
  47. package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
  48. package/build/components/TemplateKYCExample.d.ts +4 -0
  49. package/build/components/TemplateKYCExample.d.ts.map +1 -1
  50. package/build/components/TemplateKYCExample.js +7 -30
  51. package/build/components/TemplateKYCExample.js.map +1 -1
  52. package/build/components/TemplateKYCFlowRefactored.d.ts +4 -0
  53. package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
  54. package/build/components/TemplateKYCFlowRefactored.js +14 -2
  55. package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
  56. package/build/config/KYCConfig.d.ts +14 -0
  57. package/build/config/KYCConfig.d.ts.map +1 -0
  58. package/build/config/KYCConfig.js +26 -0
  59. package/build/config/KYCConfig.js.map +1 -0
  60. package/build/config/allowedDomains.d.ts.map +1 -1
  61. package/build/config/allowedDomains.js +4 -19
  62. package/build/config/allowedDomains.js.map +1 -1
  63. package/build/hooks/useOrientationVideo.d.ts +2 -1
  64. package/build/hooks/useOrientationVideo.d.ts.map +1 -1
  65. package/build/hooks/useOrientationVideo.js +3 -3
  66. package/build/hooks/useOrientationVideo.js.map +1 -1
  67. package/build/hooks/useTemplateKYCFlow.d.ts +6 -1
  68. package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  69. package/build/hooks/useTemplateKYCFlow.js +286 -23
  70. package/build/hooks/useTemplateKYCFlow.js.map +1 -1
  71. package/build/i18n/en/index.d.ts +40 -0
  72. package/build/i18n/en/index.d.ts.map +1 -1
  73. package/build/i18n/en/index.js +41 -1
  74. package/build/i18n/en/index.js.map +1 -1
  75. package/build/i18n/fr/index.d.ts +26 -0
  76. package/build/i18n/fr/index.d.ts.map +1 -1
  77. package/build/i18n/fr/index.js +27 -1
  78. package/build/i18n/fr/index.js.map +1 -1
  79. package/build/index.d.ts +1 -0
  80. package/build/index.d.ts.map +1 -1
  81. package/build/index.js +2 -0
  82. package/build/index.js.map +1 -1
  83. package/build/modules/api/CardAuthentification.d.ts +24 -3
  84. package/build/modules/api/CardAuthentification.d.ts.map +1 -1
  85. package/build/modules/api/CardAuthentification.js +68 -10
  86. package/build/modules/api/CardAuthentification.js.map +1 -1
  87. package/build/modules/api/KYCService.d.ts +7 -7
  88. package/build/modules/api/KYCService.d.ts.map +1 -1
  89. package/build/modules/api/KYCService.js +101 -37
  90. package/build/modules/api/KYCService.js.map +1 -1
  91. package/build/modules/api/SelfieVerification.d.ts +3 -1
  92. package/build/modules/api/SelfieVerification.d.ts.map +1 -1
  93. package/build/modules/api/SelfieVerification.js +17 -1
  94. package/build/modules/api/SelfieVerification.js.map +1 -1
  95. package/build/modules/api/TemplateService.d.ts +0 -1
  96. package/build/modules/api/TemplateService.d.ts.map +1 -1
  97. package/build/modules/api/TemplateService.js +3 -3
  98. package/build/modules/api/TemplateService.js.map +1 -1
  99. package/build/types/KYC.types.d.ts +124 -3
  100. package/build/types/KYC.types.d.ts.map +1 -1
  101. package/build/types/KYC.types.js.map +1 -1
  102. package/build/types/env.types.d.ts +13 -0
  103. package/build/types/env.types.d.ts.map +1 -0
  104. package/build/types/env.types.js +2 -0
  105. package/build/types/env.types.js.map +1 -0
  106. package/build/utils/deviceDetection.d.ts +6 -0
  107. package/build/utils/deviceDetection.d.ts.map +1 -0
  108. package/build/utils/deviceDetection.js +12 -0
  109. package/build/utils/deviceDetection.js.map +1 -0
  110. package/build/utils/platformAlert.d.ts.map +1 -1
  111. package/build/utils/platformAlert.js.map +1 -1
  112. package/build/utils/template-transformer.d.ts.map +1 -1
  113. package/build/utils/template-transformer.js +12 -0
  114. package/build/utils/template-transformer.js.map +1 -1
  115. package/build/web/WebKYCEntry.d.ts.map +1 -1
  116. package/build/web/WebKYCEntry.js +82 -38
  117. package/build/web/WebKYCEntry.js.map +1 -1
  118. package/package.json +1 -1
  119. package/plugin/build/withVisionCamera.js +3 -4
  120. package/plugin/src/withVisionCamera.js +3 -4
  121. package/plugin/src/withVisionCamera.ts +3 -4
  122. package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
  123. package/src/components/KYCElements/EmailVerificationTemplate.tsx +264 -0
  124. package/src/components/KYCElements/IDCardCapture.tsx +216 -15
  125. package/src/components/KYCElements/OrientationVideoCapture.tsx +4 -1
  126. package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +4 -1
  127. package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +4 -1
  128. package/src/components/KYCElements/PersonalInformationTemplate.tsx +158 -0
  129. package/src/components/KYCElements/PhoneVerificationTemplate.tsx +253 -0
  130. package/src/components/KYCElements/SelfieCaptureTemplate.tsx +6 -3
  131. package/src/components/TemplateKYCExample.tsx +31 -46
  132. package/src/components/TemplateKYCFlowRefactored.tsx +27 -1
  133. package/src/config/KYCConfig.ts +34 -0
  134. package/src/config/allowedDomains.ts +7 -26
  135. package/src/hooks/useOrientationVideo.ts +5 -4
  136. package/src/hooks/useTemplateKYCFlow.tsx +314 -21
  137. package/src/i18n/en/index.ts +43 -2
  138. package/src/i18n/fr/index.ts +28 -1
  139. package/src/index.ts +3 -0
  140. package/src/modules/api/CardAuthentification.ts +75 -10
  141. package/src/modules/api/KYCService.ts +117 -37
  142. package/src/modules/api/SelfieVerification.ts +25 -3
  143. package/src/modules/api/TemplateService.ts +4 -4
  144. package/src/types/KYC.types.ts +146 -3
  145. package/src/types/env.types.ts +13 -0
  146. package/src/utils/deviceDetection.ts +11 -0
  147. package/src/utils/platformAlert.ts +1 -0
  148. package/src/utils/template-transformer.ts +20 -8
  149. 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 ? (<Image
522
- source={{ uri: silentCaptureResult.path }}
523
- style={{
524
- width: '100%',
525
- height: 200,
526
- borderRadius: 12,
527
- resizeMode: 'cover',
528
- }}
529
- />) : null}
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
+ });