@blocklet/payment-react 1.18.20 → 1.18.21

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.
@@ -35,6 +35,7 @@ type Props = {
35
35
  dialogProps?: DialogProps;
36
36
  detailLinkOptions?: DetailLinkOptions;
37
37
  successToast?: boolean;
38
+ alertMessage?: string; // only for customer
38
39
  children?: (
39
40
  handlePay: (item: SummaryItem) => void,
40
41
  data: {
@@ -88,6 +89,7 @@ function OverdueInvoicePayment({
88
89
  onPaid = () => {},
89
90
  detailLinkOptions = { enabled: true },
90
91
  successToast = true,
92
+ alertMessage = '',
91
93
  }: Props) {
92
94
  const { t } = useLocaleContext();
93
95
  const { connect } = usePaymentContext();
@@ -99,7 +101,6 @@ function OverdueInvoicePayment({
99
101
 
100
102
  const sourceType = subscriptionId ? 'subscription' : 'customer';
101
103
  const sourceId = subscriptionId || customerId;
102
-
103
104
  const {
104
105
  data = {
105
106
  summary: {},
@@ -340,19 +341,25 @@ function OverdueInvoicePayment({
340
341
  });
341
342
  }
342
343
  if (customerId) {
344
+ let title = '';
343
345
  if (summaryList.length === 1) {
344
- return t('payment.customer.overdue.title', {
346
+ title = t('payment.customer.overdue.title', {
345
347
  subscriptionCount: data.subscriptionCount || 0,
346
348
  count: data.invoices?.length,
347
349
  total: formatAmount(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
348
350
  symbol: summaryList[0]?.currency?.symbol,
349
351
  method: getMethodText(summaryList[0]?.method),
350
352
  });
353
+ } else {
354
+ title = t('payment.customer.overdue.simpleTitle', {
355
+ subscriptionCount: data.subscriptionCount || 0,
356
+ count: data.invoices?.length,
357
+ });
351
358
  }
352
- return t('payment.customer.overdue.simpleTitle', {
353
- subscriptionCount: data.subscriptionCount || 0,
354
- count: data.invoices?.length,
355
- });
359
+ if (alertMessage) {
360
+ return `${title}${alertMessage}`;
361
+ }
362
+ return `${title}${t('payment.customer.overdue.defaultAlert')}`;
356
363
  }
357
364
 
358
365
  return '';
@@ -512,6 +519,7 @@ OverdueInvoicePayment.defaultProps = {
512
519
  subscriptionId: undefined,
513
520
  customerId: undefined,
514
521
  successToast: true,
522
+ alertMessage: '',
515
523
  };
516
524
 
517
525
  export default OverdueInvoicePayment;
@@ -2,7 +2,11 @@ let phoneUtil: any = null;
2
2
 
3
3
  export const getPhoneUtil = async () => {
4
4
  if (!phoneUtil) {
5
- const { PhoneNumberUtil } = await import(/* webpackChunkName: "phone-util" */ 'google-libphonenumber');
5
+ const result = await import(/* webpackChunkName: "phone-util" */ 'google-libphonenumber');
6
+ const PhoneNumberUtil = (result.default || result)?.PhoneNumberUtil;
7
+ if (!PhoneNumberUtil) {
8
+ throw new Error('PhoneNumberUtil not found');
9
+ }
6
10
  phoneUtil = PhoneNumberUtil.getInstance();
7
11
  }
8
12
  return phoneUtil;
@@ -10,7 +14,14 @@ export const getPhoneUtil = async () => {
10
14
 
11
15
  export const validatePhoneNumber = async (phoneNumber: string) => {
12
16
  try {
13
- const util = await getPhoneUtil();
17
+ let util: any = null;
18
+ try {
19
+ util = await getPhoneUtil();
20
+ } catch (err) {
21
+ const pattern = /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/im;
22
+ return pattern.test(phoneNumber);
23
+ }
24
+
14
25
  const parsed = util.parseAndKeepRawInput(phoneNumber);
15
26
  return util.isValidNumber(parsed);
16
27
  } catch (err) {
@@ -18,3 +29,79 @@ export const validatePhoneNumber = async (phoneNumber: string) => {
18
29
  return false;
19
30
  }
20
31
  };
32
+
33
+ /**
34
+ * Format a phone number to international format
35
+ * @param phoneNumber The original phone number
36
+ * @param defaultCountry Default country code (ISO 3166-1 alpha-2)
37
+ * @returns Formatted phone number
38
+ */
39
+ export const formatPhone = (phoneNumber: string | undefined, defaultCountry = 'US') => {
40
+ if (!phoneNumber || phoneNumber.trim() === '') {
41
+ return '';
42
+ }
43
+
44
+ // Remove all non-digit characters (preserve plus sign)
45
+ const cleanedNumber = phoneNumber.replace(/[^\d+]/g, '');
46
+
47
+ // If already in international format (starting with +), return cleaned number
48
+ if (cleanedNumber.startsWith('+')) {
49
+ return cleanedNumber;
50
+ }
51
+
52
+ // Country code mapping
53
+ const COUNTRY_CODES: Record<string, string> = {
54
+ US: '1', // United States
55
+ CA: '1', // Canada
56
+ CN: '86', // China
57
+ HK: '852', // Hong Kong
58
+ IN: '91', // India
59
+ UK: '44', // United Kingdom
60
+ GB: '44', // United Kingdom
61
+ JP: '81', // Japan
62
+ KR: '82', // South Korea
63
+ AU: '61', // Australia
64
+ DE: '49', // Germany
65
+ FR: '33', // France
66
+ IT: '39', // Italy
67
+ ES: '34', // Spain
68
+ BR: '55', // Brazil
69
+ RU: '7', // Russia
70
+ MX: '52', // Mexico
71
+ SG: '65', // Singapore
72
+ AE: '971', // UAE
73
+ };
74
+
75
+ // Country-specific patterns
76
+ const COUNTRY_PATTERNS: [RegExp, string][] = [
77
+ [/^1[3-9]\d{9}$/, '86'], // China mobile: 11 digits, starts with 1
78
+ [/^\d{10}$/, '1'], // US/Canada: 10 digits
79
+ [/^[6-9]\d{9}$/, '91'], // India: 10 digits, starts with 6-9
80
+ [/^0[1-9]\d{8,9}$/, '81'], // Japan: 10-11 digits, starts with 0
81
+ [/^07\d{9}$/, '44'], // UK mobile: 11 digits, starts with 07
82
+ [/^04\d{8}$/, '61'], // Australia mobile: 10 digits, starts with 04
83
+ [/^01[0-9]\d{7,8}$/, '82'], // Korea mobile: 10-11 digits, starts with 01
84
+ [/^[0-9]\d{8}$/, '86'], // China landline: 9 digits
85
+ ];
86
+
87
+ // Remove leading zero (common in many countries)
88
+ let numberToFormat = cleanedNumber;
89
+ if (numberToFormat.startsWith('0')) {
90
+ numberToFormat = numberToFormat.substring(1);
91
+ }
92
+
93
+ // Try to match with country-specific patterns
94
+ for (const [pattern, countryCode] of COUNTRY_PATTERNS) {
95
+ if (pattern.test(cleanedNumber)) {
96
+ // For numbers starting with 0 that need the zero removed
97
+ if (cleanedNumber.startsWith('0') && !['1', '86'].includes(countryCode)) {
98
+ return `+${countryCode}${cleanedNumber.substring(1)}`;
99
+ }
100
+ return `+${countryCode}${cleanedNumber}`;
101
+ }
102
+ }
103
+
104
+ // If no pattern matched, use default country code
105
+ const countryCode = COUNTRY_CODES[defaultCountry.toUpperCase()] || defaultCountry;
106
+ return `+${countryCode}${numberToFormat}`;
107
+ };
@@ -249,8 +249,7 @@ export default flat({
249
249
  warning: 'Past due invoices need to be paid immediately, otherwise you can not make new purchases anymore.',
250
250
  alert: {
251
251
  title: 'You have unpaid invoices',
252
- description:
253
- 'Seems you have unpaid invoices from previous subscriptions, new purchases are not allowed unless you have paid all past due invoices.',
252
+ customMessage: 'Please pay immediately, otherwise new purchases or subscriptions will be prohibited.',
254
253
  confirm: 'Pay Now',
255
254
  },
256
255
  view: 'View Due Invoices',
@@ -331,9 +330,10 @@ export default flat({
331
330
  },
332
331
  overdue: {
333
332
  title:
334
- 'You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}{method}. Please pay immediately to avoid service disruption.',
335
- simpleTitle: 'You have {count} due invoices. Please pay now to ensure uninterrupted service.',
333
+ 'You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}{method}. ',
334
+ simpleTitle: 'You have {count} due invoices. ',
336
335
  empty: 'Great! You have no due invoices.',
336
+ defaultAlert: 'Please pay immediately to avoid service disruption.',
337
337
  },
338
338
  },
339
339
  invoice: {
@@ -245,6 +245,7 @@ export default flat({
245
245
  alert: {
246
246
  title: '你有欠费账单',
247
247
  description: '看起来你有欠费的账单,在你支付所有欠费账单之前,新的购买或者订阅将被禁止,请不要调皮。',
248
+ customMessage: '请立即支付,否则新的购买或者订阅将被禁止。',
248
249
  confirm: '去支付',
249
250
  },
250
251
  view: '查看欠费明细',
@@ -321,10 +322,10 @@ export default flat({
321
322
  owner: '订阅拥有者',
322
323
  },
323
324
  overdue: {
324
- title:
325
- '您有 {count} 张欠费账单,涉及 {subscriptionCount} 个订阅,总金额 {total} {symbol}{method}。请立即支付,以免影响您的使用。',
326
- simpleTitle: '您有 {count} 张欠费账单,请立即支付,以免影响您的使用。',
325
+ title: '您有 {count} 张欠费账单,涉及 {subscriptionCount} 个订阅,总金额 {total} {symbol}{method}。',
326
+ simpleTitle: '您有 {count} 张欠费账单,',
327
327
  empty: '恭喜!您当前没有欠费账单。',
328
+ defaultAlert: '请立即支付,以免影响您的使用。',
328
329
  },
329
330
  },
330
331
  invoice: {
@@ -36,6 +36,7 @@ import ProductDonation from './product-donation';
36
36
  import ConfirmDialog from '../components/confirm';
37
37
  import PaymentBeneficiaries, { TBeneficiary } from '../components/payment-beneficiaries';
38
38
  import DonationSkeleton from './skeleton/donation';
39
+ import { formatPhone } from '../libs/phone-validator';
39
40
 
40
41
  const getBenefits = async (id: string, url?: string) => {
41
42
  const { data } = await api.get(`/api/payment-links/${id}/benefits?${url ? `url=${url}` : ''}`);
@@ -102,20 +103,24 @@ function PaymentInner({
102
103
  defaultValues: {
103
104
  customer_name: customer?.name || session?.user?.fullName || '',
104
105
  customer_email: customer?.email || session?.user?.email || '',
105
- customer_phone: customer?.phone || session?.user?.phone || '',
106
+ customer_phone: formatPhone(customer?.phone || session?.user?.phone || ''),
106
107
  payment_method: defaultMethodId,
107
108
  payment_currency: defaultCurrencyId,
108
109
  billing_address: Object.assign(
109
110
  {
110
- country: '',
111
- state: '',
112
- city: '',
113
- line1: '',
114
- line2: '',
115
- postal_code: '',
111
+ country: session?.user?.address?.country || '',
112
+ state: session?.user?.address?.province || '',
113
+ city: session?.user?.address?.city || '',
114
+ line1: session?.user?.address?.line1 || '',
115
+ line2: session?.user?.address?.line2 || '',
116
+ postal_code: session?.user?.address?.postalCode || '',
116
117
  },
117
118
  customer?.address || {},
118
- { country: isValidCountry(customer?.address?.country || '') ? customer?.address?.country : 'us' }
119
+ {
120
+ country: isValidCountry(customer?.address?.country || session?.user?.address?.country || '')
121
+ ? customer?.address?.country
122
+ : 'us',
123
+ }
119
124
  ),
120
125
  },
121
126
  });
@@ -21,7 +21,6 @@ import { dispatch } from 'use-bus';
21
21
  import isEmail from 'validator/es/lib/isEmail';
22
22
 
23
23
  import isEmpty from 'lodash/isEmpty';
24
- import ConfirmDialog from '../../components/confirm';
25
24
  import FormInput from '../../components/input';
26
25
  import { usePaymentContext } from '../../contexts/payment';
27
26
  import { useSubscription } from '../../hooks/subscription';
@@ -40,8 +39,9 @@ import CurrencySelector from './currency';
40
39
  import PhoneInput from './phone';
41
40
  import StripeCheckout from './stripe';
42
41
  import { useMobile } from '../../hooks/mobile';
43
- import { validatePhoneNumber } from '../../libs/phone-validator';
42
+ import { formatPhone, validatePhoneNumber } from '../../libs/phone-validator';
44
43
  import LoadingButton from '../../components/loading-button';
44
+ import OverdueInvoicePayment from '../../components/over-due-invoice-payment';
45
45
 
46
46
  export const waitForCheckoutComplete = async (sessionId: string) => {
47
47
  let result: CheckoutContext;
@@ -83,6 +83,63 @@ type PageData = CheckoutContext &
83
83
  isDonation?: boolean;
84
84
  };
85
85
 
86
+ type UserInfo = {
87
+ name?: string;
88
+ fullName?: string;
89
+ email?: string;
90
+ phone?: string;
91
+ address?: {
92
+ country?: string;
93
+ state?: string;
94
+ province?: string;
95
+ line1?: string;
96
+ line2?: string;
97
+ city?: string;
98
+ postal_code?: string;
99
+ postalCode?: string;
100
+ };
101
+ metadata?: {
102
+ phone?: {
103
+ country?: string;
104
+ phoneNumber?: string;
105
+ };
106
+ };
107
+ };
108
+
109
+ const setUserFormValues = (
110
+ userInfo: UserInfo,
111
+ currentValues: any,
112
+ setValue: Function,
113
+ options: { preferExisting?: boolean; showPhone?: boolean } = {}
114
+ ) => {
115
+ const { preferExisting = true } = options;
116
+ const basicFields = {
117
+ customer_name: userInfo.name || userInfo.fullName,
118
+ customer_email: userInfo.email,
119
+ customer_phone: formatPhone(userInfo.phone),
120
+ };
121
+ const addressFields: Record<string, any> = {
122
+ 'billing_address.state': userInfo.address?.state || userInfo.address?.province,
123
+ 'billing_address.line1': userInfo.address?.line1,
124
+ 'billing_address.line2': userInfo.address?.line2,
125
+ 'billing_address.city': userInfo.address?.city,
126
+ 'billing_address.postal_code': userInfo.address?.postal_code || userInfo.address?.postalCode,
127
+ 'billing_address.country': userInfo.address?.country,
128
+ };
129
+
130
+ if (options.showPhone) {
131
+ addressFields['billing_address.country'] = userInfo.metadata?.phone?.country || userInfo.address?.country;
132
+ }
133
+
134
+ const allFields = { ...addressFields, ...basicFields };
135
+
136
+ Object.entries(allFields).forEach(([field, value]) => {
137
+ if (!preferExisting || !currentValues[field.split('.')[0]]) {
138
+ setValue(field, value);
139
+ }
140
+ });
141
+ };
142
+
86
143
  PaymentForm.defaultProps = {
87
144
  onlyShowBtn: false,
88
145
  isDonation: false,
@@ -185,22 +242,30 @@ export default function PaymentForm({
185
242
  useEffect(() => {
186
243
  if (session?.user) {
187
244
  const values = getValues();
188
- if (!values.customer_name) {
189
- setValue('customer_name', session.user.fullName);
190
- }
191
- if (!values.customer_email) {
192
- setValue('customer_email', session.user.email);
193
- }
194
- if (!values.customer_phone) {
195
- setValue('customer_phone', session.user.phone);
196
- }
197
- }
198
- if (!session?.user) {
199
- setValue('customer_name', '');
200
- setValue('customer_email', '');
201
- setValue('customer_phone', '');
245
+ setUserFormValues(session.user, values, setValue, {
246
+ preferExisting: false,
247
+ showPhone: checkoutSession.phone_number_collection?.enabled,
248
+ });
249
+ } else {
250
+ setUserFormValues(
251
+ {
252
+ name: '',
253
+ email: '',
254
+ phone: '',
255
+ address: {
256
+ state: '',
257
+ line1: '',
258
+ line2: '',
259
+ city: '',
260
+ postal_code: '',
261
+ },
262
+ },
263
+ {},
264
+ setValue,
265
+ { preferExisting: false, showPhone: checkoutSession.phone_number_collection?.enabled }
266
+ );
202
267
  }
203
- }, [session?.user, getValues, setValue]);
268
+ }, [session?.user, getValues, setValue, checkoutSession.phone_number_collection?.enabled]);
204
269
 
205
270
  useEffect(() => {
206
271
  setValue('payment_method', (currencies[paymentCurrencyIndex] as any)?.method?.id);
@@ -248,7 +313,7 @@ export default function PaymentForm({
248
313
 
249
314
  const method = paymentMethods.find((x) => x.id === paymentMethod) as TPaymentMethodExpanded;
250
315
  const isDonationMode = checkoutSession?.submit_type === 'donate' && isDonation;
251
- const showForm = session?.user;
316
+ const showForm = !!session?.user;
252
317
  const skipBindWallet = method.type === 'stripe';
253
318
 
254
319
  const handleConnected = async () => {
@@ -275,33 +340,9 @@ export default function PaymentForm({
275
340
  const { data: profile } = await api.get('/api/customers/me?fallback=1');
276
341
  if (profile) {
277
342
  const values = getValues();
278
- if (!values.customer_name) {
279
- setValue('customer_name', profile.name);
280
- }
281
- if (!values.customer_email) {
282
- setValue('customer_email', profile.email);
283
- }
284
- if (!values.customer_phone) {
285
- setValue('customer_phone', profile.phone);
286
- }
287
- if (profile.address?.country) {
288
- setValue('billing_address.country', profile.address.country);
289
- }
290
- if (profile.address?.state) {
291
- setValue('billing_address.state', profile.address.state);
292
- }
293
- if (profile.address?.line1) {
294
- setValue('billing_address.line1', profile.address.line1);
295
- }
296
- if (profile.address?.line2) {
297
- setValue('billing_address.line2', profile.address.line2);
298
- }
299
- if (profile.address?.city) {
300
- setValue('billing_address.city', profile.address.city);
301
- }
302
- if (profile.address?.postal_code) {
303
- setValue('billing_address.postal_code', profile.address.postal_code);
304
- }
343
+ setUserFormValues(profile, values, setValue, {
344
+ showPhone: checkoutSession.phone_number_collection?.enabled,
345
+ });
305
346
  }
306
347
  };
307
348
 
@@ -473,18 +514,31 @@ export default function PaymentForm({
473
514
  </Button>
474
515
  </Box>
475
516
  {state.customerLimited && (
476
- <ConfirmDialog
477
- onConfirm={() =>
478
- window.open(
479
- joinURL(getPrefix(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`),
480
- '_self'
481
- )
482
- }
483
- onCancel={() => setState({ customerLimited: false })}
484
- confirm={t('payment.customer.pastDue.alert.confirm')}
485
- title={t('payment.customer.pastDue.alert.title')}
486
- message={t('payment.customer.pastDue.alert.description')}
487
- color="primary"
517
+ <OverdueInvoicePayment
518
+ customerId={customer?.id || session?.user?.did}
519
+ onPaid={() => {
520
+ setState({ customerLimited: false });
521
+ onAction();
522
+ }}
523
+ alertMessage={t('payment.customer.pastDue.alert.customMessage')}
524
+ detailLinkOptions={{
525
+ enabled: true,
526
+ onClick: () => {
527
+ setState({ customerLimited: false });
528
+ window.open(
529
+ joinURL(
530
+ getPrefix(),
531
+ `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`
532
+ ),
533
+ '_self'
534
+ );
535
+ },
536
+ }}
537
+ dialogProps={{
538
+ open: state.customerLimited,
539
+ onClose: () => setState({ customerLimited: false }),
540
+ title: t('payment.customer.pastDue.alert.title'),
541
+ }}
488
542
  />
489
543
  )}
490
544
  </>
@@ -619,18 +673,28 @@ export default function PaymentForm({
619
673
  </Stack>
620
674
  </Fade>
621
675
  {state.customerLimited && (
622
- <ConfirmDialog
623
- onConfirm={() =>
624
- window.open(
625
- joinURL(getPrefix(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`),
626
- '_self'
627
- )
628
- }
629
- onCancel={() => setState({ customerLimited: false })}
630
- confirm={t('payment.customer.pastDue.alert.confirm')}
631
- title={t('payment.customer.pastDue.alert.title')}
632
- message={t('payment.customer.pastDue.alert.description')}
633
- color="primary"
676
+ <OverdueInvoicePayment
677
+ customerId={customer?.id || session?.user?.didssion?.user?.did}
678
+ onPaid={() => {
679
+ setState({ customerLimited: false });
680
+ onAction();
681
+ }}
682
+ alertMessage={t('payment.customer.pastDue.alert.customMessage')}
683
+ detailLinkOptions={{
684
+ enabled: true,
685
+ onClick: () => {
686
+ setState({ customerLimited: false });
687
+ window.open(
688
+ joinURL(getPrefix(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`),
689
+ '_self'
690
+ );
691
+ },
692
+ }}
693
+ dialogProps={{
694
+ open: state.customerLimited,
695
+ onClose: () => setState({ customerLimited: false }),
696
+ title: t('payment.customer.pastDue.alert.title'),
697
+ }}
634
698
  />
635
699
  )}
636
700
  </>
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable react/prop-types */
2
2
  import { InputAdornment } from '@mui/material';
3
3
  import omit from 'lodash/omit';
4
- import { useEffect } from 'react';
4
+ import { useEffect, useRef, useCallback } from 'react';
5
5
  import { useFormContext, useWatch } from 'react-hook-form';
6
6
  import { defaultCountries, usePhoneInput } from 'react-international-phone';
7
7
  import type { CountryIso2 } from 'react-international-phone';
@@ -15,28 +15,50 @@ export default function PhoneInput({ ...props }) {
15
15
  const { control, getValues, setValue } = useFormContext();
16
16
  const values = getValues();
17
17
 
18
+ const isUpdatingRef = useRef(false);
19
+
20
+ const safeUpdate = useCallback((callback: () => void) => {
21
+ if (isUpdatingRef.current) return;
22
+
23
+ try {
24
+ isUpdatingRef.current = true;
25
+ callback();
26
+ } finally {
27
+ requestAnimationFrame(() => {
28
+ isUpdatingRef.current = false;
29
+ });
30
+ }
31
+ }, []);
32
+
18
33
  const { phone, handlePhoneValueChange, inputRef, country, setCountry } = usePhoneInput({
19
34
  defaultCountry: isValidCountry(values[countryFieldName]) ? values[countryFieldName] : 'us',
20
35
  value: values[props.name] || '',
21
36
  countries: defaultCountries,
22
- onChange: (data: any) => {
23
- setValue(props.name, data.phone);
24
- setValue(countryFieldName, data.country);
37
+ onChange: (data) => {
38
+ safeUpdate(() => {
39
+ setValue(props.name, data.phone);
40
+ setValue(countryFieldName, data.country);
41
+ });
25
42
  },
26
43
  });
27
44
 
28
45
  const userCountry = useWatch({ control, name: countryFieldName });
29
46
  useEffect(() => {
30
- if (userCountry !== country) {
47
+ if (!userCountry || userCountry === country) return;
48
+
49
+ safeUpdate(() => {
31
50
  setCountry(userCountry);
32
- }
33
- // eslint-disable-next-line react-hooks/exhaustive-deps
34
- }, [userCountry]);
51
+ });
52
+ }, [userCountry, country, setCountry, safeUpdate]);
35
53
 
36
- const onCountryChange = (v: CountryIso2) => {
37
- setCountry(v);
38
- setValue(countryFieldName, v);
39
- };
54
+ const onCountryChange = useCallback(
55
+ (v: CountryIso2) => {
56
+ safeUpdate(() => {
57
+ setCountry(v);
58
+ });
59
+ },
60
+ [setCountry, safeUpdate]
61
+ );
40
62
 
41
63
  return (
42
64
  // @ts-ignore
@@ -41,6 +41,7 @@ import PaymentSkeleton from './skeleton/payment';
41
41
  import PaymentSuccess from './success';
42
42
  import PaymentSummary from './summary';
43
43
  import { useMobile } from '../hooks/mobile';
44
+ import { formatPhone } from '../libs/phone-validator';
44
45
 
45
46
  // eslint-disable-next-line react/no-unused-prop-types
46
47
  type Props = CheckoutContext & CheckoutCallbacks & { completed?: boolean; error?: any; showCheckoutSummary?: boolean };
@@ -78,20 +79,24 @@ function PaymentInner({
78
79
  defaultValues: {
79
80
  customer_name: customer?.name || session?.user?.fullName || '',
80
81
  customer_email: customer?.email || session?.user?.email || '',
81
- customer_phone: customer?.phone || session?.user?.phone || '',
82
+ customer_phone: formatPhone(customer?.phone || session?.user?.phone || ''),
82
83
  payment_method: defaultMethodId,
83
84
  payment_currency: defaultCurrencyId,
84
85
  billing_address: Object.assign(
85
86
  {
86
- country: '',
87
- state: '',
88
- city: '',
89
- line1: '',
90
- line2: '',
91
- postal_code: '',
87
+ country: session?.user?.address?.country || '',
88
+ state: session?.user?.address?.province || '',
89
+ city: session?.user?.address?.city || '',
90
+ line1: session?.user?.address?.line1 || '',
91
+ line2: session?.user?.address?.line2 || '',
92
+ postal_code: session?.user?.address?.postalCode || '',
92
93
  },
93
94
  customer?.address || {},
94
- { country: isValidCountry(customer?.address?.country || '') ? customer?.address?.country : 'us' }
95
+ {
96
+ country: isValidCountry(customer?.address?.country || session?.user?.address?.country || '')
97
+ ? customer?.address?.country
98
+ : 'us',
99
+ }
95
100
  ),
96
101
  },
97
102
  });
@@ -48,10 +48,6 @@ export default function ProductDonation({
48
48
  };
49
49
 
50
50
  const getDefaultPreset = () => {
51
- if (settings?.amount?.preset) {
52
- return formatAmount(settings.amount.preset);
53
- }
54
-
55
51
  try {
56
52
  const savedPreset = localStorage.getItem(getUserStorageKey(DONATION_PRESET_KEY_BASE));
57
53
  if (savedPreset) {
@@ -67,7 +63,13 @@ export default function ProductDonation({
67
63
  }
68
64
  if (presets.length > 0) {
69
65
  const middleIndex = Math.floor(presets.length / 2);
70
- return presets[middleIndex] || presets[0];
66
+ return presets[middleIndex];
67
+ }
68
+ if (settings?.amount?.preset) {
69
+ return formatAmount(settings.amount.preset);
70
+ }
71
+ if (presets.length > 0) {
72
+ return presets[0];
71
73
  }
72
74
  return '0';
73
75
  };