@sanctum-key/react-native-sdk 1.0.9 → 1.0.11

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 (180) hide show
  1. package/README.md +3 -3
  2. package/android/build/.transforms/{c9d62bb333688ab562f51958998d5a48 → 9e34a0354bf8964d60c4c1392f5aa5b2}/transformed/classes/classes_dex/classes.dex +0 -0
  3. package/android/build/generated/source/buildConfig/debug/kyc/{SanctumKey → sanctumkey}/com/BuildConfig.java +2 -2
  4. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +1 -1
  5. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +1 -1
  6. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  7. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  8. package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/xml_file_paths.xml.flat +0 -0
  9. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +2 -2
  10. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +1 -1
  11. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +1 -1
  12. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +1 -1
  13. package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +1 -1
  14. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/kyc/{SanctumKey → sanctumkey}/com/BuildConfig.class +0 -0
  15. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +42 -42
  16. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +1 -1
  17. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  18. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +1 -1
  19. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  20. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  21. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  22. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  23. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  24. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  25. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  26. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  27. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  28. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  29. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  30. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  31. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  32. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  33. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  34. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  35. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  36. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  37. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  38. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  39. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  40. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  41. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  42. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  43. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  44. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  45. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  46. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  47. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  48. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  49. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  50. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  51. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  52. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  53. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  54. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  55. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  56. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  57. package/android/build/outputs/logs/manifest-merger-debug-report.txt +52 -52
  58. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  59. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$1$5$1.class +0 -0
  60. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$1$5$2.class +0 -0
  61. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$1.class +0 -0
  62. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$2.class +0 -0
  63. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$3.class +0 -0
  64. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$4.class +0 -0
  65. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$5.class +0 -0
  66. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$6.class +0 -0
  67. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$1.class +0 -0
  68. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$2.class +0 -0
  69. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$3.class +0 -0
  70. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$4.class +0 -0
  71. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$$inlined$View$1.class +0 -0
  72. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$lambda$4$$inlined$Prop$1.class +0 -0
  73. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule$definition$lambda$5$lambda$4$$inlined$Prop$2.class +0 -0
  74. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkModule.class +0 -0
  75. package/android/build/tmp/kotlin-classes/debug/kyc/{SanctumKey → sanctumkey}/com/SanctumKeySdkView.class +0 -0
  76. package/android/build.gradle +2 -2
  77. package/android/src/main/AndroidManifest.xml +1 -1
  78. package/android/src/main/java/kyc/{transfergratis/com/TransfergratisSdkModule.kt → sanctumkey/com/SanctumKeySdkModule.kt} +21 -18
  79. package/android/src/main/java/kyc/{transfergratis/com/TransfergratisSdkView.kt → sanctumkey/com/SanctumKeySdkView.kt} +2 -2
  80. package/build/package.json +5 -5
  81. package/build/src/App.d.ts +2 -2
  82. package/build/src/App.d.ts.map +1 -1
  83. package/build/src/App.js +2 -2
  84. package/build/src/App.js.map +1 -1
  85. package/build/src/{TransfergratisSdk.types.d.ts → SanctumKeySdk.types.d.ts} +3 -3
  86. package/build/src/SanctumKeySdk.types.d.ts.map +1 -0
  87. package/build/src/SanctumKeySdk.types.js +2 -0
  88. package/build/src/SanctumKeySdk.types.js.map +1 -0
  89. package/build/src/{TransfergratisSdkModule.d.ts → SanctumKeySdkModule.d.ts} +4 -4
  90. package/build/src/SanctumKeySdkModule.d.ts.map +1 -0
  91. package/build/src/{TransfergratisSdkModule.js → SanctumKeySdkModule.js} +2 -2
  92. package/build/src/SanctumKeySdkModule.js.map +1 -0
  93. package/build/src/{TransfergratisSdkModule.web.d.ts → SanctumKeySdkModule.web.d.ts} +4 -4
  94. package/build/src/SanctumKeySdkModule.web.d.ts.map +1 -0
  95. package/build/src/{TransfergratisSdkModule.web.js → SanctumKeySdkModule.web.js} +3 -3
  96. package/build/src/SanctumKeySdkModule.web.js.map +1 -0
  97. package/build/src/SanctumKeySdkView.d.ts +4 -0
  98. package/build/src/SanctumKeySdkView.d.ts.map +1 -0
  99. package/build/src/SanctumKeySdkView.js +7 -0
  100. package/build/src/SanctumKeySdkView.js.map +1 -0
  101. package/build/src/SanctumKeySdkView.web.d.ts +4 -0
  102. package/build/src/SanctumKeySdkView.web.d.ts.map +1 -0
  103. package/build/src/{TransfergratisSdkView.web.js → SanctumKeySdkView.web.js} +2 -2
  104. package/build/src/SanctumKeySdkView.web.js.map +1 -0
  105. package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
  106. package/build/src/components/KYCElements/CountrySelection.js +259 -63
  107. package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
  108. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  109. package/build/src/components/KYCElements/IDCardCapture.js +231 -69
  110. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  111. package/build/src/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -1
  112. package/build/src/components/KYCElements/PhoneVerificationTemplate.js +160 -21
  113. package/build/src/components/KYCElements/PhoneVerificationTemplate.js.map +1 -1
  114. package/build/src/components/NativeCameraView.js +1 -1
  115. package/build/src/components/NativeCameraView.js.map +1 -1
  116. package/build/src/components/TemplateKYCExample.d.ts +4 -3
  117. package/build/src/components/TemplateKYCExample.d.ts.map +1 -1
  118. package/build/src/components/TemplateKYCExample.js +2 -2
  119. package/build/src/components/TemplateKYCExample.js.map +1 -1
  120. package/build/src/config/allowedDomains.js +6 -6
  121. package/build/src/config/allowedDomains.js.map +1 -1
  122. package/build/src/config/region_mapping.json +727 -0
  123. package/build/src/index.d.ts +3 -3
  124. package/build/src/index.d.ts.map +1 -1
  125. package/build/src/index.js +3 -3
  126. package/build/src/index.js.map +1 -1
  127. package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
  128. package/build/src/modules/api/CardAuthentification.js +3 -7
  129. package/build/src/modules/api/CardAuthentification.js.map +1 -1
  130. package/build/src/modules/api/KYCService.d.ts +1 -2
  131. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  132. package/build/src/modules/api/KYCService.js +112 -60
  133. package/build/src/modules/api/KYCService.js.map +1 -1
  134. package/build/src/modules/camera/NativeCameraModule.js +17 -17
  135. package/build/src/modules/camera/NativeCameraModule.js.map +1 -1
  136. package/build/src/web/WebKYCEntry.d.ts +2 -2
  137. package/build/src/web/WebKYCEntry.d.ts.map +1 -1
  138. package/build/src/web/WebKYCEntry.js +3 -2
  139. package/build/src/web/WebKYCEntry.js.map +1 -1
  140. package/expo-module.config.json +3 -3
  141. package/ios/TransfergratisSdk.podspec +2 -2
  142. package/ios/TransfergratisSdkModule.swift +12 -12
  143. package/package.json +5 -5
  144. package/src/App.tsx +2 -2
  145. package/src/{TransfergratisSdk.types.ts → SanctumKeySdk.types.ts} +2 -2
  146. package/src/{TransfergratisSdkModule.ts → SanctumKeySdkModule.ts} +3 -3
  147. package/src/{TransfergratisSdkModule.web.ts → SanctumKeySdkModule.web.ts} +3 -3
  148. package/src/SanctumKeySdkView.tsx +11 -0
  149. package/src/{TransfergratisSdkView.web.tsx → SanctumKeySdkView.web.tsx} +2 -2
  150. package/src/components/KYCElements/CountrySelection.tsx +300 -74
  151. package/src/components/KYCElements/IDCardCapture.tsx +322 -157
  152. package/src/components/KYCElements/PhoneVerificationTemplate.tsx +201 -29
  153. package/src/components/NativeCameraView.tsx +1 -1
  154. package/src/components/TemplateKYCExample.tsx +23 -4
  155. package/src/config/allowedDomains.ts +6 -6
  156. package/src/i18n/README.md +1 -1
  157. package/src/index.ts +3 -3
  158. package/src/modules/api/CardAuthentification.ts +5 -8
  159. package/src/modules/api/KYCService.ts +174 -106
  160. package/src/modules/camera/NativeCameraModule.ts +17 -17
  161. package/src/web/WebKYCEntry.tsx +3 -3
  162. package/android/build/.transforms/ab90740579f5bd05b27b4343ada2d1c9/transformed/classes/classes_dex/classes.dex +0 -0
  163. package/android/build/.transforms/c9d62bb333688ab562f51958998d5a48/results.bin +0 -1
  164. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/BuildConfig.class.uniqueId0 +0 -0
  165. package/build/src/TransfergratisSdk.types.d.ts.map +0 -1
  166. package/build/src/TransfergratisSdk.types.js +0 -2
  167. package/build/src/TransfergratisSdk.types.js.map +0 -1
  168. package/build/src/TransfergratisSdkModule.d.ts.map +0 -1
  169. package/build/src/TransfergratisSdkModule.js.map +0 -1
  170. package/build/src/TransfergratisSdkModule.web.d.ts.map +0 -1
  171. package/build/src/TransfergratisSdkModule.web.js.map +0 -1
  172. package/build/src/TransfergratisSdkView.d.ts +0 -4
  173. package/build/src/TransfergratisSdkView.d.ts.map +0 -1
  174. package/build/src/TransfergratisSdkView.js +0 -7
  175. package/build/src/TransfergratisSdkView.js.map +0 -1
  176. package/build/src/TransfergratisSdkView.web.d.ts +0 -4
  177. package/build/src/TransfergratisSdkView.web.d.ts.map +0 -1
  178. package/build/src/TransfergratisSdkView.web.js.map +0 -1
  179. package/src/TransfergratisSdkView.tsx +0 -11
  180. /package/android/build/.transforms/{ab90740579f5bd05b27b4343ada2d1c9 → 9e34a0354bf8964d60c4c1392f5aa5b2}/results.bin +0 -0
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useRef, useEffect } from 'react';
2
- import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert, Pressable } from 'react-native';
2
+ import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert, Pressable, Modal, FlatList } from 'react-native';
3
3
  import { TemplateComponent, LocalizedText } from '../../types/KYC.types';
4
4
  import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
5
5
  import { useI18n } from '../../hooks/useI18n';
@@ -17,6 +17,19 @@ interface PhoneVerificationTemplateProps {
17
17
  type VerificationStep = 'phone' | 'otp';
18
18
  const CODE_LENGTH = 6;
19
19
 
20
+ // 🌍 The Country Codes Array
21
+ const COUNTRY_CODES = [
22
+ { code: '+254', label: '🇰🇪 Kenya (+254)' },
23
+ { code: '+255', label: '🇹🇿 Tanzania (+255)' },
24
+ { code: '+256', label: '🇺🇬 Uganda (+256)' },
25
+ { code: '+250', label: '🇷🇼 Rwanda (+250)' },
26
+ { code: '+234', label: '🇳🇬 Nigeria (+234)' },
27
+ { code: '+27', label: '🇿🇦 South Africa (+27)' },
28
+ { code: '+44', label: '🇬🇧 UK (+44)' },
29
+ { code: '+1', label: '🇺🇸 US/Canada (+1)' },
30
+ { code: '+91', label: '🇮🇳 India (+91)' },
31
+ ];
32
+
20
33
  export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps> = ({
21
34
  component,
22
35
  value,
@@ -31,10 +44,16 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
31
44
 
32
45
  // State
33
46
  const [step, setStep] = useState<VerificationStep>('phone');
47
+ const [countryCode, setCountryCode] = useState('+254');
34
48
  const [phone, setPhone] = useState('');
49
+ const [showCountryPicker, setShowCountryPicker] = useState(false);
50
+
35
51
  const [otp, setOtp] = useState('');
36
52
  const [localError, setLocalError] = useState<string | null>(null);
37
53
  const [isSimulating, setIsSimulating] = useState(false);
54
+
55
+ // Track actual focus state for visual feedback
56
+ const [isInputFocused, setIsInputFocused] = useState(false);
38
57
 
39
58
  const inputRef = useRef<TextInput>(null);
40
59
 
@@ -52,6 +71,22 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
52
71
  }
53
72
  }, [otp]);
54
73
 
74
+ // --- SAFE AUTO FOCUS LOGIC ---
75
+ useEffect(() => {
76
+ let focusTimer: ReturnType<typeof setTimeout>;
77
+
78
+ // Only attempt focus when we are on the OTP step AND the loading state is completely finished
79
+ if (step === 'otp' && !isSimulating) {
80
+ focusTimer = setTimeout(() => {
81
+ inputRef.current?.focus();
82
+ }, 300); // 300ms guarantees view is painted before requesting keyboard
83
+ }
84
+
85
+ return () => {
86
+ if (focusTimer) clearTimeout(focusTimer);
87
+ };
88
+ }, [step, isSimulating]);
89
+
55
90
  const handleSendCode = async () => {
56
91
  const trimmedPhone = phone.trim();
57
92
  if (!trimmedPhone || trimmedPhone.length < 5) {
@@ -62,11 +97,11 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
62
97
  setLocalError(null);
63
98
  setIsSimulating(true);
64
99
 
100
+ const fullPhoneNumber = `${countryCode}${trimmedPhone}`;
101
+
65
102
  try {
66
- await kycService.sendWhatsAppVerificationCode(sessionId, trimmedPhone, auth);
103
+ await kycService.sendWhatsAppVerificationCode(sessionId, fullPhoneNumber, auth);
67
104
  setStep('otp');
68
- // Auto-focus the OTP input shortly after switching steps
69
- setTimeout(() => inputRef.current?.focus(), 100);
70
105
  } catch (err: any) {
71
106
  const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send verification code');
72
107
  setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
@@ -83,29 +118,32 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
83
118
 
84
119
  setLocalError(null);
85
120
  setIsSimulating(true);
121
+
122
+ const fullPhoneNumber = `${countryCode}${phone.trim()}`;
86
123
 
87
124
  try {
88
- await kycService.verifyWhatsAppCode(sessionId, otp.trim(), auth);
89
- const data = { phone, otp, verified: true };
125
+ await kycService.verifyWhatsAppCode(sessionId, otp.trim(), fullPhoneNumber, auth);
126
+
127
+ const data = { phone: fullPhoneNumber, otp, verified: true };
90
128
  onValueChange(data);
91
129
  actions.nextComponent(data);
92
130
  } catch (err: any) {
93
131
  const msg = errorMessage(err) ?? err?.message ?? (t('errors.wrongCode') || 'Invalid verification code');
94
132
  setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
95
- setOtp(''); // Clear the boxes on error so they can type again
96
- inputRef.current?.focus();
133
+ setOtp('');
134
+ inputRef.current?.focus();
97
135
  } finally {
98
136
  setIsSimulating(false);
99
137
  }
100
138
  };
101
139
 
102
140
  const onChangePhone = (text: string) => {
103
- setPhone(text);
141
+ const cleaned = text.replace(/[^0-9]/g, '');
142
+ setPhone(cleaned);
104
143
  if (localError) setLocalError(null);
105
144
  };
106
145
 
107
146
  const onChangeOtp = (text: string) => {
108
- // Only allow numbers
109
147
  const cleaned = text.replace(/[^0-9]/g, '');
110
148
  setOtp(cleaned);
111
149
  if (localError) setLocalError(null);
@@ -123,16 +161,19 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
123
161
  <Pressable style={styles.otpBoxesContainer} onPress={() => inputRef.current?.focus()}>
124
162
  {boxes.map((_, index) => {
125
163
  const digit = otp[index] || '';
126
- const isCurrent = index === otp.length;
127
164
  const isFilled = index < otp.length;
165
+
166
+ // Only highlight if the input is ACTUALLY focused.
167
+ const isActiveIndex = index === otp.length || (index === CODE_LENGTH - 1 && otp.length === CODE_LENGTH);
168
+ const isCurrent = isInputFocused && isActiveIndex;
128
169
 
129
170
  return (
130
171
  <View
131
172
  key={index}
132
173
  style={[
133
174
  styles.otpBox,
134
- isCurrent && styles.otpBoxActive,
135
- isFilled && styles.otpBoxFilled
175
+ isFilled && styles.otpBoxFilled,
176
+ isCurrent && styles.otpBoxActive // Active overrides filled
136
177
  ]}
137
178
  >
138
179
  <Text style={styles.otpBoxText}>{digit}</Text>
@@ -147,22 +188,34 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
147
188
  <View style={styles.container}>
148
189
  <Text style={styles.title}>{title}</Text>
149
190
  <Text style={styles.instructions}>
150
- {step === 'phone' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${phone}`)}
191
+ {step === 'phone' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${countryCode} ${phone}`)}
151
192
  </Text>
152
193
 
153
194
  <View style={styles.contentContainer}>
154
195
  {step === 'phone' ? (
155
196
  <View style={styles.inputContainer}>
156
197
  <Text style={styles.label}>{t('common.phone') || 'Phone Number'}</Text>
157
- <TextInput
158
- style={styles.input}
159
- placeholder="+1234567890"
160
- value={phone}
161
- onChangeText={onChangePhone}
162
- keyboardType="phone-pad"
163
- autoComplete="tel"
164
- editable={!isSimulating}
165
- />
198
+
199
+ <View style={styles.phoneInputRow}>
200
+ <TouchableOpacity
201
+ style={styles.countryPickerBtn}
202
+ onPress={() => setShowCountryPicker(true)}
203
+ disabled={isSimulating}
204
+ >
205
+ <Text style={styles.countryPickerText}>{countryCode}</Text>
206
+ <Text style={styles.dropdownIcon}>▼</Text>
207
+ </TouchableOpacity>
208
+
209
+ <TextInput
210
+ style={styles.phoneInput}
211
+ placeholder="712 345 678"
212
+ value={phone}
213
+ onChangeText={onChangePhone}
214
+ keyboardType="phone-pad"
215
+ autoComplete="tel"
216
+ editable={!isSimulating}
217
+ />
218
+ </View>
166
219
  </View>
167
220
  ) : (
168
221
  <View style={styles.inputContainer}>
@@ -170,7 +223,7 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
170
223
 
171
224
  <View style={styles.otpWrapper}>
172
225
  {renderOtpBoxes()}
173
- {/* Hidden TextInput overlaid to handle native keyboard & pasting seamlessly */}
226
+
174
227
  <TextInput
175
228
  ref={inputRef}
176
229
  style={styles.hiddenInput}
@@ -181,6 +234,8 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
181
234
  editable={!isSimulating}
182
235
  textContentType="oneTimeCode"
183
236
  caretHidden={true}
237
+ onFocus={() => setIsInputFocused(true)}
238
+ onBlur={() => setIsInputFocused(false)}
184
239
  />
185
240
  </View>
186
241
 
@@ -210,12 +265,14 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
210
265
  if (isSimulating) return;
211
266
  setLocalError(null);
212
267
  setIsSimulating(true);
268
+ const fullPhoneNumber = `${countryCode}${phone.trim()}`;
213
269
  try {
214
- await kycService.sendWhatsAppVerificationCode(sessionId, phone.trim(), auth);
270
+ await kycService.sendWhatsAppVerificationCode(sessionId, fullPhoneNumber, auth);
215
271
  Alert.alert(
216
272
  t('common.codeResent') || 'Code Resent',
217
- t('common.codeResentMessage', { email: phone }) || 'Code resent to ' + phone
273
+ t('common.codeResentMessage', { email: fullPhoneNumber }) || 'Code resent to ' + fullPhoneNumber
218
274
  );
275
+ inputRef.current?.focus();
219
276
  } catch (err: any) {
220
277
  const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send code');
221
278
  setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
@@ -230,6 +287,45 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
230
287
  </TouchableOpacity>
231
288
  )}
232
289
  </View>
290
+
291
+ {/* COUNTRY PICKER MODAL */}
292
+ <Modal
293
+ visible={showCountryPicker}
294
+ animationType="slide"
295
+ transparent={true}
296
+ onRequestClose={() => setShowCountryPicker(false)}
297
+ >
298
+ <TouchableOpacity
299
+ style={styles.modalOverlay}
300
+ activeOpacity={1}
301
+ onPress={() => setShowCountryPicker(false)}
302
+ >
303
+ <View style={styles.modalContent}>
304
+ <View style={styles.modalHeader}>
305
+ <Text style={styles.modalTitle}>Select Country</Text>
306
+ <TouchableOpacity onPress={() => setShowCountryPicker(false)}>
307
+ <Text style={styles.modalClose}>✕</Text>
308
+ </TouchableOpacity>
309
+ </View>
310
+ <FlatList
311
+ data={COUNTRY_CODES}
312
+ keyExtractor={(item) => item.code}
313
+ renderItem={({ item }) => (
314
+ <TouchableOpacity
315
+ style={styles.countryItem}
316
+ onPress={() => {
317
+ setCountryCode(item.code);
318
+ setShowCountryPicker(false);
319
+ }}
320
+ >
321
+ <Text style={styles.countryItemLabel}>{item.label}</Text>
322
+ {countryCode === item.code && <Text style={styles.checkMark}>✓</Text>}
323
+ </TouchableOpacity>
324
+ )}
325
+ />
326
+ </View>
327
+ </TouchableOpacity>
328
+ </Modal>
233
329
  </View>
234
330
  );
235
331
  };
@@ -272,7 +368,35 @@ const styles = StyleSheet.create({
272
368
  marginBottom: 8,
273
369
  marginLeft: 4,
274
370
  },
275
- input: {
371
+ phoneInputRow: {
372
+ flexDirection: 'row',
373
+ alignItems: 'center',
374
+ gap: 10,
375
+ },
376
+ countryPickerBtn: {
377
+ flexDirection: 'row',
378
+ alignItems: 'center',
379
+ justifyContent: 'space-between',
380
+ borderWidth: 1,
381
+ borderColor: '#e0e0e0',
382
+ paddingHorizontal: 12,
383
+ paddingVertical: 16,
384
+ borderRadius: 12,
385
+ backgroundColor: '#f8f9fa',
386
+ minWidth: 90,
387
+ },
388
+ countryPickerText: {
389
+ fontSize: 16,
390
+ color: '#333',
391
+ fontWeight: '600',
392
+ },
393
+ dropdownIcon: {
394
+ fontSize: 12,
395
+ color: '#666',
396
+ marginLeft: 8,
397
+ },
398
+ phoneInput: {
399
+ flex: 1,
276
400
  borderWidth: 1,
277
401
  borderColor: '#e0e0e0',
278
402
  padding: 16,
@@ -281,6 +405,54 @@ const styles = StyleSheet.create({
281
405
  backgroundColor: '#f8f9fa',
282
406
  color: '#333',
283
407
  },
408
+ modalOverlay: {
409
+ flex: 1,
410
+ backgroundColor: 'rgba(0,0,0,0.5)',
411
+ justifyContent: 'flex-end',
412
+ },
413
+ modalContent: {
414
+ backgroundColor: 'white',
415
+ borderTopLeftRadius: 24,
416
+ borderTopRightRadius: 24,
417
+ maxHeight: '60%',
418
+ paddingBottom: 40,
419
+ },
420
+ modalHeader: {
421
+ flexDirection: 'row',
422
+ justifyContent: 'space-between',
423
+ alignItems: 'center',
424
+ padding: 20,
425
+ borderBottomWidth: 1,
426
+ borderBottomColor: '#f0f0f0',
427
+ },
428
+ modalTitle: {
429
+ fontSize: 18,
430
+ fontWeight: '700',
431
+ color: '#1a1a1a',
432
+ },
433
+ modalClose: {
434
+ fontSize: 20,
435
+ color: '#666',
436
+ padding: 5,
437
+ },
438
+ countryItem: {
439
+ flexDirection: 'row',
440
+ justifyContent: 'space-between',
441
+ alignItems: 'center',
442
+ paddingVertical: 16,
443
+ paddingHorizontal: 24,
444
+ borderBottomWidth: 1,
445
+ borderBottomColor: '#f8f9fa',
446
+ },
447
+ countryItemLabel: {
448
+ fontSize: 16,
449
+ color: '#333',
450
+ },
451
+ checkMark: {
452
+ color: '#2DBD60',
453
+ fontSize: 18,
454
+ fontWeight: 'bold',
455
+ },
284
456
  otpWrapper: {
285
457
  position: 'relative',
286
458
  width: '100%',
@@ -295,7 +467,7 @@ const styles = StyleSheet.create({
295
467
  },
296
468
  otpBox: {
297
469
  width: '14%',
298
- aspectRatio: 1, // keeps it perfectly square
470
+ aspectRatio: 1,
299
471
  borderWidth: 1,
300
472
  borderColor: '#e0e0e0',
301
473
  borderRadius: 12,
@@ -323,7 +495,7 @@ const styles = StyleSheet.create({
323
495
  left: 0,
324
496
  width: '100%',
325
497
  height: '100%',
326
- opacity: 0, // completely invisible but handles native keyboard interactions perfectly
498
+ opacity: 0,
327
499
  },
328
500
  errorText: {
329
501
  color: '#dc2626',
@@ -10,7 +10,7 @@ export interface NativeCameraViewProps {
10
10
  onError?: (event: any) => void;
11
11
  }
12
12
 
13
- const NativeCameraViewComponent = requireNativeViewManager('TransfergratisSdk_TransfergratisSdkView');
13
+ const NativeCameraViewComponent = requireNativeViewManager('SanctumKeySdk_SanctumKeySdkView');
14
14
 
15
15
  export const NativeCameraView: React.FC<NativeCameraViewProps> = (props) => {
16
16
 
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { JSX } from 'react';
2
2
  import { View, SafeAreaView } from 'react-native';
3
3
  import { TemplateKYCFlow } from './TemplateKYCFlowRefactored';
4
4
  import { KYCTemplate, VerificationState } from '../types/KYC.types';
@@ -136,7 +136,8 @@ const advancedVerificationTemplate: KYCTemplate = {
136
136
  ]
137
137
  };
138
138
 
139
- export const TemplateKYCExample: React.FC<{
139
+
140
+ export interface TemplateKYCExampleProps {
140
141
  onComplete: (data: VerificationState) => void;
141
142
  onCancel: () => void;
142
143
  onError: (error: string) => void;
@@ -151,7 +152,25 @@ export const TemplateKYCExample: React.FC<{
151
152
  initialCountryResume?: { code: string; documentType: string; region?: string };
152
153
  referenceId?: string;
153
154
  onSessionSave?: (sessionId: string) => void;
154
- }> = ({ onComplete, onCancel, onError, language, API_KEY, templateId, template, env = 'PRODUCTION', serverEnv, existingSessionId, initialComponentIndex, initialCountryResume, referenceId, onSessionSave }) => {
155
+ }
156
+
157
+ export function TemplateKYCExample({
158
+ onComplete,
159
+ onCancel,
160
+ onError,
161
+ language,
162
+ API_KEY,
163
+ templateId,
164
+ template,
165
+ env = 'PRODUCTION',
166
+ serverEnv,
167
+ existingSessionId,
168
+ initialComponentIndex,
169
+ initialCountryResume,
170
+ referenceId,
171
+ onSessionSave
172
+ }: TemplateKYCExampleProps): JSX.Element { // <--- Explicit Return Type
173
+
155
174
  const handleComplete = (data: VerificationState) => {
156
175
  console.log('KYC Template completed with data:', data);
157
176
  onComplete(data);
@@ -194,5 +213,5 @@ export const TemplateKYCExample: React.FC<{
194
213
  </View>
195
214
  </SafeAreaView>
196
215
  );
197
- };
216
+ }
198
217
 
@@ -12,11 +12,11 @@ export interface AllowedDomainConfig {
12
12
  // Default configuration - can be overridden via environment variables
13
13
  const DEFAULT_CONFIG: AllowedDomainConfig = {
14
14
  domains: [
15
- 'transfergratis.com',
16
- 'www.transfergratis.com',
17
- 'admin.transfergratis.com',
18
- 'dashboard.transfergratis.com',
19
- 'preweb.transfergratis.net',
15
+ 'sanctumkey.com',
16
+ 'www.sanctumkey.com',
17
+ 'admin.sanctumkey.com',
18
+ 'dashboard.sanctumkey.com',
19
+ 'preweb.sanctumkey.net',
20
20
  // Add other trusted domains here
21
21
  ],
22
22
  enforceHttps: true,
@@ -59,7 +59,7 @@ export const isDomainAllowed = (domain: string): boolean => {
59
59
  return true;
60
60
  }
61
61
 
62
- // Subdomain match (e.g., app.transfergratis.com matches transfergratis.com)
62
+ // Subdomain match (e.g., app.SanctumKey.com matches SanctumKey.com)
63
63
  if (domain.endsWith('.' + allowedDomain)) {
64
64
  return true;
65
65
  }
@@ -1,4 +1,4 @@
1
- # 🌍 Système d'Internationalisation (i18n) - Transfergratis SDK
1
+ # 🌍 Système d'Internationalisation (i18n) - SanctumKey SDK
2
2
 
3
3
  Ce système d'internationalisation permet de traduire facilement votre application KYC en plusieurs langues.
4
4
 
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './TransfergratisSdk.types';
1
+ export * from './SanctumKeySdk.types';
2
2
 
3
3
 
4
4
  // Export KYC types
@@ -8,9 +8,9 @@ export * from './types/KYC.types';
8
8
  export * from './types/env.types';
9
9
 
10
10
 
11
- export { TemplateKYCExample as LaunchTransferGratisKYC } from './components/TemplateKYCExample';
11
+ export { TemplateKYCExample as LaunchSanctumKeyKYC } from './components/TemplateKYCExample';
12
12
  // Backward compatibility for existing integrations using the typo.
13
- export { TemplateKYCExample as LauchTransferGratisKYC } from './components/TemplateKYCExample';
13
+ export { TemplateKYCExample as LauchSanctumKeyKYC } from './components/TemplateKYCExample';
14
14
 
15
15
  // Export Template Flow Components
16
16
  export { TemplateKYCFlow } from './components/TemplateKYCFlowRefactored';
@@ -82,7 +82,6 @@ export async function frontVerification(
82
82
  console.log("Front verification START", JSON.stringify({ result }, null, 2));
83
83
  logger.log("Front verification", JSON.stringify({ result }, null, 2));
84
84
 
85
- // 🚨 FIX 1: Bulletproof Case-Insensitive Check
86
85
  const authMethods = Array.isArray(result.regionMapping?.authMethod)
87
86
  ? result.regionMapping.authMethod.map(m => String(m).toUpperCase())
88
87
  : [];
@@ -164,7 +163,6 @@ export async function frontVerification(
164
163
  bbox = crop.bbox;
165
164
  } catch { }
166
165
 
167
- // 🚨 FIX 2: Execute MRZ if required (Removed restrictive guards)
168
166
  if (hasMrz) {
169
167
  try {
170
168
  logger.log("Tentative d'extraction MRZ (Front)");
@@ -176,7 +174,7 @@ export async function frontVerification(
176
174
  postfix: result?.currentSide || 'front',
177
175
  token: token,
178
176
  template_path: result?.templatePath || '',
179
- mrz_type: result?.mrzType || 'TD1' // Fallback to ensure it always runs
177
+ mrz_type: result?.mrzType || 'TD1'
180
178
  },
181
179
  env
182
180
  );
@@ -201,7 +199,6 @@ export async function frontVerification(
201
199
  }
202
200
  }
203
201
 
204
- // ─── backVerification ────────────────────────────────────────────────────────
205
202
 
206
203
  export async function backVerification(
207
204
  result: {
@@ -219,12 +216,13 @@ export async function backVerification(
219
216
  try {
220
217
  if (!result.path) throw new Error('No path provided');
221
218
  logger.log("result.regionMapping", result.regionMapping, result.currentSide, result.code);
219
+ logger.log('result object', result)
222
220
 
223
- // 🚨 FIX 3: Robust Auth Method Resolution for the Back Side
224
221
  const authMethods = Array.isArray(result.regionMapping?.authMethod)
225
222
  ? result.regionMapping.authMethod.map(m => String(m).toUpperCase())
226
223
  : [];
227
- const hasMrz = authMethods.some(m => m.includes('MRZ'));
224
+
225
+ const hasMrz = authMethods.some(m => m.includes('MRZ'))
228
226
  const hasBarcode = authMethods.some(m => m.includes('BARCODE') || m.includes('2D'));
229
227
 
230
228
  if (env === 'SANDBOX') {
@@ -338,7 +336,6 @@ export async function backVerification(
338
336
 
339
337
  let extractionResult: any = {};
340
338
 
341
- // 🚨 FIX 4: Guaranteed MRZ Extraction Attachment
342
339
  if (hasMrz) {
343
340
  try {
344
341
  logger.log("Tentative d'extraction MRZ (Back)");
@@ -481,7 +478,7 @@ export async function checkTemplateType(
481
478
  logger.log("templateType result", JSON.stringify(truncateFields(templateType), null, 2));
482
479
  return templateType;
483
480
  } catch (e: any) {
484
- logger.error('Error checking template type:', JSON.stringify(errorMessage(e), null, 2));
481
+ logger.error('Errorrr checking template type:', JSON.stringify(errorMessage(e), null, 2));
485
482
  if (e?.message === 'CARD_NOT_FULLY_IN_FRAME' || e?.message === 'TOO_FAR_AWAY' || e?.message?.includes('ne correspond pas')) throw e;
486
483
  throw new Error(e?.message || 'Erreur de vérification du template');
487
484
  }