@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.
- package/README.md +4 -4
- package/android/build.gradle +2 -2
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/java/kyc/transfergratis/com/TransfergratisSdkModule.kt +6 -6
- package/android/src/main/java/kyc/transfergratis/com/TransfergratisSdkView.kt +2 -2
- package/build/package.json +5 -5
- package/build/src/App.d.ts +2 -2
- package/build/src/App.d.ts.map +1 -1
- package/build/src/App.js +2 -2
- package/build/src/App.js.map +1 -1
- package/build/src/{SanctumKeySdk.types.d.ts → TransfergratisSdk.types.d.ts} +3 -3
- package/build/src/TransfergratisSdk.types.d.ts.map +1 -0
- package/build/src/TransfergratisSdk.types.js +2 -0
- package/build/src/TransfergratisSdk.types.js.map +1 -0
- package/build/src/{SanctumKeySdkModule.d.ts → TransfergratisSdkModule.d.ts} +4 -4
- package/build/src/TransfergratisSdkModule.d.ts.map +1 -0
- package/build/src/{SanctumKeySdkModule.js → TransfergratisSdkModule.js} +2 -2
- package/build/src/TransfergratisSdkModule.js.map +1 -0
- package/build/src/{SanctumKeySdkModule.web.d.ts → TransfergratisSdkModule.web.d.ts} +4 -4
- package/build/src/TransfergratisSdkModule.web.d.ts.map +1 -0
- package/build/src/{SanctumKeySdkModule.web.js → TransfergratisSdkModule.web.js} +3 -3
- package/build/src/TransfergratisSdkModule.web.js.map +1 -0
- package/build/src/TransfergratisSdkView.d.ts +4 -0
- package/build/src/TransfergratisSdkView.d.ts.map +1 -0
- package/build/src/TransfergratisSdkView.js +7 -0
- package/build/src/TransfergratisSdkView.js.map +1 -0
- package/build/src/TransfergratisSdkView.web.d.ts +4 -0
- package/build/src/TransfergratisSdkView.web.d.ts.map +1 -0
- package/build/src/{SanctumKeySdkView.web.js → TransfergratisSdkView.web.js} +2 -2
- package/build/src/TransfergratisSdkView.web.js.map +1 -0
- package/build/src/api/axios.js +2 -2
- package/build/src/api/axios.js.map +1 -1
- package/build/src/components/EnhancedCameraView.d.ts.map +1 -1
- package/build/src/components/EnhancedCameraView.js +12 -61
- package/build/src/components/EnhancedCameraView.js.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.js +259 -63
- package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
- package/build/src/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/EmailVerificationTemplate.js +11 -32
- package/build/src/components/KYCElements/EmailVerificationTemplate.js.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.js +222 -68
- package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/src/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/PhoneVerificationTemplate.js +9 -11
- package/build/src/components/KYCElements/PhoneVerificationTemplate.js.map +1 -1
- package/build/src/components/NativeCameraView.js +1 -1
- package/build/src/components/NativeCameraView.js.map +1 -1
- package/build/src/config/KYCConfig.js +1 -1
- package/build/src/config/KYCConfig.js.map +1 -1
- package/build/src/config/allowedDomains.js +6 -6
- package/build/src/config/allowedDomains.js.map +1 -1
- package/build/src/config/region_mapping.json +727 -0
- package/build/src/index.d.ts +3 -3
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +3 -3
- package/build/src/index.js.map +1 -1
- package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/src/modules/api/CardAuthentification.js +3 -7
- package/build/src/modules/api/CardAuthentification.js.map +1 -1
- package/build/src/modules/api/KYCService.d.ts +1 -2
- package/build/src/modules/api/KYCService.d.ts.map +1 -1
- package/build/src/modules/api/KYCService.js +103 -63
- package/build/src/modules/api/KYCService.js.map +1 -1
- package/build/src/modules/camera/NativeCameraModule.js +17 -17
- package/build/src/modules/camera/NativeCameraModule.js.map +1 -1
- package/expo-module.config.json +2 -2
- package/ios/TransfergratisSdk.podspec +2 -2
- package/ios/TransfergratisSdkModule.swift +12 -12
- package/package.json +5 -5
- package/src/App.tsx +2 -2
- package/src/{SanctumKeySdk.types.ts → TransfergratisSdk.types.ts} +2 -2
- package/src/{SanctumKeySdkModule.ts → TransfergratisSdkModule.ts} +3 -3
- package/src/{SanctumKeySdkModule.web.ts → TransfergratisSdkModule.web.ts} +3 -3
- package/src/TransfergratisSdkView.tsx +11 -0
- package/src/{SanctumKeySdkView.web.tsx → TransfergratisSdkView.web.tsx} +2 -2
- package/src/api/axios.ts +2 -2
- package/src/components/EnhancedCameraView.tsx +34 -99
- package/src/components/KYCElements/CountrySelection.tsx +300 -74
- package/src/components/KYCElements/EmailVerificationTemplate.tsx +10 -36
- package/src/components/KYCElements/IDCardCapture.tsx +310 -156
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +9 -11
- package/src/components/NativeCameraView.tsx +1 -1
- package/src/config/KYCConfig.ts +1 -1
- package/src/config/allowedDomains.ts +6 -6
- package/src/i18n/README.md +1 -1
- package/src/index.ts +3 -3
- package/src/modules/api/CardAuthentification.ts +5 -8
- package/src/modules/api/KYCService.ts +167 -116
- package/src/modules/camera/NativeCameraModule.ts +17 -17
- package/build/src/SanctumKeySdk.types.d.ts.map +0 -1
- package/build/src/SanctumKeySdk.types.js +0 -2
- package/build/src/SanctumKeySdk.types.js.map +0 -1
- package/build/src/SanctumKeySdkModule.d.ts.map +0 -1
- package/build/src/SanctumKeySdkModule.js.map +0 -1
- package/build/src/SanctumKeySdkModule.web.d.ts.map +0 -1
- package/build/src/SanctumKeySdkModule.web.js.map +0 -1
- package/build/src/SanctumKeySdkView.d.ts +0 -4
- package/build/src/SanctumKeySdkView.d.ts.map +0 -1
- package/build/src/SanctumKeySdkView.js +0 -7
- package/build/src/SanctumKeySdkView.js.map +0 -1
- package/build/src/SanctumKeySdkView.web.d.ts +0 -4
- package/build/src/SanctumKeySdkView.web.d.ts.map +0 -1
- package/build/src/SanctumKeySdkView.web.js.map +0 -1
- package/src/SanctumKeySdkView.tsx +0 -11
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import {
|
|
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
|
-
|
|
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: '
|
|
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: '
|
|
17
|
-
{ value: '
|
|
18
|
-
{ value: '
|
|
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: '
|
|
21
|
-
{ value: '
|
|
22
|
-
{ value: '
|
|
23
|
-
{ value: '
|
|
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
|
-
|
|
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
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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:
|
|
322
|
+
marginBottom: 16,
|
|
94
323
|
lineHeight: 22,
|
|
95
324
|
},
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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();
|
|
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
|
-
|
|
160
|
-
|
|
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,
|
|
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,
|
|
331
|
+
opacity: 0,
|
|
358
332
|
},
|
|
359
333
|
errorText: {
|
|
360
334
|
color: '#dc2626',
|