@blocklet/payment-react 1.21.13 → 1.21.14
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/.aigne/doc-smith/config.yaml +2 -2
- package/es/components/country-select.d.ts +6 -2
- package/es/components/country-select.js +170 -30
- package/es/components/source-data-viewer.js +25 -14
- package/es/history/credit/transactions-list.js +11 -1
- package/es/index.d.ts +1 -0
- package/es/libs/validator.d.ts +161 -0
- package/es/libs/validator.js +172 -61
- package/es/locales/en.js +1 -0
- package/es/locales/zh.js +1 -0
- package/es/payment/form/address.d.ts +1 -2
- package/es/payment/form/address.js +38 -41
- package/es/payment/form/index.js +130 -13
- package/lib/components/country-select.d.ts +6 -2
- package/lib/components/country-select.js +173 -40
- package/lib/components/source-data-viewer.js +5 -3
- package/lib/history/credit/transactions-list.js +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/libs/validator.d.ts +161 -0
- package/lib/libs/validator.js +173 -6
- package/lib/locales/en.js +1 -0
- package/lib/locales/zh.js +1 -0
- package/lib/payment/form/address.d.ts +1 -2
- package/lib/payment/form/address.js +51 -55
- package/lib/payment/form/index.js +168 -12
- package/package.json +3 -3
- package/src/components/country-select.tsx +176 -25
- package/src/components/source-data-viewer.tsx +9 -3
- package/src/history/credit/transactions-list.tsx +6 -1
- package/src/index.ts +2 -0
- package/src/libs/validator.ts +173 -61
- package/src/locales/en.tsx +1 -0
- package/src/locales/zh.tsx +1 -0
- package/src/payment/form/address.tsx +45 -50
- package/src/payment/form/index.tsx +157 -12
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/indent */
|
|
2
2
|
import { useMemo, useState, useEffect, ChangeEvent, useRef, KeyboardEvent } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Box,
|
|
5
|
+
MenuItem,
|
|
6
|
+
Typography,
|
|
7
|
+
TextField,
|
|
8
|
+
Dialog,
|
|
9
|
+
DialogContent,
|
|
10
|
+
IconButton,
|
|
11
|
+
Select,
|
|
12
|
+
Slide,
|
|
13
|
+
Stack,
|
|
14
|
+
} from '@mui/material';
|
|
15
|
+
import { Clear as ClearIcon } from '@mui/icons-material';
|
|
4
16
|
import { useFormContext } from 'react-hook-form';
|
|
5
17
|
import { FlagEmoji, defaultCountries, parseCountry } from 'react-international-phone';
|
|
6
18
|
import type { SlideProps, SxProps } from '@mui/material';
|
|
7
19
|
import type { CountryIso2 } from 'react-international-phone';
|
|
8
20
|
import { useMobile } from '../hooks/mobile';
|
|
9
21
|
|
|
22
|
+
function useFormContextSafe() {
|
|
23
|
+
try {
|
|
24
|
+
return useFormContext();
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
10
30
|
function Transition({ ref, ...props }: { ref: React.RefObject<unknown | null> } & SlideProps) {
|
|
11
31
|
return <Slide direction="up" ref={ref} timeout={200} {...props} />;
|
|
12
32
|
}
|
|
@@ -14,22 +34,30 @@ function Transition({ ref, ...props }: { ref: React.RefObject<unknown | null> }
|
|
|
14
34
|
export type CountrySelectProps = {
|
|
15
35
|
value: CountryIso2;
|
|
16
36
|
onChange: (value: CountryIso2) => void;
|
|
17
|
-
name
|
|
37
|
+
name?: string;
|
|
18
38
|
sx?: SxProps;
|
|
19
39
|
showDialCode?: boolean;
|
|
40
|
+
label?: string;
|
|
41
|
+
allowClear?: boolean;
|
|
42
|
+
bordered?: boolean;
|
|
43
|
+
disabled?: boolean;
|
|
20
44
|
};
|
|
21
45
|
|
|
22
46
|
export default function CountrySelect({
|
|
23
47
|
ref = undefined,
|
|
24
48
|
value,
|
|
25
49
|
onChange,
|
|
26
|
-
name,
|
|
50
|
+
name = '',
|
|
27
51
|
sx = {},
|
|
28
52
|
showDialCode = false,
|
|
53
|
+
label = '',
|
|
54
|
+
bordered = false,
|
|
55
|
+
allowClear = false,
|
|
56
|
+
disabled = false,
|
|
29
57
|
}: CountrySelectProps & {
|
|
30
58
|
ref?: React.RefObject<HTMLDivElement | null>;
|
|
31
59
|
}) {
|
|
32
|
-
const
|
|
60
|
+
const formContext = useFormContextSafe();
|
|
33
61
|
const [open, setOpen] = useState(false);
|
|
34
62
|
const [searchText, setSearchText] = useState('');
|
|
35
63
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
@@ -154,10 +182,21 @@ export default function CountrySelect({
|
|
|
154
182
|
|
|
155
183
|
const handleCountryClick = (code: CountryIso2) => {
|
|
156
184
|
onChange(code);
|
|
157
|
-
|
|
185
|
+
if (formContext && name) {
|
|
186
|
+
formContext.setValue(name, code);
|
|
187
|
+
}
|
|
158
188
|
setOpen(false);
|
|
159
189
|
};
|
|
160
190
|
|
|
191
|
+
const handleClear = (e: React.MouseEvent) => {
|
|
192
|
+
e.preventDefault();
|
|
193
|
+
e.stopPropagation();
|
|
194
|
+
onChange('' as CountryIso2);
|
|
195
|
+
if (formContext && name) {
|
|
196
|
+
formContext.setValue(name, '');
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
161
200
|
const handleSearchChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
162
201
|
e.stopPropagation();
|
|
163
202
|
setSearchText(e.target.value);
|
|
@@ -222,13 +261,14 @@ export default function CountrySelect({
|
|
|
222
261
|
inputRef={inputRef}
|
|
223
262
|
autoFocus={!isMobile}
|
|
224
263
|
fullWidth
|
|
225
|
-
placeholder=
|
|
264
|
+
placeholder={label || 'Search country...'}
|
|
226
265
|
value={searchText}
|
|
227
266
|
onChange={handleSearchChange}
|
|
228
267
|
onKeyDown={handleKeyDown}
|
|
229
268
|
onClick={(e) => e.stopPropagation()}
|
|
230
269
|
size="small"
|
|
231
270
|
variant="outlined"
|
|
271
|
+
disabled={disabled}
|
|
232
272
|
/>
|
|
233
273
|
</Box>
|
|
234
274
|
<Box
|
|
@@ -324,6 +364,7 @@ export default function CountrySelect({
|
|
|
324
364
|
display: 'flex',
|
|
325
365
|
flexDirection: 'column',
|
|
326
366
|
overflowY: 'hidden',
|
|
367
|
+
width: '100%',
|
|
327
368
|
},
|
|
328
369
|
},
|
|
329
370
|
},
|
|
@@ -341,7 +382,7 @@ export default function CountrySelect({
|
|
|
341
382
|
},
|
|
342
383
|
'.MuiSelect-select': {
|
|
343
384
|
padding: '8px',
|
|
344
|
-
paddingRight: '24px !important',
|
|
385
|
+
paddingRight: allowClear && value ? '48px !important' : '24px !important',
|
|
345
386
|
},
|
|
346
387
|
svg: {
|
|
347
388
|
right: 0,
|
|
@@ -354,8 +395,11 @@ export default function CountrySelect({
|
|
|
354
395
|
value={value}
|
|
355
396
|
onChange={(e) => {
|
|
356
397
|
onChange(e.target.value as CountryIso2);
|
|
357
|
-
|
|
398
|
+
if (formContext && name) {
|
|
399
|
+
formContext.setValue(name, e.target.value);
|
|
400
|
+
}
|
|
358
401
|
}}
|
|
402
|
+
disabled={disabled}
|
|
359
403
|
renderValue={(code) => (
|
|
360
404
|
<Box
|
|
361
405
|
sx={{
|
|
@@ -364,9 +408,58 @@ export default function CountrySelect({
|
|
|
364
408
|
flexWrap: 'nowrap',
|
|
365
409
|
gap: 0.5,
|
|
366
410
|
cursor: 'pointer',
|
|
411
|
+
width: '100%',
|
|
367
412
|
}}>
|
|
368
|
-
|
|
369
|
-
|
|
413
|
+
{code ? (
|
|
414
|
+
<Stack
|
|
415
|
+
direction="row"
|
|
416
|
+
sx={{
|
|
417
|
+
alignItems: 'center',
|
|
418
|
+
gap: 0.5,
|
|
419
|
+
justifyContent: 'space-between',
|
|
420
|
+
width: '100%',
|
|
421
|
+
}}>
|
|
422
|
+
<Stack
|
|
423
|
+
direction="row"
|
|
424
|
+
sx={{
|
|
425
|
+
alignItems: 'center',
|
|
426
|
+
gap: 0.5,
|
|
427
|
+
}}>
|
|
428
|
+
<FlagEmoji iso2={code} style={{ display: 'flex' }} />
|
|
429
|
+
<Typography sx={{ flex: 1 }}>{countryDetail?.name}</Typography>
|
|
430
|
+
</Stack>
|
|
431
|
+
|
|
432
|
+
{allowClear && value && (
|
|
433
|
+
<Box
|
|
434
|
+
onClick={handleClear}
|
|
435
|
+
onMouseDown={(event) => {
|
|
436
|
+
event.stopPropagation();
|
|
437
|
+
event.preventDefault();
|
|
438
|
+
}}
|
|
439
|
+
onTouchStart={(event) => {
|
|
440
|
+
event.stopPropagation();
|
|
441
|
+
}}
|
|
442
|
+
sx={{
|
|
443
|
+
display: 'flex',
|
|
444
|
+
alignItems: 'center',
|
|
445
|
+
cursor: 'pointer',
|
|
446
|
+
p: 0,
|
|
447
|
+
borderRadius: '50%',
|
|
448
|
+
border: 'none',
|
|
449
|
+
background: 'transparent',
|
|
450
|
+
zIndex: 2,
|
|
451
|
+
marginRight: '-28px',
|
|
452
|
+
'&:hover': {
|
|
453
|
+
backgroundColor: 'action.hover',
|
|
454
|
+
},
|
|
455
|
+
}}>
|
|
456
|
+
<ClearIcon fontSize="small" />
|
|
457
|
+
</Box>
|
|
458
|
+
)}
|
|
459
|
+
</Stack>
|
|
460
|
+
) : (
|
|
461
|
+
<Typography sx={{ color: 'text.secondary', flex: 1 }}>{label || 'Select country...'}</Typography>
|
|
462
|
+
)}
|
|
370
463
|
</Box>
|
|
371
464
|
)}>
|
|
372
465
|
{countryListContent}
|
|
@@ -377,7 +470,10 @@ export default function CountrySelect({
|
|
|
377
470
|
return (
|
|
378
471
|
<Box ref={ref} sx={{ ...sx }}>
|
|
379
472
|
<Box
|
|
380
|
-
onClick={() =>
|
|
473
|
+
onClick={() => {
|
|
474
|
+
if (disabled) return;
|
|
475
|
+
setOpen(true);
|
|
476
|
+
}}
|
|
381
477
|
sx={{
|
|
382
478
|
display: 'flex',
|
|
383
479
|
alignItems: 'center',
|
|
@@ -387,7 +483,12 @@ export default function CountrySelect({
|
|
|
387
483
|
padding: '8px',
|
|
388
484
|
paddingRight: '24px',
|
|
389
485
|
position: 'relative',
|
|
390
|
-
|
|
486
|
+
...(!bordered
|
|
487
|
+
? {
|
|
488
|
+
border: 'none',
|
|
489
|
+
}
|
|
490
|
+
: {}),
|
|
491
|
+
|
|
391
492
|
'-webkit-tap-highlight-color': 'transparent',
|
|
392
493
|
userSelect: 'none',
|
|
393
494
|
background: 'none',
|
|
@@ -397,10 +498,57 @@ export default function CountrySelect({
|
|
|
397
498
|
outline: 'none',
|
|
398
499
|
},
|
|
399
500
|
|
|
501
|
+
...(disabled
|
|
502
|
+
? {
|
|
503
|
+
backgroundColor: 'grey.100',
|
|
504
|
+
cursor: 'not-allowed',
|
|
505
|
+
color: 'text.disabled',
|
|
506
|
+
'&:hover, &:focus, &:active': {
|
|
507
|
+
backgroundColor: 'grey.100',
|
|
508
|
+
color: 'text.disabled',
|
|
509
|
+
},
|
|
510
|
+
}
|
|
511
|
+
: {}),
|
|
512
|
+
|
|
400
513
|
touchAction: 'manipulation',
|
|
401
514
|
}}>
|
|
402
|
-
|
|
403
|
-
|
|
515
|
+
{value ? (
|
|
516
|
+
<>
|
|
517
|
+
<FlagEmoji iso2={value} style={{ display: 'flex' }} />
|
|
518
|
+
<Typography sx={{ flex: 1 }}>{countryDetail?.name}</Typography>
|
|
519
|
+
{allowClear && (
|
|
520
|
+
<Box
|
|
521
|
+
component="button"
|
|
522
|
+
type="button"
|
|
523
|
+
onClick={handleClear}
|
|
524
|
+
onMouseDown={(event) => {
|
|
525
|
+
event.stopPropagation();
|
|
526
|
+
event.preventDefault();
|
|
527
|
+
}}
|
|
528
|
+
onTouchStart={(event) => {
|
|
529
|
+
event.stopPropagation();
|
|
530
|
+
}}
|
|
531
|
+
sx={{
|
|
532
|
+
display: 'flex',
|
|
533
|
+
alignItems: 'center',
|
|
534
|
+
cursor: 'pointer',
|
|
535
|
+
p: 0.5,
|
|
536
|
+
mr: 1,
|
|
537
|
+
borderRadius: '50%',
|
|
538
|
+
|
|
539
|
+
border: 'none',
|
|
540
|
+
background: 'transparent',
|
|
541
|
+
'&:hover': {
|
|
542
|
+
backgroundColor: 'action.hover',
|
|
543
|
+
},
|
|
544
|
+
}}>
|
|
545
|
+
<ClearIcon fontSize="small" />
|
|
546
|
+
</Box>
|
|
547
|
+
)}
|
|
548
|
+
</>
|
|
549
|
+
) : (
|
|
550
|
+
<Typography sx={{ color: 'text.secondary', flex: 1 }}>{label || 'Select country...'}</Typography>
|
|
551
|
+
)}
|
|
404
552
|
<Box
|
|
405
553
|
sx={{
|
|
406
554
|
position: 'absolute',
|
|
@@ -418,18 +566,21 @@ export default function CountrySelect({
|
|
|
418
566
|
onClose={() => setOpen(false)}
|
|
419
567
|
fullWidth
|
|
420
568
|
maxWidth="xs"
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
569
|
+
slotProps={{
|
|
570
|
+
paper: {
|
|
571
|
+
sx: {
|
|
572
|
+
position: 'absolute',
|
|
573
|
+
bottom: 0,
|
|
574
|
+
m: 0,
|
|
575
|
+
p: 0,
|
|
576
|
+
borderBottomLeftRadius: 0,
|
|
577
|
+
borderBottomRightRadius: 0,
|
|
578
|
+
width: '100%',
|
|
579
|
+
},
|
|
432
580
|
},
|
|
581
|
+
}}
|
|
582
|
+
slots={{
|
|
583
|
+
transition: Transition,
|
|
433
584
|
}}>
|
|
434
585
|
<Box sx={{ p: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
435
586
|
<Typography variant="h6">Select Country</Typography>
|
|
@@ -180,7 +180,13 @@ function SourceDataViewer({
|
|
|
180
180
|
|
|
181
181
|
if (compact) {
|
|
182
182
|
return (
|
|
183
|
-
<Stack
|
|
183
|
+
<Stack
|
|
184
|
+
direction="row"
|
|
185
|
+
spacing={1}
|
|
186
|
+
useFlexGap
|
|
187
|
+
sx={{
|
|
188
|
+
flexWrap: 'wrap',
|
|
189
|
+
}}>
|
|
184
190
|
{displayItems.map((field) => (
|
|
185
191
|
<Chip
|
|
186
192
|
key={field.key}
|
|
@@ -241,8 +247,8 @@ function SourceDataViewer({
|
|
|
241
247
|
}}>
|
|
242
248
|
<Typography
|
|
243
249
|
variant="body2"
|
|
244
|
-
color="text.secondary"
|
|
245
250
|
sx={{
|
|
251
|
+
color: 'text.secondary',
|
|
246
252
|
fontSize: '0.8rem',
|
|
247
253
|
minWidth: 100,
|
|
248
254
|
fontWeight: 600,
|
|
@@ -276,8 +282,8 @@ function SourceDataViewer({
|
|
|
276
282
|
}}>
|
|
277
283
|
<Typography
|
|
278
284
|
variant="body2"
|
|
279
|
-
color="text.secondary"
|
|
280
285
|
sx={{
|
|
286
|
+
color: 'text.secondary',
|
|
281
287
|
fontSize: '0.8rem',
|
|
282
288
|
minWidth: 100,
|
|
283
289
|
fontWeight: 600,
|
|
@@ -269,7 +269,12 @@ const TransactionsTable = React.memo((props: Props) => {
|
|
|
269
269
|
customBodyRenderLite: (_: string, index: number) => {
|
|
270
270
|
const item = data?.list[index] as any;
|
|
271
271
|
return (
|
|
272
|
-
<Typography
|
|
272
|
+
<Typography
|
|
273
|
+
variant="body2"
|
|
274
|
+
sx={{
|
|
275
|
+
color: 'text.secondary',
|
|
276
|
+
fontSize: '0.875rem',
|
|
277
|
+
}}>
|
|
273
278
|
{formatToDate(item.created_at, locale, 'YYYY-MM-DD HH:mm')}
|
|
274
279
|
</Typography>
|
|
275
280
|
);
|
package/src/index.ts
CHANGED
package/src/libs/validator.ts
CHANGED
|
@@ -1,69 +1,181 @@
|
|
|
1
|
-
import isPostalCode, { PostalCodeLocale } from 'validator/lib/isPostalCode';
|
|
2
1
|
import { t } from '../locales';
|
|
3
2
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
]
|
|
3
|
+
const threeDigit = /^\d{3}$/;
|
|
4
|
+
const fourDigit = /^\d{4}$/;
|
|
5
|
+
const fiveDigit = /^\d{5}$/;
|
|
6
|
+
const sixDigit = /^\d{6}$/;
|
|
7
|
+
|
|
8
|
+
export const postalCodePatterns = {
|
|
9
|
+
GB: /^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}$/i,
|
|
10
|
+
JE: /^JE\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$/i,
|
|
11
|
+
GG: /^GY\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$/i,
|
|
12
|
+
IM: /^IM\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$/i,
|
|
13
|
+
|
|
14
|
+
US: /^\d{5}([ -]\d{4})?$/,
|
|
15
|
+
CA: /^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ ]?\d[ABCEGHJ-NPRSTV-Z]\d$/i,
|
|
16
|
+
DE: /^\d{5}$/,
|
|
17
|
+
JP: /^\d{3}-?\d{4}$/,
|
|
18
|
+
FR: /^\d{2}[ ]?\d{3}$/,
|
|
19
|
+
AU: fourDigit,
|
|
20
|
+
IT: /^\d{5}$/,
|
|
21
|
+
CH: fourDigit,
|
|
22
|
+
AT: fourDigit,
|
|
23
|
+
ES: /^\d{5}$/,
|
|
24
|
+
NL: /^\d{4}[ ]?[A-Z]{2}$/i,
|
|
25
|
+
BE: fourDigit,
|
|
26
|
+
DK: fourDigit,
|
|
27
|
+
SE: /^\d{3}[ ]?\d{2}$/,
|
|
28
|
+
NO: fourDigit,
|
|
29
|
+
BR: /^\d{5}-?\d{3}$/,
|
|
30
|
+
PT: /^\d{4}(-\d{3})?$/,
|
|
31
|
+
FI: fiveDigit,
|
|
32
|
+
AX: /^22\d{3}$/,
|
|
33
|
+
KR: /^\d{5}$/, // 2015年起使用5位数字邮编
|
|
34
|
+
CN: /^\d{6}$/,
|
|
35
|
+
TW: /^\d{3}(\d{2})?$/,
|
|
36
|
+
SG: sixDigit,
|
|
37
|
+
DZ: fiveDigit,
|
|
38
|
+
AD: /^AD\d{3}$/,
|
|
39
|
+
AR: /^([A-HJ-NP-Z])?\d{4}([A-Z]{3})?$/i,
|
|
40
|
+
AM: /^(37)?\d{4}$/,
|
|
41
|
+
AZ: /^\d{4}$/,
|
|
42
|
+
BH: /^((1[0-2]|[2-9])\d{2})?$/,
|
|
43
|
+
BD: fourDigit,
|
|
44
|
+
BB: /^(BB\d{5})?$/i,
|
|
45
|
+
BY: sixDigit,
|
|
46
|
+
BM: /^[A-Z]{2}[ ]?[A-Z0-9]{2}$/i,
|
|
47
|
+
BA: /^\d{5}$/,
|
|
48
|
+
IO: /^BBND 1ZZ$/i,
|
|
49
|
+
BN: /^[A-Z]{2}[ ]?\d{4}$/i,
|
|
50
|
+
BG: fourDigit,
|
|
51
|
+
KH: fiveDigit,
|
|
52
|
+
CV: fourDigit,
|
|
53
|
+
CL: /^\d{7}$/,
|
|
54
|
+
CR: /^\d{4,5}|\d{3}-\d{4}$/,
|
|
55
|
+
HR: /^\d{5}$/,
|
|
56
|
+
CY: fourDigit,
|
|
57
|
+
CZ: /^\d{3}[ ]?\d{2}$/,
|
|
58
|
+
DO: fiveDigit,
|
|
59
|
+
EC: /^([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?$/i,
|
|
60
|
+
EG: fiveDigit,
|
|
61
|
+
EE: fiveDigit,
|
|
62
|
+
FO: threeDigit,
|
|
63
|
+
GE: fourDigit,
|
|
64
|
+
GR: /^\d{3}[ ]?\d{2}$/,
|
|
65
|
+
GL: /^39\d{2}$/,
|
|
66
|
+
GT: fiveDigit,
|
|
67
|
+
HT: /^\d{4}$/,
|
|
68
|
+
HN: /^(?:\d{5})?$/,
|
|
69
|
+
HU: fourDigit,
|
|
70
|
+
IS: threeDigit,
|
|
71
|
+
IN: /^[1-9]\d{5}$/,
|
|
72
|
+
ID: fiveDigit,
|
|
73
|
+
IL: fiveDigit,
|
|
74
|
+
JO: fiveDigit,
|
|
75
|
+
KZ: sixDigit,
|
|
76
|
+
KE: fiveDigit,
|
|
77
|
+
KW: fiveDigit,
|
|
78
|
+
LA: fiveDigit,
|
|
79
|
+
LV: fourDigit,
|
|
80
|
+
LB: /^(\d{4}([ ]?\d{4})?)?$/,
|
|
81
|
+
LI: /^(948[5-9])|(949[0-7])$/,
|
|
82
|
+
LT: fiveDigit,
|
|
83
|
+
LU: fourDigit,
|
|
84
|
+
MK: fourDigit,
|
|
85
|
+
MY: fiveDigit,
|
|
86
|
+
MV: fiveDigit,
|
|
87
|
+
MT: /^[A-Z]{3}[ ]?\d{2,4}$/i,
|
|
88
|
+
MU: /^(\d{3}[A-Z]{2}\d{3})?$/i,
|
|
89
|
+
MX: fiveDigit,
|
|
90
|
+
MD: fourDigit,
|
|
91
|
+
MC: /^980\d{2}$/,
|
|
92
|
+
MA: fiveDigit,
|
|
93
|
+
NP: fiveDigit,
|
|
94
|
+
NZ: fourDigit,
|
|
95
|
+
NI: /^((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?$/,
|
|
96
|
+
NG: /^(\d{6})?$/,
|
|
97
|
+
OM: /^(PC )?\d{3}$/i,
|
|
98
|
+
PK: fiveDigit,
|
|
99
|
+
PY: fourDigit,
|
|
100
|
+
PH: fourDigit,
|
|
101
|
+
PL: /^\d{2}-\d{3}$/,
|
|
102
|
+
PR: /^00[679]\d{2}([ -]\d{4})?$/,
|
|
103
|
+
RO: sixDigit,
|
|
104
|
+
RU: sixDigit,
|
|
105
|
+
SM: /^4789\d$/,
|
|
106
|
+
SA: fiveDigit,
|
|
107
|
+
SN: fiveDigit,
|
|
108
|
+
SK: /^\d{3}[ ]?\d{2}$/,
|
|
109
|
+
SI: fourDigit,
|
|
110
|
+
ZA: fourDigit,
|
|
111
|
+
LK: fiveDigit,
|
|
112
|
+
TJ: sixDigit,
|
|
113
|
+
TH: fiveDigit,
|
|
114
|
+
TN: fourDigit,
|
|
115
|
+
TR: fiveDigit,
|
|
116
|
+
TM: sixDigit,
|
|
117
|
+
UA: fiveDigit,
|
|
118
|
+
UY: fiveDigit,
|
|
119
|
+
UZ: sixDigit,
|
|
120
|
+
VA: /^00120$/,
|
|
121
|
+
VE: fourDigit,
|
|
122
|
+
ZM: fiveDigit,
|
|
123
|
+
|
|
124
|
+
// Territories & special regions
|
|
125
|
+
AS: /^96799$/,
|
|
126
|
+
CC: /^6799$/,
|
|
127
|
+
CK: fourDigit,
|
|
128
|
+
RS: sixDigit,
|
|
129
|
+
ME: /^8\d{4}$/,
|
|
130
|
+
CS: /^\d{5}$/, // historical
|
|
131
|
+
YU: /^\d{5}$/, // historical
|
|
132
|
+
CX: /^6798$/,
|
|
133
|
+
ET: fourDigit,
|
|
134
|
+
FK: /^FIQQ 1ZZ$/i,
|
|
135
|
+
NF: /^2899$/,
|
|
136
|
+
FM: /^(9694[1-4])([ -]\d{4})?$/,
|
|
137
|
+
GF: /^9[78]3\d{2}$/,
|
|
138
|
+
GN: threeDigit,
|
|
139
|
+
GP: /^9[78][01]\d{2}$/,
|
|
140
|
+
GS: /^SIQQ 1ZZ$/i,
|
|
141
|
+
GU: /^969[123]\d([ -]\d{4})?$/,
|
|
142
|
+
GW: fourDigit,
|
|
143
|
+
HM: fourDigit,
|
|
144
|
+
IQ: fiveDigit,
|
|
145
|
+
KG: sixDigit,
|
|
146
|
+
LR: fourDigit,
|
|
147
|
+
LS: threeDigit,
|
|
148
|
+
MG: threeDigit,
|
|
149
|
+
MH: /^969[67]\d([ -]\d{4})?$/,
|
|
150
|
+
MN: sixDigit,
|
|
151
|
+
MP: /^9695[012]([ -]\d{4})?$/,
|
|
152
|
+
MQ: /^9[78]2\d{2}$/,
|
|
153
|
+
NC: /^988\d{2}$/,
|
|
154
|
+
NE: fourDigit,
|
|
155
|
+
VI: /^008(([0-4]\d)|(5[01]))([ -]\d{4})?$/,
|
|
156
|
+
VN: sixDigit,
|
|
157
|
+
PF: /^987\d{2}$/,
|
|
158
|
+
PG: threeDigit,
|
|
159
|
+
PM: /^9[78]5\d{2}$/,
|
|
160
|
+
PN: /^PCRN 1ZZ$/i,
|
|
161
|
+
PW: /^96940$/,
|
|
162
|
+
RE: /^9[78]4\d{2}$/,
|
|
163
|
+
SH: /^(ASCN|STHL) 1ZZ$/i,
|
|
164
|
+
SJ: fourDigit,
|
|
165
|
+
SO: fiveDigit,
|
|
166
|
+
SZ: /^[HLMS]\d{3}$/i,
|
|
167
|
+
TC: /^TKCA 1ZZ$/i,
|
|
168
|
+
WF: /^986\d{2}$/,
|
|
169
|
+
XK: fiveDigit,
|
|
170
|
+
YT: /^976\d{2}$/,
|
|
171
|
+
};
|
|
172
|
+
|
|
61
173
|
export function validatePostalCode(postalCode: string, country?: string): boolean {
|
|
62
174
|
if (!postalCode) return true;
|
|
63
|
-
const countryUpper = country?.toUpperCase();
|
|
64
|
-
const isSupported = country && POSTAL_CODE_SUPPORTED_COUNTRIES.includes(countryUpper as PostalCodeLocale);
|
|
65
175
|
try {
|
|
66
|
-
|
|
176
|
+
const countryUpper = country?.toUpperCase() as keyof typeof postalCodePatterns;
|
|
177
|
+
if (!countryUpper) return false;
|
|
178
|
+
return !postalCodePatterns[countryUpper] || postalCodePatterns[countryUpper].test(postalCode);
|
|
67
179
|
} catch (error) {
|
|
68
180
|
console.error(error);
|
|
69
181
|
return false;
|
package/src/locales/en.tsx
CHANGED
|
@@ -227,6 +227,7 @@ export default flat({
|
|
|
227
227
|
phonePlaceholder: 'Phone number',
|
|
228
228
|
phoneTip: 'In case we need to contact you about your order',
|
|
229
229
|
},
|
|
230
|
+
customerInfo: 'Customer Information',
|
|
230
231
|
upsell: {
|
|
231
232
|
save: 'Save with {recurring} billing',
|
|
232
233
|
revert: 'Switch to {recurring} billing',
|