@open-mercato/ui 0.6.7-develop.6660.1.90e1e2eef6 โ 0.6.7-develop.6669.1.40b669666b
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/.turbo/turbo-build.log +1 -1
- package/dist/backend/fields/phone.js +65 -0
- package/dist/backend/fields/phone.js.map +7 -0
- package/dist/backend/fields/registry.generated.js +1 -0
- package/dist/backend/fields/registry.generated.js.map +2 -2
- package/dist/backend/inputs/PhoneNumberField.js +273 -21
- package/dist/backend/inputs/PhoneNumberField.js.map +2 -2
- package/dist/backend/utils/customFieldDefs.js.map +2 -2
- package/package.json +3 -3
- package/src/backend/__tests__/custom-field-columns.test.ts +28 -0
- package/src/backend/__tests__/custom-field-filters.test.ts +3 -0
- package/src/backend/__tests__/custom-field-forms.test.ts +4 -0
- package/src/backend/fields/__tests__/phone.test.tsx +99 -0
- package/src/backend/fields/phone.tsx +98 -0
- package/src/backend/fields/registry.generated.ts +1 -0
- package/src/backend/inputs/PhoneNumberField.tsx +307 -26
- package/src/backend/inputs/__tests__/PhoneNumberField.test.tsx +71 -1
- package/src/backend/utils/customFieldDefs.ts +2 -0
|
@@ -30,35 +30,316 @@ export type PhoneCountry = {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* deterministic. The default fallback is the first entry.
|
|
33
|
+
* Emoji flag for an ISO 3166-1 alpha-2 code, assembled from the two regional
|
|
34
|
+
* indicator symbols. Deriving it keeps the (large) dictionary free of hand-typed
|
|
35
|
+
* emoji and guarantees the flag always matches the code.
|
|
37
36
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
37
|
+
function iso2ToFlagEmoji(iso2: string): string {
|
|
38
|
+
const letters = iso2.toUpperCase().replace(/[^A-Z]/g, '')
|
|
39
|
+
if (letters.length !== 2) return ''
|
|
40
|
+
const base = 0x1f1e6
|
|
41
|
+
return String.fromCodePoint(
|
|
42
|
+
base + letters.charCodeAt(0) - 65,
|
|
43
|
+
base + letters.charCodeAt(1) - 65,
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Complete static dictionary of geographic countries and territories that have
|
|
49
|
+
* an ISO 3166-1 alpha-2 code and an international calling code, based on the
|
|
50
|
+
* ITU / Wikipedia list of telephone country codes.
|
|
51
|
+
*
|
|
52
|
+
* Rules baked into this data:
|
|
53
|
+
* - Labels are English; flags are derived from the ISO code (`iso2ToFlagEmoji`).
|
|
54
|
+
* - Non-geographic / international service codes (`+800`, `+808`, `+870`,
|
|
55
|
+
* `+881`, `+882`, โฆ) are intentionally excluded.
|
|
56
|
+
* - North American Numbering Plan territories carry their full `+1<NPA>` dial
|
|
57
|
+
* code (e.g. Bahamas `+1242`) so longest-prefix matching resolves them before
|
|
58
|
+
* the generic `+1`. The US and Canada BOTH use a bare `+1` and cannot be told
|
|
59
|
+
* apart from the prefix alone โ auto-detection favours the US.
|
|
60
|
+
* - Several sovereign countries share a calling code with dependent territories
|
|
61
|
+
* (e.g. `+44` UK/Guernsey/Jersey/Isle of Man); `PRIMARY_DIAL_OWNERS` records
|
|
62
|
+
* the country that wins auto-detection for those shared codes.
|
|
63
|
+
*/
|
|
64
|
+
const RAW_PHONE_COUNTRIES: Array<Omit<PhoneCountry, 'flag'>> = [
|
|
65
|
+
{ iso2: 'US', dialCode: '+1', label: 'United States' },
|
|
66
|
+
{ iso2: 'CA', dialCode: '+1', label: 'Canada' },
|
|
67
|
+
{ iso2: 'AG', dialCode: '+1268', label: 'Antigua and Barbuda' },
|
|
68
|
+
{ iso2: 'AI', dialCode: '+1264', label: 'Anguilla' },
|
|
69
|
+
{ iso2: 'AS', dialCode: '+1684', label: 'American Samoa' },
|
|
70
|
+
{ iso2: 'BB', dialCode: '+1246', label: 'Barbados' },
|
|
71
|
+
{ iso2: 'BM', dialCode: '+1441', label: 'Bermuda' },
|
|
72
|
+
{ iso2: 'BS', dialCode: '+1242', label: 'Bahamas' },
|
|
73
|
+
{ iso2: 'DM', dialCode: '+1767', label: 'Dominica' },
|
|
74
|
+
{ iso2: 'DO', dialCode: '+1809', label: 'Dominican Republic' },
|
|
75
|
+
{ iso2: 'GD', dialCode: '+1473', label: 'Grenada' },
|
|
76
|
+
{ iso2: 'GU', dialCode: '+1671', label: 'Guam' },
|
|
77
|
+
{ iso2: 'JM', dialCode: '+1876', label: 'Jamaica' },
|
|
78
|
+
{ iso2: 'KN', dialCode: '+1869', label: 'Saint Kitts and Nevis' },
|
|
79
|
+
{ iso2: 'KY', dialCode: '+1345', label: 'Cayman Islands' },
|
|
80
|
+
{ iso2: 'LC', dialCode: '+1758', label: 'Saint Lucia' },
|
|
81
|
+
{ iso2: 'MP', dialCode: '+1670', label: 'Northern Mariana Islands' },
|
|
82
|
+
{ iso2: 'MS', dialCode: '+1664', label: 'Montserrat' },
|
|
83
|
+
{ iso2: 'PR', dialCode: '+1787', label: 'Puerto Rico' },
|
|
84
|
+
{ iso2: 'SX', dialCode: '+1721', label: 'Sint Maarten' },
|
|
85
|
+
{ iso2: 'TC', dialCode: '+1649', label: 'Turks and Caicos Islands' },
|
|
86
|
+
{ iso2: 'TT', dialCode: '+1868', label: 'Trinidad and Tobago' },
|
|
87
|
+
{ iso2: 'VC', dialCode: '+1784', label: 'Saint Vincent and the Grenadines' },
|
|
88
|
+
{ iso2: 'VG', dialCode: '+1284', label: 'British Virgin Islands' },
|
|
89
|
+
{ iso2: 'VI', dialCode: '+1340', label: 'U.S. Virgin Islands' },
|
|
90
|
+
{ iso2: 'EG', dialCode: '+20', label: 'Egypt' },
|
|
91
|
+
{ iso2: 'SS', dialCode: '+211', label: 'South Sudan' },
|
|
92
|
+
{ iso2: 'MA', dialCode: '+212', label: 'Morocco' },
|
|
93
|
+
{ iso2: 'EH', dialCode: '+212', label: 'Western Sahara' },
|
|
94
|
+
{ iso2: 'DZ', dialCode: '+213', label: 'Algeria' },
|
|
95
|
+
{ iso2: 'TN', dialCode: '+216', label: 'Tunisia' },
|
|
96
|
+
{ iso2: 'LY', dialCode: '+218', label: 'Libya' },
|
|
97
|
+
{ iso2: 'GM', dialCode: '+220', label: 'Gambia' },
|
|
98
|
+
{ iso2: 'SN', dialCode: '+221', label: 'Senegal' },
|
|
99
|
+
{ iso2: 'MR', dialCode: '+222', label: 'Mauritania' },
|
|
100
|
+
{ iso2: 'ML', dialCode: '+223', label: 'Mali' },
|
|
101
|
+
{ iso2: 'GN', dialCode: '+224', label: 'Guinea' },
|
|
102
|
+
{ iso2: 'CI', dialCode: '+225', label: "Cรดte d'Ivoire" },
|
|
103
|
+
{ iso2: 'BF', dialCode: '+226', label: 'Burkina Faso' },
|
|
104
|
+
{ iso2: 'NE', dialCode: '+227', label: 'Niger' },
|
|
105
|
+
{ iso2: 'TG', dialCode: '+228', label: 'Togo' },
|
|
106
|
+
{ iso2: 'BJ', dialCode: '+229', label: 'Benin' },
|
|
107
|
+
{ iso2: 'MU', dialCode: '+230', label: 'Mauritius' },
|
|
108
|
+
{ iso2: 'LR', dialCode: '+231', label: 'Liberia' },
|
|
109
|
+
{ iso2: 'SL', dialCode: '+232', label: 'Sierra Leone' },
|
|
110
|
+
{ iso2: 'GH', dialCode: '+233', label: 'Ghana' },
|
|
111
|
+
{ iso2: 'NG', dialCode: '+234', label: 'Nigeria' },
|
|
112
|
+
{ iso2: 'TD', dialCode: '+235', label: 'Chad' },
|
|
113
|
+
{ iso2: 'CF', dialCode: '+236', label: 'Central African Republic' },
|
|
114
|
+
{ iso2: 'CM', dialCode: '+237', label: 'Cameroon' },
|
|
115
|
+
{ iso2: 'CV', dialCode: '+238', label: 'Cape Verde' },
|
|
116
|
+
{ iso2: 'ST', dialCode: '+239', label: 'Sรฃo Tomรฉ and Prรญncipe' },
|
|
117
|
+
{ iso2: 'GQ', dialCode: '+240', label: 'Equatorial Guinea' },
|
|
118
|
+
{ iso2: 'GA', dialCode: '+241', label: 'Gabon' },
|
|
119
|
+
{ iso2: 'CG', dialCode: '+242', label: 'Republic of the Congo' },
|
|
120
|
+
{ iso2: 'CD', dialCode: '+243', label: 'DR Congo' },
|
|
121
|
+
{ iso2: 'AO', dialCode: '+244', label: 'Angola' },
|
|
122
|
+
{ iso2: 'GW', dialCode: '+245', label: 'Guinea-Bissau' },
|
|
123
|
+
{ iso2: 'IO', dialCode: '+246', label: 'British Indian Ocean Territory' },
|
|
124
|
+
{ iso2: 'SC', dialCode: '+248', label: 'Seychelles' },
|
|
125
|
+
{ iso2: 'SD', dialCode: '+249', label: 'Sudan' },
|
|
126
|
+
{ iso2: 'RW', dialCode: '+250', label: 'Rwanda' },
|
|
127
|
+
{ iso2: 'ET', dialCode: '+251', label: 'Ethiopia' },
|
|
128
|
+
{ iso2: 'SO', dialCode: '+252', label: 'Somalia' },
|
|
129
|
+
{ iso2: 'DJ', dialCode: '+253', label: 'Djibouti' },
|
|
130
|
+
{ iso2: 'KE', dialCode: '+254', label: 'Kenya' },
|
|
131
|
+
{ iso2: 'TZ', dialCode: '+255', label: 'Tanzania' },
|
|
132
|
+
{ iso2: 'UG', dialCode: '+256', label: 'Uganda' },
|
|
133
|
+
{ iso2: 'BI', dialCode: '+257', label: 'Burundi' },
|
|
134
|
+
{ iso2: 'MZ', dialCode: '+258', label: 'Mozambique' },
|
|
135
|
+
{ iso2: 'ZM', dialCode: '+260', label: 'Zambia' },
|
|
136
|
+
{ iso2: 'MG', dialCode: '+261', label: 'Madagascar' },
|
|
137
|
+
{ iso2: 'RE', dialCode: '+262', label: 'Rรฉunion' },
|
|
138
|
+
{ iso2: 'YT', dialCode: '+262', label: 'Mayotte' },
|
|
139
|
+
{ iso2: 'ZW', dialCode: '+263', label: 'Zimbabwe' },
|
|
140
|
+
{ iso2: 'NA', dialCode: '+264', label: 'Namibia' },
|
|
141
|
+
{ iso2: 'MW', dialCode: '+265', label: 'Malawi' },
|
|
142
|
+
{ iso2: 'LS', dialCode: '+266', label: 'Lesotho' },
|
|
143
|
+
{ iso2: 'BW', dialCode: '+267', label: 'Botswana' },
|
|
144
|
+
{ iso2: 'SZ', dialCode: '+268', label: 'Eswatini' },
|
|
145
|
+
{ iso2: 'KM', dialCode: '+269', label: 'Comoros' },
|
|
146
|
+
{ iso2: 'ZA', dialCode: '+27', label: 'South Africa' },
|
|
147
|
+
{ iso2: 'SH', dialCode: '+290', label: 'Saint Helena' },
|
|
148
|
+
{ iso2: 'ER', dialCode: '+291', label: 'Eritrea' },
|
|
149
|
+
{ iso2: 'AW', dialCode: '+297', label: 'Aruba' },
|
|
150
|
+
{ iso2: 'FO', dialCode: '+298', label: 'Faroe Islands' },
|
|
151
|
+
{ iso2: 'GL', dialCode: '+299', label: 'Greenland' },
|
|
152
|
+
{ iso2: 'GR', dialCode: '+30', label: 'Greece' },
|
|
153
|
+
{ iso2: 'NL', dialCode: '+31', label: 'Netherlands' },
|
|
154
|
+
{ iso2: 'BE', dialCode: '+32', label: 'Belgium' },
|
|
155
|
+
{ iso2: 'FR', dialCode: '+33', label: 'France' },
|
|
156
|
+
{ iso2: 'ES', dialCode: '+34', label: 'Spain' },
|
|
157
|
+
{ iso2: 'GI', dialCode: '+350', label: 'Gibraltar' },
|
|
158
|
+
{ iso2: 'PT', dialCode: '+351', label: 'Portugal' },
|
|
159
|
+
{ iso2: 'LU', dialCode: '+352', label: 'Luxembourg' },
|
|
160
|
+
{ iso2: 'IE', dialCode: '+353', label: 'Ireland' },
|
|
161
|
+
{ iso2: 'IS', dialCode: '+354', label: 'Iceland' },
|
|
162
|
+
{ iso2: 'AL', dialCode: '+355', label: 'Albania' },
|
|
163
|
+
{ iso2: 'MT', dialCode: '+356', label: 'Malta' },
|
|
164
|
+
{ iso2: 'CY', dialCode: '+357', label: 'Cyprus' },
|
|
165
|
+
{ iso2: 'FI', dialCode: '+358', label: 'Finland' },
|
|
166
|
+
{ iso2: 'AX', dialCode: '+358', label: 'ร
land Islands' },
|
|
167
|
+
{ iso2: 'BG', dialCode: '+359', label: 'Bulgaria' },
|
|
168
|
+
{ iso2: 'HU', dialCode: '+36', label: 'Hungary' },
|
|
169
|
+
{ iso2: 'LT', dialCode: '+370', label: 'Lithuania' },
|
|
170
|
+
{ iso2: 'LV', dialCode: '+371', label: 'Latvia' },
|
|
171
|
+
{ iso2: 'EE', dialCode: '+372', label: 'Estonia' },
|
|
172
|
+
{ iso2: 'MD', dialCode: '+373', label: 'Moldova' },
|
|
173
|
+
{ iso2: 'AM', dialCode: '+374', label: 'Armenia' },
|
|
174
|
+
{ iso2: 'BY', dialCode: '+375', label: 'Belarus' },
|
|
175
|
+
{ iso2: 'AD', dialCode: '+376', label: 'Andorra' },
|
|
176
|
+
{ iso2: 'MC', dialCode: '+377', label: 'Monaco' },
|
|
177
|
+
{ iso2: 'SM', dialCode: '+378', label: 'San Marino' },
|
|
178
|
+
{ iso2: 'VA', dialCode: '+379', label: 'Vatican City' },
|
|
179
|
+
{ iso2: 'UA', dialCode: '+380', label: 'Ukraine' },
|
|
180
|
+
{ iso2: 'RS', dialCode: '+381', label: 'Serbia' },
|
|
181
|
+
{ iso2: 'ME', dialCode: '+382', label: 'Montenegro' },
|
|
182
|
+
{ iso2: 'XK', dialCode: '+383', label: 'Kosovo' },
|
|
183
|
+
{ iso2: 'HR', dialCode: '+385', label: 'Croatia' },
|
|
184
|
+
{ iso2: 'SI', dialCode: '+386', label: 'Slovenia' },
|
|
185
|
+
{ iso2: 'BA', dialCode: '+387', label: 'Bosnia and Herzegovina' },
|
|
186
|
+
{ iso2: 'MK', dialCode: '+389', label: 'North Macedonia' },
|
|
187
|
+
{ iso2: 'IT', dialCode: '+39', label: 'Italy' },
|
|
188
|
+
{ iso2: 'RO', dialCode: '+40', label: 'Romania' },
|
|
189
|
+
{ iso2: 'CH', dialCode: '+41', label: 'Switzerland' },
|
|
190
|
+
{ iso2: 'CZ', dialCode: '+420', label: 'Czechia' },
|
|
191
|
+
{ iso2: 'SK', dialCode: '+421', label: 'Slovakia' },
|
|
192
|
+
{ iso2: 'LI', dialCode: '+423', label: 'Liechtenstein' },
|
|
193
|
+
{ iso2: 'AT', dialCode: '+43', label: 'Austria' },
|
|
194
|
+
{ iso2: 'GB', dialCode: '+44', label: 'United Kingdom' },
|
|
195
|
+
{ iso2: 'GG', dialCode: '+44', label: 'Guernsey' },
|
|
196
|
+
{ iso2: 'JE', dialCode: '+44', label: 'Jersey' },
|
|
197
|
+
{ iso2: 'IM', dialCode: '+44', label: 'Isle of Man' },
|
|
198
|
+
{ iso2: 'DK', dialCode: '+45', label: 'Denmark' },
|
|
199
|
+
{ iso2: 'SE', dialCode: '+46', label: 'Sweden' },
|
|
200
|
+
{ iso2: 'NO', dialCode: '+47', label: 'Norway' },
|
|
201
|
+
{ iso2: 'SJ', dialCode: '+47', label: 'Svalbard and Jan Mayen' },
|
|
202
|
+
{ iso2: 'PL', dialCode: '+48', label: 'Poland' },
|
|
203
|
+
{ iso2: 'DE', dialCode: '+49', label: 'Germany' },
|
|
204
|
+
{ iso2: 'FK', dialCode: '+500', label: 'Falkland Islands' },
|
|
205
|
+
{ iso2: 'BZ', dialCode: '+501', label: 'Belize' },
|
|
206
|
+
{ iso2: 'GT', dialCode: '+502', label: 'Guatemala' },
|
|
207
|
+
{ iso2: 'SV', dialCode: '+503', label: 'El Salvador' },
|
|
208
|
+
{ iso2: 'HN', dialCode: '+504', label: 'Honduras' },
|
|
209
|
+
{ iso2: 'NI', dialCode: '+505', label: 'Nicaragua' },
|
|
210
|
+
{ iso2: 'CR', dialCode: '+506', label: 'Costa Rica' },
|
|
211
|
+
{ iso2: 'PA', dialCode: '+507', label: 'Panama' },
|
|
212
|
+
{ iso2: 'PM', dialCode: '+508', label: 'Saint Pierre and Miquelon' },
|
|
213
|
+
{ iso2: 'HT', dialCode: '+509', label: 'Haiti' },
|
|
214
|
+
{ iso2: 'PE', dialCode: '+51', label: 'Peru' },
|
|
215
|
+
{ iso2: 'MX', dialCode: '+52', label: 'Mexico' },
|
|
216
|
+
{ iso2: 'CU', dialCode: '+53', label: 'Cuba' },
|
|
217
|
+
{ iso2: 'AR', dialCode: '+54', label: 'Argentina' },
|
|
218
|
+
{ iso2: 'BR', dialCode: '+55', label: 'Brazil' },
|
|
219
|
+
{ iso2: 'CL', dialCode: '+56', label: 'Chile' },
|
|
220
|
+
{ iso2: 'CO', dialCode: '+57', label: 'Colombia' },
|
|
221
|
+
{ iso2: 'VE', dialCode: '+58', label: 'Venezuela' },
|
|
222
|
+
{ iso2: 'GP', dialCode: '+590', label: 'Guadeloupe' },
|
|
223
|
+
{ iso2: 'BL', dialCode: '+590', label: 'Saint Barthรฉlemy' },
|
|
224
|
+
{ iso2: 'MF', dialCode: '+590', label: 'Saint Martin' },
|
|
225
|
+
{ iso2: 'BO', dialCode: '+591', label: 'Bolivia' },
|
|
226
|
+
{ iso2: 'GY', dialCode: '+592', label: 'Guyana' },
|
|
227
|
+
{ iso2: 'EC', dialCode: '+593', label: 'Ecuador' },
|
|
228
|
+
{ iso2: 'GF', dialCode: '+594', label: 'French Guiana' },
|
|
229
|
+
{ iso2: 'PY', dialCode: '+595', label: 'Paraguay' },
|
|
230
|
+
{ iso2: 'MQ', dialCode: '+596', label: 'Martinique' },
|
|
231
|
+
{ iso2: 'SR', dialCode: '+597', label: 'Suriname' },
|
|
232
|
+
{ iso2: 'UY', dialCode: '+598', label: 'Uruguay' },
|
|
233
|
+
{ iso2: 'CW', dialCode: '+599', label: 'Curaรงao' },
|
|
234
|
+
{ iso2: 'BQ', dialCode: '+599', label: 'Caribbean Netherlands' },
|
|
235
|
+
{ iso2: 'MY', dialCode: '+60', label: 'Malaysia' },
|
|
236
|
+
{ iso2: 'AU', dialCode: '+61', label: 'Australia' },
|
|
237
|
+
{ iso2: 'CX', dialCode: '+61', label: 'Christmas Island' },
|
|
238
|
+
{ iso2: 'CC', dialCode: '+61', label: 'Cocos (Keeling) Islands' },
|
|
239
|
+
{ iso2: 'ID', dialCode: '+62', label: 'Indonesia' },
|
|
240
|
+
{ iso2: 'PH', dialCode: '+63', label: 'Philippines' },
|
|
241
|
+
{ iso2: 'NZ', dialCode: '+64', label: 'New Zealand' },
|
|
242
|
+
{ iso2: 'SG', dialCode: '+65', label: 'Singapore' },
|
|
243
|
+
{ iso2: 'TH', dialCode: '+66', label: 'Thailand' },
|
|
244
|
+
{ iso2: 'TL', dialCode: '+670', label: 'Timor-Leste' },
|
|
245
|
+
{ iso2: 'NF', dialCode: '+672', label: 'Norfolk Island' },
|
|
246
|
+
{ iso2: 'BN', dialCode: '+673', label: 'Brunei' },
|
|
247
|
+
{ iso2: 'NR', dialCode: '+674', label: 'Nauru' },
|
|
248
|
+
{ iso2: 'PG', dialCode: '+675', label: 'Papua New Guinea' },
|
|
249
|
+
{ iso2: 'TO', dialCode: '+676', label: 'Tonga' },
|
|
250
|
+
{ iso2: 'SB', dialCode: '+677', label: 'Solomon Islands' },
|
|
251
|
+
{ iso2: 'VU', dialCode: '+678', label: 'Vanuatu' },
|
|
252
|
+
{ iso2: 'FJ', dialCode: '+679', label: 'Fiji' },
|
|
253
|
+
{ iso2: 'PW', dialCode: '+680', label: 'Palau' },
|
|
254
|
+
{ iso2: 'WF', dialCode: '+681', label: 'Wallis and Futuna' },
|
|
255
|
+
{ iso2: 'CK', dialCode: '+682', label: 'Cook Islands' },
|
|
256
|
+
{ iso2: 'NU', dialCode: '+683', label: 'Niue' },
|
|
257
|
+
{ iso2: 'WS', dialCode: '+685', label: 'Samoa' },
|
|
258
|
+
{ iso2: 'KI', dialCode: '+686', label: 'Kiribati' },
|
|
259
|
+
{ iso2: 'NC', dialCode: '+687', label: 'New Caledonia' },
|
|
260
|
+
{ iso2: 'TV', dialCode: '+688', label: 'Tuvalu' },
|
|
261
|
+
{ iso2: 'PF', dialCode: '+689', label: 'French Polynesia' },
|
|
262
|
+
{ iso2: 'TK', dialCode: '+690', label: 'Tokelau' },
|
|
263
|
+
{ iso2: 'FM', dialCode: '+691', label: 'Micronesia' },
|
|
264
|
+
{ iso2: 'MH', dialCode: '+692', label: 'Marshall Islands' },
|
|
265
|
+
{ iso2: 'RU', dialCode: '+7', label: 'Russia' },
|
|
266
|
+
{ iso2: 'KZ', dialCode: '+7', label: 'Kazakhstan' },
|
|
267
|
+
{ iso2: 'JP', dialCode: '+81', label: 'Japan' },
|
|
268
|
+
{ iso2: 'KR', dialCode: '+82', label: 'South Korea' },
|
|
269
|
+
{ iso2: 'VN', dialCode: '+84', label: 'Vietnam' },
|
|
270
|
+
{ iso2: 'KP', dialCode: '+850', label: 'North Korea' },
|
|
271
|
+
{ iso2: 'HK', dialCode: '+852', label: 'Hong Kong' },
|
|
272
|
+
{ iso2: 'MO', dialCode: '+853', label: 'Macau' },
|
|
273
|
+
{ iso2: 'KH', dialCode: '+855', label: 'Cambodia' },
|
|
274
|
+
{ iso2: 'LA', dialCode: '+856', label: 'Laos' },
|
|
275
|
+
{ iso2: 'CN', dialCode: '+86', label: 'China' },
|
|
276
|
+
{ iso2: 'BD', dialCode: '+880', label: 'Bangladesh' },
|
|
277
|
+
{ iso2: 'TW', dialCode: '+886', label: 'Taiwan' },
|
|
278
|
+
{ iso2: 'TR', dialCode: '+90', label: 'Turkey' },
|
|
279
|
+
{ iso2: 'IN', dialCode: '+91', label: 'India' },
|
|
280
|
+
{ iso2: 'PK', dialCode: '+92', label: 'Pakistan' },
|
|
281
|
+
{ iso2: 'AF', dialCode: '+93', label: 'Afghanistan' },
|
|
282
|
+
{ iso2: 'LK', dialCode: '+94', label: 'Sri Lanka' },
|
|
283
|
+
{ iso2: 'MM', dialCode: '+95', label: 'Myanmar' },
|
|
284
|
+
{ iso2: 'MV', dialCode: '+960', label: 'Maldives' },
|
|
285
|
+
{ iso2: 'LB', dialCode: '+961', label: 'Lebanon' },
|
|
286
|
+
{ iso2: 'JO', dialCode: '+962', label: 'Jordan' },
|
|
287
|
+
{ iso2: 'SY', dialCode: '+963', label: 'Syria' },
|
|
288
|
+
{ iso2: 'IQ', dialCode: '+964', label: 'Iraq' },
|
|
289
|
+
{ iso2: 'KW', dialCode: '+965', label: 'Kuwait' },
|
|
290
|
+
{ iso2: 'SA', dialCode: '+966', label: 'Saudi Arabia' },
|
|
291
|
+
{ iso2: 'YE', dialCode: '+967', label: 'Yemen' },
|
|
292
|
+
{ iso2: 'OM', dialCode: '+968', label: 'Oman' },
|
|
293
|
+
{ iso2: 'PS', dialCode: '+970', label: 'Palestine' },
|
|
294
|
+
{ iso2: 'AE', dialCode: '+971', label: 'United Arab Emirates' },
|
|
295
|
+
{ iso2: 'IL', dialCode: '+972', label: 'Israel' },
|
|
296
|
+
{ iso2: 'BH', dialCode: '+973', label: 'Bahrain' },
|
|
297
|
+
{ iso2: 'QA', dialCode: '+974', label: 'Qatar' },
|
|
298
|
+
{ iso2: 'BT', dialCode: '+975', label: 'Bhutan' },
|
|
299
|
+
{ iso2: 'MN', dialCode: '+976', label: 'Mongolia' },
|
|
300
|
+
{ iso2: 'NP', dialCode: '+977', label: 'Nepal' },
|
|
301
|
+
{ iso2: 'TJ', dialCode: '+992', label: 'Tajikistan' },
|
|
302
|
+
{ iso2: 'TM', dialCode: '+993', label: 'Turkmenistan' },
|
|
303
|
+
{ iso2: 'AZ', dialCode: '+994', label: 'Azerbaijan' },
|
|
304
|
+
{ iso2: 'GE', dialCode: '+995', label: 'Georgia' },
|
|
305
|
+
{ iso2: 'KG', dialCode: '+996', label: 'Kyrgyzstan' },
|
|
306
|
+
{ iso2: 'UZ', dialCode: '+998', label: 'Uzbekistan' },
|
|
307
|
+
{ iso2: 'IR', dialCode: '+98', label: 'Iran' },
|
|
55
308
|
]
|
|
56
309
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
310
|
+
export const PHONE_COUNTRIES: PhoneCountry[] = RAW_PHONE_COUNTRIES
|
|
311
|
+
.map((country) => ({ ...country, flag: iso2ToFlagEmoji(country.iso2) }))
|
|
312
|
+
.sort((a, b) => a.label.localeCompare(b.label, 'en', { sensitivity: 'base' }))
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Sovereign/primary country that wins auto-detection for a calling code shared
|
|
316
|
+
* by several territories. US vs. Canada is the one irreducible ambiguity โ both
|
|
317
|
+
* are `+1` โ and it resolves to the US.
|
|
318
|
+
*/
|
|
319
|
+
const PRIMARY_DIAL_OWNERS: Record<string, string> = {
|
|
320
|
+
'+1': 'US',
|
|
321
|
+
'+7': 'RU',
|
|
322
|
+
'+44': 'GB',
|
|
323
|
+
'+47': 'NO',
|
|
324
|
+
'+61': 'AU',
|
|
325
|
+
'+212': 'MA',
|
|
326
|
+
'+262': 'RE',
|
|
327
|
+
'+358': 'FI',
|
|
328
|
+
'+590': 'GP',
|
|
329
|
+
'+599': 'CW',
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const DEFAULT_COUNTRY =
|
|
333
|
+
PHONE_COUNTRIES.find((country) => country.iso2 === 'US') ?? PHONE_COUNTRIES[0]
|
|
334
|
+
|
|
335
|
+
// Match longer prefixes first (e.g. `+1242` before `+1`); for equal-length codes
|
|
336
|
+
// shared by several territories, prefer the sovereign in `PRIMARY_DIAL_OWNERS`.
|
|
337
|
+
const COUNTRIES_BY_DIAL_LENGTH = [...PHONE_COUNTRIES].sort((a, b) => {
|
|
338
|
+
if (b.dialCode.length !== a.dialCode.length) return b.dialCode.length - a.dialCode.length
|
|
339
|
+
const aPrimary = PRIMARY_DIAL_OWNERS[a.dialCode] === a.iso2 ? 0 : 1
|
|
340
|
+
const bPrimary = PRIMARY_DIAL_OWNERS[b.dialCode] === b.iso2 ? 0 : 1
|
|
341
|
+
return aPrimary - bPrimary
|
|
342
|
+
})
|
|
62
343
|
|
|
63
344
|
function findCountryByIso(iso2: string): PhoneCountry | undefined {
|
|
64
345
|
return PHONE_COUNTRIES.find((c) => c.iso2 === iso2)
|
|
@@ -22,7 +22,7 @@ jest.mock('@open-mercato/shared/lib/phone', () => ({
|
|
|
22
22
|
|
|
23
23
|
import * as React from 'react'
|
|
24
24
|
import { fireEvent, render, screen } from '@testing-library/react'
|
|
25
|
-
import { PhoneNumberField } from '../PhoneNumberField'
|
|
25
|
+
import { PHONE_COUNTRIES, PhoneNumberField } from '../PhoneNumberField'
|
|
26
26
|
|
|
27
27
|
function PhoneFieldHarness(props: Partial<React.ComponentProps<typeof PhoneNumberField>>) {
|
|
28
28
|
const [value, setValue] = React.useState<string | undefined>(undefined)
|
|
@@ -76,4 +76,74 @@ describe('PhoneNumberField', () => {
|
|
|
76
76
|
expect(screen.queryByText('Use an international phone number.')).not.toBeInTheDocument()
|
|
77
77
|
expect(input).toHaveAttribute('aria-invalid', 'true')
|
|
78
78
|
})
|
|
79
|
+
|
|
80
|
+
it('honours a restricted country list via the countries prop', () => {
|
|
81
|
+
render(
|
|
82
|
+
<PhoneFieldHarness
|
|
83
|
+
value="+383 44 123 456"
|
|
84
|
+
countries={[{ iso2: 'PL', dialCode: '+48', label: 'Poland', flag: '๐ต๐ฑ' }]}
|
|
85
|
+
/>,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
// The value still parses against the full dictionary (Kosovo), but the
|
|
89
|
+
// picker only offers the restricted list.
|
|
90
|
+
expect(screen.getByText('+383')).toBeInTheDocument()
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('PhoneNumberField country dictionary', () => {
|
|
95
|
+
it('exposes a complete, well-formed geographic dictionary', () => {
|
|
96
|
+
expect(PHONE_COUNTRIES.length).toBeGreaterThan(200)
|
|
97
|
+
|
|
98
|
+
for (const country of PHONE_COUNTRIES) {
|
|
99
|
+
expect(country.iso2).toMatch(/^[A-Z]{2}$/)
|
|
100
|
+
expect(country.dialCode).toMatch(/^\+\d+$/)
|
|
101
|
+
expect(country.label.length).toBeGreaterThan(0)
|
|
102
|
+
expect(country.flag.length).toBeGreaterThan(0)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const isoCodes = PHONE_COUNTRIES.map((country) => country.iso2)
|
|
106
|
+
expect(new Set(isoCodes).size).toBe(isoCodes.length)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('includes representative codes from every numbering zone', () => {
|
|
110
|
+
const dialByIso = new Map(PHONE_COUNTRIES.map((country) => [country.iso2, country.dialCode]))
|
|
111
|
+
expect(dialByIso.get('XK')).toBe('+383')
|
|
112
|
+
expect(dialByIso.get('BS')).toBe('+1242')
|
|
113
|
+
expect(dialByIso.get('BR')).toBe('+55')
|
|
114
|
+
expect(dialByIso.get('AU')).toBe('+61')
|
|
115
|
+
expect(dialByIso.get('JP')).toBe('+81')
|
|
116
|
+
expect(dialByIso.get('TR')).toBe('+90')
|
|
117
|
+
expect(dialByIso.get('PS')).toBe('+970')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('excludes non-geographic international service codes', () => {
|
|
121
|
+
for (const code of ['+800', '+808', '+870', '+881', '+882']) {
|
|
122
|
+
expect(PHONE_COUNTRIES.some((country) => country.dialCode === code)).toBe(false)
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('derives each flag emoji from the ISO code', () => {
|
|
127
|
+
expect(PHONE_COUNTRIES.find((country) => country.iso2 === 'US')?.flag).toBe('๐บ๐ธ')
|
|
128
|
+
expect(PHONE_COUNTRIES.find((country) => country.iso2 === 'XK')?.flag).toBe('๐ฝ๐ฐ')
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
describe('PhoneNumberField initial country detection', () => {
|
|
133
|
+
const cases: Array<[string, string]> = [
|
|
134
|
+
['+1242 555 0100', '+1242'],
|
|
135
|
+
['+1 212 555 1234', '+1'],
|
|
136
|
+
['+383 44 123 456', '+383'],
|
|
137
|
+
['+55 11 91234 5678', '+55'],
|
|
138
|
+
['+61 2 1234 5678', '+61'],
|
|
139
|
+
['+81 3 1234 5678', '+81'],
|
|
140
|
+
['+90 212 123 4567', '+90'],
|
|
141
|
+
['+970 59 123 4567', '+970'],
|
|
142
|
+
['+44 20 7946 0000', '+44'],
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
it.each(cases)('resolves %s to dial code %s (longest prefix, sovereign first)', (value, expected) => {
|
|
146
|
+
render(<PhoneFieldHarness value={value} />)
|
|
147
|
+
expect(screen.getByText(expected)).toBeInTheDocument()
|
|
148
|
+
})
|
|
79
149
|
})
|
|
@@ -24,6 +24,8 @@ export type CustomFieldDefDto = {
|
|
|
24
24
|
// attachments-specific config
|
|
25
25
|
maxAttachmentSizeMb?: number
|
|
26
26
|
acceptExtensions?: string[]
|
|
27
|
+
// phone-specific config
|
|
28
|
+
defaultCountryIso2?: string
|
|
27
29
|
// optional validation rules
|
|
28
30
|
validation?: Array<
|
|
29
31
|
| { rule: 'required'; message: string }
|