@blocklet/payment-react 1.18.19 → 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 +7 -5
- package/es/locales/zh.js +7 -4
- package/es/payment/donation-form.js +62 -22
- 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 +7 -5
- package/lib/locales/zh.js +7 -4
- package/lib/payment/donation-form.js +51 -15
- 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 +6 -5
- package/src/locales/zh.tsx +6 -4
- package/src/payment/donation-form.tsx +57 -19
- 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
|
@@ -18,7 +18,6 @@ var _ufo = require("ufo");
|
|
|
18
18
|
var _useBus = require("use-bus");
|
|
19
19
|
var _isEmail = _interopRequireDefault(require("validator/es/lib/isEmail"));
|
|
20
20
|
var _isEmpty = _interopRequireDefault(require("lodash/isEmpty"));
|
|
21
|
-
var _confirm = _interopRequireDefault(require("../../components/confirm"));
|
|
22
21
|
var _input = _interopRequireDefault(require("../../components/input"));
|
|
23
22
|
var _payment = require("../../contexts/payment");
|
|
24
23
|
var _subscription = require("../../hooks/subscription");
|
|
@@ -31,6 +30,7 @@ var _stripe = _interopRequireDefault(require("./stripe"));
|
|
|
31
30
|
var _mobile = require("../../hooks/mobile");
|
|
32
31
|
var _phoneValidator = require("../../libs/phone-validator");
|
|
33
32
|
var _loadingButton = _interopRequireDefault(require("../../components/loading-button"));
|
|
33
|
+
var _overDueInvoicePayment = _interopRequireDefault(require("../../components/over-due-invoice-payment"));
|
|
34
34
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
35
35
|
const waitForCheckoutComplete = async sessionId => {
|
|
36
36
|
let result;
|
|
@@ -58,6 +58,36 @@ const hasDidWallet = user => {
|
|
|
58
58
|
return connected.some(x => x.provider === "wallet");
|
|
59
59
|
};
|
|
60
60
|
exports.hasDidWallet = hasDidWallet;
|
|
61
|
+
const setUserFormValues = (userInfo, currentValues, setValue, options = {}) => {
|
|
62
|
+
const {
|
|
63
|
+
preferExisting = true
|
|
64
|
+
} = options;
|
|
65
|
+
const basicFields = {
|
|
66
|
+
customer_name: userInfo.name || userInfo.fullName,
|
|
67
|
+
customer_email: userInfo.email,
|
|
68
|
+
customer_phone: (0, _phoneValidator.formatPhone)(userInfo.phone)
|
|
69
|
+
};
|
|
70
|
+
const addressFields = {
|
|
71
|
+
"billing_address.state": userInfo.address?.state || userInfo.address?.province,
|
|
72
|
+
"billing_address.line1": userInfo.address?.line1,
|
|
73
|
+
"billing_address.line2": userInfo.address?.line2,
|
|
74
|
+
"billing_address.city": userInfo.address?.city,
|
|
75
|
+
"billing_address.postal_code": userInfo.address?.postal_code || userInfo.address?.postalCode,
|
|
76
|
+
"billing_address.country": userInfo.address?.country
|
|
77
|
+
};
|
|
78
|
+
if (options.showPhone) {
|
|
79
|
+
addressFields["billing_address.country"] = userInfo.metadata?.phone?.country || userInfo.address?.country;
|
|
80
|
+
}
|
|
81
|
+
const allFields = {
|
|
82
|
+
...addressFields,
|
|
83
|
+
...basicFields
|
|
84
|
+
};
|
|
85
|
+
Object.entries(allFields).forEach(([field, value]) => {
|
|
86
|
+
if (!preferExisting || !currentValues[field.split(".")[0]]) {
|
|
87
|
+
setValue(field, value);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
};
|
|
61
91
|
PaymentForm.defaultProps = {
|
|
62
92
|
onlyShowBtn: false,
|
|
63
93
|
isDonation: false
|
|
@@ -148,22 +178,28 @@ function PaymentForm({
|
|
|
148
178
|
(0, _react.useEffect)(() => {
|
|
149
179
|
if (session?.user) {
|
|
150
180
|
const values = getValues();
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
181
|
+
setUserFormValues(session.user, values, setValue, {
|
|
182
|
+
preferExisting: false,
|
|
183
|
+
showPhone: checkoutSession.phone_number_collection?.enabled
|
|
184
|
+
});
|
|
185
|
+
} else {
|
|
186
|
+
setUserFormValues({
|
|
187
|
+
name: "",
|
|
188
|
+
email: "",
|
|
189
|
+
phone: "",
|
|
190
|
+
address: {
|
|
191
|
+
state: "",
|
|
192
|
+
line1: "",
|
|
193
|
+
line2: "",
|
|
194
|
+
city: "",
|
|
195
|
+
postal_code: ""
|
|
196
|
+
}
|
|
197
|
+
}, {}, setValue, {
|
|
198
|
+
preferExisting: false,
|
|
199
|
+
showPhone: checkoutSession.phone_number_collection?.enabled
|
|
200
|
+
});
|
|
165
201
|
}
|
|
166
|
-
}, [session?.user, getValues, setValue]);
|
|
202
|
+
}, [session?.user, getValues, setValue, checkoutSession.phone_number_collection?.enabled]);
|
|
167
203
|
(0, _react.useEffect)(() => {
|
|
168
204
|
setValue("payment_method", currencies[paymentCurrencyIndex]?.method?.id);
|
|
169
205
|
setValue("payment_currency", currencies[paymentCurrencyIndex]?.id);
|
|
@@ -199,7 +235,7 @@ function PaymentForm({
|
|
|
199
235
|
});
|
|
200
236
|
const method = paymentMethods.find(x => x.id === paymentMethod);
|
|
201
237
|
const isDonationMode = checkoutSession?.submit_type === "donate" && isDonation;
|
|
202
|
-
const showForm = session?.user;
|
|
238
|
+
const showForm = !!session?.user;
|
|
203
239
|
const skipBindWallet = method.type === "stripe";
|
|
204
240
|
const handleConnected = async () => {
|
|
205
241
|
try {
|
|
@@ -232,33 +268,9 @@ function PaymentForm({
|
|
|
232
268
|
} = await _api.default.get("/api/customers/me?fallback=1");
|
|
233
269
|
if (profile) {
|
|
234
270
|
const values = getValues();
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
if (!values.customer_email) {
|
|
239
|
-
setValue("customer_email", profile.email);
|
|
240
|
-
}
|
|
241
|
-
if (!values.customer_phone) {
|
|
242
|
-
setValue("customer_phone", profile.phone);
|
|
243
|
-
}
|
|
244
|
-
if (profile.address?.country) {
|
|
245
|
-
setValue("billing_address.country", profile.address.country);
|
|
246
|
-
}
|
|
247
|
-
if (profile.address?.state) {
|
|
248
|
-
setValue("billing_address.state", profile.address.state);
|
|
249
|
-
}
|
|
250
|
-
if (profile.address?.line1) {
|
|
251
|
-
setValue("billing_address.line1", profile.address.line1);
|
|
252
|
-
}
|
|
253
|
-
if (profile.address?.line2) {
|
|
254
|
-
setValue("billing_address.line2", profile.address.line2);
|
|
255
|
-
}
|
|
256
|
-
if (profile.address?.city) {
|
|
257
|
-
setValue("billing_address.city", profile.address.city);
|
|
258
|
-
}
|
|
259
|
-
if (profile.address?.postal_code) {
|
|
260
|
-
setValue("billing_address.postal_code", profile.address.postal_code);
|
|
261
|
-
}
|
|
271
|
+
setUserFormValues(profile, values, setValue, {
|
|
272
|
+
showPhone: checkoutSession.phone_number_collection?.enabled
|
|
273
|
+
});
|
|
262
274
|
}
|
|
263
275
|
};
|
|
264
276
|
const onFormSubmit = async data => {
|
|
@@ -445,15 +457,31 @@ function PaymentForm({
|
|
|
445
457
|
}
|
|
446
458
|
}), state.submitting || state.paying ? t("payment.checkout.processing") : buttonText]
|
|
447
459
|
})
|
|
448
|
-
}), state.customerLimited && /* @__PURE__ */(0, _jsxRuntime.jsx)(
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
460
|
+
}), state.customerLimited && /* @__PURE__ */(0, _jsxRuntime.jsx)(_overDueInvoicePayment.default, {
|
|
461
|
+
customerId: customer?.id || session?.user?.did,
|
|
462
|
+
onPaid: () => {
|
|
463
|
+
setState({
|
|
464
|
+
customerLimited: false
|
|
465
|
+
});
|
|
466
|
+
onAction();
|
|
467
|
+
},
|
|
468
|
+
alertMessage: t("payment.customer.pastDue.alert.customMessage"),
|
|
469
|
+
detailLinkOptions: {
|
|
470
|
+
enabled: true,
|
|
471
|
+
onClick: () => {
|
|
472
|
+
setState({
|
|
473
|
+
customerLimited: false
|
|
474
|
+
});
|
|
475
|
+
window.open((0, _ufo.joinURL)((0, _util.getPrefix)(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`), "_self");
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
dialogProps: {
|
|
479
|
+
open: state.customerLimited,
|
|
480
|
+
onClose: () => setState({
|
|
481
|
+
customerLimited: false
|
|
482
|
+
}),
|
|
483
|
+
title: t("payment.customer.pastDue.alert.title")
|
|
484
|
+
}
|
|
457
485
|
})]
|
|
458
486
|
});
|
|
459
487
|
}
|
|
@@ -600,15 +628,31 @@ function PaymentForm({
|
|
|
600
628
|
})
|
|
601
629
|
})]
|
|
602
630
|
})
|
|
603
|
-
}), state.customerLimited && /* @__PURE__ */(0, _jsxRuntime.jsx)(
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
631
|
+
}), state.customerLimited && /* @__PURE__ */(0, _jsxRuntime.jsx)(_overDueInvoicePayment.default, {
|
|
632
|
+
customerId: customer?.id || session?.user?.didssion?.user?.did,
|
|
633
|
+
onPaid: () => {
|
|
634
|
+
setState({
|
|
635
|
+
customerLimited: false
|
|
636
|
+
});
|
|
637
|
+
onAction();
|
|
638
|
+
},
|
|
639
|
+
alertMessage: t("payment.customer.pastDue.alert.customMessage"),
|
|
640
|
+
detailLinkOptions: {
|
|
641
|
+
enabled: true,
|
|
642
|
+
onClick: () => {
|
|
643
|
+
setState({
|
|
644
|
+
customerLimited: false
|
|
645
|
+
});
|
|
646
|
+
window.open((0, _ufo.joinURL)((0, _util.getPrefix)(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`), "_self");
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
dialogProps: {
|
|
650
|
+
open: state.customerLimited,
|
|
651
|
+
onClose: () => setState({
|
|
652
|
+
customerLimited: false
|
|
653
|
+
}),
|
|
654
|
+
title: t("payment.customer.pastDue.alert.title")
|
|
655
|
+
}
|
|
612
656
|
})]
|
|
613
657
|
});
|
|
614
658
|
}
|
|
@@ -24,6 +24,18 @@ function PhoneInput({
|
|
|
24
24
|
setValue
|
|
25
25
|
} = (0, _reactHookForm.useFormContext)();
|
|
26
26
|
const values = getValues();
|
|
27
|
+
const isUpdatingRef = (0, _react.useRef)(false);
|
|
28
|
+
const safeUpdate = (0, _react.useCallback)(callback => {
|
|
29
|
+
if (isUpdatingRef.current) return;
|
|
30
|
+
try {
|
|
31
|
+
isUpdatingRef.current = true;
|
|
32
|
+
callback();
|
|
33
|
+
} finally {
|
|
34
|
+
requestAnimationFrame(() => {
|
|
35
|
+
isUpdatingRef.current = false;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}, []);
|
|
27
39
|
const {
|
|
28
40
|
phone,
|
|
29
41
|
handlePhoneValueChange,
|
|
@@ -35,8 +47,10 @@ function PhoneInput({
|
|
|
35
47
|
value: values[props.name] || "",
|
|
36
48
|
countries: _reactInternationalPhone.defaultCountries,
|
|
37
49
|
onChange: data => {
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
safeUpdate(() => {
|
|
51
|
+
setValue(props.name, data.phone);
|
|
52
|
+
setValue(countryFieldName, data.country);
|
|
53
|
+
});
|
|
40
54
|
}
|
|
41
55
|
});
|
|
42
56
|
const userCountry = (0, _reactHookForm.useWatch)({
|
|
@@ -44,14 +58,16 @@ function PhoneInput({
|
|
|
44
58
|
name: countryFieldName
|
|
45
59
|
});
|
|
46
60
|
(0, _react.useEffect)(() => {
|
|
47
|
-
if (userCountry
|
|
61
|
+
if (!userCountry || userCountry === country) return;
|
|
62
|
+
safeUpdate(() => {
|
|
48
63
|
setCountry(userCountry);
|
|
49
|
-
}
|
|
50
|
-
}, [userCountry]);
|
|
51
|
-
const onCountryChange = v => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
});
|
|
65
|
+
}, [userCountry, country, setCountry, safeUpdate]);
|
|
66
|
+
const onCountryChange = (0, _react.useCallback)(v => {
|
|
67
|
+
safeUpdate(() => {
|
|
68
|
+
setCountry(v);
|
|
69
|
+
});
|
|
70
|
+
}, [setCountry, safeUpdate]);
|
|
55
71
|
return (
|
|
56
72
|
// @ts-ignore
|
|
57
73
|
/* @__PURE__ */
|
package/lib/payment/index.js
CHANGED
|
@@ -28,6 +28,7 @@ var _payment2 = _interopRequireDefault(require("./skeleton/payment"));
|
|
|
28
28
|
var _success = _interopRequireDefault(require("./success"));
|
|
29
29
|
var _summary = _interopRequireDefault(require("./summary"));
|
|
30
30
|
var _mobile = require("../hooks/mobile");
|
|
31
|
+
var _phoneValidator = require("../libs/phone-validator");
|
|
31
32
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
32
33
|
PaymentInner.defaultProps = {
|
|
33
34
|
completed: false,
|
|
@@ -68,18 +69,18 @@ function PaymentInner({
|
|
|
68
69
|
defaultValues: {
|
|
69
70
|
customer_name: customer?.name || session?.user?.fullName || "",
|
|
70
71
|
customer_email: customer?.email || session?.user?.email || "",
|
|
71
|
-
customer_phone: customer?.phone || session?.user?.phone || "",
|
|
72
|
+
customer_phone: (0, _phoneValidator.formatPhone)(customer?.phone || session?.user?.phone || ""),
|
|
72
73
|
payment_method: defaultMethodId,
|
|
73
74
|
payment_currency: defaultCurrencyId,
|
|
74
75
|
billing_address: Object.assign({
|
|
75
|
-
country: "",
|
|
76
|
-
state: "",
|
|
77
|
-
city: "",
|
|
78
|
-
line1: "",
|
|
79
|
-
line2: "",
|
|
80
|
-
postal_code: ""
|
|
76
|
+
country: session?.user?.address?.country || "",
|
|
77
|
+
state: session?.user?.address?.province || "",
|
|
78
|
+
city: session?.user?.address?.city || "",
|
|
79
|
+
line1: session?.user?.address?.line1 || "",
|
|
80
|
+
line2: session?.user?.address?.line2 || "",
|
|
81
|
+
postal_code: session?.user?.address?.postalCode || ""
|
|
81
82
|
}, customer?.address || {}, {
|
|
82
|
-
country: (0, _util2.isValidCountry)(customer?.address?.country || "") ? customer?.address?.country : "us"
|
|
83
|
+
country: (0, _util2.isValidCountry)(customer?.address?.country || session?.user?.address?.country || "") ? customer?.address?.country : "us"
|
|
83
84
|
})
|
|
84
85
|
}
|
|
85
86
|
});
|
|
@@ -47,9 +47,6 @@ function ProductDonation({
|
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
const getDefaultPreset = () => {
|
|
50
|
-
if (settings?.amount?.preset) {
|
|
51
|
-
return formatAmount(settings.amount.preset);
|
|
52
|
-
}
|
|
53
50
|
try {
|
|
54
51
|
const savedPreset = localStorage.getItem(getUserStorageKey(DONATION_PRESET_KEY_BASE));
|
|
55
52
|
if (savedPreset) {
|
|
@@ -65,7 +62,13 @@ function ProductDonation({
|
|
|
65
62
|
}
|
|
66
63
|
if (presets.length > 0) {
|
|
67
64
|
const middleIndex = Math.floor(presets.length / 2);
|
|
68
|
-
return presets[middleIndex]
|
|
65
|
+
return presets[middleIndex];
|
|
66
|
+
}
|
|
67
|
+
if (settings?.amount?.preset) {
|
|
68
|
+
return formatAmount(settings.amount.preset);
|
|
69
|
+
}
|
|
70
|
+
if (presets.length > 0) {
|
|
71
|
+
return presets[0];
|
|
69
72
|
}
|
|
70
73
|
return "0";
|
|
71
74
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.21",
|
|
4
4
|
"description": "Reusable react components for payment kit v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@arcblock/did-connect": "^2.12.
|
|
58
|
-
"@arcblock/ux": "^2.12.
|
|
57
|
+
"@arcblock/did-connect": "^2.12.43",
|
|
58
|
+
"@arcblock/ux": "^2.12.43",
|
|
59
59
|
"@arcblock/ws": "^1.19.15",
|
|
60
|
-
"@blocklet/ui-react": "^2.12.
|
|
60
|
+
"@blocklet/ui-react": "^2.12.43",
|
|
61
61
|
"@mui/icons-material": "^5.16.6",
|
|
62
62
|
"@mui/lab": "^5.0.0-alpha.173",
|
|
63
63
|
"@mui/material": "^5.16.6",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"@babel/core": "^7.25.2",
|
|
94
94
|
"@babel/preset-env": "^7.25.2",
|
|
95
95
|
"@babel/preset-react": "^7.24.7",
|
|
96
|
-
"@blocklet/payment-types": "1.18.
|
|
96
|
+
"@blocklet/payment-types": "1.18.21",
|
|
97
97
|
"@storybook/addon-essentials": "^7.6.20",
|
|
98
98
|
"@storybook/addon-interactions": "^7.6.20",
|
|
99
99
|
"@storybook/addon-links": "^7.6.20",
|
|
@@ -124,5 +124,5 @@
|
|
|
124
124
|
"vite-plugin-babel": "^1.2.0",
|
|
125
125
|
"vite-plugin-node-polyfills": "^0.21.0"
|
|
126
126
|
},
|
|
127
|
-
"gitHead": "
|
|
127
|
+
"gitHead": "cf08902482dded20ee91402ed6d4678383965daf"
|
|
128
128
|
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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
|
|
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
|
-
|
|
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
|
+
};
|
package/src/locales/en.tsx
CHANGED
|
@@ -134,6 +134,7 @@ export default flat({
|
|
|
134
134
|
empty: 'No supporters yet',
|
|
135
135
|
gaveTips: '{count} people gave tips',
|
|
136
136
|
tipAmount: 'Tip Amount',
|
|
137
|
+
tabHint: 'to switch amount',
|
|
137
138
|
benefits: {
|
|
138
139
|
one: '{name} will receive all tips',
|
|
139
140
|
multiple: 'Tips will be distributed to {count} beneficiaries',
|
|
@@ -147,7 +148,7 @@ export default flat({
|
|
|
147
148
|
later: 'Configure Later',
|
|
148
149
|
configTip: 'Configure donation settings in Payment Kit',
|
|
149
150
|
},
|
|
150
|
-
cardPay: '{action} with card',
|
|
151
|
+
cardPay: '{action} with bank card',
|
|
151
152
|
empty: 'No thing to pay',
|
|
152
153
|
per: 'per',
|
|
153
154
|
pay: 'Pay {payee}',
|
|
@@ -248,8 +249,7 @@ export default flat({
|
|
|
248
249
|
warning: 'Past due invoices need to be paid immediately, otherwise you can not make new purchases anymore.',
|
|
249
250
|
alert: {
|
|
250
251
|
title: 'You have unpaid invoices',
|
|
251
|
-
|
|
252
|
-
'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.',
|
|
253
253
|
confirm: 'Pay Now',
|
|
254
254
|
},
|
|
255
255
|
view: 'View Due Invoices',
|
|
@@ -330,9 +330,10 @@ export default flat({
|
|
|
330
330
|
},
|
|
331
331
|
overdue: {
|
|
332
332
|
title:
|
|
333
|
-
'You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}{method}.
|
|
334
|
-
simpleTitle: 'You have {count} due invoices.
|
|
333
|
+
'You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}{method}. ',
|
|
334
|
+
simpleTitle: 'You have {count} due invoices. ',
|
|
335
335
|
empty: 'Great! You have no due invoices.',
|
|
336
|
+
defaultAlert: 'Please pay immediately to avoid service disruption.',
|
|
336
337
|
},
|
|
337
338
|
},
|
|
338
339
|
invoice: {
|
package/src/locales/zh.tsx
CHANGED
|
@@ -133,6 +133,7 @@ export default flat({
|
|
|
133
133
|
empty: '❤️ 支持一下',
|
|
134
134
|
gaveTips: '已有 {count} 人打赏',
|
|
135
135
|
tipAmount: '打赏金额',
|
|
136
|
+
tabHint: '快速切换金额',
|
|
136
137
|
benefits: {
|
|
137
138
|
one: '{name} 将获得全部打赏',
|
|
138
139
|
multiple: '打赏将按比例分配给 {count} 位受益人',
|
|
@@ -146,7 +147,7 @@ export default flat({
|
|
|
146
147
|
later: '稍后配置',
|
|
147
148
|
configTip: '前往 Payment Kit 配置打赏选项',
|
|
148
149
|
},
|
|
149
|
-
cardPay: '
|
|
150
|
+
cardPay: '使用银行卡{action}',
|
|
150
151
|
empty: '没有可支付的项目',
|
|
151
152
|
per: '每',
|
|
152
153
|
pay: '付款给 {payee}',
|
|
@@ -244,6 +245,7 @@ export default flat({
|
|
|
244
245
|
alert: {
|
|
245
246
|
title: '你有欠费账单',
|
|
246
247
|
description: '看起来你有欠费的账单,在你支付所有欠费账单之前,新的购买或者订阅将被禁止,请不要调皮。',
|
|
248
|
+
customMessage: '请立即支付,否则新的购买或者订阅将被禁止。',
|
|
247
249
|
confirm: '去支付',
|
|
248
250
|
},
|
|
249
251
|
view: '查看欠费明细',
|
|
@@ -320,10 +322,10 @@ export default flat({
|
|
|
320
322
|
owner: '订阅拥有者',
|
|
321
323
|
},
|
|
322
324
|
overdue: {
|
|
323
|
-
title:
|
|
324
|
-
|
|
325
|
-
simpleTitle: '您有 {count} 张欠费账单,请立即支付,以免影响您的使用。',
|
|
325
|
+
title: '您有 {count} 张欠费账单,涉及 {subscriptionCount} 个订阅,总金额 {total} {symbol}{method}。',
|
|
326
|
+
simpleTitle: '您有 {count} 张欠费账单,',
|
|
326
327
|
empty: '恭喜!您当前没有欠费账单。',
|
|
328
|
+
defaultAlert: '请立即支付,以免影响您的使用。',
|
|
327
329
|
},
|
|
328
330
|
},
|
|
329
331
|
invoice: {
|