@blocklet/payment-react 1.21.12 → 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.
@@ -1,12 +1,32 @@
1
1
  /* eslint-disable @typescript-eslint/indent */
2
2
  import { useMemo, useState, useEffect, ChangeEvent, useRef, KeyboardEvent } from 'react';
3
- import { Box, MenuItem, Typography, TextField, Dialog, DialogContent, IconButton, Select, Slide } from '@mui/material';
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: string;
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 { setValue } = useFormContext();
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
- setValue(name, code);
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="Search country..."
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
- setValue(name, e.target.value);
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
- <FlagEmoji iso2={code} style={{ display: 'flex' }} />
369
- <Typography>{countryDetail?.name}</Typography>
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={() => setOpen(true)}
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
- border: 'none',
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
- <FlagEmoji iso2={value} style={{ display: 'flex' }} />
403
- <Typography>{countryDetail?.name}</Typography>
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
- // @ts-expect-error
422
- TransitionComponent={Transition}
423
- PaperProps={{
424
- sx: {
425
- position: 'absolute',
426
- bottom: 0,
427
- m: 0,
428
- p: 0,
429
- borderBottomLeftRadius: 0,
430
- borderBottomRightRadius: 0,
431
- width: '100%',
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 direction="row" spacing={1} flexWrap="wrap" useFlexGap>
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 variant="body2" color="text.secondary" sx={{ fontSize: '0.875rem' }}>
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
@@ -107,3 +107,5 @@ export {
107
107
  PromotionCode,
108
108
  SourceDataViewer,
109
109
  };
110
+
111
+ export type { CountrySelectProps } from './components/country-select';
@@ -1,69 +1,181 @@
1
- import isPostalCode, { PostalCodeLocale } from 'validator/lib/isPostalCode';
2
1
  import { t } from '../locales';
3
2
 
4
- const POSTAL_CODE_SUPPORTED_COUNTRIES: PostalCodeLocale[] = [
5
- 'AD',
6
- 'AT',
7
- 'AU',
8
- 'BE',
9
- 'BG',
10
- 'BR',
11
- 'CA',
12
- 'CH',
13
- 'CN',
14
- 'CZ',
15
- 'DE',
16
- 'DK',
17
- 'DZ',
18
- 'EE',
19
- 'ES',
20
- 'FI',
21
- 'FR',
22
- 'GB',
23
- 'GR',
24
- 'HR',
25
- 'HU',
26
- 'ID',
27
- 'IE',
28
- 'IL',
29
- 'IN',
30
- 'IR',
31
- 'IS',
32
- 'IT',
33
- 'JP',
34
- 'KE',
35
- 'KR',
36
- 'LI',
37
- 'LT',
38
- 'LU',
39
- 'LV',
40
- 'MX',
41
- 'MT',
42
- 'NL',
43
- 'NO',
44
- 'NZ',
45
- 'PL',
46
- 'PR',
47
- 'PT',
48
- 'RO',
49
- 'RU',
50
- 'SA',
51
- 'SE',
52
- 'SI',
53
- 'SK',
54
- 'TN',
55
- 'TW',
56
- 'UA',
57
- 'US',
58
- 'ZA',
59
- 'ZM',
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
- return isPostalCode(postalCode, isSupported ? (countryUpper as PostalCodeLocale) : 'any');
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;
@@ -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',
@@ -224,6 +224,7 @@ export default flat({
224
224
  phonePlaceholder: '电话号码',
225
225
  phoneTip: '以防需要与您联系有关您的订单',
226
226
  },
227
+ customerInfo: '客户信息',
227
228
  upsell: {
228
229
  save: '使用{recurring}计费方式',
229
230
  revert: '切换到{recurring}计费方式',