@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.
- package/es/components/over-due-invoice-payment.d.ts +3 -1
- package/es/components/over-due-invoice-payment.js +15 -7
- package/es/libs/phone-validator.d.ts +7 -0
- package/es/libs/phone-validator.js +93 -2
- package/es/locales/en.js +5 -4
- package/es/locales/zh.js +5 -3
- package/es/payment/donation-form.js +11 -8
- package/es/payment/form/index.js +101 -65
- package/es/payment/form/phone.js +31 -10
- package/es/payment/index.js +11 -8
- package/es/payment/product-donation.js +7 -4
- package/lib/components/over-due-invoice-payment.d.ts +3 -1
- package/lib/components/over-due-invoice-payment.js +15 -7
- package/lib/libs/phone-validator.d.ts +7 -0
- package/lib/libs/phone-validator.js +97 -6
- package/lib/locales/en.js +5 -4
- package/lib/locales/zh.js +5 -3
- package/lib/payment/donation-form.js +9 -8
- package/lib/payment/form/index.js +106 -62
- package/lib/payment/form/phone.js +25 -9
- package/lib/payment/index.js +9 -8
- package/lib/payment/product-donation.js +7 -4
- package/package.json +6 -6
- package/src/components/over-due-invoice-payment.tsx +14 -6
- package/src/libs/phone-validator.ts +89 -2
- package/src/locales/en.tsx +4 -4
- package/src/locales/zh.tsx +4 -3
- package/src/payment/donation-form.tsx +13 -8
- package/src/payment/form/index.tsx +133 -69
- package/src/payment/form/phone.tsx +34 -12
- package/src/payment/index.tsx +13 -8
- package/src/payment/product-donation.tsx +7 -5
|
@@ -17,6 +17,7 @@ type Props = {
|
|
|
17
17
|
dialogProps?: DialogProps;
|
|
18
18
|
detailLinkOptions?: DetailLinkOptions;
|
|
19
19
|
successToast?: boolean;
|
|
20
|
+
alertMessage?: string;
|
|
20
21
|
children?: (handlePay: (item: SummaryItem) => void, data: {
|
|
21
22
|
subscription?: Subscription;
|
|
22
23
|
summary: {
|
|
@@ -32,7 +33,7 @@ type SummaryItem = {
|
|
|
32
33
|
currency: PaymentCurrency;
|
|
33
34
|
method: PaymentMethod;
|
|
34
35
|
};
|
|
35
|
-
declare function OverdueInvoicePayment({ subscriptionId, customerId, mode, dialogProps, children, onPaid, detailLinkOptions, successToast, }: Props): import("react").JSX.Element | null;
|
|
36
|
+
declare function OverdueInvoicePayment({ subscriptionId, customerId, mode, dialogProps, children, onPaid, detailLinkOptions, successToast, alertMessage, }: Props): import("react").JSX.Element | null;
|
|
36
37
|
declare namespace OverdueInvoicePayment {
|
|
37
38
|
var defaultProps: {
|
|
38
39
|
mode: string;
|
|
@@ -47,6 +48,7 @@ declare namespace OverdueInvoicePayment {
|
|
|
47
48
|
subscriptionId: undefined;
|
|
48
49
|
customerId: undefined;
|
|
49
50
|
successToast: boolean;
|
|
51
|
+
alertMessage: string;
|
|
50
52
|
};
|
|
51
53
|
}
|
|
52
54
|
export default OverdueInvoicePayment;
|
|
@@ -35,7 +35,8 @@ function OverdueInvoicePayment({
|
|
|
35
35
|
onPaid = () => {
|
|
36
36
|
},
|
|
37
37
|
detailLinkOptions = { enabled: true },
|
|
38
|
-
successToast = true
|
|
38
|
+
successToast = true,
|
|
39
|
+
alertMessage = ""
|
|
39
40
|
}) {
|
|
40
41
|
const { t } = useLocaleContext();
|
|
41
42
|
const { connect } = usePaymentContext();
|
|
@@ -245,19 +246,25 @@ function OverdueInvoicePayment({
|
|
|
245
246
|
});
|
|
246
247
|
}
|
|
247
248
|
if (customerId) {
|
|
249
|
+
let title = "";
|
|
248
250
|
if (summaryList.length === 1) {
|
|
249
|
-
|
|
251
|
+
title = t("payment.customer.overdue.title", {
|
|
250
252
|
subscriptionCount: data.subscriptionCount || 0,
|
|
251
253
|
count: data.invoices?.length,
|
|
252
254
|
total: formatAmount(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
|
|
253
255
|
symbol: summaryList[0]?.currency?.symbol,
|
|
254
256
|
method: getMethodText(summaryList[0]?.method)
|
|
255
257
|
});
|
|
258
|
+
} else {
|
|
259
|
+
title = t("payment.customer.overdue.simpleTitle", {
|
|
260
|
+
subscriptionCount: data.subscriptionCount || 0,
|
|
261
|
+
count: data.invoices?.length
|
|
262
|
+
});
|
|
256
263
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
})
|
|
264
|
+
if (alertMessage) {
|
|
265
|
+
return `${title}${alertMessage}`;
|
|
266
|
+
}
|
|
267
|
+
return `${title}${t("payment.customer.overdue.defaultAlert")}`;
|
|
261
268
|
}
|
|
262
269
|
return "";
|
|
263
270
|
};
|
|
@@ -388,6 +395,7 @@ OverdueInvoicePayment.defaultProps = {
|
|
|
388
395
|
detailLinkOptions: { enabled: true },
|
|
389
396
|
subscriptionId: void 0,
|
|
390
397
|
customerId: void 0,
|
|
391
|
-
successToast: true
|
|
398
|
+
successToast: true,
|
|
399
|
+
alertMessage: ""
|
|
392
400
|
};
|
|
393
401
|
export default OverdueInvoicePayment;
|
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
export declare const getPhoneUtil: () => Promise<any>;
|
|
2
2
|
export declare const validatePhoneNumber: (phoneNumber: string) => Promise<any>;
|
|
3
|
+
/**
|
|
4
|
+
* Format a phone number to international format
|
|
5
|
+
* @param phoneNumber The original phone number
|
|
6
|
+
* @param defaultCountry Default country code (ISO 3166-1 alpha-2)
|
|
7
|
+
* @returns Formatted phone number
|
|
8
|
+
*/
|
|
9
|
+
export declare const formatPhone: (phoneNumber: string | undefined, defaultCountry?: string) => string;
|
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
let phoneUtil = null;
|
|
2
2
|
export const getPhoneUtil = async () => {
|
|
3
3
|
if (!phoneUtil) {
|
|
4
|
-
const
|
|
4
|
+
const result = await import(
|
|
5
5
|
/* webpackChunkName: "phone-util" */
|
|
6
6
|
"google-libphonenumber"
|
|
7
7
|
);
|
|
8
|
+
const PhoneNumberUtil = (result.default || result)?.PhoneNumberUtil;
|
|
9
|
+
if (!PhoneNumberUtil) {
|
|
10
|
+
throw new Error("PhoneNumberUtil not found");
|
|
11
|
+
}
|
|
8
12
|
phoneUtil = PhoneNumberUtil.getInstance();
|
|
9
13
|
}
|
|
10
14
|
return phoneUtil;
|
|
11
15
|
};
|
|
12
16
|
export const validatePhoneNumber = async (phoneNumber) => {
|
|
13
17
|
try {
|
|
14
|
-
|
|
18
|
+
let util = null;
|
|
19
|
+
try {
|
|
20
|
+
util = await getPhoneUtil();
|
|
21
|
+
} catch (err) {
|
|
22
|
+
const pattern = /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/im;
|
|
23
|
+
return pattern.test(phoneNumber);
|
|
24
|
+
}
|
|
15
25
|
const parsed = util.parseAndKeepRawInput(phoneNumber);
|
|
16
26
|
return util.isValidNumber(parsed);
|
|
17
27
|
} catch (err) {
|
|
@@ -19,3 +29,84 @@ export const validatePhoneNumber = async (phoneNumber) => {
|
|
|
19
29
|
return false;
|
|
20
30
|
}
|
|
21
31
|
};
|
|
32
|
+
export const formatPhone = (phoneNumber, defaultCountry = "US") => {
|
|
33
|
+
if (!phoneNumber || phoneNumber.trim() === "") {
|
|
34
|
+
return "";
|
|
35
|
+
}
|
|
36
|
+
const cleanedNumber = phoneNumber.replace(/[^\d+]/g, "");
|
|
37
|
+
if (cleanedNumber.startsWith("+")) {
|
|
38
|
+
return cleanedNumber;
|
|
39
|
+
}
|
|
40
|
+
const COUNTRY_CODES = {
|
|
41
|
+
US: "1",
|
|
42
|
+
// United States
|
|
43
|
+
CA: "1",
|
|
44
|
+
// Canada
|
|
45
|
+
CN: "86",
|
|
46
|
+
// China
|
|
47
|
+
HK: "852",
|
|
48
|
+
// Hong Kong
|
|
49
|
+
IN: "91",
|
|
50
|
+
// India
|
|
51
|
+
UK: "44",
|
|
52
|
+
// United Kingdom
|
|
53
|
+
GB: "44",
|
|
54
|
+
// United Kingdom
|
|
55
|
+
JP: "81",
|
|
56
|
+
// Japan
|
|
57
|
+
KR: "82",
|
|
58
|
+
// South Korea
|
|
59
|
+
AU: "61",
|
|
60
|
+
// Australia
|
|
61
|
+
DE: "49",
|
|
62
|
+
// Germany
|
|
63
|
+
FR: "33",
|
|
64
|
+
// France
|
|
65
|
+
IT: "39",
|
|
66
|
+
// Italy
|
|
67
|
+
ES: "34",
|
|
68
|
+
// Spain
|
|
69
|
+
BR: "55",
|
|
70
|
+
// Brazil
|
|
71
|
+
RU: "7",
|
|
72
|
+
// Russia
|
|
73
|
+
MX: "52",
|
|
74
|
+
// Mexico
|
|
75
|
+
SG: "65",
|
|
76
|
+
// Singapore
|
|
77
|
+
AE: "971"
|
|
78
|
+
// UAE
|
|
79
|
+
};
|
|
80
|
+
const COUNTRY_PATTERNS = [
|
|
81
|
+
[/^1[3-9]\d{9}$/, "86"],
|
|
82
|
+
// China mobile: 11 digits, starts with 1
|
|
83
|
+
[/^\d{10}$/, "1"],
|
|
84
|
+
// US/Canada: 10 digits
|
|
85
|
+
[/^[6-9]\d{9}$/, "91"],
|
|
86
|
+
// India: 10 digits, starts with 6-9
|
|
87
|
+
[/^0[1-9]\d{8,9}$/, "81"],
|
|
88
|
+
// Japan: 10-11 digits, starts with 0
|
|
89
|
+
[/^07\d{9}$/, "44"],
|
|
90
|
+
// UK mobile: 11 digits, starts with 07
|
|
91
|
+
[/^04\d{8}$/, "61"],
|
|
92
|
+
// Australia mobile: 10 digits, starts with 04
|
|
93
|
+
[/^01[0-9]\d{7,8}$/, "82"],
|
|
94
|
+
// Korea mobile: 10-11 digits, starts with 01
|
|
95
|
+
[/^[0-9]\d{8}$/, "86"]
|
|
96
|
+
// China landline: 9 digits
|
|
97
|
+
];
|
|
98
|
+
let numberToFormat = cleanedNumber;
|
|
99
|
+
if (numberToFormat.startsWith("0")) {
|
|
100
|
+
numberToFormat = numberToFormat.substring(1);
|
|
101
|
+
}
|
|
102
|
+
for (const [pattern, countryCode2] of COUNTRY_PATTERNS) {
|
|
103
|
+
if (pattern.test(cleanedNumber)) {
|
|
104
|
+
if (cleanedNumber.startsWith("0") && !["1", "86"].includes(countryCode2)) {
|
|
105
|
+
return `+${countryCode2}${cleanedNumber.substring(1)}`;
|
|
106
|
+
}
|
|
107
|
+
return `+${countryCode2}${cleanedNumber}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const countryCode = COUNTRY_CODES[defaultCountry.toUpperCase()] || defaultCountry;
|
|
111
|
+
return `+${countryCode}${numberToFormat}`;
|
|
112
|
+
};
|
package/es/locales/en.js
CHANGED
|
@@ -242,7 +242,7 @@ export default flat({
|
|
|
242
242
|
warning: "Past due invoices need to be paid immediately, otherwise you can not make new purchases anymore.",
|
|
243
243
|
alert: {
|
|
244
244
|
title: "You have unpaid invoices",
|
|
245
|
-
|
|
245
|
+
customMessage: "Please pay immediately, otherwise new purchases or subscriptions will be prohibited.",
|
|
246
246
|
confirm: "Pay Now"
|
|
247
247
|
},
|
|
248
248
|
view: "View Due Invoices"
|
|
@@ -318,9 +318,10 @@ export default flat({
|
|
|
318
318
|
owner: "Subscription Owner"
|
|
319
319
|
},
|
|
320
320
|
overdue: {
|
|
321
|
-
title: "You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}{method}.
|
|
322
|
-
simpleTitle: "You have {count} due invoices.
|
|
323
|
-
empty: "Great! You have no due invoices."
|
|
321
|
+
title: "You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}{method}. ",
|
|
322
|
+
simpleTitle: "You have {count} due invoices. ",
|
|
323
|
+
empty: "Great! You have no due invoices.",
|
|
324
|
+
defaultAlert: "Please pay immediately to avoid service disruption."
|
|
324
325
|
}
|
|
325
326
|
},
|
|
326
327
|
invoice: {
|
package/es/locales/zh.js
CHANGED
|
@@ -243,6 +243,7 @@ export default flat({
|
|
|
243
243
|
alert: {
|
|
244
244
|
title: "\u4F60\u6709\u6B20\u8D39\u8D26\u5355",
|
|
245
245
|
description: "\u770B\u8D77\u6765\u4F60\u6709\u6B20\u8D39\u7684\u8D26\u5355\uFF0C\u5728\u4F60\u652F\u4ED8\u6240\u6709\u6B20\u8D39\u8D26\u5355\u4E4B\u524D\uFF0C\u65B0\u7684\u8D2D\u4E70\u6216\u8005\u8BA2\u9605\u5C06\u88AB\u7981\u6B62\uFF0C\u8BF7\u4E0D\u8981\u8C03\u76AE\u3002",
|
|
246
|
+
customMessage: "\u8BF7\u7ACB\u5373\u652F\u4ED8\uFF0C\u5426\u5219\u65B0\u7684\u8D2D\u4E70\u6216\u8005\u8BA2\u9605\u5C06\u88AB\u7981\u6B62\u3002",
|
|
246
247
|
confirm: "\u53BB\u652F\u4ED8"
|
|
247
248
|
},
|
|
248
249
|
view: "\u67E5\u770B\u6B20\u8D39\u660E\u7EC6"
|
|
@@ -318,9 +319,10 @@ export default flat({
|
|
|
318
319
|
owner: "\u8BA2\u9605\u62E5\u6709\u8005"
|
|
319
320
|
},
|
|
320
321
|
overdue: {
|
|
321
|
-
title: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u6D89\u53CA {subscriptionCount} \u4E2A\u8BA2\u9605\uFF0C\u603B\u91D1\u989D {total} {symbol}{method}\u3002
|
|
322
|
-
simpleTitle: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355
|
|
323
|
-
empty: "\u606D\u559C\uFF01\u60A8\u5F53\u524D\u6CA1\u6709\u6B20\u8D39\u8D26\u5355\u3002"
|
|
322
|
+
title: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u6D89\u53CA {subscriptionCount} \u4E2A\u8BA2\u9605\uFF0C\u603B\u91D1\u989D {total} {symbol}{method}\u3002",
|
|
323
|
+
simpleTitle: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355,",
|
|
324
|
+
empty: "\u606D\u559C\uFF01\u60A8\u5F53\u524D\u6CA1\u6709\u6B20\u8D39\u8D26\u5355\u3002",
|
|
325
|
+
defaultAlert: "\u8BF7\u7ACB\u5373\u652F\u4ED8\uFF0C\u4EE5\u514D\u5F71\u54CD\u60A8\u7684\u4F7F\u7528\u3002"
|
|
324
326
|
}
|
|
325
327
|
},
|
|
326
328
|
invoice: {
|
|
@@ -29,6 +29,7 @@ import ProductDonation from "./product-donation.js";
|
|
|
29
29
|
import ConfirmDialog from "../components/confirm.js";
|
|
30
30
|
import PaymentBeneficiaries from "../components/payment-beneficiaries.js";
|
|
31
31
|
import DonationSkeleton from "./skeleton/donation.js";
|
|
32
|
+
import { formatPhone } from "../libs/phone-validator.js";
|
|
32
33
|
const getBenefits = async (id, url) => {
|
|
33
34
|
const { data } = await api.get(`/api/payment-links/${id}/benefits?${url ? `url=${url}` : ""}`);
|
|
34
35
|
return data;
|
|
@@ -80,20 +81,22 @@ function PaymentInner({
|
|
|
80
81
|
defaultValues: {
|
|
81
82
|
customer_name: customer?.name || session?.user?.fullName || "",
|
|
82
83
|
customer_email: customer?.email || session?.user?.email || "",
|
|
83
|
-
customer_phone: customer?.phone || session?.user?.phone || "",
|
|
84
|
+
customer_phone: formatPhone(customer?.phone || session?.user?.phone || ""),
|
|
84
85
|
payment_method: defaultMethodId,
|
|
85
86
|
payment_currency: defaultCurrencyId,
|
|
86
87
|
billing_address: Object.assign(
|
|
87
88
|
{
|
|
88
|
-
country: "",
|
|
89
|
-
state: "",
|
|
90
|
-
city: "",
|
|
91
|
-
line1: "",
|
|
92
|
-
line2: "",
|
|
93
|
-
postal_code: ""
|
|
89
|
+
country: session?.user?.address?.country || "",
|
|
90
|
+
state: session?.user?.address?.province || "",
|
|
91
|
+
city: session?.user?.address?.city || "",
|
|
92
|
+
line1: session?.user?.address?.line1 || "",
|
|
93
|
+
line2: session?.user?.address?.line2 || "",
|
|
94
|
+
postal_code: session?.user?.address?.postalCode || ""
|
|
94
95
|
},
|
|
95
96
|
customer?.address || {},
|
|
96
|
-
{
|
|
97
|
+
{
|
|
98
|
+
country: isValidCountry(customer?.address?.country || session?.user?.address?.country || "") ? customer?.address?.country : "us"
|
|
99
|
+
}
|
|
97
100
|
)
|
|
98
101
|
}
|
|
99
102
|
});
|
package/es/payment/form/index.js
CHANGED
|
@@ -11,7 +11,6 @@ import { joinURL } from "ufo";
|
|
|
11
11
|
import { dispatch } from "use-bus";
|
|
12
12
|
import isEmail from "validator/es/lib/isEmail";
|
|
13
13
|
import isEmpty from "lodash/isEmpty";
|
|
14
|
-
import ConfirmDialog from "../../components/confirm.js";
|
|
15
14
|
import FormInput from "../../components/input.js";
|
|
16
15
|
import { usePaymentContext } from "../../contexts/payment.js";
|
|
17
16
|
import { useSubscription } from "../../hooks/subscription.js";
|
|
@@ -29,8 +28,9 @@ import CurrencySelector from "./currency.js";
|
|
|
29
28
|
import PhoneInput from "./phone.js";
|
|
30
29
|
import StripeCheckout from "./stripe/index.js";
|
|
31
30
|
import { useMobile } from "../../hooks/mobile.js";
|
|
32
|
-
import { validatePhoneNumber } from "../../libs/phone-validator.js";
|
|
31
|
+
import { formatPhone, validatePhoneNumber } from "../../libs/phone-validator.js";
|
|
33
32
|
import LoadingButton from "../../components/loading-button.js";
|
|
33
|
+
import OverdueInvoicePayment from "../../components/over-due-invoice-payment.js";
|
|
34
34
|
export const waitForCheckoutComplete = async (sessionId) => {
|
|
35
35
|
let result;
|
|
36
36
|
await pWaitFor(
|
|
@@ -53,6 +53,31 @@ export const hasDidWallet = (user) => {
|
|
|
53
53
|
const connected = user?.connectedAccounts || user?.extraConfigs?.connectedAccounts || [];
|
|
54
54
|
return connected.some((x) => x.provider === "wallet");
|
|
55
55
|
};
|
|
56
|
+
const setUserFormValues = (userInfo, currentValues, setValue, options = {}) => {
|
|
57
|
+
const { preferExisting = true } = options;
|
|
58
|
+
const basicFields = {
|
|
59
|
+
customer_name: userInfo.name || userInfo.fullName,
|
|
60
|
+
customer_email: userInfo.email,
|
|
61
|
+
customer_phone: formatPhone(userInfo.phone)
|
|
62
|
+
};
|
|
63
|
+
const addressFields = {
|
|
64
|
+
"billing_address.state": userInfo.address?.state || userInfo.address?.province,
|
|
65
|
+
"billing_address.line1": userInfo.address?.line1,
|
|
66
|
+
"billing_address.line2": userInfo.address?.line2,
|
|
67
|
+
"billing_address.city": userInfo.address?.city,
|
|
68
|
+
"billing_address.postal_code": userInfo.address?.postal_code || userInfo.address?.postalCode,
|
|
69
|
+
"billing_address.country": userInfo.address?.country
|
|
70
|
+
};
|
|
71
|
+
if (options.showPhone) {
|
|
72
|
+
addressFields["billing_address.country"] = userInfo.metadata?.phone?.country || userInfo.address?.country;
|
|
73
|
+
}
|
|
74
|
+
const allFields = { ...addressFields, ...basicFields };
|
|
75
|
+
Object.entries(allFields).forEach(([field, value]) => {
|
|
76
|
+
if (!preferExisting || !currentValues[field.split(".")[0]]) {
|
|
77
|
+
setValue(field, value);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
56
81
|
PaymentForm.defaultProps = {
|
|
57
82
|
onlyShowBtn: false,
|
|
58
83
|
isDonation: false
|
|
@@ -129,22 +154,30 @@ export default function PaymentForm({
|
|
|
129
154
|
useEffect(() => {
|
|
130
155
|
if (session?.user) {
|
|
131
156
|
const values = getValues();
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
157
|
+
setUserFormValues(session.user, values, setValue, {
|
|
158
|
+
preferExisting: false,
|
|
159
|
+
showPhone: checkoutSession.phone_number_collection?.enabled
|
|
160
|
+
});
|
|
161
|
+
} else {
|
|
162
|
+
setUserFormValues(
|
|
163
|
+
{
|
|
164
|
+
name: "",
|
|
165
|
+
email: "",
|
|
166
|
+
phone: "",
|
|
167
|
+
address: {
|
|
168
|
+
state: "",
|
|
169
|
+
line1: "",
|
|
170
|
+
line2: "",
|
|
171
|
+
city: "",
|
|
172
|
+
postal_code: ""
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{},
|
|
176
|
+
setValue,
|
|
177
|
+
{ preferExisting: false, showPhone: checkoutSession.phone_number_collection?.enabled }
|
|
178
|
+
);
|
|
146
179
|
}
|
|
147
|
-
}, [session?.user, getValues, setValue]);
|
|
180
|
+
}, [session?.user, getValues, setValue, checkoutSession.phone_number_collection?.enabled]);
|
|
148
181
|
useEffect(() => {
|
|
149
182
|
setValue("payment_method", currencies[paymentCurrencyIndex]?.method?.id);
|
|
150
183
|
setValue("payment_currency", currencies[paymentCurrencyIndex]?.id);
|
|
@@ -175,7 +208,7 @@ export default function PaymentForm({
|
|
|
175
208
|
buttonText = session?.user || isDonation ? buttonText : t("payment.checkout.connect", { action: buttonText });
|
|
176
209
|
const method = paymentMethods.find((x) => x.id === paymentMethod);
|
|
177
210
|
const isDonationMode = checkoutSession?.submit_type === "donate" && isDonation;
|
|
178
|
-
const showForm = session?.user;
|
|
211
|
+
const showForm = !!session?.user;
|
|
179
212
|
const skipBindWallet = method.type === "stripe";
|
|
180
213
|
const handleConnected = async () => {
|
|
181
214
|
try {
|
|
@@ -199,33 +232,9 @@ export default function PaymentForm({
|
|
|
199
232
|
const { data: profile } = await api.get("/api/customers/me?fallback=1");
|
|
200
233
|
if (profile) {
|
|
201
234
|
const values = getValues();
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
if (!values.customer_email) {
|
|
206
|
-
setValue("customer_email", profile.email);
|
|
207
|
-
}
|
|
208
|
-
if (!values.customer_phone) {
|
|
209
|
-
setValue("customer_phone", profile.phone);
|
|
210
|
-
}
|
|
211
|
-
if (profile.address?.country) {
|
|
212
|
-
setValue("billing_address.country", profile.address.country);
|
|
213
|
-
}
|
|
214
|
-
if (profile.address?.state) {
|
|
215
|
-
setValue("billing_address.state", profile.address.state);
|
|
216
|
-
}
|
|
217
|
-
if (profile.address?.line1) {
|
|
218
|
-
setValue("billing_address.line1", profile.address.line1);
|
|
219
|
-
}
|
|
220
|
-
if (profile.address?.line2) {
|
|
221
|
-
setValue("billing_address.line2", profile.address.line2);
|
|
222
|
-
}
|
|
223
|
-
if (profile.address?.city) {
|
|
224
|
-
setValue("billing_address.city", profile.address.city);
|
|
225
|
-
}
|
|
226
|
-
if (profile.address?.postal_code) {
|
|
227
|
-
setValue("billing_address.postal_code", profile.address.postal_code);
|
|
228
|
-
}
|
|
235
|
+
setUserFormValues(profile, values, setValue, {
|
|
236
|
+
showPhone: checkoutSession.phone_number_collection?.enabled
|
|
237
|
+
});
|
|
229
238
|
}
|
|
230
239
|
};
|
|
231
240
|
const onFormSubmit = async (data) => {
|
|
@@ -377,17 +386,32 @@ export default function PaymentForm({
|
|
|
377
386
|
}
|
|
378
387
|
) }),
|
|
379
388
|
state.customerLimited && /* @__PURE__ */ jsx(
|
|
380
|
-
|
|
389
|
+
OverdueInvoicePayment,
|
|
381
390
|
{
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
+
customerId: customer?.id || session?.user?.did,
|
|
392
|
+
onPaid: () => {
|
|
393
|
+
setState({ customerLimited: false });
|
|
394
|
+
onAction();
|
|
395
|
+
},
|
|
396
|
+
alertMessage: t("payment.customer.pastDue.alert.customMessage"),
|
|
397
|
+
detailLinkOptions: {
|
|
398
|
+
enabled: true,
|
|
399
|
+
onClick: () => {
|
|
400
|
+
setState({ customerLimited: false });
|
|
401
|
+
window.open(
|
|
402
|
+
joinURL(
|
|
403
|
+
getPrefix(),
|
|
404
|
+
`/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`
|
|
405
|
+
),
|
|
406
|
+
"_self"
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
dialogProps: {
|
|
411
|
+
open: state.customerLimited,
|
|
412
|
+
onClose: () => setState({ customerLimited: false }),
|
|
413
|
+
title: t("payment.customer.pastDue.alert.title")
|
|
414
|
+
}
|
|
391
415
|
}
|
|
392
416
|
)
|
|
393
417
|
] });
|
|
@@ -528,17 +552,29 @@ export default function PaymentForm({
|
|
|
528
552
|
["subscription", "setup"].includes(checkoutSession.mode) && /* @__PURE__ */ jsx(Typography, { sx: { mt: 2.5, color: "text.lighter", fontSize: "0.7875rem", lineHeight: "0.9625rem" }, children: t("payment.checkout.confirm", { payee }) })
|
|
529
553
|
] }) }),
|
|
530
554
|
state.customerLimited && /* @__PURE__ */ jsx(
|
|
531
|
-
|
|
555
|
+
OverdueInvoicePayment,
|
|
532
556
|
{
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
557
|
+
customerId: customer?.id || session?.user?.didssion?.user?.did,
|
|
558
|
+
onPaid: () => {
|
|
559
|
+
setState({ customerLimited: false });
|
|
560
|
+
onAction();
|
|
561
|
+
},
|
|
562
|
+
alertMessage: t("payment.customer.pastDue.alert.customMessage"),
|
|
563
|
+
detailLinkOptions: {
|
|
564
|
+
enabled: true,
|
|
565
|
+
onClick: () => {
|
|
566
|
+
setState({ customerLimited: false });
|
|
567
|
+
window.open(
|
|
568
|
+
joinURL(getPrefix(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`),
|
|
569
|
+
"_self"
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
dialogProps: {
|
|
574
|
+
open: state.customerLimited,
|
|
575
|
+
onClose: () => setState({ customerLimited: false }),
|
|
576
|
+
title: t("payment.customer.pastDue.alert.title")
|
|
577
|
+
}
|
|
542
578
|
}
|
|
543
579
|
)
|
|
544
580
|
] });
|
package/es/payment/form/phone.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
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 FormInput from "../../components/input.js";
|
|
@@ -11,25 +11,46 @@ export default function PhoneInput({ ...props }) {
|
|
|
11
11
|
const countryFieldName = props.countryFieldName || "billing_address.country";
|
|
12
12
|
const { control, getValues, setValue } = useFormContext();
|
|
13
13
|
const values = getValues();
|
|
14
|
+
const isUpdatingRef = useRef(false);
|
|
15
|
+
const safeUpdate = useCallback((callback) => {
|
|
16
|
+
if (isUpdatingRef.current)
|
|
17
|
+
return;
|
|
18
|
+
try {
|
|
19
|
+
isUpdatingRef.current = true;
|
|
20
|
+
callback();
|
|
21
|
+
} finally {
|
|
22
|
+
requestAnimationFrame(() => {
|
|
23
|
+
isUpdatingRef.current = false;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}, []);
|
|
14
27
|
const { phone, handlePhoneValueChange, inputRef, country, setCountry } = usePhoneInput({
|
|
15
28
|
defaultCountry: isValidCountry(values[countryFieldName]) ? values[countryFieldName] : "us",
|
|
16
29
|
value: values[props.name] || "",
|
|
17
30
|
countries: defaultCountries,
|
|
18
31
|
onChange: (data) => {
|
|
19
|
-
|
|
20
|
-
|
|
32
|
+
safeUpdate(() => {
|
|
33
|
+
setValue(props.name, data.phone);
|
|
34
|
+
setValue(countryFieldName, data.country);
|
|
35
|
+
});
|
|
21
36
|
}
|
|
22
37
|
});
|
|
23
38
|
const userCountry = useWatch({ control, name: countryFieldName });
|
|
24
39
|
useEffect(() => {
|
|
25
|
-
if (userCountry
|
|
40
|
+
if (!userCountry || userCountry === country)
|
|
41
|
+
return;
|
|
42
|
+
safeUpdate(() => {
|
|
26
43
|
setCountry(userCountry);
|
|
27
|
-
}
|
|
28
|
-
}, [userCountry]);
|
|
29
|
-
const onCountryChange = (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
});
|
|
45
|
+
}, [userCountry, country, setCountry, safeUpdate]);
|
|
46
|
+
const onCountryChange = useCallback(
|
|
47
|
+
(v) => {
|
|
48
|
+
safeUpdate(() => {
|
|
49
|
+
setCountry(v);
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
[setCountry, safeUpdate]
|
|
53
|
+
);
|
|
33
54
|
return (
|
|
34
55
|
// @ts-ignore
|
|
35
56
|
/* @__PURE__ */ jsx(
|
package/es/payment/index.js
CHANGED
|
@@ -28,6 +28,7 @@ import PaymentSkeleton from "./skeleton/payment.js";
|
|
|
28
28
|
import PaymentSuccess from "./success.js";
|
|
29
29
|
import PaymentSummary from "./summary.js";
|
|
30
30
|
import { useMobile } from "../hooks/mobile.js";
|
|
31
|
+
import { formatPhone } from "../libs/phone-validator.js";
|
|
31
32
|
PaymentInner.defaultProps = {
|
|
32
33
|
completed: false,
|
|
33
34
|
showCheckoutSummary: true
|
|
@@ -58,20 +59,22 @@ function PaymentInner({
|
|
|
58
59
|
defaultValues: {
|
|
59
60
|
customer_name: customer?.name || session?.user?.fullName || "",
|
|
60
61
|
customer_email: customer?.email || session?.user?.email || "",
|
|
61
|
-
customer_phone: customer?.phone || session?.user?.phone || "",
|
|
62
|
+
customer_phone: formatPhone(customer?.phone || session?.user?.phone || ""),
|
|
62
63
|
payment_method: defaultMethodId,
|
|
63
64
|
payment_currency: defaultCurrencyId,
|
|
64
65
|
billing_address: Object.assign(
|
|
65
66
|
{
|
|
66
|
-
country: "",
|
|
67
|
-
state: "",
|
|
68
|
-
city: "",
|
|
69
|
-
line1: "",
|
|
70
|
-
line2: "",
|
|
71
|
-
postal_code: ""
|
|
67
|
+
country: session?.user?.address?.country || "",
|
|
68
|
+
state: session?.user?.address?.province || "",
|
|
69
|
+
city: session?.user?.address?.city || "",
|
|
70
|
+
line1: session?.user?.address?.line1 || "",
|
|
71
|
+
line2: session?.user?.address?.line2 || "",
|
|
72
|
+
postal_code: session?.user?.address?.postalCode || ""
|
|
72
73
|
},
|
|
73
74
|
customer?.address || {},
|
|
74
|
-
{
|
|
75
|
+
{
|
|
76
|
+
country: isValidCountry(customer?.address?.country || session?.user?.address?.country || "") ? customer?.address?.country : "us"
|
|
77
|
+
}
|
|
75
78
|
)
|
|
76
79
|
}
|
|
77
80
|
});
|
|
@@ -35,9 +35,6 @@ export default function ProductDonation({
|
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
37
|
const getDefaultPreset = () => {
|
|
38
|
-
if (settings?.amount?.preset) {
|
|
39
|
-
return formatAmount(settings.amount.preset);
|
|
40
|
-
}
|
|
41
38
|
try {
|
|
42
39
|
const savedPreset = localStorage.getItem(getUserStorageKey(DONATION_PRESET_KEY_BASE));
|
|
43
40
|
if (savedPreset) {
|
|
@@ -53,7 +50,13 @@ export default function ProductDonation({
|
|
|
53
50
|
}
|
|
54
51
|
if (presets.length > 0) {
|
|
55
52
|
const middleIndex = Math.floor(presets.length / 2);
|
|
56
|
-
return presets[middleIndex]
|
|
53
|
+
return presets[middleIndex];
|
|
54
|
+
}
|
|
55
|
+
if (settings?.amount?.preset) {
|
|
56
|
+
return formatAmount(settings.amount.preset);
|
|
57
|
+
}
|
|
58
|
+
if (presets.length > 0) {
|
|
59
|
+
return presets[0];
|
|
57
60
|
}
|
|
58
61
|
return "0";
|
|
59
62
|
};
|
|
@@ -17,6 +17,7 @@ type Props = {
|
|
|
17
17
|
dialogProps?: DialogProps;
|
|
18
18
|
detailLinkOptions?: DetailLinkOptions;
|
|
19
19
|
successToast?: boolean;
|
|
20
|
+
alertMessage?: string;
|
|
20
21
|
children?: (handlePay: (item: SummaryItem) => void, data: {
|
|
21
22
|
subscription?: Subscription;
|
|
22
23
|
summary: {
|
|
@@ -32,7 +33,7 @@ type SummaryItem = {
|
|
|
32
33
|
currency: PaymentCurrency;
|
|
33
34
|
method: PaymentMethod;
|
|
34
35
|
};
|
|
35
|
-
declare function OverdueInvoicePayment({ subscriptionId, customerId, mode, dialogProps, children, onPaid, detailLinkOptions, successToast, }: Props): import("react").JSX.Element | null;
|
|
36
|
+
declare function OverdueInvoicePayment({ subscriptionId, customerId, mode, dialogProps, children, onPaid, detailLinkOptions, successToast, alertMessage, }: Props): import("react").JSX.Element | null;
|
|
36
37
|
declare namespace OverdueInvoicePayment {
|
|
37
38
|
var defaultProps: {
|
|
38
39
|
mode: string;
|
|
@@ -47,6 +48,7 @@ declare namespace OverdueInvoicePayment {
|
|
|
47
48
|
subscriptionId: undefined;
|
|
48
49
|
customerId: undefined;
|
|
49
50
|
successToast: boolean;
|
|
51
|
+
alertMessage: string;
|
|
50
52
|
};
|
|
51
53
|
}
|
|
52
54
|
export default OverdueInvoicePayment;
|