@blocklet/payment-react 1.18.34 → 1.18.35
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/libs/util.d.ts +1 -0
- package/es/libs/util.js +13 -0
- package/es/libs/validator.d.ts +1 -0
- package/es/libs/validator.js +14 -0
- package/es/locales/en.js +2 -1
- package/es/locales/zh.js +2 -1
- package/es/payment/form/address.d.ts +5 -1
- package/es/payment/form/address.js +26 -13
- package/es/payment/form/index.js +43 -10
- package/lib/libs/util.d.ts +1 -0
- package/lib/libs/util.js +16 -1
- package/lib/libs/validator.d.ts +1 -0
- package/lib/libs/validator.js +14 -0
- package/lib/locales/en.js +2 -1
- package/lib/locales/zh.js +2 -1
- package/lib/payment/form/address.d.ts +5 -1
- package/lib/payment/form/address.js +21 -12
- package/lib/payment/form/index.js +39 -10
- package/package.json +3 -3
- package/src/libs/util.ts +15 -0
- package/src/libs/validator.ts +14 -0
- package/src/locales/en.tsx +1 -0
- package/src/locales/zh.tsx +1 -0
- package/src/payment/form/address.tsx +25 -10
- package/src/payment/form/index.tsx +39 -7
package/es/libs/util.d.ts
CHANGED
package/es/libs/util.js
CHANGED
|
@@ -979,3 +979,16 @@ export function parseMarkedText(text) {
|
|
|
979
979
|
}
|
|
980
980
|
return result.filter((p) => p.content !== "");
|
|
981
981
|
}
|
|
982
|
+
export function getTokenBalanceLink(method, address) {
|
|
983
|
+
if (!method || !address) {
|
|
984
|
+
return "";
|
|
985
|
+
}
|
|
986
|
+
const explorerHost = method?.settings?.[method?.type]?.explorer_host || "";
|
|
987
|
+
if (method.type === "arcblock" && address) {
|
|
988
|
+
return joinURL(explorerHost, "accounts", address, "tokens");
|
|
989
|
+
}
|
|
990
|
+
if (["ethereum", "base"].includes(method.type) && address) {
|
|
991
|
+
return joinURL(explorerHost, "address", address);
|
|
992
|
+
}
|
|
993
|
+
return "";
|
|
994
|
+
}
|
package/es/libs/validator.d.ts
CHANGED
package/es/libs/validator.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import isPostalCode from "validator/lib/isPostalCode";
|
|
2
|
+
import { t } from "../locales/index.js";
|
|
2
3
|
const POSTAL_CODE_SUPPORTED_COUNTRIES = [
|
|
3
4
|
"AD",
|
|
4
5
|
"AT",
|
|
@@ -68,3 +69,16 @@ export function validatePostalCode(postalCode, country) {
|
|
|
68
69
|
return false;
|
|
69
70
|
}
|
|
70
71
|
}
|
|
72
|
+
export function getFieldValidation(fieldName, validations, locale = "en") {
|
|
73
|
+
if (!validations || !validations[fieldName])
|
|
74
|
+
return {};
|
|
75
|
+
const fieldValidation = validations[fieldName];
|
|
76
|
+
const rules = {};
|
|
77
|
+
if (fieldValidation.pattern) {
|
|
78
|
+
rules.pattern = {
|
|
79
|
+
value: new RegExp(fieldValidation.pattern),
|
|
80
|
+
message: fieldValidation.pattern_message?.[locale] || t("payment.checkout.invalid", locale)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return rules;
|
|
84
|
+
}
|
package/es/locales/en.js
CHANGED
|
@@ -232,7 +232,8 @@ export default flat({
|
|
|
232
232
|
confirmPrompt: "Please confirm the details before proceeding.",
|
|
233
233
|
payer: "Account",
|
|
234
234
|
amount: "Amount",
|
|
235
|
-
failed: "Account changed, please pay manually."
|
|
235
|
+
failed: "Account changed, please pay manually.",
|
|
236
|
+
balanceLink: "View Balance"
|
|
236
237
|
}
|
|
237
238
|
},
|
|
238
239
|
customer: {
|
package/es/locales/zh.js
CHANGED
|
@@ -232,7 +232,8 @@ export default flat({
|
|
|
232
232
|
confirmPrompt: "\u8BF7\u786E\u8BA4\u652F\u4ED8\u4FE1\u606F\u65E0\u8BEF\u540E\u7EE7\u7EED\u3002",
|
|
233
233
|
payer: "\u8D26\u6237\u5730\u5740",
|
|
234
234
|
amount: "\u652F\u4ED8\u91D1\u989D",
|
|
235
|
-
failed: "\u8D26\u6237\u53D1\u751F\u53D8\u5316\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5B8C\u6210\u652F\u4ED8\uFF0C\u8BF7\u624B\u52A8\u652F\u4ED8\u3002"
|
|
235
|
+
failed: "\u8D26\u6237\u53D1\u751F\u53D8\u5316\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5B8C\u6210\u652F\u4ED8\uFF0C\u8BF7\u624B\u52A8\u652F\u4ED8\u3002",
|
|
236
|
+
balanceLink: "\u67E5\u770B\u4F59\u989D"
|
|
236
237
|
}
|
|
237
238
|
},
|
|
238
239
|
customer: {
|
|
@@ -3,11 +3,15 @@ type Props = {
|
|
|
3
3
|
mode: string;
|
|
4
4
|
stripe: boolean;
|
|
5
5
|
sx?: SxProps;
|
|
6
|
+
fieldValidation?: Record<string, any>;
|
|
7
|
+
errorPosition?: 'right' | 'bottom';
|
|
6
8
|
};
|
|
7
|
-
declare function AddressForm({ mode, stripe, sx }: Props): import("react").JSX.Element | null;
|
|
9
|
+
declare function AddressForm({ mode, stripe, sx, fieldValidation, errorPosition }: Props): import("react").JSX.Element | null;
|
|
8
10
|
declare namespace AddressForm {
|
|
9
11
|
var defaultProps: {
|
|
10
12
|
sx: {};
|
|
13
|
+
fieldValidation: {};
|
|
14
|
+
errorPosition: string;
|
|
11
15
|
};
|
|
12
16
|
}
|
|
13
17
|
export default AddressForm;
|
|
@@ -4,11 +4,13 @@ import { Fade, FormLabel, InputAdornment, Stack } from "@mui/material";
|
|
|
4
4
|
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
|
5
5
|
import FormInput from "../../components/input.js";
|
|
6
6
|
import CountrySelect from "../../components/country-select.js";
|
|
7
|
-
import { validatePostalCode } from "../../libs/validator.js";
|
|
7
|
+
import { getFieldValidation, validatePostalCode } from "../../libs/validator.js";
|
|
8
8
|
AddressForm.defaultProps = {
|
|
9
|
-
sx: {}
|
|
9
|
+
sx: {},
|
|
10
|
+
fieldValidation: {},
|
|
11
|
+
errorPosition: "right"
|
|
10
12
|
};
|
|
11
|
-
export default function AddressForm({ mode, stripe, sx = {} }) {
|
|
13
|
+
export default function AddressForm({ mode, stripe, sx = {}, fieldValidation, errorPosition }) {
|
|
12
14
|
const { t } = useLocaleContext();
|
|
13
15
|
const { control } = useFormContext();
|
|
14
16
|
const country = useWatch({ control, name: "billing_address.country" });
|
|
@@ -19,8 +21,11 @@ export default function AddressForm({ mode, stripe, sx = {} }) {
|
|
|
19
21
|
FormInput,
|
|
20
22
|
{
|
|
21
23
|
name: "billing_address.line1",
|
|
22
|
-
rules: {
|
|
23
|
-
|
|
24
|
+
rules: {
|
|
25
|
+
required: t("payment.checkout.required"),
|
|
26
|
+
...getFieldValidation("billing_address.line1", fieldValidation)
|
|
27
|
+
},
|
|
28
|
+
errorPosition,
|
|
24
29
|
variant: "outlined",
|
|
25
30
|
placeholder: t("payment.checkout.billing.line1")
|
|
26
31
|
}
|
|
@@ -30,8 +35,11 @@ export default function AddressForm({ mode, stripe, sx = {} }) {
|
|
|
30
35
|
FormInput,
|
|
31
36
|
{
|
|
32
37
|
name: "billing_address.city",
|
|
33
|
-
rules: {
|
|
34
|
-
|
|
38
|
+
rules: {
|
|
39
|
+
required: t("payment.checkout.required"),
|
|
40
|
+
...getFieldValidation("billing_address.city", fieldValidation)
|
|
41
|
+
},
|
|
42
|
+
errorPosition,
|
|
35
43
|
variant: "outlined",
|
|
36
44
|
placeholder: t("payment.checkout.billing.city")
|
|
37
45
|
}
|
|
@@ -41,8 +49,11 @@ export default function AddressForm({ mode, stripe, sx = {} }) {
|
|
|
41
49
|
FormInput,
|
|
42
50
|
{
|
|
43
51
|
name: "billing_address.state",
|
|
44
|
-
rules: {
|
|
45
|
-
|
|
52
|
+
rules: {
|
|
53
|
+
required: t("payment.checkout.required"),
|
|
54
|
+
...getFieldValidation("billing_address.state", fieldValidation)
|
|
55
|
+
},
|
|
56
|
+
errorPosition,
|
|
46
57
|
variant: "outlined",
|
|
47
58
|
placeholder: t("payment.checkout.billing.state")
|
|
48
59
|
}
|
|
@@ -57,9 +68,10 @@ export default function AddressForm({ mode, stripe, sx = {} }) {
|
|
|
57
68
|
validate: (x) => {
|
|
58
69
|
const isValid = validatePostalCode(x, country);
|
|
59
70
|
return isValid ? true : t("payment.checkout.invalid");
|
|
60
|
-
}
|
|
71
|
+
},
|
|
72
|
+
...getFieldValidation("billing_address.postal_code", fieldValidation)
|
|
61
73
|
},
|
|
62
|
-
errorPosition
|
|
74
|
+
errorPosition,
|
|
63
75
|
variant: "outlined",
|
|
64
76
|
placeholder: t("payment.checkout.billing.postal_code"),
|
|
65
77
|
InputProps: {
|
|
@@ -98,9 +110,10 @@ export default function AddressForm({ mode, stripe, sx = {} }) {
|
|
|
98
110
|
validate: (x) => {
|
|
99
111
|
const isValid = validatePostalCode(x, country);
|
|
100
112
|
return isValid ? true : t("payment.checkout.invalid");
|
|
101
|
-
}
|
|
113
|
+
},
|
|
114
|
+
...getFieldValidation("billing_address.postal_code", fieldValidation)
|
|
102
115
|
},
|
|
103
|
-
errorPosition
|
|
116
|
+
errorPosition,
|
|
104
117
|
variant: "outlined",
|
|
105
118
|
placeholder: t("payment.checkout.billing.postal_code"),
|
|
106
119
|
wrapperStyle: { height: "40px" },
|
package/es/payment/form/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import "react-international-phone/style.css";
|
|
3
3
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
4
4
|
import Toast from "@arcblock/ux/lib/Toast";
|
|
5
|
-
import { Box, Button, CircularProgress, Divider, Fade, FormLabel, Stack, Typography } from "@mui/material";
|
|
5
|
+
import { Box, Button, CircularProgress, Divider, Fade, FormLabel, Stack, Tooltip, Typography } from "@mui/material";
|
|
6
6
|
import { useMemoizedFn, useSetState } from "ahooks";
|
|
7
7
|
import pWaitFor from "p-wait-for";
|
|
8
8
|
import { useEffect, useMemo, useRef } from "react";
|
|
@@ -13,7 +13,7 @@ import isEmail from "validator/es/lib/isEmail";
|
|
|
13
13
|
import { fromUnitToToken } from "@ocap/util";
|
|
14
14
|
import DID from "@arcblock/ux/lib/DID";
|
|
15
15
|
import isEmpty from "lodash/isEmpty";
|
|
16
|
-
import { HelpOutline } from "@mui/icons-material";
|
|
16
|
+
import { HelpOutline, OpenInNew } from "@mui/icons-material";
|
|
17
17
|
import FormInput from "../../components/input.js";
|
|
18
18
|
import { usePaymentContext } from "../../contexts/payment.js";
|
|
19
19
|
import { useSubscription } from "../../hooks/subscription.js";
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
formatQuantityInventory,
|
|
25
25
|
getPrefix,
|
|
26
26
|
getStatementDescriptor,
|
|
27
|
+
getTokenBalanceLink,
|
|
27
28
|
isCrossOrigin
|
|
28
29
|
} from "../../libs/util.js";
|
|
29
30
|
import AddressForm from "./address.js";
|
|
@@ -36,6 +37,7 @@ import LoadingButton from "../../components/loading-button.js";
|
|
|
36
37
|
import OverdueInvoicePayment from "../../components/over-due-invoice-payment.js";
|
|
37
38
|
import { saveCurrencyPreference } from "../../libs/currency.js";
|
|
38
39
|
import ConfirmDialog from "../../components/confirm.js";
|
|
40
|
+
import { getFieldValidation } from "../../libs/validator.js";
|
|
39
41
|
export const waitForCheckoutComplete = async (sessionId) => {
|
|
40
42
|
let result;
|
|
41
43
|
await pWaitFor(
|
|
@@ -104,6 +106,7 @@ export default function PaymentForm({
|
|
|
104
106
|
const { isMobile } = useMobile();
|
|
105
107
|
const { session, connect, payable } = usePaymentContext();
|
|
106
108
|
const subscription = useSubscription("events");
|
|
109
|
+
const formErrorPosition = isMobile ? "bottom" : "right";
|
|
107
110
|
const {
|
|
108
111
|
control,
|
|
109
112
|
getValues,
|
|
@@ -456,6 +459,7 @@ export default function PaymentForm({
|
|
|
456
459
|
window.removeEventListener("keydown", handleKeyDown);
|
|
457
460
|
};
|
|
458
461
|
}, [state.submitting, state.paying, state.stripePaying, quantityInventoryStatus, payable]);
|
|
462
|
+
const balanceLink = getTokenBalanceLink(method, state.fastCheckoutInfo?.payer || "");
|
|
459
463
|
const FastCheckoutConfirmDialog = state.fastCheckoutInfo && /* @__PURE__ */ jsx(
|
|
460
464
|
ConfirmDialog,
|
|
461
465
|
{
|
|
@@ -469,7 +473,23 @@ export default function PaymentForm({
|
|
|
469
473
|
/* @__PURE__ */ jsxs(Stack, { spacing: 1, children: [
|
|
470
474
|
/* @__PURE__ */ jsxs(Stack, { flexDirection: "row", alignItems: "center", justifyContent: "space-between", children: [
|
|
471
475
|
/* @__PURE__ */ jsx(Typography, { color: "text.primary", sx: { whiteSpace: "nowrap" }, children: t("payment.checkout.fastPay.payer") }),
|
|
472
|
-
/* @__PURE__ */
|
|
476
|
+
/* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
|
|
477
|
+
/* @__PURE__ */ jsx(DID, { did: state.fastCheckoutInfo.payer || "", compact: true, responsive: false }),
|
|
478
|
+
balanceLink && /* @__PURE__ */ jsx(Tooltip, { title: t("payment.checkout.fastPay.balanceLink"), placement: "top", children: /* @__PURE__ */ jsx(
|
|
479
|
+
OpenInNew,
|
|
480
|
+
{
|
|
481
|
+
sx: {
|
|
482
|
+
color: "text.lighter",
|
|
483
|
+
fontSize: "0.85rem",
|
|
484
|
+
cursor: "pointer",
|
|
485
|
+
"&:hover": { color: "text.primary" }
|
|
486
|
+
},
|
|
487
|
+
onClick: () => {
|
|
488
|
+
window.open(balanceLink, "_blank");
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
) })
|
|
492
|
+
] })
|
|
473
493
|
] }),
|
|
474
494
|
/* @__PURE__ */ jsxs(Stack, { flexDirection: "row", alignItems: "center", justifyContent: "space-between", children: [
|
|
475
495
|
/* @__PURE__ */ jsx(Typography, { color: "text.primary", children: t("payment.checkout.fastPay.amount") }),
|
|
@@ -609,9 +629,10 @@ export default function PaymentForm({
|
|
|
609
629
|
{
|
|
610
630
|
name: "customer_name",
|
|
611
631
|
variant: "outlined",
|
|
612
|
-
errorPosition:
|
|
632
|
+
errorPosition: formErrorPosition,
|
|
613
633
|
rules: {
|
|
614
|
-
required: t("payment.checkout.required")
|
|
634
|
+
required: t("payment.checkout.required"),
|
|
635
|
+
...getFieldValidation("customer_name", checkoutSession.metadata?.page_info?.field_validation, locale)
|
|
615
636
|
}
|
|
616
637
|
}
|
|
617
638
|
),
|
|
@@ -621,10 +642,15 @@ export default function PaymentForm({
|
|
|
621
642
|
{
|
|
622
643
|
name: "customer_email",
|
|
623
644
|
variant: "outlined",
|
|
624
|
-
errorPosition:
|
|
645
|
+
errorPosition: formErrorPosition,
|
|
625
646
|
rules: {
|
|
626
647
|
required: t("payment.checkout.required"),
|
|
627
|
-
validate: (x) => isEmail(x) ? true : t("payment.checkout.invalid")
|
|
648
|
+
validate: (x) => isEmail(x) ? true : t("payment.checkout.invalid"),
|
|
649
|
+
...getFieldValidation(
|
|
650
|
+
"customer_email",
|
|
651
|
+
checkoutSession.metadata?.page_info?.field_validation,
|
|
652
|
+
locale
|
|
653
|
+
)
|
|
628
654
|
}
|
|
629
655
|
}
|
|
630
656
|
),
|
|
@@ -635,14 +661,19 @@ export default function PaymentForm({
|
|
|
635
661
|
{
|
|
636
662
|
name: "customer_phone",
|
|
637
663
|
variant: "outlined",
|
|
638
|
-
errorPosition:
|
|
664
|
+
errorPosition: formErrorPosition,
|
|
639
665
|
placeholder: "Phone number",
|
|
640
666
|
rules: {
|
|
641
667
|
required: t("payment.checkout.required"),
|
|
642
668
|
validate: async (x) => {
|
|
643
669
|
const isValid = await validatePhoneNumber(x);
|
|
644
670
|
return isValid ? true : t("payment.checkout.invalid");
|
|
645
|
-
}
|
|
671
|
+
},
|
|
672
|
+
...getFieldValidation(
|
|
673
|
+
"customer_phone",
|
|
674
|
+
checkoutSession.metadata?.page_info?.field_validation,
|
|
675
|
+
locale
|
|
676
|
+
)
|
|
646
677
|
}
|
|
647
678
|
}
|
|
648
679
|
)
|
|
@@ -652,7 +683,9 @@ export default function PaymentForm({
|
|
|
652
683
|
{
|
|
653
684
|
mode: checkoutSession.billing_address_collection,
|
|
654
685
|
stripe: method?.type === "stripe",
|
|
655
|
-
sx: { marginTop: "0 !important" }
|
|
686
|
+
sx: { marginTop: "0 !important" },
|
|
687
|
+
fieldValidation: checkoutSession.metadata?.page_info?.field_validation,
|
|
688
|
+
errorPosition: formErrorPosition
|
|
656
689
|
}
|
|
657
690
|
)
|
|
658
691
|
]
|
package/lib/libs/util.d.ts
CHANGED
package/lib/libs/util.js
CHANGED
|
@@ -44,7 +44,9 @@ exports.getRefundStatusColor = getRefundStatusColor;
|
|
|
44
44
|
exports.getStatementDescriptor = getStatementDescriptor;
|
|
45
45
|
exports.getSubscriptionAction = void 0;
|
|
46
46
|
exports.getSubscriptionStatusColor = getSubscriptionStatusColor;
|
|
47
|
-
exports.
|
|
47
|
+
exports.getSubscriptionTimeSummary = void 0;
|
|
48
|
+
exports.getTokenBalanceLink = getTokenBalanceLink;
|
|
49
|
+
exports.getTxLink = void 0;
|
|
48
50
|
exports.getUserProfileLink = getUserProfileLink;
|
|
49
51
|
exports.getWebhookStatusColor = getWebhookStatusColor;
|
|
50
52
|
exports.getWordBreakStyle = getWordBreakStyle;
|
|
@@ -1169,4 +1171,17 @@ function parseMarkedText(text) {
|
|
|
1169
1171
|
}
|
|
1170
1172
|
}
|
|
1171
1173
|
return result.filter(p => p.content !== "");
|
|
1174
|
+
}
|
|
1175
|
+
function getTokenBalanceLink(method, address) {
|
|
1176
|
+
if (!method || !address) {
|
|
1177
|
+
return "";
|
|
1178
|
+
}
|
|
1179
|
+
const explorerHost = method?.settings?.[method?.type]?.explorer_host || "";
|
|
1180
|
+
if (method.type === "arcblock" && address) {
|
|
1181
|
+
return (0, _ufo.joinURL)(explorerHost, "accounts", address, "tokens");
|
|
1182
|
+
}
|
|
1183
|
+
if (["ethereum", "base"].includes(method.type) && address) {
|
|
1184
|
+
return (0, _ufo.joinURL)(explorerHost, "address", address);
|
|
1185
|
+
}
|
|
1186
|
+
return "";
|
|
1172
1187
|
}
|
package/lib/libs/validator.d.ts
CHANGED
package/lib/libs/validator.js
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.getFieldValidation = getFieldValidation;
|
|
6
7
|
exports.validatePostalCode = validatePostalCode;
|
|
7
8
|
var _isPostalCode = _interopRequireDefault(require("validator/lib/isPostalCode"));
|
|
9
|
+
var _locales = require("../locales");
|
|
8
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
11
|
const POSTAL_CODE_SUPPORTED_COUNTRIES = ["AD", "AT", "AU", "BE", "BG", "BR", "CA", "CH", "CN", "CZ", "DE", "DK", "DZ", "EE", "ES", "FI", "FR", "GB", "GR", "HR", "HU", "ID", "IE", "IL", "IN", "IR", "IS", "IT", "JP", "KE", "KR", "LI", "LT", "LU", "LV", "MX", "MT", "NL", "NO", "NZ", "PL", "PR", "PT", "RO", "RU", "SA", "SE", "SI", "SK", "TN", "TW", "UA", "US", "ZA", "ZM"];
|
|
10
12
|
function validatePostalCode(postalCode, country) {
|
|
@@ -17,4 +19,16 @@ function validatePostalCode(postalCode, country) {
|
|
|
17
19
|
console.error(error);
|
|
18
20
|
return false;
|
|
19
21
|
}
|
|
22
|
+
}
|
|
23
|
+
function getFieldValidation(fieldName, validations, locale = "en") {
|
|
24
|
+
if (!validations || !validations[fieldName]) return {};
|
|
25
|
+
const fieldValidation = validations[fieldName];
|
|
26
|
+
const rules = {};
|
|
27
|
+
if (fieldValidation.pattern) {
|
|
28
|
+
rules.pattern = {
|
|
29
|
+
value: new RegExp(fieldValidation.pattern),
|
|
30
|
+
message: fieldValidation.pattern_message?.[locale] || (0, _locales.t)("payment.checkout.invalid", locale)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return rules;
|
|
20
34
|
}
|
package/lib/locales/en.js
CHANGED
|
@@ -239,7 +239,8 @@ module.exports = (0, _flat.default)({
|
|
|
239
239
|
confirmPrompt: "Please confirm the details before proceeding.",
|
|
240
240
|
payer: "Account",
|
|
241
241
|
amount: "Amount",
|
|
242
|
-
failed: "Account changed, please pay manually."
|
|
242
|
+
failed: "Account changed, please pay manually.",
|
|
243
|
+
balanceLink: "View Balance"
|
|
243
244
|
}
|
|
244
245
|
},
|
|
245
246
|
customer: {
|
package/lib/locales/zh.js
CHANGED
|
@@ -239,7 +239,8 @@ module.exports = (0, _flat.default)({
|
|
|
239
239
|
confirmPrompt: "\u8BF7\u786E\u8BA4\u652F\u4ED8\u4FE1\u606F\u65E0\u8BEF\u540E\u7EE7\u7EED\u3002",
|
|
240
240
|
payer: "\u8D26\u6237\u5730\u5740",
|
|
241
241
|
amount: "\u652F\u4ED8\u91D1\u989D",
|
|
242
|
-
failed: "\u8D26\u6237\u53D1\u751F\u53D8\u5316\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5B8C\u6210\u652F\u4ED8\uFF0C\u8BF7\u624B\u52A8\u652F\u4ED8\u3002"
|
|
242
|
+
failed: "\u8D26\u6237\u53D1\u751F\u53D8\u5316\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5B8C\u6210\u652F\u4ED8\uFF0C\u8BF7\u624B\u52A8\u652F\u4ED8\u3002",
|
|
243
|
+
balanceLink: "\u67E5\u770B\u4F59\u989D"
|
|
243
244
|
}
|
|
244
245
|
},
|
|
245
246
|
customer: {
|
|
@@ -3,11 +3,15 @@ type Props = {
|
|
|
3
3
|
mode: string;
|
|
4
4
|
stripe: boolean;
|
|
5
5
|
sx?: SxProps;
|
|
6
|
+
fieldValidation?: Record<string, any>;
|
|
7
|
+
errorPosition?: 'right' | 'bottom';
|
|
6
8
|
};
|
|
7
|
-
declare function AddressForm({ mode, stripe, sx }: Props): import("react").JSX.Element | null;
|
|
9
|
+
declare function AddressForm({ mode, stripe, sx, fieldValidation, errorPosition }: Props): import("react").JSX.Element | null;
|
|
8
10
|
declare namespace AddressForm {
|
|
9
11
|
var defaultProps: {
|
|
10
12
|
sx: {};
|
|
13
|
+
fieldValidation: {};
|
|
14
|
+
errorPosition: string;
|
|
11
15
|
};
|
|
12
16
|
}
|
|
13
17
|
export default AddressForm;
|
|
@@ -13,12 +13,16 @@ var _countrySelect = _interopRequireDefault(require("../../components/country-se
|
|
|
13
13
|
var _validator = require("../../libs/validator");
|
|
14
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
15
|
AddressForm.defaultProps = {
|
|
16
|
-
sx: {}
|
|
16
|
+
sx: {},
|
|
17
|
+
fieldValidation: {},
|
|
18
|
+
errorPosition: "right"
|
|
17
19
|
};
|
|
18
20
|
function AddressForm({
|
|
19
21
|
mode,
|
|
20
22
|
stripe,
|
|
21
|
-
sx = {}
|
|
23
|
+
sx = {},
|
|
24
|
+
fieldValidation,
|
|
25
|
+
errorPosition
|
|
22
26
|
}) {
|
|
23
27
|
const {
|
|
24
28
|
t
|
|
@@ -46,9 +50,10 @@ function AddressForm({
|
|
|
46
50
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_input.default, {
|
|
47
51
|
name: "billing_address.line1",
|
|
48
52
|
rules: {
|
|
49
|
-
required: t("payment.checkout.required")
|
|
53
|
+
required: t("payment.checkout.required"),
|
|
54
|
+
...(0, _validator.getFieldValidation)("billing_address.line1", fieldValidation)
|
|
50
55
|
},
|
|
51
|
-
errorPosition
|
|
56
|
+
errorPosition,
|
|
52
57
|
variant: "outlined",
|
|
53
58
|
placeholder: t("payment.checkout.billing.line1")
|
|
54
59
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.FormLabel, {
|
|
@@ -57,9 +62,10 @@ function AddressForm({
|
|
|
57
62
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_input.default, {
|
|
58
63
|
name: "billing_address.city",
|
|
59
64
|
rules: {
|
|
60
|
-
required: t("payment.checkout.required")
|
|
65
|
+
required: t("payment.checkout.required"),
|
|
66
|
+
...(0, _validator.getFieldValidation)("billing_address.city", fieldValidation)
|
|
61
67
|
},
|
|
62
|
-
errorPosition
|
|
68
|
+
errorPosition,
|
|
63
69
|
variant: "outlined",
|
|
64
70
|
placeholder: t("payment.checkout.billing.city")
|
|
65
71
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.FormLabel, {
|
|
@@ -68,9 +74,10 @@ function AddressForm({
|
|
|
68
74
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_input.default, {
|
|
69
75
|
name: "billing_address.state",
|
|
70
76
|
rules: {
|
|
71
|
-
required: t("payment.checkout.required")
|
|
77
|
+
required: t("payment.checkout.required"),
|
|
78
|
+
...(0, _validator.getFieldValidation)("billing_address.state", fieldValidation)
|
|
72
79
|
},
|
|
73
|
-
errorPosition
|
|
80
|
+
errorPosition,
|
|
74
81
|
variant: "outlined",
|
|
75
82
|
placeholder: t("payment.checkout.billing.state")
|
|
76
83
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.FormLabel, {
|
|
@@ -83,9 +90,10 @@ function AddressForm({
|
|
|
83
90
|
validate: x => {
|
|
84
91
|
const isValid = (0, _validator.validatePostalCode)(x, country);
|
|
85
92
|
return isValid ? true : t("payment.checkout.invalid");
|
|
86
|
-
}
|
|
93
|
+
},
|
|
94
|
+
...(0, _validator.getFieldValidation)("billing_address.postal_code", fieldValidation)
|
|
87
95
|
},
|
|
88
|
-
errorPosition
|
|
96
|
+
errorPosition,
|
|
89
97
|
variant: "outlined",
|
|
90
98
|
placeholder: t("payment.checkout.billing.postal_code"),
|
|
91
99
|
InputProps: {
|
|
@@ -139,9 +147,10 @@ function AddressForm({
|
|
|
139
147
|
validate: x => {
|
|
140
148
|
const isValid = (0, _validator.validatePostalCode)(x, country);
|
|
141
149
|
return isValid ? true : t("payment.checkout.invalid");
|
|
142
|
-
}
|
|
150
|
+
},
|
|
151
|
+
...(0, _validator.getFieldValidation)("billing_address.postal_code", fieldValidation)
|
|
143
152
|
},
|
|
144
|
-
errorPosition
|
|
153
|
+
errorPosition,
|
|
145
154
|
variant: "outlined",
|
|
146
155
|
placeholder: t("payment.checkout.billing.postal_code"),
|
|
147
156
|
wrapperStyle: {
|
|
@@ -36,6 +36,7 @@ var _loadingButton = _interopRequireDefault(require("../../components/loading-bu
|
|
|
36
36
|
var _overDueInvoicePayment = _interopRequireDefault(require("../../components/over-due-invoice-payment"));
|
|
37
37
|
var _currency2 = require("../../libs/currency");
|
|
38
38
|
var _confirm = _interopRequireDefault(require("../../components/confirm"));
|
|
39
|
+
var _validator = require("../../libs/validator");
|
|
39
40
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
40
41
|
const waitForCheckoutComplete = async sessionId => {
|
|
41
42
|
let result;
|
|
@@ -123,6 +124,7 @@ function PaymentForm({
|
|
|
123
124
|
payable
|
|
124
125
|
} = (0, _payment.usePaymentContext)();
|
|
125
126
|
const subscription = (0, _subscription.useSubscription)("events");
|
|
127
|
+
const formErrorPosition = isMobile ? "bottom" : "right";
|
|
126
128
|
const {
|
|
127
129
|
control,
|
|
128
130
|
getValues,
|
|
@@ -535,6 +537,7 @@ function PaymentForm({
|
|
|
535
537
|
window.removeEventListener("keydown", handleKeyDown);
|
|
536
538
|
};
|
|
537
539
|
}, [state.submitting, state.paying, state.stripePaying, quantityInventoryStatus, payable]);
|
|
540
|
+
const balanceLink = (0, _util2.getTokenBalanceLink)(method, state.fastCheckoutInfo?.payer || "");
|
|
538
541
|
const FastCheckoutConfirmDialog = state.fastCheckoutInfo && /* @__PURE__ */(0, _jsxRuntime.jsx)(_confirm.default, {
|
|
539
542
|
onConfirm: handleFastCheckoutConfirm,
|
|
540
543
|
onCancel: handleFastCheckoutCancel,
|
|
@@ -561,12 +564,33 @@ function PaymentForm({
|
|
|
561
564
|
whiteSpace: "nowrap"
|
|
562
565
|
},
|
|
563
566
|
children: t("payment.checkout.fastPay.payer")
|
|
564
|
-
}), /* @__PURE__ */(0, _jsxRuntime.
|
|
565
|
-
|
|
567
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
|
|
568
|
+
sx: {
|
|
569
|
+
display: "flex",
|
|
570
|
+
alignItems: "center",
|
|
571
|
+
gap: 0.5
|
|
572
|
+
},
|
|
573
|
+
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_DID.default, {
|
|
566
574
|
did: state.fastCheckoutInfo.payer || "",
|
|
567
575
|
compact: true,
|
|
568
576
|
responsive: false
|
|
569
|
-
})
|
|
577
|
+
}), balanceLink && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Tooltip, {
|
|
578
|
+
title: t("payment.checkout.fastPay.balanceLink"),
|
|
579
|
+
placement: "top",
|
|
580
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.OpenInNew, {
|
|
581
|
+
sx: {
|
|
582
|
+
color: "text.lighter",
|
|
583
|
+
fontSize: "0.85rem",
|
|
584
|
+
cursor: "pointer",
|
|
585
|
+
"&:hover": {
|
|
586
|
+
color: "text.primary"
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
onClick: () => {
|
|
590
|
+
window.open(balanceLink, "_blank");
|
|
591
|
+
}
|
|
592
|
+
})
|
|
593
|
+
})]
|
|
570
594
|
})]
|
|
571
595
|
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
572
596
|
flexDirection: "row",
|
|
@@ -709,9 +733,10 @@ function PaymentForm({
|
|
|
709
733
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_input.default, {
|
|
710
734
|
name: "customer_name",
|
|
711
735
|
variant: "outlined",
|
|
712
|
-
errorPosition:
|
|
736
|
+
errorPosition: formErrorPosition,
|
|
713
737
|
rules: {
|
|
714
|
-
required: t("payment.checkout.required")
|
|
738
|
+
required: t("payment.checkout.required"),
|
|
739
|
+
...(0, _validator.getFieldValidation)("customer_name", checkoutSession.metadata?.page_info?.field_validation, locale)
|
|
715
740
|
}
|
|
716
741
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.FormLabel, {
|
|
717
742
|
className: "base-label",
|
|
@@ -719,10 +744,11 @@ function PaymentForm({
|
|
|
719
744
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_input.default, {
|
|
720
745
|
name: "customer_email",
|
|
721
746
|
variant: "outlined",
|
|
722
|
-
errorPosition:
|
|
747
|
+
errorPosition: formErrorPosition,
|
|
723
748
|
rules: {
|
|
724
749
|
required: t("payment.checkout.required"),
|
|
725
|
-
validate: x => (0, _isEmail.default)(x) ? true : t("payment.checkout.invalid")
|
|
750
|
+
validate: x => (0, _isEmail.default)(x) ? true : t("payment.checkout.invalid"),
|
|
751
|
+
...(0, _validator.getFieldValidation)("customer_email", checkoutSession.metadata?.page_info?.field_validation, locale)
|
|
726
752
|
}
|
|
727
753
|
}), checkoutSession.phone_number_collection?.enabled && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
728
754
|
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.FormLabel, {
|
|
@@ -731,14 +757,15 @@ function PaymentForm({
|
|
|
731
757
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_phone.default, {
|
|
732
758
|
name: "customer_phone",
|
|
733
759
|
variant: "outlined",
|
|
734
|
-
errorPosition:
|
|
760
|
+
errorPosition: formErrorPosition,
|
|
735
761
|
placeholder: "Phone number",
|
|
736
762
|
rules: {
|
|
737
763
|
required: t("payment.checkout.required"),
|
|
738
764
|
validate: async x => {
|
|
739
765
|
const isValid = await (0, _phoneValidator.validatePhoneNumber)(x);
|
|
740
766
|
return isValid ? true : t("payment.checkout.invalid");
|
|
741
|
-
}
|
|
767
|
+
},
|
|
768
|
+
...(0, _validator.getFieldValidation)("customer_phone", checkoutSession.metadata?.page_info?.field_validation, locale)
|
|
742
769
|
}
|
|
743
770
|
})]
|
|
744
771
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_address.default, {
|
|
@@ -746,7 +773,9 @@ function PaymentForm({
|
|
|
746
773
|
stripe: method?.type === "stripe",
|
|
747
774
|
sx: {
|
|
748
775
|
marginTop: "0 !important"
|
|
749
|
-
}
|
|
776
|
+
},
|
|
777
|
+
fieldValidation: checkoutSession.metadata?.page_info?.field_validation,
|
|
778
|
+
errorPosition: formErrorPosition
|
|
750
779
|
})]
|
|
751
780
|
})]
|
|
752
781
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.35",
|
|
4
4
|
"description": "Reusable react components for payment kit v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -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.35",
|
|
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": "802a98b5ca81475f8cd7b9dcbb77fce7240b9788"
|
|
128
128
|
}
|
package/src/libs/util.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-nested-ternary */
|
|
2
2
|
/* eslint-disable @typescript-eslint/indent */
|
|
3
3
|
import type {
|
|
4
|
+
ChainType,
|
|
4
5
|
PaymentDetails,
|
|
5
6
|
PriceCurrency,
|
|
6
7
|
PriceRecurring,
|
|
@@ -1259,3 +1260,17 @@ export function parseMarkedText(text: string): Array<{
|
|
|
1259
1260
|
|
|
1260
1261
|
return result.filter((p) => p.content !== '');
|
|
1261
1262
|
}
|
|
1263
|
+
|
|
1264
|
+
export function getTokenBalanceLink(method: TPaymentMethod, address: string) {
|
|
1265
|
+
if (!method || !address) {
|
|
1266
|
+
return '';
|
|
1267
|
+
}
|
|
1268
|
+
const explorerHost = (method?.settings?.[method?.type as ChainType] as any)?.explorer_host || '';
|
|
1269
|
+
if (method.type === 'arcblock' && address) {
|
|
1270
|
+
return joinURL(explorerHost, 'accounts', address, 'tokens');
|
|
1271
|
+
}
|
|
1272
|
+
if (['ethereum', 'base'].includes(method.type) && address) {
|
|
1273
|
+
return joinURL(explorerHost, 'address', address);
|
|
1274
|
+
}
|
|
1275
|
+
return '';
|
|
1276
|
+
}
|
package/src/libs/validator.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import isPostalCode, { PostalCodeLocale } from 'validator/lib/isPostalCode';
|
|
2
|
+
import { t } from '../locales';
|
|
2
3
|
|
|
3
4
|
const POSTAL_CODE_SUPPORTED_COUNTRIES: PostalCodeLocale[] = [
|
|
4
5
|
'AD',
|
|
@@ -68,3 +69,16 @@ export function validatePostalCode(postalCode: string, country?: string): boolea
|
|
|
68
69
|
return false;
|
|
69
70
|
}
|
|
70
71
|
}
|
|
72
|
+
|
|
73
|
+
export function getFieldValidation(fieldName: string, validations?: Record<string, any>, locale: string = 'en') {
|
|
74
|
+
if (!validations || !validations[fieldName]) return {};
|
|
75
|
+
const fieldValidation = validations[fieldName];
|
|
76
|
+
const rules: Record<string, any> = {};
|
|
77
|
+
if (fieldValidation.pattern) {
|
|
78
|
+
rules.pattern = {
|
|
79
|
+
value: new RegExp(fieldValidation.pattern),
|
|
80
|
+
message: fieldValidation.pattern_message?.[locale] || t('payment.checkout.invalid', locale),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return rules;
|
|
84
|
+
}
|
package/src/locales/en.tsx
CHANGED
package/src/locales/zh.tsx
CHANGED
|
@@ -4,19 +4,23 @@ import type { SxProps } from '@mui/material';
|
|
|
4
4
|
import { Controller, useFormContext, useWatch } from 'react-hook-form';
|
|
5
5
|
import FormInput from '../../components/input';
|
|
6
6
|
import CountrySelect from '../../components/country-select';
|
|
7
|
-
import { validatePostalCode } from '../../libs/validator';
|
|
7
|
+
import { getFieldValidation, validatePostalCode } from '../../libs/validator';
|
|
8
8
|
|
|
9
9
|
type Props = {
|
|
10
10
|
mode: string;
|
|
11
11
|
stripe: boolean;
|
|
12
12
|
sx?: SxProps;
|
|
13
|
+
fieldValidation?: Record<string, any>;
|
|
14
|
+
errorPosition?: 'right' | 'bottom';
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
AddressForm.defaultProps = {
|
|
16
18
|
sx: {},
|
|
19
|
+
fieldValidation: {},
|
|
20
|
+
errorPosition: 'right',
|
|
17
21
|
};
|
|
18
22
|
|
|
19
|
-
export default function AddressForm({ mode, stripe, sx = {} }: Props) {
|
|
23
|
+
export default function AddressForm({ mode, stripe, sx = {}, fieldValidation, errorPosition }: Props) {
|
|
20
24
|
const { t } = useLocaleContext();
|
|
21
25
|
const { control } = useFormContext();
|
|
22
26
|
const country = useWatch({ control, name: 'billing_address.country' });
|
|
@@ -28,24 +32,33 @@ export default function AddressForm({ mode, stripe, sx = {} }: Props) {
|
|
|
28
32
|
<FormLabel className="base-label">{t('payment.checkout.billing.line1')}</FormLabel>
|
|
29
33
|
<FormInput
|
|
30
34
|
name="billing_address.line1"
|
|
31
|
-
rules={{
|
|
32
|
-
|
|
35
|
+
rules={{
|
|
36
|
+
required: t('payment.checkout.required'),
|
|
37
|
+
...getFieldValidation('billing_address.line1', fieldValidation),
|
|
38
|
+
}}
|
|
39
|
+
errorPosition={errorPosition}
|
|
33
40
|
variant="outlined"
|
|
34
41
|
placeholder={t('payment.checkout.billing.line1')}
|
|
35
42
|
/>
|
|
36
43
|
<FormLabel className="base-label">{t('payment.checkout.billing.city')}</FormLabel>
|
|
37
44
|
<FormInput
|
|
38
45
|
name="billing_address.city"
|
|
39
|
-
rules={{
|
|
40
|
-
|
|
46
|
+
rules={{
|
|
47
|
+
required: t('payment.checkout.required'),
|
|
48
|
+
...getFieldValidation('billing_address.city', fieldValidation),
|
|
49
|
+
}}
|
|
50
|
+
errorPosition={errorPosition}
|
|
41
51
|
variant="outlined"
|
|
42
52
|
placeholder={t('payment.checkout.billing.city')}
|
|
43
53
|
/>
|
|
44
54
|
<FormLabel className="base-label">{t('payment.checkout.billing.state')}</FormLabel>
|
|
45
55
|
<FormInput
|
|
46
56
|
name="billing_address.state"
|
|
47
|
-
rules={{
|
|
48
|
-
|
|
57
|
+
rules={{
|
|
58
|
+
required: t('payment.checkout.required'),
|
|
59
|
+
...getFieldValidation('billing_address.state', fieldValidation),
|
|
60
|
+
}}
|
|
61
|
+
errorPosition={errorPosition}
|
|
49
62
|
variant="outlined"
|
|
50
63
|
placeholder={t('payment.checkout.billing.state')}
|
|
51
64
|
/>
|
|
@@ -58,8 +71,9 @@ export default function AddressForm({ mode, stripe, sx = {} }: Props) {
|
|
|
58
71
|
const isValid = validatePostalCode(x, country);
|
|
59
72
|
return isValid ? true : t('payment.checkout.invalid');
|
|
60
73
|
},
|
|
74
|
+
...getFieldValidation('billing_address.postal_code', fieldValidation),
|
|
61
75
|
}}
|
|
62
|
-
errorPosition=
|
|
76
|
+
errorPosition={errorPosition}
|
|
63
77
|
variant="outlined"
|
|
64
78
|
placeholder={t('payment.checkout.billing.postal_code')}
|
|
65
79
|
InputProps={{
|
|
@@ -104,8 +118,9 @@ export default function AddressForm({ mode, stripe, sx = {} }: Props) {
|
|
|
104
118
|
const isValid = validatePostalCode(x, country);
|
|
105
119
|
return isValid ? true : t('payment.checkout.invalid');
|
|
106
120
|
},
|
|
121
|
+
...getFieldValidation('billing_address.postal_code', fieldValidation),
|
|
107
122
|
}}
|
|
108
|
-
errorPosition=
|
|
123
|
+
errorPosition={errorPosition}
|
|
109
124
|
variant="outlined"
|
|
110
125
|
placeholder={t('payment.checkout.billing.postal_code')}
|
|
111
126
|
wrapperStyle={{ height: '40px' }}
|
|
@@ -5,7 +5,7 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
|
5
5
|
// import { useTheme } from '@arcblock/ux/lib/Theme';
|
|
6
6
|
import Toast from '@arcblock/ux/lib/Toast';
|
|
7
7
|
import type { TCheckoutSession, TCustomer, TPaymentIntent, TPaymentMethodExpanded } from '@blocklet/payment-types';
|
|
8
|
-
import { Box, Button, CircularProgress, Divider, Fade, FormLabel, Stack, Typography } from '@mui/material';
|
|
8
|
+
import { Box, Button, CircularProgress, Divider, Fade, FormLabel, Stack, Tooltip, Typography } from '@mui/material';
|
|
9
9
|
import { useMemoizedFn, useSetState } from 'ahooks';
|
|
10
10
|
import pWaitFor from 'p-wait-for';
|
|
11
11
|
import { useEffect, useMemo, useRef } from 'react';
|
|
@@ -17,7 +17,7 @@ import { fromUnitToToken } from '@ocap/util';
|
|
|
17
17
|
import DID from '@arcblock/ux/lib/DID';
|
|
18
18
|
|
|
19
19
|
import isEmpty from 'lodash/isEmpty';
|
|
20
|
-
import { HelpOutline } from '@mui/icons-material';
|
|
20
|
+
import { HelpOutline, OpenInNew } from '@mui/icons-material';
|
|
21
21
|
import FormInput from '../../components/input';
|
|
22
22
|
import { usePaymentContext } from '../../contexts/payment';
|
|
23
23
|
import { useSubscription } from '../../hooks/subscription';
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
formatQuantityInventory,
|
|
29
29
|
getPrefix,
|
|
30
30
|
getStatementDescriptor,
|
|
31
|
+
getTokenBalanceLink,
|
|
31
32
|
isCrossOrigin,
|
|
32
33
|
} from '../../libs/util';
|
|
33
34
|
import type { CheckoutCallbacks, CheckoutContext } from '../../types';
|
|
@@ -41,6 +42,7 @@ import LoadingButton from '../../components/loading-button';
|
|
|
41
42
|
import OverdueInvoicePayment from '../../components/over-due-invoice-payment';
|
|
42
43
|
import { saveCurrencyPreference } from '../../libs/currency';
|
|
43
44
|
import ConfirmDialog from '../../components/confirm';
|
|
45
|
+
import { getFieldValidation } from '../../libs/validator';
|
|
44
46
|
|
|
45
47
|
export const waitForCheckoutComplete = async (sessionId: string) => {
|
|
46
48
|
let result: CheckoutContext;
|
|
@@ -175,6 +177,7 @@ export default function PaymentForm({
|
|
|
175
177
|
const { isMobile } = useMobile();
|
|
176
178
|
const { session, connect, payable } = usePaymentContext();
|
|
177
179
|
const subscription = useSubscription('events');
|
|
180
|
+
const formErrorPosition = isMobile ? 'bottom' : 'right';
|
|
178
181
|
const {
|
|
179
182
|
control,
|
|
180
183
|
getValues,
|
|
@@ -596,6 +599,7 @@ export default function PaymentForm({
|
|
|
596
599
|
};
|
|
597
600
|
}, [state.submitting, state.paying, state.stripePaying, quantityInventoryStatus, payable]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
598
601
|
|
|
602
|
+
const balanceLink = getTokenBalanceLink(method, state.fastCheckoutInfo?.payer || '');
|
|
599
603
|
const FastCheckoutConfirmDialog = state.fastCheckoutInfo && (
|
|
600
604
|
<ConfirmDialog
|
|
601
605
|
onConfirm={handleFastCheckoutConfirm}
|
|
@@ -611,9 +615,24 @@ export default function PaymentForm({
|
|
|
611
615
|
<Typography color="text.primary" sx={{ whiteSpace: 'nowrap' }}>
|
|
612
616
|
{t('payment.checkout.fastPay.payer')}
|
|
613
617
|
</Typography>
|
|
614
|
-
<
|
|
618
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
|
615
619
|
<DID did={state.fastCheckoutInfo.payer || ''} compact responsive={false} />
|
|
616
|
-
|
|
620
|
+
{balanceLink && (
|
|
621
|
+
<Tooltip title={t('payment.checkout.fastPay.balanceLink')} placement="top">
|
|
622
|
+
<OpenInNew
|
|
623
|
+
sx={{
|
|
624
|
+
color: 'text.lighter',
|
|
625
|
+
fontSize: '0.85rem',
|
|
626
|
+
cursor: 'pointer',
|
|
627
|
+
'&:hover': { color: 'text.primary' },
|
|
628
|
+
}}
|
|
629
|
+
onClick={() => {
|
|
630
|
+
window.open(balanceLink, '_blank');
|
|
631
|
+
}}
|
|
632
|
+
/>
|
|
633
|
+
</Tooltip>
|
|
634
|
+
)}
|
|
635
|
+
</Box>
|
|
617
636
|
</Stack>
|
|
618
637
|
<Stack flexDirection="row" alignItems="center" justifyContent="space-between">
|
|
619
638
|
<Typography color="text.primary">{t('payment.checkout.fastPay.amount')}</Typography>
|
|
@@ -748,19 +767,25 @@ export default function PaymentForm({
|
|
|
748
767
|
<FormInput
|
|
749
768
|
name="customer_name"
|
|
750
769
|
variant="outlined"
|
|
751
|
-
errorPosition=
|
|
770
|
+
errorPosition={formErrorPosition}
|
|
752
771
|
rules={{
|
|
753
772
|
required: t('payment.checkout.required'),
|
|
773
|
+
...getFieldValidation('customer_name', checkoutSession.metadata?.page_info?.field_validation, locale),
|
|
754
774
|
}}
|
|
755
775
|
/>
|
|
756
776
|
<FormLabel className="base-label">{t('payment.checkout.customer.email')}</FormLabel>
|
|
757
777
|
<FormInput
|
|
758
778
|
name="customer_email"
|
|
759
779
|
variant="outlined"
|
|
760
|
-
errorPosition=
|
|
780
|
+
errorPosition={formErrorPosition}
|
|
761
781
|
rules={{
|
|
762
782
|
required: t('payment.checkout.required'),
|
|
763
783
|
validate: (x) => (isEmail(x) ? true : t('payment.checkout.invalid')),
|
|
784
|
+
...getFieldValidation(
|
|
785
|
+
'customer_email',
|
|
786
|
+
checkoutSession.metadata?.page_info?.field_validation,
|
|
787
|
+
locale
|
|
788
|
+
),
|
|
764
789
|
}}
|
|
765
790
|
/>
|
|
766
791
|
{checkoutSession.phone_number_collection?.enabled && (
|
|
@@ -769,7 +794,7 @@ export default function PaymentForm({
|
|
|
769
794
|
<PhoneInput
|
|
770
795
|
name="customer_phone"
|
|
771
796
|
variant="outlined"
|
|
772
|
-
errorPosition=
|
|
797
|
+
errorPosition={formErrorPosition}
|
|
773
798
|
placeholder="Phone number"
|
|
774
799
|
rules={{
|
|
775
800
|
required: t('payment.checkout.required'),
|
|
@@ -777,6 +802,11 @@ export default function PaymentForm({
|
|
|
777
802
|
const isValid = await validatePhoneNumber(x);
|
|
778
803
|
return isValid ? true : t('payment.checkout.invalid');
|
|
779
804
|
},
|
|
805
|
+
...getFieldValidation(
|
|
806
|
+
'customer_phone',
|
|
807
|
+
checkoutSession.metadata?.page_info?.field_validation,
|
|
808
|
+
locale
|
|
809
|
+
),
|
|
780
810
|
}}
|
|
781
811
|
/>
|
|
782
812
|
</>
|
|
@@ -785,6 +815,8 @@ export default function PaymentForm({
|
|
|
785
815
|
mode={checkoutSession.billing_address_collection as string}
|
|
786
816
|
stripe={method?.type === 'stripe'}
|
|
787
817
|
sx={{ marginTop: '0 !important' }}
|
|
818
|
+
fieldValidation={checkoutSession.metadata?.page_info?.field_validation}
|
|
819
|
+
errorPosition={formErrorPosition}
|
|
788
820
|
/>
|
|
789
821
|
</Stack>
|
|
790
822
|
)}
|