@blocklet/payment-react 1.18.23 → 1.18.25
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/hooks/keyboard.js +3 -0
- package/es/libs/util.d.ts +2 -2
- package/es/libs/util.js +7 -4
- package/es/payment/form/index.js +1 -1
- package/es/payment/form/stripe/form.js +59 -11
- package/es/payment/product-donation.js +17 -25
- package/lib/hooks/keyboard.js +3 -0
- package/lib/libs/util.d.ts +2 -2
- package/lib/libs/util.js +7 -4
- package/lib/payment/form/index.js +1 -1
- package/lib/payment/form/stripe/form.js +78 -25
- package/lib/payment/product-donation.js +19 -33
- package/package.json +6 -6
- package/src/hooks/keyboard.ts +5 -3
- package/src/libs/util.ts +18 -4
- package/src/payment/form/index.tsx +1 -1
- package/src/payment/form/stripe/form.tsx +85 -24
- package/src/payment/product-donation.tsx +18 -25
package/es/hooks/keyboard.js
CHANGED
|
@@ -39,6 +39,9 @@ export const useTabNavigation = (items, onSelect, options) => {
|
|
|
39
39
|
return i;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
if (includeCustom && navigableElements.length > 0) {
|
|
43
|
+
return navigableElements.length - 1;
|
|
44
|
+
}
|
|
42
45
|
}
|
|
43
46
|
return -1;
|
|
44
47
|
}, [items, includeCustom, isCustomSelected, currentValue, valueType, compareValue, findNavigableElements]);
|
package/es/libs/util.d.ts
CHANGED
|
@@ -10,8 +10,8 @@ export declare function formatDateTime(date: Date | string | number, locale?: st
|
|
|
10
10
|
export declare const formatLocale: (locale?: string) => string;
|
|
11
11
|
export declare const formatPrettyMsLocale: (locale: string) => "zh_CN" | "en_US";
|
|
12
12
|
export declare const formatError: (err: any) => any;
|
|
13
|
-
export declare function formatBNStr(str?: string, decimals?: number, precision?: number, trim?: boolean): string;
|
|
14
|
-
export declare function formatNumber(n: number | string, precision?: number, trim?: boolean): string;
|
|
13
|
+
export declare function formatBNStr(str?: string, decimals?: number, precision?: number, trim?: boolean, thousandSeparated?: boolean): string;
|
|
14
|
+
export declare function formatNumber(n: number | string, precision?: number, trim?: boolean, thousandSeparated?: boolean): string;
|
|
15
15
|
export declare const formatPrice: (price: TPrice, currency: TPaymentCurrency, unit_label?: string, quantity?: number, bn?: boolean, locale?: string) => string;
|
|
16
16
|
export declare const formatPriceAmount: (price: TPrice, currency: TPaymentCurrency, unit_label?: string, quantity?: number, bn?: boolean) => string;
|
|
17
17
|
export declare function getStatementDescriptor(items: any[]): any;
|
package/es/libs/util.js
CHANGED
|
@@ -85,16 +85,19 @@ export const formatError = (err) => {
|
|
|
85
85
|
}
|
|
86
86
|
return err.message;
|
|
87
87
|
};
|
|
88
|
-
export function formatBNStr(str = "", decimals = 18, precision = 6, trim = true) {
|
|
89
|
-
|
|
88
|
+
export function formatBNStr(str = "", decimals = 18, precision = 6, trim = true, thousandSeparated = true) {
|
|
89
|
+
if (!str) {
|
|
90
|
+
return "0";
|
|
91
|
+
}
|
|
92
|
+
return formatNumber(fromUnitToToken(str, decimals), precision, trim, thousandSeparated);
|
|
90
93
|
}
|
|
91
|
-
export function formatNumber(n, precision = 6, trim = true) {
|
|
94
|
+
export function formatNumber(n, precision = 6, trim = true, thousandSeparated = true) {
|
|
92
95
|
if (!n || n === "0") {
|
|
93
96
|
return "0";
|
|
94
97
|
}
|
|
95
98
|
const num = numbro(n);
|
|
96
99
|
const options = {
|
|
97
|
-
thousandSeparated
|
|
100
|
+
thousandSeparated,
|
|
98
101
|
...(precision || precision === 0) && { mantissa: precision }
|
|
99
102
|
};
|
|
100
103
|
const result = num.format(options);
|
package/es/payment/form/index.js
CHANGED
|
@@ -183,7 +183,7 @@ export default function PaymentForm({
|
|
|
183
183
|
const values = getValues();
|
|
184
184
|
let userInfo = session.user;
|
|
185
185
|
try {
|
|
186
|
-
const { data: customerInfo } = await api.get(
|
|
186
|
+
const { data: customerInfo } = await api.get("/api/customers/me?skipSummary=1&fallback=1");
|
|
187
187
|
userInfo = mergeUserInfo(customerInfo, userInfo);
|
|
188
188
|
} catch (err) {
|
|
189
189
|
userInfo = mergeUserInfo(customer || {}, userInfo);
|
|
@@ -9,6 +9,13 @@ import { useEffect, useCallback } from "react";
|
|
|
9
9
|
import { useMobile } from "../../../hooks/mobile.js";
|
|
10
10
|
import LoadingButton from "../../../components/loading-button.js";
|
|
11
11
|
const { Elements, PaymentElement, useElements, useStripe, loadStripe, LinkAuthenticationElement } = globalThis.__STRIPE_COMPONENTS__;
|
|
12
|
+
const PaymentElementContainer = styled("div")`
|
|
13
|
+
opacity: 0;
|
|
14
|
+
transition: opacity 300ms ease;
|
|
15
|
+
&.visible {
|
|
16
|
+
opacity: 1;
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
12
19
|
function StripeCheckoutForm({
|
|
13
20
|
clientSecret,
|
|
14
21
|
intentType,
|
|
@@ -23,8 +30,32 @@ function StripeCheckoutForm({
|
|
|
23
30
|
const [state, setState] = useSetState({
|
|
24
31
|
message: "",
|
|
25
32
|
confirming: false,
|
|
26
|
-
loaded: false
|
|
33
|
+
loaded: false,
|
|
34
|
+
showBillingForm: false,
|
|
35
|
+
isTransitioning: false
|
|
27
36
|
});
|
|
37
|
+
const handlePaymentMethodChange = (event) => {
|
|
38
|
+
const method = event.value?.type;
|
|
39
|
+
const needsBillingInfo = method === "google_pay" || method === "apple_pay";
|
|
40
|
+
const shouldShowForm = needsBillingInfo && !isCompleteBillingAddress(customer.address);
|
|
41
|
+
if (shouldShowForm && !state.showBillingForm) {
|
|
42
|
+
setState({ isTransitioning: true });
|
|
43
|
+
setTimeout(() => {
|
|
44
|
+
setState({
|
|
45
|
+
isTransitioning: false,
|
|
46
|
+
showBillingForm: true
|
|
47
|
+
});
|
|
48
|
+
}, 300);
|
|
49
|
+
} else {
|
|
50
|
+
setState({
|
|
51
|
+
showBillingForm: false,
|
|
52
|
+
isTransitioning: false
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const isCompleteBillingAddress = (address) => {
|
|
57
|
+
return address && address.line1 && address.city && address.state && address.postal_code && address.country;
|
|
58
|
+
};
|
|
28
59
|
useEffect(() => {
|
|
29
60
|
if (!stripe) {
|
|
30
61
|
return;
|
|
@@ -57,19 +88,33 @@ function StripeCheckoutForm({
|
|
|
57
88
|
try {
|
|
58
89
|
setState({ confirming: true });
|
|
59
90
|
const method = intentType === "payment_intent" ? "confirmPayment" : "confirmSetup";
|
|
91
|
+
const { error: submitError } = await elements.submit();
|
|
92
|
+
if (submitError) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
60
95
|
const { error } = await stripe[method]({
|
|
61
96
|
elements,
|
|
62
97
|
redirect: "if_required",
|
|
63
98
|
confirmParams: {
|
|
64
99
|
return_url: returnUrl || window.location.href,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
100
|
+
...!state.showBillingForm ? {
|
|
101
|
+
payment_method_data: {
|
|
102
|
+
billing_details: {
|
|
103
|
+
name: customer.name,
|
|
104
|
+
phone: customer.phone,
|
|
105
|
+
email: customer.email,
|
|
106
|
+
address: {
|
|
107
|
+
...customer.address || {},
|
|
108
|
+
country: customer.address?.country || "us",
|
|
109
|
+
line1: customer.address?.line1 || "",
|
|
110
|
+
line2: customer.address?.line2 || "",
|
|
111
|
+
city: customer.address?.city || "",
|
|
112
|
+
state: customer.address?.state || "",
|
|
113
|
+
postal_code: customer.address?.postal_code || "00000"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
71
116
|
}
|
|
72
|
-
}
|
|
117
|
+
} : {}
|
|
73
118
|
}
|
|
74
119
|
});
|
|
75
120
|
setState({ confirming: false });
|
|
@@ -98,12 +143,14 @@ function StripeCheckoutForm({
|
|
|
98
143
|
}
|
|
99
144
|
}
|
|
100
145
|
),
|
|
101
|
-
/* @__PURE__ */ jsx(
|
|
146
|
+
/* @__PURE__ */ jsx(PaymentElementContainer, { className: !state.isTransitioning ? "visible" : "", children: /* @__PURE__ */ jsx(
|
|
102
147
|
PaymentElement,
|
|
103
148
|
{
|
|
104
149
|
options: {
|
|
105
150
|
layout: "auto",
|
|
106
|
-
fields: {
|
|
151
|
+
fields: {
|
|
152
|
+
billingDetails: state.showBillingForm ? "auto" : "never"
|
|
153
|
+
},
|
|
107
154
|
readOnly: state.confirming,
|
|
108
155
|
defaultValues: {
|
|
109
156
|
billingDetails: {
|
|
@@ -114,9 +161,10 @@ function StripeCheckoutForm({
|
|
|
114
161
|
}
|
|
115
162
|
}
|
|
116
163
|
},
|
|
164
|
+
onChange: handlePaymentMethodChange,
|
|
117
165
|
onReady: () => setState({ loaded: true })
|
|
118
166
|
}
|
|
119
|
-
),
|
|
167
|
+
) }),
|
|
120
168
|
(!stripe || !elements || !state.loaded) && /* @__PURE__ */ jsx(Center, { relative: "parent", children: /* @__PURE__ */ jsx(CircularProgress, {}) }),
|
|
121
169
|
stripe && elements && state.loaded && /* @__PURE__ */ jsx(
|
|
122
170
|
LoadingButton,
|
|
@@ -52,12 +52,6 @@ export default function ProductDonation({
|
|
|
52
52
|
const middleIndex = Math.floor(presets.length / 2);
|
|
53
53
|
return presets[middleIndex];
|
|
54
54
|
}
|
|
55
|
-
if (settings?.amount?.preset) {
|
|
56
|
-
return formatAmount(settings.amount.preset);
|
|
57
|
-
}
|
|
58
|
-
if (presets.length > 0) {
|
|
59
|
-
return presets[0];
|
|
60
|
-
}
|
|
61
55
|
return "0";
|
|
62
56
|
};
|
|
63
57
|
const supportPreset = presets.length > 0;
|
|
@@ -106,26 +100,24 @@ export default function ProductDonation({
|
|
|
106
100
|
containerRef
|
|
107
101
|
});
|
|
108
102
|
useEffect(() => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
setPayable(false);
|
|
126
|
-
}
|
|
103
|
+
const currentPreset = getDefaultPreset();
|
|
104
|
+
const isCustom = currentPreset === "custom";
|
|
105
|
+
setState({
|
|
106
|
+
selected: isCustom ? "" : currentPreset,
|
|
107
|
+
custom: !supportPreset || currentPreset === "custom",
|
|
108
|
+
input: defaultCustomAmount,
|
|
109
|
+
error: ""
|
|
110
|
+
});
|
|
111
|
+
if (!isCustom) {
|
|
112
|
+
onChange({ priceId: item.price_id, amount: currentPreset });
|
|
113
|
+
setPayable(true);
|
|
114
|
+
} else if (defaultCustomAmount) {
|
|
115
|
+
onChange({ priceId: item.price_id, amount: defaultCustomAmount });
|
|
116
|
+
setPayable(true);
|
|
117
|
+
} else {
|
|
118
|
+
setPayable(false);
|
|
127
119
|
}
|
|
128
|
-
}, [settings.amount.preset, settings.amount.presets]);
|
|
120
|
+
}, [settings.amount.preset, settings.amount.presets, supportPreset]);
|
|
129
121
|
useEffect(() => {
|
|
130
122
|
if (containerRef.current) {
|
|
131
123
|
containerRef.current.focus();
|
package/lib/hooks/keyboard.js
CHANGED
|
@@ -44,6 +44,9 @@ const useTabNavigation = (items, onSelect, options) => {
|
|
|
44
44
|
return i;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
if (includeCustom && navigableElements.length > 0) {
|
|
48
|
+
return navigableElements.length - 1;
|
|
49
|
+
}
|
|
47
50
|
}
|
|
48
51
|
return -1;
|
|
49
52
|
}, [items, includeCustom, isCustomSelected, currentValue, valueType, compareValue, findNavigableElements]);
|
package/lib/libs/util.d.ts
CHANGED
|
@@ -10,8 +10,8 @@ export declare function formatDateTime(date: Date | string | number, locale?: st
|
|
|
10
10
|
export declare const formatLocale: (locale?: string) => string;
|
|
11
11
|
export declare const formatPrettyMsLocale: (locale: string) => "zh_CN" | "en_US";
|
|
12
12
|
export declare const formatError: (err: any) => any;
|
|
13
|
-
export declare function formatBNStr(str?: string, decimals?: number, precision?: number, trim?: boolean): string;
|
|
14
|
-
export declare function formatNumber(n: number | string, precision?: number, trim?: boolean): string;
|
|
13
|
+
export declare function formatBNStr(str?: string, decimals?: number, precision?: number, trim?: boolean, thousandSeparated?: boolean): string;
|
|
14
|
+
export declare function formatNumber(n: number | string, precision?: number, trim?: boolean, thousandSeparated?: boolean): string;
|
|
15
15
|
export declare const formatPrice: (price: TPrice, currency: TPaymentCurrency, unit_label?: string, quantity?: number, bn?: boolean, locale?: string) => string;
|
|
16
16
|
export declare const formatPriceAmount: (price: TPrice, currency: TPaymentCurrency, unit_label?: string, quantity?: number, bn?: boolean) => string;
|
|
17
17
|
export declare function getStatementDescriptor(items: any[]): any;
|
package/lib/libs/util.js
CHANGED
|
@@ -156,16 +156,19 @@ const formatError = err => {
|
|
|
156
156
|
return err.message;
|
|
157
157
|
};
|
|
158
158
|
exports.formatError = formatError;
|
|
159
|
-
function formatBNStr(str = "", decimals = 18, precision = 6, trim = true) {
|
|
160
|
-
|
|
159
|
+
function formatBNStr(str = "", decimals = 18, precision = 6, trim = true, thousandSeparated = true) {
|
|
160
|
+
if (!str) {
|
|
161
|
+
return "0";
|
|
162
|
+
}
|
|
163
|
+
return formatNumber((0, _util.fromUnitToToken)(str, decimals), precision, trim, thousandSeparated);
|
|
161
164
|
}
|
|
162
|
-
function formatNumber(n, precision = 6, trim = true) {
|
|
165
|
+
function formatNumber(n, precision = 6, trim = true, thousandSeparated = true) {
|
|
163
166
|
if (!n || n === "0") {
|
|
164
167
|
return "0";
|
|
165
168
|
}
|
|
166
169
|
const num = (0, _numbro.default)(n);
|
|
167
170
|
const options = {
|
|
168
|
-
thousandSeparated
|
|
171
|
+
thousandSeparated,
|
|
169
172
|
...((precision || precision === 0) && {
|
|
170
173
|
mantissa: precision
|
|
171
174
|
})
|
|
@@ -209,7 +209,7 @@ function PaymentForm({
|
|
|
209
209
|
try {
|
|
210
210
|
const {
|
|
211
211
|
data: customerInfo
|
|
212
|
-
} = await _api.default.get(
|
|
212
|
+
} = await _api.default.get("/api/customers/me?skipSummary=1&fallback=1");
|
|
213
213
|
userInfo = mergeUserInfo(customerInfo, userInfo);
|
|
214
214
|
} catch (err) {
|
|
215
215
|
userInfo = mergeUserInfo(customer || {}, userInfo);
|
|
@@ -23,6 +23,13 @@ const {
|
|
|
23
23
|
loadStripe,
|
|
24
24
|
LinkAuthenticationElement
|
|
25
25
|
} = globalThis.__STRIPE_COMPONENTS__;
|
|
26
|
+
const PaymentElementContainer = (0, _system.styled)("div")`
|
|
27
|
+
opacity: 0;
|
|
28
|
+
transition: opacity 300ms ease;
|
|
29
|
+
&.visible {
|
|
30
|
+
opacity: 1;
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
26
33
|
function StripeCheckoutForm({
|
|
27
34
|
clientSecret,
|
|
28
35
|
intentType,
|
|
@@ -39,8 +46,34 @@ function StripeCheckoutForm({
|
|
|
39
46
|
const [state, setState] = (0, _ahooks.useSetState)({
|
|
40
47
|
message: "",
|
|
41
48
|
confirming: false,
|
|
42
|
-
loaded: false
|
|
49
|
+
loaded: false,
|
|
50
|
+
showBillingForm: false,
|
|
51
|
+
isTransitioning: false
|
|
43
52
|
});
|
|
53
|
+
const handlePaymentMethodChange = event => {
|
|
54
|
+
const method = event.value?.type;
|
|
55
|
+
const needsBillingInfo = method === "google_pay" || method === "apple_pay";
|
|
56
|
+
const shouldShowForm = needsBillingInfo && !isCompleteBillingAddress(customer.address);
|
|
57
|
+
if (shouldShowForm && !state.showBillingForm) {
|
|
58
|
+
setState({
|
|
59
|
+
isTransitioning: true
|
|
60
|
+
});
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
setState({
|
|
63
|
+
isTransitioning: false,
|
|
64
|
+
showBillingForm: true
|
|
65
|
+
});
|
|
66
|
+
}, 300);
|
|
67
|
+
} else {
|
|
68
|
+
setState({
|
|
69
|
+
showBillingForm: false,
|
|
70
|
+
isTransitioning: false
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const isCompleteBillingAddress = address => {
|
|
75
|
+
return address && address.line1 && address.city && address.state && address.postal_code && address.country;
|
|
76
|
+
};
|
|
44
77
|
(0, _react.useEffect)(() => {
|
|
45
78
|
if (!stripe) {
|
|
46
79
|
return;
|
|
@@ -81,6 +114,12 @@ function StripeCheckoutForm({
|
|
|
81
114
|
confirming: true
|
|
82
115
|
});
|
|
83
116
|
const method = intentType === "payment_intent" ? "confirmPayment" : "confirmSetup";
|
|
117
|
+
const {
|
|
118
|
+
error: submitError
|
|
119
|
+
} = await elements.submit();
|
|
120
|
+
if (submitError) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
84
123
|
const {
|
|
85
124
|
error
|
|
86
125
|
} = await stripe[method]({
|
|
@@ -88,14 +127,24 @@ function StripeCheckoutForm({
|
|
|
88
127
|
redirect: "if_required",
|
|
89
128
|
confirmParams: {
|
|
90
129
|
return_url: returnUrl || window.location.href,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
130
|
+
...(!state.showBillingForm ? {
|
|
131
|
+
payment_method_data: {
|
|
132
|
+
billing_details: {
|
|
133
|
+
name: customer.name,
|
|
134
|
+
phone: customer.phone,
|
|
135
|
+
email: customer.email,
|
|
136
|
+
address: {
|
|
137
|
+
...(customer.address || {}),
|
|
138
|
+
country: customer.address?.country || "us",
|
|
139
|
+
line1: customer.address?.line1 || "",
|
|
140
|
+
line2: customer.address?.line2 || "",
|
|
141
|
+
city: customer.address?.city || "",
|
|
142
|
+
state: customer.address?.state || "",
|
|
143
|
+
postal_code: customer.address?.postal_code || "00000"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
97
146
|
}
|
|
98
|
-
}
|
|
147
|
+
} : {})
|
|
99
148
|
}
|
|
100
149
|
});
|
|
101
150
|
setState({
|
|
@@ -128,24 +177,28 @@ function StripeCheckoutForm({
|
|
|
128
177
|
options: {
|
|
129
178
|
defaultEmail: customer.email
|
|
130
179
|
}
|
|
131
|
-
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
180
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(PaymentElementContainer, {
|
|
181
|
+
className: !state.isTransitioning ? "visible" : "",
|
|
182
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(PaymentElement, {
|
|
183
|
+
options: {
|
|
184
|
+
layout: "auto",
|
|
185
|
+
fields: {
|
|
186
|
+
billingDetails: state.showBillingForm ? "auto" : "never"
|
|
187
|
+
},
|
|
188
|
+
readOnly: state.confirming,
|
|
189
|
+
defaultValues: {
|
|
190
|
+
billingDetails: {
|
|
191
|
+
name: customer.name,
|
|
192
|
+
phone: customer.phone,
|
|
193
|
+
email: customer.email,
|
|
194
|
+
address: customer.address
|
|
195
|
+
}
|
|
144
196
|
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
197
|
+
},
|
|
198
|
+
onChange: handlePaymentMethodChange,
|
|
199
|
+
onReady: () => setState({
|
|
200
|
+
loaded: true
|
|
201
|
+
})
|
|
149
202
|
})
|
|
150
203
|
}), (!stripe || !elements || !state.loaded) && /* @__PURE__ */(0, _jsxRuntime.jsx)(_Center.default, {
|
|
151
204
|
relative: "parent",
|
|
@@ -64,12 +64,6 @@ function ProductDonation({
|
|
|
64
64
|
const middleIndex = Math.floor(presets.length / 2);
|
|
65
65
|
return presets[middleIndex];
|
|
66
66
|
}
|
|
67
|
-
if (settings?.amount?.preset) {
|
|
68
|
-
return formatAmount(settings.amount.preset);
|
|
69
|
-
}
|
|
70
|
-
if (presets.length > 0) {
|
|
71
|
-
return presets[0];
|
|
72
|
-
}
|
|
73
67
|
return "0";
|
|
74
68
|
};
|
|
75
69
|
const supportPreset = presets.length > 0;
|
|
@@ -136,38 +130,30 @@ function ProductDonation({
|
|
|
136
130
|
containerRef
|
|
137
131
|
});
|
|
138
132
|
(0, _react.useEffect)(() => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
133
|
+
const currentPreset = getDefaultPreset();
|
|
134
|
+
const isCustom = currentPreset === "custom";
|
|
135
|
+
setState({
|
|
136
|
+
selected: isCustom ? "" : currentPreset,
|
|
137
|
+
custom: !supportPreset || currentPreset === "custom",
|
|
138
|
+
input: defaultCustomAmount,
|
|
139
|
+
error: ""
|
|
140
|
+
});
|
|
141
|
+
if (!isCustom) {
|
|
144
142
|
onChange({
|
|
145
143
|
priceId: item.price_id,
|
|
146
|
-
amount:
|
|
144
|
+
amount: currentPreset
|
|
147
145
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
input: isCustom ? getSavedCustomAmount() : ""
|
|
146
|
+
setPayable(true);
|
|
147
|
+
} else if (defaultCustomAmount) {
|
|
148
|
+
onChange({
|
|
149
|
+
priceId: item.price_id,
|
|
150
|
+
amount: defaultCustomAmount
|
|
154
151
|
});
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
amount: defaultPreset
|
|
159
|
-
});
|
|
160
|
-
} else if (defaultCustomAmount) {
|
|
161
|
-
onChange({
|
|
162
|
-
priceId: item.price_id,
|
|
163
|
-
amount: defaultCustomAmount
|
|
164
|
-
});
|
|
165
|
-
setPayable(true);
|
|
166
|
-
} else {
|
|
167
|
-
setPayable(false);
|
|
168
|
-
}
|
|
152
|
+
setPayable(true);
|
|
153
|
+
} else {
|
|
154
|
+
setPayable(false);
|
|
169
155
|
}
|
|
170
|
-
}, [settings.amount.preset, settings.amount.presets]);
|
|
156
|
+
}, [settings.amount.preset, settings.amount.presets, supportPreset]);
|
|
171
157
|
(0, _react.useEffect)(() => {
|
|
172
158
|
if (containerRef.current) {
|
|
173
159
|
containerRef.current.focus();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.25",
|
|
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.52",
|
|
58
|
+
"@arcblock/ux": "^2.12.52",
|
|
59
59
|
"@arcblock/ws": "^1.19.15",
|
|
60
|
-
"@blocklet/ui-react": "^2.12.
|
|
60
|
+
"@blocklet/ui-react": "^2.12.52",
|
|
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.25",
|
|
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": "1665ec667d621a3e607650e486cb0967371b9771"
|
|
128
128
|
}
|
package/src/hooks/keyboard.ts
CHANGED
|
@@ -86,12 +86,14 @@ export const useTabNavigation = <T>(
|
|
|
86
86
|
// if tabbed, find current focused element
|
|
87
87
|
const focusedElement = document.activeElement;
|
|
88
88
|
const navigableElements = findNavigableElements();
|
|
89
|
-
|
|
90
89
|
for (let i = 0; i < navigableElements.length; i++) {
|
|
91
90
|
if (navigableElements[i] === focusedElement) {
|
|
92
91
|
return i;
|
|
93
92
|
}
|
|
94
93
|
}
|
|
94
|
+
if (includeCustom && navigableElements.length > 0) {
|
|
95
|
+
return navigableElements.length - 1;
|
|
96
|
+
}
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
return -1;
|
|
@@ -107,10 +109,10 @@ export const useTabNavigation = <T>(
|
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
if (isShiftKey) {
|
|
110
|
-
// Shift+Tab
|
|
112
|
+
// Shift+Tab backward
|
|
111
113
|
return currentIndex === 0 ? totalOptions - 1 : currentIndex - 1;
|
|
112
114
|
}
|
|
113
|
-
// Tab
|
|
115
|
+
// Tab next
|
|
114
116
|
return currentIndex === totalOptions - 1 ? 0 : currentIndex + 1;
|
|
115
117
|
},
|
|
116
118
|
[items, includeCustom]
|
package/src/libs/util.ts
CHANGED
|
@@ -130,17 +130,31 @@ export const formatError = (err: any) => {
|
|
|
130
130
|
return err.message;
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
-
export function formatBNStr(
|
|
134
|
-
|
|
133
|
+
export function formatBNStr(
|
|
134
|
+
str: string = '',
|
|
135
|
+
decimals: number = 18,
|
|
136
|
+
precision: number = 6,
|
|
137
|
+
trim: boolean = true,
|
|
138
|
+
thousandSeparated: boolean = true
|
|
139
|
+
) {
|
|
140
|
+
if (!str) {
|
|
141
|
+
return '0';
|
|
142
|
+
}
|
|
143
|
+
return formatNumber(fromUnitToToken(str, decimals), precision, trim, thousandSeparated);
|
|
135
144
|
}
|
|
136
145
|
|
|
137
|
-
export function formatNumber(
|
|
146
|
+
export function formatNumber(
|
|
147
|
+
n: number | string,
|
|
148
|
+
precision: number = 6,
|
|
149
|
+
trim: boolean = true,
|
|
150
|
+
thousandSeparated: boolean = true
|
|
151
|
+
) {
|
|
138
152
|
if (!n || n === '0') {
|
|
139
153
|
return '0';
|
|
140
154
|
}
|
|
141
155
|
const num = numbro(n);
|
|
142
156
|
const options = {
|
|
143
|
-
thousandSeparated
|
|
157
|
+
thousandSeparated,
|
|
144
158
|
...((precision || precision === 0) && { mantissa: precision }),
|
|
145
159
|
};
|
|
146
160
|
const result = num.format(options);
|
|
@@ -272,7 +272,7 @@ export default function PaymentForm({
|
|
|
272
272
|
const values = getValues();
|
|
273
273
|
let userInfo = session.user;
|
|
274
274
|
try {
|
|
275
|
-
const { data: customerInfo } = await api.get(
|
|
275
|
+
const { data: customerInfo } = await api.get('/api/customers/me?skipSummary=1&fallback=1');
|
|
276
276
|
userInfo = mergeUserInfo(customerInfo, userInfo);
|
|
277
277
|
} catch (err) {
|
|
278
278
|
// @ts-ignore
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/indent */
|
|
1
2
|
import Center from '@arcblock/ux/lib/Center';
|
|
2
3
|
import Dialog from '@arcblock/ux/lib/Dialog';
|
|
3
4
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
@@ -21,6 +22,14 @@ export type StripeCheckoutFormProps = {
|
|
|
21
22
|
returnUrl: string;
|
|
22
23
|
};
|
|
23
24
|
|
|
25
|
+
const PaymentElementContainer = styled('div')`
|
|
26
|
+
opacity: 0;
|
|
27
|
+
transition: opacity 300ms ease;
|
|
28
|
+
&.visible {
|
|
29
|
+
opacity: 1;
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
|
|
24
33
|
// @doc https://stripe.com/docs/js/elements_object/create_payment_element
|
|
25
34
|
function StripeCheckoutForm({
|
|
26
35
|
clientSecret,
|
|
@@ -38,8 +47,36 @@ function StripeCheckoutForm({
|
|
|
38
47
|
message: '',
|
|
39
48
|
confirming: false,
|
|
40
49
|
loaded: false,
|
|
50
|
+
showBillingForm: false,
|
|
51
|
+
isTransitioning: false,
|
|
41
52
|
});
|
|
42
53
|
|
|
54
|
+
const handlePaymentMethodChange = (event: any) => {
|
|
55
|
+
const method = event.value?.type;
|
|
56
|
+
const needsBillingInfo = method === 'google_pay' || method === 'apple_pay';
|
|
57
|
+
const shouldShowForm = needsBillingInfo && !isCompleteBillingAddress(customer.address);
|
|
58
|
+
|
|
59
|
+
if (shouldShowForm && !state.showBillingForm) {
|
|
60
|
+
setState({ isTransitioning: true });
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
setState({
|
|
63
|
+
isTransitioning: false,
|
|
64
|
+
showBillingForm: true,
|
|
65
|
+
});
|
|
66
|
+
}, 300);
|
|
67
|
+
} else {
|
|
68
|
+
// if shouldShowForm is false, set showBillingForm to false immediately
|
|
69
|
+
setState({
|
|
70
|
+
showBillingForm: false,
|
|
71
|
+
isTransitioning: false,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const isCompleteBillingAddress = (address: any) => {
|
|
77
|
+
return address && address.line1 && address.city && address.state && address.postal_code && address.country;
|
|
78
|
+
};
|
|
79
|
+
|
|
43
80
|
useEffect(() => {
|
|
44
81
|
if (!stripe) {
|
|
45
82
|
return;
|
|
@@ -78,19 +115,37 @@ function StripeCheckoutForm({
|
|
|
78
115
|
try {
|
|
79
116
|
setState({ confirming: true });
|
|
80
117
|
const method = intentType === 'payment_intent' ? 'confirmPayment' : 'confirmSetup';
|
|
118
|
+
|
|
119
|
+
const { error: submitError } = await elements.submit();
|
|
120
|
+
if (submitError) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
81
124
|
const { error } = await stripe[method]({
|
|
82
125
|
elements,
|
|
83
126
|
redirect: 'if_required',
|
|
84
127
|
confirmParams: {
|
|
85
128
|
return_url: returnUrl || window.location.href,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
129
|
+
...(!state.showBillingForm
|
|
130
|
+
? {
|
|
131
|
+
payment_method_data: {
|
|
132
|
+
billing_details: {
|
|
133
|
+
name: customer.name,
|
|
134
|
+
phone: customer.phone,
|
|
135
|
+
email: customer.email,
|
|
136
|
+
address: {
|
|
137
|
+
...(customer.address || {}),
|
|
138
|
+
country: customer.address?.country || 'us',
|
|
139
|
+
line1: customer.address?.line1 || '',
|
|
140
|
+
line2: customer.address?.line2 || '',
|
|
141
|
+
city: customer.address?.city || '',
|
|
142
|
+
state: customer.address?.state || '',
|
|
143
|
+
postal_code: customer.address?.postal_code || '00000',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
: {}),
|
|
94
149
|
},
|
|
95
150
|
});
|
|
96
151
|
setState({ confirming: false });
|
|
@@ -98,7 +153,6 @@ function StripeCheckoutForm({
|
|
|
98
153
|
if (error.type === 'validation_error') {
|
|
99
154
|
return;
|
|
100
155
|
}
|
|
101
|
-
|
|
102
156
|
setState({ message: error.message as string });
|
|
103
157
|
return;
|
|
104
158
|
}
|
|
@@ -119,22 +173,29 @@ function StripeCheckoutForm({
|
|
|
119
173
|
defaultEmail: customer.email,
|
|
120
174
|
}}
|
|
121
175
|
/>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
name: customer.name,
|
|
130
|
-
phone: customer.phone,
|
|
131
|
-
email: customer.email,
|
|
132
|
-
address: customer.address,
|
|
176
|
+
|
|
177
|
+
<PaymentElementContainer className={!state.isTransitioning ? 'visible' : ''}>
|
|
178
|
+
<PaymentElement
|
|
179
|
+
options={{
|
|
180
|
+
layout: 'auto',
|
|
181
|
+
fields: {
|
|
182
|
+
billingDetails: state.showBillingForm ? 'auto' : 'never',
|
|
133
183
|
},
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
184
|
+
readOnly: state.confirming,
|
|
185
|
+
defaultValues: {
|
|
186
|
+
billingDetails: {
|
|
187
|
+
name: customer.name,
|
|
188
|
+
phone: customer.phone,
|
|
189
|
+
email: customer.email,
|
|
190
|
+
address: customer.address,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
}}
|
|
194
|
+
onChange={handlePaymentMethodChange}
|
|
195
|
+
onReady={() => setState({ loaded: true })}
|
|
196
|
+
/>
|
|
197
|
+
</PaymentElementContainer>
|
|
198
|
+
|
|
138
199
|
{(!stripe || !elements || !state.loaded) && (
|
|
139
200
|
<Center relative="parent">
|
|
140
201
|
<CircularProgress />
|
|
@@ -65,12 +65,6 @@ export default function ProductDonation({
|
|
|
65
65
|
const middleIndex = Math.floor(presets.length / 2);
|
|
66
66
|
return presets[middleIndex];
|
|
67
67
|
}
|
|
68
|
-
if (settings?.amount?.preset) {
|
|
69
|
-
return formatAmount(settings.amount.preset);
|
|
70
|
-
}
|
|
71
|
-
if (presets.length > 0) {
|
|
72
|
-
return presets[0];
|
|
73
|
-
}
|
|
74
68
|
return '0';
|
|
75
69
|
};
|
|
76
70
|
|
|
@@ -128,27 +122,26 @@ export default function ProductDonation({
|
|
|
128
122
|
});
|
|
129
123
|
|
|
130
124
|
useEffect(() => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
onChange({ priceId: item.price_id, amount: settings.amount.preset });
|
|
134
|
-
} else if (settings.amount.presets && settings.amount.presets.length > 0) {
|
|
135
|
-
const isCustom = defaultPreset === 'custom';
|
|
136
|
-
setState({
|
|
137
|
-
selected: isCustom ? '' : defaultPreset,
|
|
138
|
-
custom: isCustom,
|
|
139
|
-
input: isCustom ? getSavedCustomAmount() : '',
|
|
140
|
-
});
|
|
125
|
+
const currentPreset = getDefaultPreset();
|
|
126
|
+
const isCustom = currentPreset === 'custom';
|
|
141
127
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
128
|
+
setState({
|
|
129
|
+
selected: isCustom ? '' : currentPreset,
|
|
130
|
+
custom: !supportPreset || currentPreset === 'custom',
|
|
131
|
+
input: defaultCustomAmount,
|
|
132
|
+
error: '',
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (!isCustom) {
|
|
136
|
+
onChange({ priceId: item.price_id, amount: currentPreset });
|
|
137
|
+
setPayable(true);
|
|
138
|
+
} else if (defaultCustomAmount) {
|
|
139
|
+
onChange({ priceId: item.price_id, amount: defaultCustomAmount });
|
|
140
|
+
setPayable(true);
|
|
141
|
+
} else {
|
|
142
|
+
setPayable(false);
|
|
150
143
|
}
|
|
151
|
-
}, [settings.amount.preset, settings.amount.presets]); // eslint-disable-line
|
|
144
|
+
}, [settings.amount.preset, settings.amount.presets, supportPreset]); // eslint-disable-line
|
|
152
145
|
|
|
153
146
|
useEffect(() => {
|
|
154
147
|
if (containerRef.current) {
|