@blocklet/payment-react 1.21.15 → 1.21.17
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/.aigne/doc-smith/translation-cache.yaml +11 -0
- package/es/components/over-due-invoice-payment.js +86 -21
- package/es/components/payment-beneficiaries.js +3 -3
- package/es/components/stripe-payment-action.d.ts +16 -0
- package/es/components/stripe-payment-action.js +164 -0
- package/es/history/invoice/list.js +58 -2
- package/es/index.d.ts +3 -1
- package/es/index.js +2 -0
- package/es/libs/util.d.ts +1 -0
- package/es/libs/util.js +16 -0
- package/es/locales/en.js +18 -3
- package/es/locales/zh.js +12 -3
- package/es/payment/form/stripe/form.d.ts +4 -1
- package/es/payment/form/stripe/form.js +9 -5
- package/lib/components/over-due-invoice-payment.js +99 -31
- package/lib/components/payment-beneficiaries.js +3 -2
- package/lib/components/stripe-payment-action.d.ts +16 -0
- package/lib/components/stripe-payment-action.js +191 -0
- package/lib/history/invoice/list.js +58 -10
- package/lib/index.d.ts +3 -1
- package/lib/index.js +8 -0
- package/lib/libs/util.d.ts +1 -0
- package/lib/libs/util.js +17 -0
- package/lib/locales/en.js +18 -3
- package/lib/locales/zh.js +12 -3
- package/lib/payment/form/stripe/form.d.ts +4 -1
- package/lib/payment/form/stripe/form.js +9 -5
- package/package.json +3 -3
- package/src/components/over-due-invoice-payment.tsx +101 -29
- package/src/components/payment-beneficiaries.tsx +3 -3
- package/src/components/stripe-payment-action.tsx +220 -0
- package/src/history/invoice/list.tsx +67 -13
- package/src/index.ts +3 -0
- package/src/libs/util.ts +17 -0
- package/src/locales/en.tsx +16 -0
- package/src/locales/zh.tsx +10 -0
- package/src/payment/form/stripe/form.tsx +9 -2
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Payment Kit UI (React):
|
|
2
|
+
en: Payment Kit UI (React)
|
|
3
|
+
zh: 支付套件 UI (React)
|
|
4
|
+
zh-TW: 支付套件 UI (React)
|
|
5
|
+
ja: 決済キットUI (React)
|
|
6
|
+
"@blocklet/payment-react is a React library for blocklet payment systems with Payment Kit.":
|
|
7
|
+
en: "@blocklet/payment-react is a React library for blocklet payment systems
|
|
8
|
+
with Payment Kit."
|
|
9
|
+
zh: "@blocklet/payment-react 是一个适用于 blocklet 支付系统的 Payment Kit React 库。"
|
|
10
|
+
zh-TW: "@blocklet/payment-react 是一個適用於 blocklet 支付系統的 Payment Kit React 函式庫。"
|
|
11
|
+
ja: "@blocklet/payment-react は、blocklet決済システムに対応したPayment KitのReactライブラリです。"
|
|
@@ -14,6 +14,7 @@ import { formatAmount, formatError, getPrefix, isCrossOrigin } from "../libs/uti
|
|
|
14
14
|
import { useSubscription } from "../hooks/subscription.js";
|
|
15
15
|
import api from "../libs/api.js";
|
|
16
16
|
import LoadingButton from "./loading-button.js";
|
|
17
|
+
import StripePaymentAction from "./stripe-payment-action.js";
|
|
17
18
|
const fetchOverdueInvoices = async (params) => {
|
|
18
19
|
if (!params.subscriptionId && !params.customerId) {
|
|
19
20
|
throw new Error("Either subscriptionId or customerId must be provided");
|
|
@@ -49,11 +50,18 @@ function OverdueInvoicePayment({
|
|
|
49
50
|
const [payLoading, setPayLoading] = useState(false);
|
|
50
51
|
const [dialogOpen, setDialogOpen] = useState(dialogProps.open || false);
|
|
51
52
|
const [processedCurrencies, setProcessedCurrencies] = useState({});
|
|
52
|
-
const [paymentStatus, setPaymentStatus] = useState(
|
|
53
|
+
const [paymentStatus, setPaymentStatus] = useState(
|
|
54
|
+
{}
|
|
55
|
+
);
|
|
56
|
+
const [stripePaymentInProgress, setStripePaymentInProgress] = useState({});
|
|
57
|
+
const stripePaymentInProgressRef = useRef(stripePaymentInProgress);
|
|
53
58
|
const sourceType = subscriptionId ? "subscription" : "customer";
|
|
54
59
|
const effectiveCustomerId = customerId || session?.user?.did;
|
|
55
60
|
const sourceId = subscriptionId || effectiveCustomerId;
|
|
56
61
|
const customerIdRef = useRef(effectiveCustomerId);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
stripePaymentInProgressRef.current = stripePaymentInProgress;
|
|
64
|
+
}, [stripePaymentInProgress]);
|
|
57
65
|
const {
|
|
58
66
|
data = {
|
|
59
67
|
summary: {},
|
|
@@ -87,6 +95,28 @@ function OverdueInvoicePayment({
|
|
|
87
95
|
}, [data?.summary]);
|
|
88
96
|
const debouncedHandleInvoicePaid = debounce(
|
|
89
97
|
async (currencyId) => {
|
|
98
|
+
if (stripePaymentInProgressRef.current[currencyId]) {
|
|
99
|
+
try {
|
|
100
|
+
const checkData = await fetchOverdueInvoices({
|
|
101
|
+
subscriptionId,
|
|
102
|
+
customerId: effectiveCustomerId,
|
|
103
|
+
authToken
|
|
104
|
+
});
|
|
105
|
+
const hasRemainingInvoices = checkData.invoices?.some((inv) => inv.currency_id === currencyId);
|
|
106
|
+
if (hasRemainingInvoices) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
setStripePaymentInProgress((prev) => {
|
|
110
|
+
const newState = { ...prev };
|
|
111
|
+
delete newState[currencyId];
|
|
112
|
+
return newState;
|
|
113
|
+
});
|
|
114
|
+
setPaymentStatus((prev) => ({ ...prev, [currencyId]: "success" }));
|
|
115
|
+
} catch (err) {
|
|
116
|
+
console.error("Error checking Stripe payment completion:", err);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
90
120
|
if (successToast) {
|
|
91
121
|
Toast.close();
|
|
92
122
|
Toast.success(t("payment.customer.invoice.paySuccess"));
|
|
@@ -119,7 +149,7 @@ function OverdueInvoicePayment({
|
|
|
119
149
|
);
|
|
120
150
|
return isPaid;
|
|
121
151
|
};
|
|
122
|
-
const handleConnected = async () => {
|
|
152
|
+
const handleConnected = async (currencyId, isStripe = false) => {
|
|
123
153
|
if (isCrossOriginRequest) {
|
|
124
154
|
try {
|
|
125
155
|
const paid = await waitForInvoiceAllPaid();
|
|
@@ -129,26 +159,34 @@ function OverdueInvoicePayment({
|
|
|
129
159
|
}
|
|
130
160
|
if (paid) {
|
|
131
161
|
setDialogOpen(false);
|
|
132
|
-
onPaid(sourceId,
|
|
162
|
+
onPaid(sourceId, currencyId, sourceType);
|
|
133
163
|
}
|
|
134
164
|
} catch (err) {
|
|
135
165
|
console.error("Check payment status failed:", err);
|
|
136
166
|
}
|
|
167
|
+
} else if (isStripe) {
|
|
168
|
+
setStripePaymentInProgress((prev) => ({ ...prev, [currencyId]: true }));
|
|
169
|
+
setPaymentStatus((prev) => ({ ...prev, [currencyId]: "processing" }));
|
|
137
170
|
}
|
|
138
171
|
};
|
|
139
172
|
useEffect(() => {
|
|
140
|
-
if (subscription
|
|
141
|
-
|
|
142
|
-
const relevantId = subscriptionId || response.customer_id;
|
|
143
|
-
const uniqueKey = `${relevantId}-${response.currency_id}`;
|
|
144
|
-
if (subscriptionId && response.subscription_id === subscriptionId || effectiveCustomerId && effectiveCustomerId === response.customer_id || customerIdRef.current && customerIdRef.current === response.customer_id) {
|
|
145
|
-
if (!processedCurrencies[uniqueKey]) {
|
|
146
|
-
setProcessedCurrencies((prev) => ({ ...prev, [uniqueKey]: 1 }));
|
|
147
|
-
debouncedHandleInvoicePaid(response.currency_id);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
});
|
|
173
|
+
if (!subscription || isCrossOriginRequest) {
|
|
174
|
+
return void 0;
|
|
151
175
|
}
|
|
176
|
+
const handleInvoicePaid = ({ response }) => {
|
|
177
|
+
const relevantId = subscriptionId || response.customer_id;
|
|
178
|
+
const uniqueKey = `${relevantId}-${response.currency_id}`;
|
|
179
|
+
if (subscriptionId && response.subscription_id === subscriptionId || effectiveCustomerId && effectiveCustomerId === response.customer_id || customerIdRef.current && customerIdRef.current === response.customer_id) {
|
|
180
|
+
if (!processedCurrencies[uniqueKey]) {
|
|
181
|
+
setProcessedCurrencies((prev) => ({ ...prev, [uniqueKey]: 1 }));
|
|
182
|
+
debouncedHandleInvoicePaid(response.currency_id);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
subscription.on("invoice.paid", handleInvoicePaid);
|
|
187
|
+
return () => {
|
|
188
|
+
subscription.off("invoice.paid", handleInvoicePaid);
|
|
189
|
+
};
|
|
152
190
|
}, [subscription, subscriptionId, effectiveCustomerId]);
|
|
153
191
|
const handlePay = (item) => {
|
|
154
192
|
const { currency, method } = item;
|
|
@@ -187,7 +225,7 @@ function OverdueInvoicePayment({
|
|
|
187
225
|
},
|
|
188
226
|
onSuccess: () => {
|
|
189
227
|
connect.close();
|
|
190
|
-
handleConnected();
|
|
228
|
+
handleConnected(currency.id);
|
|
191
229
|
setPayLoading(false);
|
|
192
230
|
setPaymentStatus((prev) => ({
|
|
193
231
|
...prev,
|
|
@@ -234,7 +272,7 @@ function OverdueInvoicePayment({
|
|
|
234
272
|
}
|
|
235
273
|
return t("payment.customer.pastDue.view");
|
|
236
274
|
};
|
|
237
|
-
const renderPayButton = (item, primaryButton = true,
|
|
275
|
+
const renderPayButton = (item, primaryButton = true, options = {
|
|
238
276
|
variant: "contained"
|
|
239
277
|
}) => {
|
|
240
278
|
const { currency } = item;
|
|
@@ -244,7 +282,7 @@ function OverdueInvoicePayment({
|
|
|
244
282
|
return /* @__PURE__ */ jsx(
|
|
245
283
|
Button,
|
|
246
284
|
{
|
|
247
|
-
variant:
|
|
285
|
+
variant: options?.variant || "contained",
|
|
248
286
|
size: "small",
|
|
249
287
|
...primaryButton ? {} : {
|
|
250
288
|
color: "success",
|
|
@@ -255,20 +293,47 @@ function OverdueInvoicePayment({
|
|
|
255
293
|
);
|
|
256
294
|
}
|
|
257
295
|
if (status === "error") {
|
|
258
|
-
return /* @__PURE__ */ jsx(Button, { variant: "contained", size: "small", onClick: () => handlePay(item),
|
|
296
|
+
return /* @__PURE__ */ jsx(Button, { variant: options?.variant || "contained", size: "small", onClick: () => handlePay(item), sx: options?.sx, children: t("payment.subscription.overdue.retry") });
|
|
259
297
|
}
|
|
260
298
|
if (item.method.type === "stripe") {
|
|
261
|
-
return /* @__PURE__ */ jsx(
|
|
299
|
+
return /* @__PURE__ */ jsx(
|
|
300
|
+
StripePaymentAction,
|
|
301
|
+
{
|
|
302
|
+
subscriptionId,
|
|
303
|
+
customerId: !subscriptionId ? effectiveCustomerId : void 0,
|
|
304
|
+
currencyId: currency.id,
|
|
305
|
+
paymentMethod: item.method,
|
|
306
|
+
onSuccess: () => {
|
|
307
|
+
handleConnected(currency.id, true);
|
|
308
|
+
},
|
|
309
|
+
onError: () => {
|
|
310
|
+
setPaymentStatus((prev) => ({ ...prev, [currency.id]: "error" }));
|
|
311
|
+
setStripePaymentInProgress((prev) => ({ ...prev, [currency.id]: false }));
|
|
312
|
+
},
|
|
313
|
+
children: (onPay, paying) => /* @__PURE__ */ jsx(
|
|
314
|
+
LoadingButton,
|
|
315
|
+
{
|
|
316
|
+
variant: options?.variant || "contained",
|
|
317
|
+
size: "small",
|
|
318
|
+
disabled: paying || status === "processing",
|
|
319
|
+
loading: paying || status === "processing",
|
|
320
|
+
onClick: onPay,
|
|
321
|
+
sx: options?.sx,
|
|
322
|
+
children: status === "processing" ? t("payment.subscription.overdue.processing") : t("payment.subscription.overdue.payNow")
|
|
323
|
+
}
|
|
324
|
+
)
|
|
325
|
+
}
|
|
326
|
+
);
|
|
262
327
|
}
|
|
263
328
|
return /* @__PURE__ */ jsx(
|
|
264
329
|
LoadingButton,
|
|
265
330
|
{
|
|
266
|
-
variant: "contained",
|
|
331
|
+
variant: options?.variant || "contained",
|
|
267
332
|
size: "small",
|
|
268
333
|
disabled: inProcess,
|
|
269
334
|
loading: inProcess,
|
|
270
335
|
onClick: () => handlePay(item),
|
|
271
|
-
|
|
336
|
+
sx: options?.sx,
|
|
272
337
|
children: t("payment.subscription.overdue.payNow")
|
|
273
338
|
}
|
|
274
339
|
);
|
|
@@ -3,9 +3,9 @@ import { Avatar, Box, Stack, Typography } from "@mui/material";
|
|
|
3
3
|
import { BN } from "@ocap/util";
|
|
4
4
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
5
5
|
import DID from "@arcblock/ux/lib/DID";
|
|
6
|
-
import { formatBNStr } from "../libs/util.js";
|
|
6
|
+
import { formatBNStr, formatLinkWithLocale } from "../libs/util.js";
|
|
7
7
|
export default function PaymentBeneficiaries({ data, currency, totalAmount = "0" }) {
|
|
8
|
-
const { t } = useLocaleContext();
|
|
8
|
+
const { t, locale } = useLocaleContext();
|
|
9
9
|
return /* @__PURE__ */ jsxs(Stack, { spacing: 2, children: [
|
|
10
10
|
/* @__PURE__ */ jsx(
|
|
11
11
|
Typography,
|
|
@@ -60,7 +60,7 @@ export default function PaymentBeneficiaries({ data, currency, totalAmount = "0"
|
|
|
60
60
|
variant: "subtitle2",
|
|
61
61
|
onClick: () => {
|
|
62
62
|
if (item.url) {
|
|
63
|
-
window.open(item.url, "_blank");
|
|
63
|
+
window.open(formatLinkWithLocale(item.url, locale), "_blank");
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
sx: {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TPaymentMethod, TInvoiceExpanded } from '@blocklet/payment-types';
|
|
2
|
+
export interface StripePaymentActionProps {
|
|
3
|
+
invoice?: TInvoiceExpanded;
|
|
4
|
+
invoiceIds?: string[];
|
|
5
|
+
subscriptionId?: string;
|
|
6
|
+
customerId?: string;
|
|
7
|
+
currencyId?: string;
|
|
8
|
+
paymentMethod?: TPaymentMethod;
|
|
9
|
+
autoTrigger?: boolean;
|
|
10
|
+
onExternalPayment?: (invoiceId?: string) => void;
|
|
11
|
+
onSuccess?: () => void;
|
|
12
|
+
onError?: (error: Error) => void;
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
children?: (onPay: () => void, loading: boolean) => React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
export default function StripePaymentAction(props: StripePaymentActionProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
|
+
import Toast from "@arcblock/ux/lib/Toast";
|
|
4
|
+
import { Dialog } from "@arcblock/ux";
|
|
5
|
+
import { Button, Typography } from "@mui/material";
|
|
6
|
+
import { useSetState } from "ahooks";
|
|
7
|
+
import { useEffect, useRef } from "react";
|
|
8
|
+
import StripeForm from "../payment/form/stripe/index.js";
|
|
9
|
+
import api from "../libs/api.js";
|
|
10
|
+
import { formatError } from "../libs/util.js";
|
|
11
|
+
export default function StripePaymentAction(props) {
|
|
12
|
+
const {
|
|
13
|
+
invoice,
|
|
14
|
+
invoiceIds,
|
|
15
|
+
subscriptionId,
|
|
16
|
+
customerId,
|
|
17
|
+
currencyId,
|
|
18
|
+
paymentMethod,
|
|
19
|
+
autoTrigger = false,
|
|
20
|
+
onExternalPayment,
|
|
21
|
+
onSuccess,
|
|
22
|
+
onError,
|
|
23
|
+
onClose,
|
|
24
|
+
children
|
|
25
|
+
} = props;
|
|
26
|
+
const { t } = useLocaleContext();
|
|
27
|
+
const [state, setState] = useSetState({
|
|
28
|
+
paying: false,
|
|
29
|
+
confirmDialog: false,
|
|
30
|
+
stripeDialog: false,
|
|
31
|
+
clientSecret: null,
|
|
32
|
+
publishableKey: null,
|
|
33
|
+
customer: null
|
|
34
|
+
});
|
|
35
|
+
const autoTriggerRef = useRef(false);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (autoTrigger && !autoTriggerRef.current) {
|
|
38
|
+
autoTriggerRef.current = true;
|
|
39
|
+
handlePay();
|
|
40
|
+
}
|
|
41
|
+
}, [autoTrigger]);
|
|
42
|
+
const handlePay = async () => {
|
|
43
|
+
if (state.paying) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const hasSubscription = !!(subscriptionId || invoice?.subscription_id);
|
|
47
|
+
const method = paymentMethod || invoice?.paymentMethod;
|
|
48
|
+
const shouldShowConfirm = hasSubscription && method?.type === "stripe";
|
|
49
|
+
if (shouldShowConfirm) {
|
|
50
|
+
setState({ confirmDialog: true });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
await proceedWithPayment();
|
|
54
|
+
};
|
|
55
|
+
const proceedWithPayment = async () => {
|
|
56
|
+
setState({ paying: true, confirmDialog: false });
|
|
57
|
+
const derivedCurrencyId = currencyId || invoice?.currency_id || invoice?.paymentCurrency?.id;
|
|
58
|
+
const derivedPaymentMethod = paymentMethod || invoice?.paymentMethod;
|
|
59
|
+
const isStripePayment = derivedPaymentMethod?.type === "stripe";
|
|
60
|
+
if (isStripePayment && derivedCurrencyId) {
|
|
61
|
+
const stripePayload = {};
|
|
62
|
+
if (invoiceIds && invoiceIds.length > 0) {
|
|
63
|
+
stripePayload.invoice_ids = invoiceIds;
|
|
64
|
+
} else if (invoice) {
|
|
65
|
+
stripePayload.invoice_ids = [invoice.id];
|
|
66
|
+
} else if (subscriptionId) {
|
|
67
|
+
stripePayload.subscription_id = subscriptionId;
|
|
68
|
+
} else if (customerId) {
|
|
69
|
+
stripePayload.customer_id = customerId;
|
|
70
|
+
}
|
|
71
|
+
if (derivedCurrencyId) {
|
|
72
|
+
stripePayload.currency_id = derivedCurrencyId;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const { data: paymentData } = await api.post("/api/invoices/pay-stripe", stripePayload);
|
|
76
|
+
setState({
|
|
77
|
+
paying: false,
|
|
78
|
+
stripeDialog: true,
|
|
79
|
+
clientSecret: paymentData.client_secret,
|
|
80
|
+
publishableKey: paymentData.publishable_key,
|
|
81
|
+
customer: paymentData.customer || null
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
} catch (err) {
|
|
85
|
+
const error = formatError(err);
|
|
86
|
+
Toast.error(error);
|
|
87
|
+
setState({ paying: false });
|
|
88
|
+
onError?.(error);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
setState({ paying: false });
|
|
93
|
+
if (onExternalPayment) {
|
|
94
|
+
onExternalPayment(invoice?.id);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
Toast.error(t("payment.customer.invoice.payError"));
|
|
98
|
+
onError?.(new Error("EXTERNAL_PAYMENT_HANDLER_NOT_PROVIDED"));
|
|
99
|
+
};
|
|
100
|
+
const handleConfirmCancel = () => {
|
|
101
|
+
setState({ confirmDialog: false, paying: false });
|
|
102
|
+
onClose?.();
|
|
103
|
+
};
|
|
104
|
+
const handleStripeConfirm = () => {
|
|
105
|
+
Toast.success(t("payment.customer.invoice.payProcessing"));
|
|
106
|
+
setState({
|
|
107
|
+
paying: false,
|
|
108
|
+
stripeDialog: false,
|
|
109
|
+
clientSecret: null,
|
|
110
|
+
publishableKey: null,
|
|
111
|
+
customer: null
|
|
112
|
+
});
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
onSuccess?.();
|
|
115
|
+
}, 2e3);
|
|
116
|
+
};
|
|
117
|
+
const handleStripeCancel = () => {
|
|
118
|
+
setState({
|
|
119
|
+
paying: false,
|
|
120
|
+
stripeDialog: false,
|
|
121
|
+
clientSecret: null,
|
|
122
|
+
publishableKey: null,
|
|
123
|
+
customer: null
|
|
124
|
+
});
|
|
125
|
+
onClose?.();
|
|
126
|
+
};
|
|
127
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
128
|
+
children?.(handlePay, state.paying),
|
|
129
|
+
state.confirmDialog && /* @__PURE__ */ jsx(
|
|
130
|
+
Dialog,
|
|
131
|
+
{
|
|
132
|
+
open: state.confirmDialog,
|
|
133
|
+
title: t("payment.customer.invoice.paymentConfirmTitle"),
|
|
134
|
+
onClose: handleConfirmCancel,
|
|
135
|
+
maxWidth: "sm",
|
|
136
|
+
PaperProps: {
|
|
137
|
+
style: {
|
|
138
|
+
minHeight: 0
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
actions: [
|
|
142
|
+
/* @__PURE__ */ jsx(Button, { variant: "outlined", onClick: handleConfirmCancel, children: t("common.cancel") }, "cancel"),
|
|
143
|
+
/* @__PURE__ */ jsx(Button, { variant: "contained", onClick: proceedWithPayment, children: t("payment.customer.invoice.continue") }, "continue")
|
|
144
|
+
],
|
|
145
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "body1", sx: { color: "text.secondary", mt: -2 }, children: t("payment.customer.invoice.paymentConfirmDescription") })
|
|
146
|
+
}
|
|
147
|
+
),
|
|
148
|
+
state.stripeDialog && state.clientSecret && state.publishableKey && state.customer && /* @__PURE__ */ jsx(
|
|
149
|
+
StripeForm,
|
|
150
|
+
{
|
|
151
|
+
clientSecret: state.clientSecret,
|
|
152
|
+
intentType: "setup_intent",
|
|
153
|
+
publicKey: state.publishableKey,
|
|
154
|
+
customer: state.customer,
|
|
155
|
+
mode: "setup",
|
|
156
|
+
title: t("payment.customer.invoice.pay"),
|
|
157
|
+
submitButtonText: t("common.submit"),
|
|
158
|
+
onConfirm: handleStripeConfirm,
|
|
159
|
+
onCancel: handleStripeCancel,
|
|
160
|
+
returnUrl: window.location.href
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
] });
|
|
164
|
+
}
|
|
@@ -12,6 +12,7 @@ import Status from "../../components/status.js";
|
|
|
12
12
|
import { usePaymentContext } from "../../contexts/payment.js";
|
|
13
13
|
import { useSubscription } from "../../hooks/subscription.js";
|
|
14
14
|
import api from "../../libs/api.js";
|
|
15
|
+
import StripePaymentAction from "../../components/stripe-payment-action.js";
|
|
15
16
|
import {
|
|
16
17
|
formatBNStr,
|
|
17
18
|
formatError,
|
|
@@ -254,7 +255,37 @@ const InvoiceTable = React.memo((props) => {
|
|
|
254
255
|
const { connect } = getInvoiceLink(invoice, action);
|
|
255
256
|
const isVoid = invoice.status === "void";
|
|
256
257
|
if (action && !hidePay) {
|
|
257
|
-
|
|
258
|
+
if (connect) {
|
|
259
|
+
if (invoice.paymentMethod?.type === "stripe") {
|
|
260
|
+
return /* @__PURE__ */ jsx(
|
|
261
|
+
StripePaymentAction,
|
|
262
|
+
{
|
|
263
|
+
invoice,
|
|
264
|
+
paymentMethod: invoice.paymentMethod,
|
|
265
|
+
onSuccess: () => {
|
|
266
|
+
refresh();
|
|
267
|
+
},
|
|
268
|
+
children: (handlePay, paying) => /* @__PURE__ */ jsx(
|
|
269
|
+
Button,
|
|
270
|
+
{
|
|
271
|
+
variant: "text",
|
|
272
|
+
size: "small",
|
|
273
|
+
sx: { color: "text.link" },
|
|
274
|
+
disabled: paying,
|
|
275
|
+
onClick: (e) => {
|
|
276
|
+
e.preventDefault();
|
|
277
|
+
e.stopPropagation();
|
|
278
|
+
handlePay();
|
|
279
|
+
},
|
|
280
|
+
children: paying ? t("payment.checkout.processing") : t("payment.customer.invoice.pay")
|
|
281
|
+
}
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
return /* @__PURE__ */ jsx(Button, { variant: "text", size: "small", onClick: () => onPay(invoice.id), sx: { color: "text.link" }, children: t("payment.customer.invoice.pay") });
|
|
287
|
+
}
|
|
288
|
+
return /* @__PURE__ */ jsx(
|
|
258
289
|
Button,
|
|
259
290
|
{
|
|
260
291
|
component: "a",
|
|
@@ -518,7 +549,32 @@ const InvoiceList = React.memo((props) => {
|
|
|
518
549
|
flex: 1,
|
|
519
550
|
textAlign: "right"
|
|
520
551
|
},
|
|
521
|
-
children: action ? connect ? /* @__PURE__ */ jsx(
|
|
552
|
+
children: action ? connect ? invoice.paymentMethod?.type === "stripe" ? /* @__PURE__ */ jsx(
|
|
553
|
+
StripePaymentAction,
|
|
554
|
+
{
|
|
555
|
+
invoice,
|
|
556
|
+
paymentMethod: invoice.paymentMethod,
|
|
557
|
+
onSuccess: async () => {
|
|
558
|
+
await reloadAsync();
|
|
559
|
+
},
|
|
560
|
+
children: (handlePay, paying) => /* @__PURE__ */ jsx(
|
|
561
|
+
Button,
|
|
562
|
+
{
|
|
563
|
+
variant: "contained",
|
|
564
|
+
color: "primary",
|
|
565
|
+
size: "small",
|
|
566
|
+
sx: { whiteSpace: "nowrap" },
|
|
567
|
+
disabled: paying,
|
|
568
|
+
onClick: (e) => {
|
|
569
|
+
e.preventDefault();
|
|
570
|
+
e.stopPropagation();
|
|
571
|
+
handlePay();
|
|
572
|
+
},
|
|
573
|
+
children: paying ? t("payment.checkout.processing") : t("payment.customer.invoice.pay")
|
|
574
|
+
}
|
|
575
|
+
)
|
|
576
|
+
}
|
|
577
|
+
) : /* @__PURE__ */ jsx(
|
|
522
578
|
Button,
|
|
523
579
|
{
|
|
524
580
|
variant: "contained",
|
package/es/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ import TruncatedText from './components/truncated-text';
|
|
|
32
32
|
import Link from './components/link';
|
|
33
33
|
import { createLazyComponent } from './components/lazy-loader';
|
|
34
34
|
import OverdueInvoicePayment from './components/over-due-invoice-payment';
|
|
35
|
+
import StripePaymentAction from './components/stripe-payment-action';
|
|
35
36
|
import PaymentBeneficiaries from './components/payment-beneficiaries';
|
|
36
37
|
import LoadingButton from './components/loading-button';
|
|
37
38
|
import ResumeSubscription from './components/resume-subscription';
|
|
@@ -55,5 +56,6 @@ export * from './hooks/scroll';
|
|
|
55
56
|
export * from './hooks/keyboard';
|
|
56
57
|
export * from './libs/validator';
|
|
57
58
|
export { translations, createTranslator } from './locales';
|
|
58
|
-
export { createLazyComponent, api, dayjs, FormInput, FormLabel, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, PricingItem, CountrySelect, Table, TruncatedText, Link, OverdueInvoicePayment, PaymentBeneficiaries, LoadingButton, DonateDetails, ResumeSubscription, CreditGrantsList, CreditTransactionsList, DateRangePicker, CreditStatusChip, AutoTopupModal, AutoTopup, Collapse, PromotionCode, SourceDataViewer, };
|
|
59
|
+
export { createLazyComponent, api, dayjs, FormInput, FormLabel, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, PricingItem, CountrySelect, Table, TruncatedText, Link, OverdueInvoicePayment, StripePaymentAction, PaymentBeneficiaries, LoadingButton, DonateDetails, ResumeSubscription, CreditGrantsList, CreditTransactionsList, DateRangePicker, CreditStatusChip, AutoTopupModal, AutoTopup, Collapse, PromotionCode, SourceDataViewer, };
|
|
59
60
|
export type { CountrySelectProps } from './components/country-select';
|
|
61
|
+
export type { StripePaymentActionProps } from './components/stripe-payment-action';
|
package/es/index.js
CHANGED
|
@@ -32,6 +32,7 @@ import TruncatedText from "./components/truncated-text.js";
|
|
|
32
32
|
import Link from "./components/link.js";
|
|
33
33
|
import { createLazyComponent } from "./components/lazy-loader.js";
|
|
34
34
|
import OverdueInvoicePayment from "./components/over-due-invoice-payment.js";
|
|
35
|
+
import StripePaymentAction from "./components/stripe-payment-action.js";
|
|
35
36
|
import PaymentBeneficiaries from "./components/payment-beneficiaries.js";
|
|
36
37
|
import LoadingButton from "./components/loading-button.js";
|
|
37
38
|
import ResumeSubscription from "./components/resume-subscription.js";
|
|
@@ -88,6 +89,7 @@ export {
|
|
|
88
89
|
TruncatedText,
|
|
89
90
|
Link,
|
|
90
91
|
OverdueInvoicePayment,
|
|
92
|
+
StripePaymentAction,
|
|
91
93
|
PaymentBeneficiaries,
|
|
92
94
|
LoadingButton,
|
|
93
95
|
DonateDetails,
|
package/es/libs/util.d.ts
CHANGED
|
@@ -135,3 +135,4 @@ export declare function parseMarkedText(text: string): Array<{
|
|
|
135
135
|
export declare function getTokenBalanceLink(method: TPaymentMethod, address: string): string;
|
|
136
136
|
export declare function isCreditMetered(price: TPrice): boolean;
|
|
137
137
|
export declare function showStaking(method: TPaymentMethod, currency: TPaymentCurrency, noStake: boolean): boolean;
|
|
138
|
+
export declare function formatLinkWithLocale(url: string, locale?: string): string;
|
package/es/libs/util.js
CHANGED
|
@@ -1039,3 +1039,19 @@ export function showStaking(method, currency, noStake) {
|
|
|
1039
1039
|
}
|
|
1040
1040
|
return false;
|
|
1041
1041
|
}
|
|
1042
|
+
export function formatLinkWithLocale(url, locale) {
|
|
1043
|
+
if (!locale || !url) {
|
|
1044
|
+
return url;
|
|
1045
|
+
}
|
|
1046
|
+
try {
|
|
1047
|
+
const urlObj = new URL(url);
|
|
1048
|
+
urlObj.searchParams.set("locale", locale);
|
|
1049
|
+
return urlObj.toString();
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
if (/[?&]locale=[^&]*/.test(url)) {
|
|
1052
|
+
return url.replace(/([?&])locale=[^&]*/, `$1locale=${locale}`);
|
|
1053
|
+
}
|
|
1054
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
1055
|
+
return `${url}${separator}locale=${locale}`;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
package/es/locales/en.js
CHANGED
|
@@ -108,7 +108,8 @@ export default flat({
|
|
|
108
108
|
cancel: "Cancel"
|
|
109
109
|
},
|
|
110
110
|
paymentMethod: "Payment Method",
|
|
111
|
-
viewInvoice: "View Invoice"
|
|
111
|
+
viewInvoice: "View Invoice",
|
|
112
|
+
submit: "Submit"
|
|
112
113
|
},
|
|
113
114
|
payment: {
|
|
114
115
|
checkout: {
|
|
@@ -446,7 +447,11 @@ export default flat({
|
|
|
446
447
|
amountApplied: "Applied Credit",
|
|
447
448
|
pay: "Pay this invoice",
|
|
448
449
|
paySuccess: "You have successfully paid the invoice",
|
|
450
|
+
payProcessing: "Payment is being processed, please refresh in a moment",
|
|
449
451
|
payError: "Failed to pay the invoice",
|
|
452
|
+
sync: "Sync Status",
|
|
453
|
+
syncing: "Syncing...",
|
|
454
|
+
syncSuccess: "Synced successfully",
|
|
450
455
|
renew: "Renew the subscription",
|
|
451
456
|
renewSuccess: "You have successfully renewed the subscription",
|
|
452
457
|
renewError: "Failed to renew the subscription",
|
|
@@ -455,7 +460,16 @@ export default flat({
|
|
|
455
460
|
invoiceNumber: "Invoice Number",
|
|
456
461
|
emptyList: "No Invoices",
|
|
457
462
|
noPaymentRequired: "No Payment Required",
|
|
458
|
-
payBatch: "Pay Due Invoices"
|
|
463
|
+
payBatch: "Pay Due Invoices",
|
|
464
|
+
stripePayDescription: "Complete payment using your saved payment method or add a new one.",
|
|
465
|
+
amount: "Amount",
|
|
466
|
+
paymentConfirmTitle: "Payment Confirmation",
|
|
467
|
+
paymentConfirmDescription: "After completing this payment, the payment method you use will be automatically set as the default for this subscription. Additionally, we will retry payment for any other unpaid invoices associated with this subscription.",
|
|
468
|
+
continue: "Continue"
|
|
469
|
+
},
|
|
470
|
+
overduePayment: {
|
|
471
|
+
setupPaymentDescription: "Use your saved card or add a new one to complete payment via Stripe.",
|
|
472
|
+
totalAmount: "Total Amount"
|
|
459
473
|
},
|
|
460
474
|
payment: {
|
|
461
475
|
empty: "There are no payments",
|
|
@@ -524,7 +538,8 @@ export default flat({
|
|
|
524
538
|
list: "Past Due Invoices:",
|
|
525
539
|
empty: "There are no overdue invoices for your subscription {name}.",
|
|
526
540
|
retry: "Retry",
|
|
527
|
-
paid: "Paid"
|
|
541
|
+
paid: "Paid",
|
|
542
|
+
processing: "Processing"
|
|
528
543
|
}
|
|
529
544
|
}
|
|
530
545
|
},
|
package/es/locales/zh.js
CHANGED
|
@@ -108,7 +108,8 @@ export default flat({
|
|
|
108
108
|
cancel: "\u53D6\u6D88"
|
|
109
109
|
},
|
|
110
110
|
paymentMethod: "\u652F\u4ED8\u65B9\u5F0F",
|
|
111
|
-
viewInvoice: "\u67E5\u770B\u8D26\u5355"
|
|
111
|
+
viewInvoice: "\u67E5\u770B\u8D26\u5355",
|
|
112
|
+
submit: "\u63D0\u4EA4"
|
|
112
113
|
},
|
|
113
114
|
payment: {
|
|
114
115
|
checkout: {
|
|
@@ -450,7 +451,11 @@ export default flat({
|
|
|
450
451
|
amountApplied: "\u4F59\u989D\u53D8\u66F4",
|
|
451
452
|
pay: "\u652F\u4ED8\u6B64\u8D26\u5355",
|
|
452
453
|
paySuccess: "\u652F\u4ED8\u6210\u529F",
|
|
454
|
+
payProcessing: "\u652F\u4ED8\u5904\u7406\u4E2D\uFF0C\u8BF7\u7A0D\u5019\u5237\u65B0\u67E5\u770B",
|
|
453
455
|
payError: "\u652F\u4ED8\u5931\u8D25",
|
|
456
|
+
sync: "\u540C\u6B65\u72B6\u6001",
|
|
457
|
+
syncing: "\u540C\u6B65\u4E2D...",
|
|
458
|
+
syncSuccess: "\u540C\u6B65\u6210\u529F",
|
|
454
459
|
renew: "\u6062\u590D\u8BA2\u9605",
|
|
455
460
|
renewSuccess: "\u8BA2\u9605\u6062\u590D\u6210\u529F",
|
|
456
461
|
renewError: "\u8BA2\u9605\u6062\u590D\u5931\u8D25",
|
|
@@ -459,7 +464,10 @@ export default flat({
|
|
|
459
464
|
invoiceNumber: "\u8D26\u5355\u7F16\u53F7",
|
|
460
465
|
emptyList: "\u6CA1\u6709\u8D26\u5355",
|
|
461
466
|
noPaymentRequired: "\u65E0\u9700\u652F\u4ED8",
|
|
462
|
-
payBatch: "\u652F\u4ED8\u6B20\u6B3E"
|
|
467
|
+
payBatch: "\u652F\u4ED8\u6B20\u6B3E",
|
|
468
|
+
paymentConfirmTitle: "\u652F\u4ED8\u786E\u8BA4",
|
|
469
|
+
paymentConfirmDescription: "\u5B8C\u6210\u672C\u6B21\u652F\u4ED8\u540E\uFF0C\u60A8\u4F7F\u7528\u7684\u652F\u4ED8\u65B9\u5F0F\u5C06\u81EA\u52A8\u8BBE\u7F6E\u4E3A\u8BE5\u8BA2\u9605\u7684\u9ED8\u8BA4\u652F\u4ED8\u65B9\u5F0F\u3002\u6B64\u5916\uFF0C\u6211\u4EEC\u8FD8\u5C06\u5BF9\u8BE5\u8BA2\u9605\u7684\u5176\u4ED6\u6B20\u8D39\u8D26\u5355\u8FDB\u884C\u91CD\u8BD5\u6536\u8D39\u3002",
|
|
470
|
+
continue: "\u7EE7\u7EED"
|
|
463
471
|
},
|
|
464
472
|
payment: {
|
|
465
473
|
empty: "\u6CA1\u6709\u652F\u4ED8\u8BB0\u5F55",
|
|
@@ -528,7 +536,8 @@ export default flat({
|
|
|
528
536
|
list: "\u6B20\u8D39\u8D26\u5355\uFF1A",
|
|
529
537
|
empty: "\u60A8\u7684\u3010{name}\u3011\u8BA2\u9605\u5F53\u524D\u6CA1\u6709\u6B20\u8D39\u8D26\u5355",
|
|
530
538
|
retry: "\u91CD\u65B0\u652F\u4ED8",
|
|
531
|
-
paid: "\u5DF2\u652F\u4ED8"
|
|
539
|
+
paid: "\u5DF2\u652F\u4ED8",
|
|
540
|
+
processing: "\u652F\u4ED8\u4E2D"
|
|
532
541
|
}
|
|
533
542
|
}
|
|
534
543
|
},
|
|
@@ -6,6 +6,7 @@ export type StripeCheckoutFormProps = {
|
|
|
6
6
|
mode: string;
|
|
7
7
|
onConfirm: Function;
|
|
8
8
|
returnUrl?: string;
|
|
9
|
+
submitButtonText?: string;
|
|
9
10
|
};
|
|
10
11
|
export type StripeCheckoutProps = {
|
|
11
12
|
clientSecret: string;
|
|
@@ -16,5 +17,7 @@ export type StripeCheckoutProps = {
|
|
|
16
17
|
onConfirm: Function;
|
|
17
18
|
onCancel: Function;
|
|
18
19
|
returnUrl?: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
submitButtonText?: string;
|
|
19
22
|
};
|
|
20
|
-
export default function StripeCheckout({ clientSecret, intentType, publicKey, mode, customer, onConfirm, onCancel, returnUrl, }: StripeCheckoutProps): import("react").JSX.Element;
|
|
23
|
+
export default function StripeCheckout({ clientSecret, intentType, publicKey, mode, customer, onConfirm, onCancel, returnUrl, title, submitButtonText, }: StripeCheckoutProps): import("react").JSX.Element;
|