@sanctum-key/react-native-sdk 1.0.8 → 1.0.10

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 (106) hide show
  1. package/README.md +4 -4
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/AndroidManifest.xml +1 -1
  4. package/android/src/main/java/kyc/transfergratis/com/TransfergratisSdkModule.kt +6 -6
  5. package/android/src/main/java/kyc/transfergratis/com/TransfergratisSdkView.kt +2 -2
  6. package/build/package.json +5 -5
  7. package/build/src/App.d.ts +2 -2
  8. package/build/src/App.d.ts.map +1 -1
  9. package/build/src/App.js +2 -2
  10. package/build/src/App.js.map +1 -1
  11. package/build/src/{SanctumKeySdk.types.d.ts → TransfergratisSdk.types.d.ts} +3 -3
  12. package/build/src/TransfergratisSdk.types.d.ts.map +1 -0
  13. package/build/src/TransfergratisSdk.types.js +2 -0
  14. package/build/src/TransfergratisSdk.types.js.map +1 -0
  15. package/build/src/{SanctumKeySdkModule.d.ts → TransfergratisSdkModule.d.ts} +4 -4
  16. package/build/src/TransfergratisSdkModule.d.ts.map +1 -0
  17. package/build/src/{SanctumKeySdkModule.js → TransfergratisSdkModule.js} +2 -2
  18. package/build/src/TransfergratisSdkModule.js.map +1 -0
  19. package/build/src/{SanctumKeySdkModule.web.d.ts → TransfergratisSdkModule.web.d.ts} +4 -4
  20. package/build/src/TransfergratisSdkModule.web.d.ts.map +1 -0
  21. package/build/src/{SanctumKeySdkModule.web.js → TransfergratisSdkModule.web.js} +3 -3
  22. package/build/src/TransfergratisSdkModule.web.js.map +1 -0
  23. package/build/src/TransfergratisSdkView.d.ts +4 -0
  24. package/build/src/TransfergratisSdkView.d.ts.map +1 -0
  25. package/build/src/TransfergratisSdkView.js +7 -0
  26. package/build/src/TransfergratisSdkView.js.map +1 -0
  27. package/build/src/TransfergratisSdkView.web.d.ts +4 -0
  28. package/build/src/TransfergratisSdkView.web.d.ts.map +1 -0
  29. package/build/src/{SanctumKeySdkView.web.js → TransfergratisSdkView.web.js} +2 -2
  30. package/build/src/TransfergratisSdkView.web.js.map +1 -0
  31. package/build/src/api/axios.js +2 -2
  32. package/build/src/api/axios.js.map +1 -1
  33. package/build/src/components/EnhancedCameraView.d.ts.map +1 -1
  34. package/build/src/components/EnhancedCameraView.js +12 -61
  35. package/build/src/components/EnhancedCameraView.js.map +1 -1
  36. package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
  37. package/build/src/components/KYCElements/CountrySelection.js +259 -63
  38. package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
  39. package/build/src/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -1
  40. package/build/src/components/KYCElements/EmailVerificationTemplate.js +11 -32
  41. package/build/src/components/KYCElements/EmailVerificationTemplate.js.map +1 -1
  42. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  43. package/build/src/components/KYCElements/IDCardCapture.js +222 -68
  44. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  45. package/build/src/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -1
  46. package/build/src/components/KYCElements/PhoneVerificationTemplate.js +9 -11
  47. package/build/src/components/KYCElements/PhoneVerificationTemplate.js.map +1 -1
  48. package/build/src/components/NativeCameraView.js +1 -1
  49. package/build/src/components/NativeCameraView.js.map +1 -1
  50. package/build/src/config/KYCConfig.js +1 -1
  51. package/build/src/config/KYCConfig.js.map +1 -1
  52. package/build/src/config/allowedDomains.js +6 -6
  53. package/build/src/config/allowedDomains.js.map +1 -1
  54. package/build/src/config/region_mapping.json +727 -0
  55. package/build/src/index.d.ts +3 -3
  56. package/build/src/index.d.ts.map +1 -1
  57. package/build/src/index.js +3 -3
  58. package/build/src/index.js.map +1 -1
  59. package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
  60. package/build/src/modules/api/CardAuthentification.js +3 -7
  61. package/build/src/modules/api/CardAuthentification.js.map +1 -1
  62. package/build/src/modules/api/KYCService.d.ts +1 -2
  63. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  64. package/build/src/modules/api/KYCService.js +103 -63
  65. package/build/src/modules/api/KYCService.js.map +1 -1
  66. package/build/src/modules/camera/NativeCameraModule.js +17 -17
  67. package/build/src/modules/camera/NativeCameraModule.js.map +1 -1
  68. package/expo-module.config.json +2 -2
  69. package/ios/TransfergratisSdk.podspec +2 -2
  70. package/ios/TransfergratisSdkModule.swift +12 -12
  71. package/package.json +5 -5
  72. package/src/App.tsx +2 -2
  73. package/src/{SanctumKeySdk.types.ts → TransfergratisSdk.types.ts} +2 -2
  74. package/src/{SanctumKeySdkModule.ts → TransfergratisSdkModule.ts} +3 -3
  75. package/src/{SanctumKeySdkModule.web.ts → TransfergratisSdkModule.web.ts} +3 -3
  76. package/src/TransfergratisSdkView.tsx +11 -0
  77. package/src/{SanctumKeySdkView.web.tsx → TransfergratisSdkView.web.tsx} +2 -2
  78. package/src/api/axios.ts +2 -2
  79. package/src/components/EnhancedCameraView.tsx +34 -99
  80. package/src/components/KYCElements/CountrySelection.tsx +300 -74
  81. package/src/components/KYCElements/EmailVerificationTemplate.tsx +10 -36
  82. package/src/components/KYCElements/IDCardCapture.tsx +310 -156
  83. package/src/components/KYCElements/PhoneVerificationTemplate.tsx +9 -11
  84. package/src/components/NativeCameraView.tsx +1 -1
  85. package/src/config/KYCConfig.ts +1 -1
  86. package/src/config/allowedDomains.ts +6 -6
  87. package/src/i18n/README.md +1 -1
  88. package/src/index.ts +3 -3
  89. package/src/modules/api/CardAuthentification.ts +5 -8
  90. package/src/modules/api/KYCService.ts +167 -116
  91. package/src/modules/camera/NativeCameraModule.ts +17 -17
  92. package/build/src/SanctumKeySdk.types.d.ts.map +0 -1
  93. package/build/src/SanctumKeySdk.types.js +0 -2
  94. package/build/src/SanctumKeySdk.types.js.map +0 -1
  95. package/build/src/SanctumKeySdkModule.d.ts.map +0 -1
  96. package/build/src/SanctumKeySdkModule.js.map +0 -1
  97. package/build/src/SanctumKeySdkModule.web.d.ts.map +0 -1
  98. package/build/src/SanctumKeySdkModule.web.js.map +0 -1
  99. package/build/src/SanctumKeySdkView.d.ts +0 -4
  100. package/build/src/SanctumKeySdkView.d.ts.map +0 -1
  101. package/build/src/SanctumKeySdkView.js +0 -7
  102. package/build/src/SanctumKeySdkView.js.map +0 -1
  103. package/build/src/SanctumKeySdkView.web.d.ts +0 -4
  104. package/build/src/SanctumKeySdkView.web.d.ts.map +0 -1
  105. package/build/src/SanctumKeySdkView.web.js.map +0 -1
  106. package/src/SanctumKeySdkView.tsx +0 -11
@@ -1,5 +1,12 @@
1
- import React from 'react';
2
- import { View, Text, TouchableOpacity, StyleSheet, ScrollView } from 'react-native';
1
+ import React, { useState, useMemo } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ StyleSheet,
7
+ FlatList,
8
+ TextInput
9
+ } from 'react-native';
3
10
  import { KYCElement, KYCElementOption } from '../../types/KYC.types';
4
11
 
5
12
  interface CountrySelectionProps {
@@ -9,18 +16,198 @@ interface CountrySelectionProps {
9
16
  error?: string;
10
17
  }
11
18
 
12
- const defaultCountries: KYCElementOption[] = [
19
+ // 🌍 Comprehensive Global Country List
20
+ const ALL_COUNTRIES: KYCElementOption[] = [
21
+ { value: 'AF', label: 'Afghanistan', icon: '🇦🇫' },
22
+ { value: 'AL', label: 'Albania', icon: '🇦🇱' },
23
+ { value: 'DZ', label: 'Algeria', icon: '🇩🇿' },
24
+ { value: 'AD', label: 'Andorra', icon: '🇦🇩' },
25
+ { value: 'AO', label: 'Angola', icon: '🇦🇴' },
26
+ { value: 'AR', label: 'Argentina', icon: '🇦🇷' },
27
+ { value: 'AM', label: 'Armenia', icon: '🇦🇲' },
28
+ { value: 'AU', label: 'Australia', icon: '🇦🇺' },
29
+ { value: 'AT', label: 'Austria', icon: '🇦🇹' },
30
+ { value: 'AZ', label: 'Azerbaijan', icon: '🇦🇿' },
31
+ { value: 'BS', label: 'Bahamas', icon: '🇧🇸' },
32
+ { value: 'BH', label: 'Bahrain', icon: '🇧🇭' },
33
+ { value: 'BD', label: 'Bangladesh', icon: '🇧🇩' },
34
+ { value: 'BB', label: 'Barbados', icon: '🇧🇧' },
35
+ { value: 'BY', label: 'Belarus', icon: '🇧🇾' },
36
+ { value: 'BE', label: 'Belgium', icon: '🇧🇪' },
37
+ { value: 'BZ', label: 'Belize', icon: '🇧🇿' },
38
+ { value: 'BJ', label: 'Benin', icon: '🇧🇯' },
39
+ { value: 'BT', label: 'Bhutan', icon: '🇧🇹' },
40
+ { value: 'BO', label: 'Bolivia', icon: '🇧🇴' },
41
+ { value: 'BA', label: 'Bosnia and Herzegovina', icon: '🇧🇦' },
42
+ { value: 'BW', label: 'Botswana', icon: '🇧🇼' },
43
+ { value: 'BR', label: 'Brazil', icon: '🇧🇷' },
44
+ { value: 'BN', label: 'Brunei', icon: '🇧🇳' },
45
+ { value: 'BG', label: 'Bulgaria', icon: '🇧🇬' },
46
+ { value: 'BF', label: 'Burkina Faso', icon: '🇧🇫' },
47
+ { value: 'BI', label: 'Burundi', icon: '🇧🇮' },
48
+ { value: 'CV', label: 'Cabo Verde', icon: '🇨🇻' },
49
+ { value: 'KH', label: 'Cambodia', icon: '🇰🇭' },
50
+ { value: 'CM', label: 'Cameroon', icon: '🇨🇲' },
51
+ { value: 'CA', label: 'Canada', icon: '🇨🇦' },
52
+ { value: 'CF', label: 'Central African Republic', icon: '🇨🇫' },
53
+ { value: 'TD', label: 'Chad', icon: '🇹🇩' },
54
+ { value: 'CL', label: 'Chile', icon: '🇨🇱' },
55
+ { value: 'CN', label: 'China', icon: '🇨🇳' },
56
+ { value: 'CO', label: 'Colombia', icon: '🇨🇴' },
57
+ { value: 'KM', label: 'Comoros', icon: '🇰🇲' },
58
+ { value: 'CG', label: 'Congo', icon: '🇨🇬' },
59
+ { value: 'CD', label: 'Congo (DRC)', icon: '🇨🇩' },
60
+ { value: 'CR', label: 'Costa Rica', icon: '🇨🇷' },
61
+ { value: 'HR', label: 'Croatia', icon: '🇭🇷' },
62
+ { value: 'CU', label: 'Cuba', icon: '🇨🇺' },
63
+ { value: 'CY', label: 'Croatia', icon: '🇨🇾' },
64
+ { value: 'CZ', label: 'Czechia', icon: '🇨🇿' },
65
+ { value: 'DK', label: 'Denmark', icon: '🇩🇰' },
66
+ { value: 'DJ', label: 'Djibouti', icon: '🇩🇯' },
67
+ { value: 'DM', label: 'Dominica', icon: '🇩🇲' },
68
+ { value: 'DO', label: 'Dominican Republic', icon: '🇩🇴' },
69
+ { value: 'EC', label: 'Ecuador', icon: '🇪🇨' },
70
+ { value: 'EG', label: 'Egypt', icon: '🇪🇬' },
71
+ { value: 'SV', label: 'El Salvador', icon: '🇸🇻' },
72
+ { value: 'GQ', label: 'Equatorial Guinea', icon: '🇬🇶' },
73
+ { value: 'ER', label: 'Eritrea', icon: '🇪🇷' },
74
+ { value: 'EE', label: 'Estonia', icon: '🇪🇪' },
75
+ { value: 'SZ', label: 'Eswatini', icon: '🇸🇿' },
76
+ { value: 'ET', label: 'Ethiopia', icon: '🇪🇹' },
77
+ { value: 'FJ', label: 'Fiji', icon: '🇫🇯' },
78
+ { value: 'FI', label: 'Finland', icon: '🇫🇮' },
13
79
  { value: 'FR', label: 'France', icon: '🇫🇷' },
14
- { value: 'BE', label: 'Belgique', icon: '🇧🇪' },
80
+ { value: 'GA', label: 'Gabon', icon: '🇬🇦' },
81
+ { value: 'GM', label: 'Gambia', icon: '🇬🇲' },
82
+ { value: 'GE', label: 'Georgia', icon: '🇬🇪' },
83
+ { value: 'DE', label: 'Germany', icon: '🇩🇪' },
84
+ { value: 'GH', label: 'Ghana', icon: '🇬🇭' },
85
+ { value: 'GR', label: 'Greece', icon: '🇬🇷' },
86
+ { value: 'GD', label: 'Grenada', icon: '🇬🇩' },
87
+ { value: 'GT', label: 'Guatemala', icon: '🇬🇹' },
88
+ { value: 'GN', label: 'Guinea', icon: '🇬🇳' },
89
+ { value: 'GW', label: 'Guinea-Bissau', icon: '🇬🇼' },
90
+ { value: 'GY', label: 'Guyana', icon: '🇬🇾' },
91
+ { value: 'HT', label: 'Haiti', icon: '🇭🇹' },
92
+ { value: 'HN', label: 'Honduras', icon: '🇭🇳' },
93
+ { value: 'HU', label: 'Hungary', icon: '🇭🇺' },
94
+ { value: 'IS', label: 'Iceland', icon: '🇮🇸' },
95
+ { value: 'IN', label: 'India', icon: '🇮🇳' },
96
+ { value: 'ID', label: 'Indonesia', icon: '🇮🇩' },
97
+ { value: 'IR', label: 'Iran', icon: '🇮🇷' },
98
+ { value: 'IQ', label: 'Iraq', icon: '🇮🇶' },
99
+ { value: 'IE', label: 'Ireland', icon: '🇮🇪' },
100
+ { value: 'IL', label: 'Ireland', icon: '🇮🇪' },
101
+ { value: 'IT', label: 'Italy', icon: '🇮🇹' },
102
+ { value: 'JM', label: 'Jamaica', icon: '🇯🇲' },
103
+ { value: 'JP', label: 'Japan', icon: '🇯🇵' },
104
+ { value: 'JO', label: 'Jordan', icon: '🇯🇴' },
105
+ { value: 'KZ', label: 'Kazakhstan', icon: '🇰🇿' },
106
+ { value: 'KE', label: 'Kenya', icon: '🇰🇪' },
107
+ { value: 'KI', label: 'Kiribati', icon: '🇰🇮' },
108
+ { value: 'KP', label: 'Korea (North)', icon: '🇰🇵' },
109
+ { value: 'KR', label: 'Korea (South)', icon: '🇰🇷' },
110
+ { value: 'KW', label: 'Kuwait', icon: '🇰🇼' },
111
+ { value: 'KG', label: 'Kyrgyzstan', icon: '🇰🇬' },
112
+ { value: 'LA', label: 'Laos', icon: '🇱🇦' },
113
+ { value: 'LV', label: 'Latvia', icon: '🇱🇻' },
114
+ { value: 'LB', label: 'Lebanon', icon: '🇱🇧' },
115
+ { value: 'LS', label: 'Lesotho', icon: '🇱🇸' },
116
+ { value: 'LR', label: 'Liberia', icon: '🇱🇷' },
117
+ { value: 'LY', label: 'Libya', icon: '🇱🇾' },
118
+ { value: 'LI', label: 'Liechtenstein', icon: '🇱🇮' },
119
+ { value: 'LT', label: 'Lithuania', icon: '🇱🇹' },
15
120
  { value: 'LU', label: 'Luxembourg', icon: '🇱🇺' },
16
- { value: 'DE', label: 'Allemagne', icon: '🇩🇪' },
17
- { value: 'IT', label: 'Italie', icon: '🇮🇹' },
18
- { value: 'ES', label: 'Espagne', icon: '🇪🇸' },
121
+ { value: 'MG', label: 'Madagascar', icon: '🇲🇬' },
122
+ { value: 'MW', label: 'Malawi', icon: '🇲🇼' },
123
+ { value: 'MY', label: 'Malaysia', icon: '🇲🇾' },
124
+ { value: 'MV', label: 'Maldives', icon: '🇲🇻' },
125
+ { value: 'ML', label: 'Mali', icon: '🇲🇱' },
126
+ { value: 'MT', label: 'Malta', icon: '🇲🇹' },
127
+ { value: 'MH', label: 'Marshall Islands', icon: '🇲🇭' },
128
+ { value: 'MR', label: 'Mauritania', icon: '🇲🇷' },
129
+ { value: 'MU', label: 'Mauritius', icon: '🇲🇺' },
130
+ { value: 'MX', label: 'Mexico', icon: '🇲🇽' },
131
+ { value: 'FM', label: 'Micronesia', icon: '🇫🇲' },
132
+ { value: 'MD', label: 'Moldova', icon: '🇲🇩' },
133
+ { value: 'MC', label: 'Monaco', icon: '🇲🇨' },
134
+ { value: 'MN', label: 'Mongolia', icon: '🇲🇳' },
135
+ { value: 'ME', label: 'Montenegro', icon: '🇲🇪' },
136
+ { value: 'MA', label: 'Morocco', icon: '🇲🇦' },
137
+ { value: 'MZ', label: 'Mozambique', icon: '🇲🇿' },
138
+ { value: 'MM', label: 'Myanmar', icon: '🇲🇲' },
139
+ { value: 'NA', label: 'Namibia', icon: '🇳🇦' },
140
+ { value: 'NR', label: 'Nauru', icon: '🇳🇷' },
141
+ { value: 'NP', label: 'Nepal', icon: '🇳🇵' },
142
+ { value: 'NL', label: 'Netherlands', icon: '🇳🇱' },
143
+ { value: 'NZ', label: 'New Zealand', icon: '🇳🇿' },
144
+ { value: 'NI', label: 'Nicaragua', icon: '🇳🇮' },
145
+ { value: 'NE', label: 'Niger', icon: '🇳🇪' },
146
+ { value: 'NG', label: 'Nigeria', icon: '🇳🇬' },
147
+ { value: 'MK', label: 'North Macedonia', icon: '🇲🇰' },
148
+ { value: 'NO', label: 'Norway', icon: '🇳🇴' },
149
+ { value: 'OM', label: 'Oman', icon: '🇴🇲' },
150
+ { value: 'PK', label: 'Pakistan', icon: '🇵🇰' },
151
+ { value: 'PW', label: 'Palau', icon: '🇵🇼' },
152
+ { value: 'PA', label: 'Panama', icon: '🇵🇦' },
153
+ { value: 'PG', label: 'Papua New Guinea', icon: '🇵🇬' },
154
+ { value: 'PY', label: 'Paraguay', icon: '🇵🇾' },
155
+ { value: 'PE', label: 'Peru', icon: '🇵🇪' },
156
+ { value: 'PH', label: 'Philippines', icon: '🇵🇭' },
157
+ { value: 'PL', label: 'Poland', icon: '🇵🇱' },
19
158
  { value: 'PT', label: 'Portugal', icon: '🇵🇹' },
20
- { value: 'AT', label: 'Autriche', icon: '🇦🇹' },
21
- { value: 'CH', label: 'Suisse', icon: '🇨🇭' },
22
- { value: 'NL', label: 'Pays-Bas', icon: '🇳🇱' },
23
- { value: 'OTHER', label: 'Autre', icon: '🌍' },
159
+ { value: 'QA', label: 'Qatar', icon: '🇶🇦' },
160
+ { value: 'RO', label: 'Romania', icon: '🇷🇴' },
161
+ { value: 'RU', label: 'Russia', icon: '🇷🇺' },
162
+ { value: 'RW', label: 'Rwanda', icon: '🇷🇼' },
163
+ { value: 'WS', label: 'Samoa', icon: '🇼🇸' },
164
+ { value: 'SM', label: 'San Marino', icon: '🇸🇲' },
165
+ { value: 'ST', label: 'Sao Tome and Principe', icon: '🇸🇹' },
166
+ { value: 'SA', label: 'Saudi Arabia', icon: '🇸🇦' },
167
+ { value: 'SN', label: 'Senegal', icon: '🇸🇳' },
168
+ { value: 'RS', label: 'Serbia', icon: '🇷🇸' },
169
+ { value: 'SC', label: 'Seychelles', icon: '🇸🇨' },
170
+ { value: 'SL', label: 'Sierra Leone', icon: '🇸🇱' },
171
+ { value: 'SG', label: 'Singapore', icon: '🇸🇬' },
172
+ { value: 'SK', label: 'Slovakia', icon: '🇸🇰' },
173
+ { value: 'SI', label: 'Slovenia', icon: '🇸🇮' },
174
+ { value: 'SB', label: 'Solomon Islands', icon: '🇸🇧' },
175
+ { value: 'SO', label: 'Somalia', icon: '🇸🇴' },
176
+ { value: 'ZA', label: 'South Africa', icon: '🇿🇦' },
177
+ { value: 'ES', label: 'Spain', icon: '🇪🇸' },
178
+ { value: 'LK', label: 'Sri Lanka', icon: '🇱🇰' },
179
+ { value: 'SD', label: 'Sudan', icon: '🇸🇩' },
180
+ { value: 'SR', label: 'Suriname', icon: '🇸🇷' },
181
+ { value: 'SE', label: 'Sweden', icon: '🇸🇪' },
182
+ { value: 'CH', label: 'Switzerland', icon: '🇨🇭' },
183
+ { value: 'SY', label: 'Syria', icon: '🇸🇾' },
184
+ { value: 'TW', label: 'Taiwan', icon: '🇹🇼' },
185
+ { value: 'TJ', label: 'Tajikistan', icon: '🇹🇯' },
186
+ { value: 'TZ', label: 'Tanzania', icon: '🇹🇿' },
187
+ { value: 'TH', label: 'Thailand', icon: '🇹🇭' },
188
+ { value: 'TL', label: 'Timor-Leste', icon: '🇹🇱' },
189
+ { value: 'TG', label: 'Togo', icon: '🇹🇬' },
190
+ { value: 'TO', label: 'Tonga', icon: '🇹🇴' },
191
+ { value: 'TT', label: 'Trinidad and Tobago', icon: '🇹🇹' },
192
+ { value: 'TN', label: 'Tunisia', icon: '🇹🇳' },
193
+ { value: 'TR', label: 'Turkey', icon: '🇹🇷' },
194
+ { value: 'TM', label: 'Turkmenistan', icon: '🇹🇲' },
195
+ { value: 'TV', label: 'Tuvalu', icon: '🇹🇻' },
196
+ { value: 'UG', label: 'Uganda', icon: '🇺🇬' },
197
+ { value: 'UA', label: 'Ukraine', icon: '🇺🇦' },
198
+ { value: 'AE', label: 'United Arab Emirates', icon: '🇦🇪' },
199
+ { value: 'GB', label: 'United Kingdom', icon: '🇬🇧' },
200
+ { value: 'US', label: 'United States', icon: '🇺🇸' },
201
+ { value: 'UY', label: 'Uruguay', icon: '🇺🇾' },
202
+ { value: 'UZ', label: 'Uzbekistan', icon: '🇺🇿' },
203
+ { value: 'VU', label: 'Vanuatu', icon: '🇻🇺' },
204
+ { value: 'VA', label: 'Vatican City', icon: '🇻🇦' },
205
+ { value: 'VE', label: 'Venezuela', icon: '🇻🇪' },
206
+ { value: 'VN', label: 'Vietnam', icon: '🇻🇳' },
207
+ { value: 'YE', label: 'Yemen', icon: '🇾🇪' },
208
+ { value: 'ZM', label: 'Zambia', icon: '🇿🇲' },
209
+ { value: 'ZW', label: 'Zimbabwe', icon: '🇿🇼' },
210
+ { value: 'OTHER', label: 'Other', icon: '🌍' },
24
211
  ];
25
212
 
26
213
  export const CountrySelection: React.FC<CountrySelectionProps> = ({
@@ -29,43 +216,80 @@ export const CountrySelection: React.FC<CountrySelectionProps> = ({
29
216
  onValueChange,
30
217
  error,
31
218
  }) => {
32
- const countries = element.options || defaultCountries;
219
+ // Use the massive list if the backend didn't supply specific options
220
+ const countries = element.options && element.options.length > 0 ? element.options : ALL_COUNTRIES;
221
+ const [searchQuery, setSearchQuery] = useState('');
222
+
223
+ // Filter countries based on user input
224
+ const filteredCountries = useMemo(() => {
225
+ if (!searchQuery.trim()) return countries;
226
+ return countries.filter(country =>
227
+ country.label.toLowerCase().includes(searchQuery.toLowerCase())
228
+ );
229
+ }, [countries, searchQuery]);
230
+
231
+ // Extract the render logic into a separate function for FlatList performance
232
+ const renderCountry = ({ item: country }: { item: KYCElementOption }) => (
233
+ <TouchableOpacity
234
+ style={[
235
+ styles.option,
236
+ value === country.value && styles.selectedOption
237
+ ]}
238
+ onPress={() => onValueChange(country.value)}
239
+ activeOpacity={0.7}
240
+ >
241
+ <Text style={styles.optionIcon}>{country.icon}</Text>
242
+ <View style={styles.optionContent}>
243
+ <Text style={[
244
+ styles.optionLabel,
245
+ value === country.value && styles.selectedOptionLabel
246
+ ]}>
247
+ {country.label}
248
+ </Text>
249
+ {country.description && (
250
+ <Text style={styles.optionDescription}>{country.description}</Text>
251
+ )}
252
+ </View>
253
+ {value === country.value && (
254
+ <View style={styles.checkmark}>
255
+ <Text style={styles.checkmarkText}>✓</Text>
256
+ </View>
257
+ )}
258
+ </TouchableOpacity>
259
+ );
33
260
 
34
261
  return (
35
262
  <View style={styles.container}>
36
- <Text style={styles.title}>{element.title}</Text>
37
- <Text style={styles.description}>{element.description}</Text>
38
-
39
- <ScrollView style={styles.optionsContainer} showsVerticalScrollIndicator={false}>
40
- {countries.map((country) => (
41
- <TouchableOpacity
42
- key={country.value}
43
- style={[
44
- styles.option,
45
- value === country.value && styles.selectedOption
46
- ]}
47
- onPress={() => onValueChange(country.value)}
48
- >
49
- <Text style={styles.optionIcon}>{country.icon}</Text>
50
- <View style={styles.optionContent}>
51
- <Text style={[
52
- styles.optionLabel,
53
- value === country.value && styles.selectedOptionLabel
54
- ]}>
55
- {country.label}
56
- </Text>
57
- {country.description && (
58
- <Text style={styles.optionDescription}>{country.description}</Text>
59
- )}
60
- </View>
61
- {value === country.value && (
62
- <View style={styles.checkmark}>
63
- <Text style={styles.checkmarkText}>✓</Text>
64
- </View>
65
- )}
66
- </TouchableOpacity>
67
- ))}
68
- </ScrollView>
263
+ <View style={styles.headerContainer}>
264
+ <Text style={styles.title}>{element.title}</Text>
265
+ <Text style={styles.description}>{element.description}</Text>
266
+
267
+ {/* Search Bar for better UX */}
268
+ <TextInput
269
+ style={styles.searchInput}
270
+ placeholder="Rechercher un pays..."
271
+ placeholderTextColor="#999"
272
+ value={searchQuery}
273
+ onChangeText={setSearchQuery}
274
+ clearButtonMode="while-editing" // Adds a clear 'x' on iOS
275
+ />
276
+ </View>
277
+
278
+ <FlatList
279
+ data={filteredCountries}
280
+ keyExtractor={(item) => item.value}
281
+ renderItem={renderCountry}
282
+ showsVerticalScrollIndicator={false}
283
+ contentContainerStyle={styles.listContent}
284
+ keyboardShouldPersistTaps="handled"
285
+ initialNumToRender={15}
286
+ maxToRenderPerBatch={20}
287
+ windowSize={5}
288
+ removeClippedSubviews={true}
289
+ ListEmptyComponent={
290
+ <Text style={styles.emptyText}>Aucun pays trouvé</Text>
291
+ }
292
+ />
69
293
 
70
294
  {error && (
71
295
  <Text style={styles.errorText}>{error}</Text>
@@ -77,7 +301,12 @@ export const CountrySelection: React.FC<CountrySelectionProps> = ({
77
301
  const styles = StyleSheet.create({
78
302
  container: {
79
303
  flex: 1,
80
- padding: 16,
304
+ backgroundColor: '#fff',
305
+ },
306
+ headerContainer: {
307
+ paddingHorizontal: 16,
308
+ paddingTop: 16,
309
+ paddingBottom: 8,
81
310
  },
82
311
  title: {
83
312
  fontSize: 24,
@@ -90,11 +319,28 @@ const styles = StyleSheet.create({
90
319
  fontSize: 16,
91
320
  color: '#666',
92
321
  textAlign: 'center',
93
- marginBottom: 24,
322
+ marginBottom: 16,
94
323
  lineHeight: 22,
95
324
  },
96
- optionsContainer: {
97
- flex: 1,
325
+ searchInput: {
326
+ backgroundColor: '#f5f5f5',
327
+ borderRadius: 10,
328
+ padding: 12,
329
+ fontSize: 16,
330
+ color: '#333',
331
+ borderWidth: 1,
332
+ borderColor: '#e5e5e5',
333
+ marginBottom: 8,
334
+ },
335
+ listContent: {
336
+ paddingHorizontal: 16,
337
+ paddingBottom: 24,
338
+ },
339
+ emptyText: {
340
+ textAlign: 'center',
341
+ color: '#999',
342
+ marginTop: 20,
343
+ fontSize: 16,
98
344
  },
99
345
  option: {
100
346
  flexDirection: 'row',
@@ -106,13 +352,10 @@ const styles = StyleSheet.create({
106
352
  borderWidth: 2,
107
353
  borderColor: '#e5e5e5',
108
354
  shadowColor: '#000',
109
- shadowOffset: {
110
- width: 0,
111
- height: 2,
112
- },
113
- shadowOpacity: 0.1,
355
+ shadowOffset: { width: 0, height: 2 },
356
+ shadowOpacity: 0.05,
114
357
  shadowRadius: 3.84,
115
- elevation: 5,
358
+ elevation: 3,
116
359
  },
117
360
  selectedOption: {
118
361
  borderColor: '#4CAF50',
@@ -154,24 +397,7 @@ const styles = StyleSheet.create({
154
397
  errorText: {
155
398
  color: '#dc2626',
156
399
  fontSize: 14,
157
- marginTop: 8,},
158
- buttonContainer: {
159
- flexDirection: 'row',
160
- justifyContent: 'space-between',
161
- marginTop: 24,
162
- gap: 10,
163
- },
164
- button: {
165
- flex: 1,
166
- padding: 12,
167
- backgroundColor: '#4CAF50',
400
+ margin: 16,
168
401
  textAlign: 'center',
169
402
  },
170
- buttonText: {
171
- color: 'white',
172
- fontSize: 16,
173
- fontWeight: 'bold',
174
- textAlign: 'center',
175
- },
176
-
177
- });
403
+ });
@@ -38,9 +38,6 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
38
38
  const [otp, setOtp] = useState('');
39
39
  const [localError, setLocalError] = useState<string | null>(null);
40
40
  const [isSimulating, setIsSimulating] = useState(false);
41
-
42
- // 🚨 NEW: Track actual focus state for visual feedback
43
- const [isInputFocused, setIsInputFocused] = useState(false);
44
41
 
45
42
  const inputRef = useRef<TextInput>(null);
46
43
 
@@ -59,22 +56,6 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
59
56
  }
60
57
  }, [otp]);
61
58
 
62
- // --- AUTO FOCUS LOGIC ---
63
- useEffect(() => {
64
- let focusTimer: ReturnType<typeof setTimeout>;
65
-
66
- // Only attempt focus when we are on the OTP step AND the loading state is completely finished
67
- if (step === 'otp' && !isSimulating) {
68
- focusTimer = setTimeout(() => {
69
- inputRef.current?.focus();
70
- }, 100);
71
- }
72
-
73
- return () => {
74
- if (focusTimer) clearTimeout(focusTimer);
75
- };
76
- }, [step, isSimulating]);
77
-
78
59
  const handleSendCode = async () => {
79
60
  const trimmed = email.trim();
80
61
  if (!trimmed || !isValidEmail(trimmed)) {
@@ -88,7 +69,8 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
88
69
  try {
89
70
  await kycService.sendEmailVerificationCode(trimmed, auth);
90
71
  setStep('otp');
91
- // Note: Removed the buggy setTimeout from here. The useEffect handles it now!
72
+ // Auto-focus the OTP input shortly after switching steps
73
+ setTimeout(() => inputRef.current?.focus(), 100);
92
74
  } catch (err: any) {
93
75
  const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send verification code');
94
76
  setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
@@ -114,8 +96,8 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
114
96
  } catch (err: any) {
115
97
  const msg = errorMessage(err) ?? err?.message ?? (t('errors.wrongCode') || 'Invalid verification code');
116
98
  setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
117
- setOtp('');
118
- inputRef.current?.focus(); // Refocus on error
99
+ setOtp(''); // Clear the boxes on error so they can type again
100
+ inputRef.current?.focus();
119
101
  } finally {
120
102
  setIsSimulating(false);
121
103
  }
@@ -145,19 +127,16 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
145
127
  <Pressable style={styles.otpBoxesContainer} onPress={() => inputRef.current?.focus()}>
146
128
  {boxes.map((_, index) => {
147
129
  const digit = otp[index] || '';
130
+ const isCurrent = index === otp.length;
148
131
  const isFilled = index < otp.length;
149
-
150
- // 🚨 NEW: Only highlight if the input is ACTUALLY focused.
151
- const isActiveIndex = index === otp.length || (index === CODE_LENGTH - 1 && otp.length === CODE_LENGTH);
152
- const isCurrent = isInputFocused && isActiveIndex;
153
132
 
154
133
  return (
155
134
  <View
156
135
  key={index}
157
136
  style={[
158
137
  styles.otpBox,
159
- isFilled && styles.otpBoxFilled,
160
- isCurrent && styles.otpBoxActive // Active overrides filled
138
+ isCurrent && styles.otpBoxActive,
139
+ isFilled && styles.otpBoxFilled
161
140
  ]}
162
141
  >
163
142
  <Text style={styles.otpBoxText}>{digit}</Text>
@@ -196,7 +175,7 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
196
175
 
197
176
  <View style={styles.otpWrapper}>
198
177
  {renderOtpBoxes()}
199
-
178
+ {/* Hidden TextInput overlaid to handle native keyboard & pasting seamlessly */}
200
179
  <TextInput
201
180
  ref={inputRef}
202
181
  style={styles.hiddenInput}
@@ -207,9 +186,6 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
207
186
  editable={!isSimulating}
208
187
  textContentType="oneTimeCode"
209
188
  caretHidden={true}
210
- // 🚨 NEW: Track focus state
211
- onFocus={() => setIsInputFocused(true)}
212
- onBlur={() => setIsInputFocused(false)}
213
189
  />
214
190
  </View>
215
191
 
@@ -245,8 +221,6 @@ export const EmailVerificationTemplate: React.FC<EmailVerificationTemplateProps>
245
221
  t('common.codeResent') || 'Code Resent',
246
222
  t('common.codeResentMessage', { email }) || 'Code resent to ' + email
247
223
  );
248
- // Refocus after resending
249
- inputRef.current?.focus();
250
224
  } catch (err: any) {
251
225
  const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send code');
252
226
  setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
@@ -326,7 +300,7 @@ const styles = StyleSheet.create({
326
300
  },
327
301
  otpBox: {
328
302
  width: '14%',
329
- aspectRatio: 1, // keeps it perfectly square
303
+ aspectRatio: 1,
330
304
  borderWidth: 1,
331
305
  borderColor: '#e0e0e0',
332
306
  borderRadius: 12,
@@ -354,7 +328,7 @@ const styles = StyleSheet.create({
354
328
  left: 0,
355
329
  width: '100%',
356
330
  height: '100%',
357
- opacity: 0, // completely invisible but handles native keyboard interactions perfectly
331
+ opacity: 0,
358
332
  },
359
333
  errorText: {
360
334
  color: '#dc2626',