@blocklet/payment-react 1.13.198 → 1.13.200
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/components/blockchain/tx.js +1 -33
- package/es/history/invoice/list.js +56 -41
- package/es/history/mini-invoice/list.js +4 -4
- package/es/locales/en.js +2 -1
- package/es/locales/zh.js +4 -3
- package/es/util.d.ts +5 -1
- package/es/util.js +33 -0
- package/lib/components/blockchain/tx.js +2 -33
- package/lib/history/invoice/list.js +88 -47
- package/lib/history/mini-invoice/list.js +11 -7
- package/lib/locales/en.js +2 -1
- package/lib/locales/zh.js +4 -3
- package/lib/util.d.ts +5 -1
- package/lib/util.js +35 -2
- package/package.json +3 -3
- package/src/components/blockchain/tx.tsx +1 -34
- package/src/history/invoice/list.tsx +81 -48
- package/src/history/mini-invoice/list.tsx +7 -5
- package/src/locales/en.tsx +1 -0
- package/src/locales/zh.tsx +3 -2
- package/src/util.ts +37 -0
|
@@ -2,39 +2,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
3
|
import { OpenInNewOutlined } from "@mui/icons-material";
|
|
4
4
|
import { Link, Stack, Typography } from "@mui/material";
|
|
5
|
-
import {
|
|
6
|
-
const getTxLink = (method, details) => {
|
|
7
|
-
if (method.type === "arcblock" && details.arcblock?.tx_hash) {
|
|
8
|
-
return {
|
|
9
|
-
link: joinURL(method.settings.arcblock?.explorer_host, "/txs", details.arcblock?.tx_hash),
|
|
10
|
-
text: details.arcblock?.tx_hash
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
if (method.type === "bitcoin" && details.bitcoin?.tx_hash) {
|
|
14
|
-
return {
|
|
15
|
-
link: joinURL(method.settings.bitcoin?.explorer_host, "/tx", details.bitcoin?.tx_hash),
|
|
16
|
-
text: details.bitcoin?.tx_hash
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
if (method.type === "ethereum" && details.ethereum?.tx_hash) {
|
|
20
|
-
return {
|
|
21
|
-
link: joinURL(method.settings.ethereum?.explorer_host, "/tx", details.ethereum?.tx_hash),
|
|
22
|
-
text: details.ethereum?.tx_hash
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
if (method.type === "stripe") {
|
|
26
|
-
const dashboard = method.livemode ? "https://dashboard.stripe.com" : "https://dashboard.stripe.com/test";
|
|
27
|
-
return {
|
|
28
|
-
link: joinURL(
|
|
29
|
-
method.settings.stripe?.dashboard || dashboard,
|
|
30
|
-
"payments",
|
|
31
|
-
details.stripe?.payment_intent_id
|
|
32
|
-
),
|
|
33
|
-
text: details.stripe?.payment_intent_id
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
return { text: "N/A", link: "" };
|
|
37
|
-
};
|
|
5
|
+
import { getTxLink } from "../../util.js";
|
|
38
6
|
TxLink.defaultProps = {
|
|
39
7
|
mode: "dashboard"
|
|
40
8
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
|
+
import { OpenInNewOutlined } from "@mui/icons-material";
|
|
3
4
|
import { Box, Button, CircularProgress, Stack, Typography } from "@mui/material";
|
|
4
5
|
import { useInfiniteScroll } from "ahooks";
|
|
5
6
|
import { joinURL } from "ufo";
|
|
6
7
|
import api from "../../api.js";
|
|
7
8
|
import Status from "../../components/status.js";
|
|
8
|
-
import { formatBNStr, formatToDate, getInvoiceStatusColor, getPrefix } from "../../util.js";
|
|
9
|
+
import { formatBNStr, formatToDate, formatToDatetime, getInvoiceStatusColor, getPrefix, getTxLink } from "../../util.js";
|
|
9
10
|
const groupByDate = (items) => {
|
|
10
11
|
const grouped = {};
|
|
11
12
|
items.forEach((item) => {
|
|
@@ -26,6 +27,22 @@ const fetchData = (params = {}) => {
|
|
|
26
27
|
});
|
|
27
28
|
return api.get(`/api/invoices?${search.toString()}`).then((res) => res.data);
|
|
28
29
|
};
|
|
30
|
+
const getInvoiceLink = (invoice, action) => {
|
|
31
|
+
if (invoice.id.startsWith("in_")) {
|
|
32
|
+
return {
|
|
33
|
+
external: false,
|
|
34
|
+
url: joinURL(
|
|
35
|
+
window.location.origin,
|
|
36
|
+
getPrefix(),
|
|
37
|
+
`/customer/invoice/${invoice.id}?action=${invoice.status === "uncollectible" ? action : ""}`
|
|
38
|
+
)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
external: true,
|
|
43
|
+
url: getTxLink(invoice.paymentMethod, invoice.metadata?.payment_details).link
|
|
44
|
+
};
|
|
45
|
+
};
|
|
29
46
|
export default function CustomerInvoiceList({
|
|
30
47
|
customer_id,
|
|
31
48
|
subscription_id,
|
|
@@ -43,59 +60,57 @@ export default function CustomerInvoiceList({
|
|
|
43
60
|
return fetchData({ page, pageSize: size, status, customer_id, currency_id, subscription_id, ignoreZero: true });
|
|
44
61
|
},
|
|
45
62
|
{
|
|
46
|
-
reloadDeps: [customer_id]
|
|
63
|
+
reloadDeps: [customer_id, subscription_id, status]
|
|
47
64
|
}
|
|
48
65
|
);
|
|
49
66
|
if (loading || !data) {
|
|
50
67
|
return /* @__PURE__ */ jsx(CircularProgress, {});
|
|
51
68
|
}
|
|
52
69
|
if (data && data.list.length === 0) {
|
|
53
|
-
|
|
70
|
+
if (data.subscription && ["active", "trialing"].includes(data.subscription.status)) {
|
|
71
|
+
return /* @__PURE__ */ jsx(Typography, { color: "text.secondary", sx: { my: 0.5 }, children: t("payment.customer.invoice.next", { date: formatToDatetime(data.subscription.current_period_end * 1e3) }) });
|
|
72
|
+
}
|
|
73
|
+
return /* @__PURE__ */ jsx(Typography, { color: "text.secondary", sx: { my: 0.5 }, children: t("payment.customer.invoice.empty") });
|
|
54
74
|
}
|
|
55
75
|
const hasMore = data && data.list.length < data.count;
|
|
56
76
|
const grouped = groupByDate(data.list);
|
|
57
77
|
return /* @__PURE__ */ jsxs(Stack, { direction: "column", gap: 1, sx: { mt: 1 }, children: [
|
|
58
78
|
Object.entries(grouped).map(([date, invoices]) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
59
79
|
/* @__PURE__ */ jsx(Typography, { sx: { fontWeight: "bold", color: "text.secondary", mt: 2, mb: 1 }, children: date }),
|
|
60
|
-
invoices.map((invoice) =>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
80
|
+
invoices.map((invoice) => {
|
|
81
|
+
const link = getInvoiceLink(invoice, action);
|
|
82
|
+
return /* @__PURE__ */ jsxs(
|
|
83
|
+
Stack,
|
|
84
|
+
{
|
|
85
|
+
direction: {
|
|
86
|
+
xs: "column",
|
|
87
|
+
sm: "row"
|
|
88
|
+
},
|
|
89
|
+
sx: { my: 1 },
|
|
90
|
+
gap: {
|
|
91
|
+
xs: 0.5,
|
|
92
|
+
sm: 1.5,
|
|
93
|
+
md: 3
|
|
94
|
+
},
|
|
95
|
+
flexWrap: "nowrap",
|
|
96
|
+
children: [
|
|
97
|
+
/* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx("a", { href: link.url, target: link.external ? "_blank" : target, rel: "noreferrer", children: /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [
|
|
98
|
+
/* @__PURE__ */ jsx(Typography, { component: "span", children: invoice.number }),
|
|
99
|
+
link.external && /* @__PURE__ */ jsx(OpenInNewOutlined, { fontSize: "small", sx: { color: "text.secondary" } })
|
|
100
|
+
] }) }) }),
|
|
101
|
+
/* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(Typography, { children: formatToDate(invoice.created_at) }) }),
|
|
102
|
+
/* @__PURE__ */ jsx(Box, { flex: 2, children: /* @__PURE__ */ jsxs(Typography, { textAlign: "right", children: [
|
|
103
|
+
formatBNStr(invoice.total, invoice.paymentCurrency.decimal),
|
|
104
|
+
"\xA0",
|
|
105
|
+
invoice.paymentCurrency.symbol
|
|
106
|
+
] }) }),
|
|
107
|
+
/* @__PURE__ */ jsx(Box, { flex: 2, children: /* @__PURE__ */ jsx(Status, { label: invoice.status, color: getInvoiceStatusColor(invoice.status) }) }),
|
|
108
|
+
/* @__PURE__ */ jsx(Box, { flex: 4, children: /* @__PURE__ */ jsx(Typography, { children: invoice.description || invoice.id }) })
|
|
109
|
+
]
|
|
72
110
|
},
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"a",
|
|
77
|
-
{
|
|
78
|
-
href: joinURL(
|
|
79
|
-
window.location.origin,
|
|
80
|
-
getPrefix(),
|
|
81
|
-
`/customer/invoice/${invoice.id}?action=${invoice.status === "uncollectible" ? action : ""}`
|
|
82
|
-
),
|
|
83
|
-
target,
|
|
84
|
-
children: /* @__PURE__ */ jsx(Typography, { component: "span", children: invoice.number })
|
|
85
|
-
}
|
|
86
|
-
) }),
|
|
87
|
-
/* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(Typography, { children: formatToDate(invoice.created_at) }) }),
|
|
88
|
-
/* @__PURE__ */ jsx(Box, { flex: 2, children: /* @__PURE__ */ jsxs(Typography, { textAlign: "right", children: [
|
|
89
|
-
formatBNStr(invoice.total, invoice.paymentCurrency.decimal),
|
|
90
|
-
"\xA0",
|
|
91
|
-
invoice.paymentCurrency.symbol
|
|
92
|
-
] }) }),
|
|
93
|
-
/* @__PURE__ */ jsx(Box, { flex: 2, children: /* @__PURE__ */ jsx(Status, { label: invoice.status, color: getInvoiceStatusColor(invoice.status) }) }),
|
|
94
|
-
/* @__PURE__ */ jsx(Box, { flex: 4, children: /* @__PURE__ */ jsx(Typography, { children: invoice.description || invoice.id }) })
|
|
95
|
-
]
|
|
96
|
-
},
|
|
97
|
-
invoice.id
|
|
98
|
-
))
|
|
111
|
+
invoice.id
|
|
112
|
+
);
|
|
113
|
+
})
|
|
99
114
|
] }, date)),
|
|
100
115
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
101
116
|
hasMore && /* @__PURE__ */ jsx(Button, { variant: "text", type: "button", color: "inherit", onClick: loadMore, disabled: loadingMore, children: loadingMore ? t("common.loadingMore", { resource: t("payment.customer.invoices") }) : t("common.loadMore", { resource: t("payment.customer.invoices") }) }),
|
|
@@ -19,10 +19,10 @@ import api from "../../api.js";
|
|
|
19
19
|
import Status from "../../components/status.js";
|
|
20
20
|
import {
|
|
21
21
|
formatBNStr,
|
|
22
|
+
formatDateTime,
|
|
22
23
|
formatError,
|
|
23
24
|
formatSubscriptionProduct,
|
|
24
25
|
formatTime,
|
|
25
|
-
formatToDate,
|
|
26
26
|
getInvoiceStatusColor,
|
|
27
27
|
getPrefix,
|
|
28
28
|
getSubscriptionStatusColor
|
|
@@ -117,13 +117,14 @@ export default function MiniInvoiceList() {
|
|
|
117
117
|
/* @__PURE__ */ jsx(ListSubheader, { disableGutters: true, sx: { padding: 0 }, children: /* @__PURE__ */ jsx(Typography, { component: "h2", variant: "h6", fontSize: "16px", children: t("payment.customer.invoices") }) }),
|
|
118
118
|
invoices.length === 0 ? /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("payment.customer.invoice.empty") }) : invoices.map((item) => {
|
|
119
119
|
return /* @__PURE__ */ jsxs(ListItem, { disableGutters: true, sx: { display: "flex", justifyContent: "space-between" }, children: [
|
|
120
|
-
/* @__PURE__ */ jsx(Typography, { component: "span", sx: { flex: 3 }, children:
|
|
120
|
+
/* @__PURE__ */ jsx(Typography, { component: "span", sx: { flex: 3 }, children: formatDateTime(item.created_at, locale) }),
|
|
121
121
|
/* @__PURE__ */ jsxs(Typography, { component: "span", sx: { flex: 1, textAlign: "right" }, children: [
|
|
122
122
|
formatBNStr(item.total, item.paymentCurrency.decimal),
|
|
123
123
|
"\xA0",
|
|
124
124
|
item.paymentCurrency.symbol
|
|
125
125
|
] }),
|
|
126
|
-
/* @__PURE__ */ jsx(Typography, { component: "span", sx: { flex: 2, textAlign: "
|
|
126
|
+
/* @__PURE__ */ jsx(Typography, { component: "span", sx: { flex: 2, textAlign: "center" }, children: /* @__PURE__ */ jsx(Status, { label: item.status, color: getInvoiceStatusColor(item.status) }) }),
|
|
127
|
+
/* @__PURE__ */ jsx(Typography, { component: "span", sx: { flex: 3 }, children: /* @__PURE__ */ jsx(Typography, { children: item.description || item.id }) })
|
|
127
128
|
] }, item.id);
|
|
128
129
|
})
|
|
129
130
|
] }) }),
|
|
@@ -148,7 +149,6 @@ export default function MiniInvoiceList() {
|
|
|
148
149
|
/* @__PURE__ */ jsx(
|
|
149
150
|
Button,
|
|
150
151
|
{
|
|
151
|
-
target: "_blank",
|
|
152
152
|
variant: "contained",
|
|
153
153
|
sx: { color: "#fff!important", width: subscription.service_actions?.length ? "auto" : "100%" },
|
|
154
154
|
href: joinURL(
|
package/es/locales/en.js
CHANGED
|
@@ -231,7 +231,8 @@ export default flat({
|
|
|
231
231
|
renew: "Renew the subscription",
|
|
232
232
|
renewSuccess: "You have successfully renewed the subscription",
|
|
233
233
|
renewError: "Failed to renew the subscription",
|
|
234
|
-
empty: "There are no invoices"
|
|
234
|
+
empty: "There are no invoices",
|
|
235
|
+
next: "No invoices yet, next invoice will be generated on {date}"
|
|
235
236
|
},
|
|
236
237
|
payment: {
|
|
237
238
|
empty: "There are no payments"
|
package/es/locales/zh.js
CHANGED
|
@@ -213,7 +213,7 @@ export default flat({
|
|
|
213
213
|
review: "\u67E5\u770B\u8BA2\u9605\u8BE6\u60C5",
|
|
214
214
|
select: "\u9009\u62E9\u652F\u4ED8\u65B9\u5F0F",
|
|
215
215
|
submit: "\u786E\u8BA4\u53D8\u66F4",
|
|
216
|
-
confirm: "\u786E\u8BA4\u53D8\u66F4\u65B9\u5F0F\u610F\u5473\u7740\u4F60\u5141\u8BB8{payee}\u4F7F\u7528\u65B0\u7684\u652F\u4ED8\u65B9\u5F0F\u652F\u4ED8\u4F60\u7684\u672A\u6765\u8D26\u5355\u3002\u4F60\u53EF\u4EE5\u968F\u65F6\u518D\u6B21\u53D8\u66F4\u652F\u4ED8\u65B9\u5F0F\u3002",
|
|
216
|
+
confirm: "\u786E\u8BA4\u53D8\u66F4\u65B9\u5F0F\u610F\u5473\u7740\u4F60\u5141\u8BB8 {payee} \u4F7F\u7528\u65B0\u7684\u652F\u4ED8\u65B9\u5F0F\u652F\u4ED8\u4F60\u7684\u672A\u6765\u8D26\u5355\u3002\u4F60\u53EF\u4EE5\u968F\u65F6\u518D\u6B21\u53D8\u66F4\u652F\u4ED8\u65B9\u5F0F\u3002",
|
|
217
217
|
completed: "\u4F60\u7684\u652F\u4ED8\u65B9\u5F0F \u5DF2\u7ECF\u66F4\u65B0\u6210\u529F\u3002\u4F60\u53EF\u4EE5\u5728\u4F60\u7684\u8D26\u6237\u4E2D\u67E5\u770B\u6B64\u652F\u4ED8\u65B9\u5F0F\u7684\u8BE6\u7EC6\u4FE1\u606F\u3002"
|
|
218
218
|
},
|
|
219
219
|
invoice: {
|
|
@@ -231,7 +231,8 @@ export default flat({
|
|
|
231
231
|
renew: "\u6062\u590D\u8BA2\u9605",
|
|
232
232
|
renewSuccess: "\u8BA2\u9605\u6062\u590D\u6210\u529F",
|
|
233
233
|
renewError: "\u8BA2\u9605\u6062\u590D\u5931\u8D25",
|
|
234
|
-
empty: "\u6CA1\u6709\u4EFB\u4F55\u8D26\u5355"
|
|
234
|
+
empty: "\u6CA1\u6709\u4EFB\u4F55\u8D26\u5355",
|
|
235
|
+
next: "\u8FD8\u6CA1\u6709\u8D26\u5355\uFF0C\u4E0B\u6B21\u8D26\u5355\u5C06\u5728 {date} \u751F\u6210"
|
|
235
236
|
},
|
|
236
237
|
payment: {
|
|
237
238
|
empty: "\u6CA1\u6709\u652F\u4ED8\u8BB0\u5F55"
|
|
@@ -241,7 +242,7 @@ export default flat({
|
|
|
241
242
|
},
|
|
242
243
|
subscriptions: {
|
|
243
244
|
plan: "\u8BA2\u9605",
|
|
244
|
-
nextInvoice: "\u4E0B\
|
|
245
|
+
nextInvoice: "\u4E0B\u6B21\u8D26\u5355",
|
|
245
246
|
title: "\u8BA2\u9605\u7BA1\u7406",
|
|
246
247
|
view: "\u7BA1\u7406\u8BA2\u9605",
|
|
247
248
|
current: "\u5F53\u524D\u8BA2\u9605",
|
package/es/util.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import type { PriceCurrency, PriceRecurring, TLineItemExpanded, TPaymentCurrency, TPaymentMethodExpanded, TPrice, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
|
|
2
|
+
import type { PaymentDetails, PriceCurrency, PriceRecurring, TLineItemExpanded, TPaymentCurrency, TPaymentMethod, TPaymentMethodExpanded, TPrice, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
|
|
3
3
|
export declare const PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
|
|
4
4
|
export declare const getPrefix: () => any;
|
|
5
5
|
export declare function formatToDate(date: Date | string | number, locale?: string): any;
|
|
@@ -62,3 +62,7 @@ export declare const mergeExtraParams: (extra?: Record<string, any>) => string;
|
|
|
62
62
|
export declare const flattenPaymentMethods: (methods?: TPaymentMethodExpanded[]) => import("sequelize").InferAttributes<import("@blocklet/payment-types").PaymentCurrency, {
|
|
63
63
|
omit: never;
|
|
64
64
|
}>[];
|
|
65
|
+
export declare const getTxLink: (method: TPaymentMethod, details: PaymentDetails) => {
|
|
66
|
+
link: string;
|
|
67
|
+
text: string;
|
|
68
|
+
};
|
package/es/util.js
CHANGED
|
@@ -2,6 +2,7 @@ import { BN, fromUnitToToken } from "@ocap/util";
|
|
|
2
2
|
import trimEnd from "lodash/trimEnd";
|
|
3
3
|
import numbro from "numbro";
|
|
4
4
|
import { defaultCountries } from "react-international-phone";
|
|
5
|
+
import { joinURL } from "ufo";
|
|
5
6
|
import dayjs from "./dayjs.js";
|
|
6
7
|
import { t } from "./locales/index.js";
|
|
7
8
|
export const PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
|
|
@@ -506,3 +507,35 @@ export const flattenPaymentMethods = (methods = []) => {
|
|
|
506
507
|
});
|
|
507
508
|
return out;
|
|
508
509
|
};
|
|
510
|
+
export const getTxLink = (method, details) => {
|
|
511
|
+
if (method.type === "arcblock" && details.arcblock?.tx_hash) {
|
|
512
|
+
return {
|
|
513
|
+
link: joinURL(method.settings.arcblock?.explorer_host, "/txs", details.arcblock?.tx_hash),
|
|
514
|
+
text: details.arcblock?.tx_hash
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
if (method.type === "bitcoin" && details.bitcoin?.tx_hash) {
|
|
518
|
+
return {
|
|
519
|
+
link: joinURL(method.settings.bitcoin?.explorer_host, "/tx", details.bitcoin?.tx_hash),
|
|
520
|
+
text: details.bitcoin?.tx_hash
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
if (method.type === "ethereum" && details.ethereum?.tx_hash) {
|
|
524
|
+
return {
|
|
525
|
+
link: joinURL(method.settings.ethereum?.explorer_host, "/tx", details.ethereum?.tx_hash),
|
|
526
|
+
text: details.ethereum?.tx_hash
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
if (method.type === "stripe") {
|
|
530
|
+
const dashboard = method.livemode ? "https://dashboard.stripe.com" : "https://dashboard.stripe.com/test";
|
|
531
|
+
return {
|
|
532
|
+
link: joinURL(
|
|
533
|
+
method.settings.stripe?.dashboard || dashboard,
|
|
534
|
+
"payments",
|
|
535
|
+
details.stripe?.payment_intent_id
|
|
536
|
+
),
|
|
537
|
+
text: details.stripe?.payment_intent_id
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
return { text: "N/A", link: "" };
|
|
541
|
+
};
|
|
@@ -8,38 +8,7 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
8
8
|
var _context = require("@arcblock/ux/lib/Locale/context");
|
|
9
9
|
var _iconsMaterial = require("@mui/icons-material");
|
|
10
10
|
var _material = require("@mui/material");
|
|
11
|
-
var
|
|
12
|
-
const getTxLink = (method, details) => {
|
|
13
|
-
if (method.type === "arcblock" && details.arcblock?.tx_hash) {
|
|
14
|
-
return {
|
|
15
|
-
link: (0, _ufo.joinURL)(method.settings.arcblock?.explorer_host, "/txs", details.arcblock?.tx_hash),
|
|
16
|
-
text: details.arcblock?.tx_hash
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
if (method.type === "bitcoin" && details.bitcoin?.tx_hash) {
|
|
20
|
-
return {
|
|
21
|
-
link: (0, _ufo.joinURL)(method.settings.bitcoin?.explorer_host, "/tx", details.bitcoin?.tx_hash),
|
|
22
|
-
text: details.bitcoin?.tx_hash
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
if (method.type === "ethereum" && details.ethereum?.tx_hash) {
|
|
26
|
-
return {
|
|
27
|
-
link: (0, _ufo.joinURL)(method.settings.ethereum?.explorer_host, "/tx", details.ethereum?.tx_hash),
|
|
28
|
-
text: details.ethereum?.tx_hash
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
if (method.type === "stripe") {
|
|
32
|
-
const dashboard = method.livemode ? "https://dashboard.stripe.com" : "https://dashboard.stripe.com/test";
|
|
33
|
-
return {
|
|
34
|
-
link: (0, _ufo.joinURL)(method.settings.stripe?.dashboard || dashboard, "payments", details.stripe?.payment_intent_id),
|
|
35
|
-
text: details.stripe?.payment_intent_id
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
return {
|
|
39
|
-
text: "N/A",
|
|
40
|
-
link: ""
|
|
41
|
-
};
|
|
42
|
-
};
|
|
11
|
+
var _util = require("../../util");
|
|
43
12
|
TxLink.defaultProps = {
|
|
44
13
|
mode: "dashboard"
|
|
45
14
|
};
|
|
@@ -57,7 +26,7 @@ function TxLink(props) {
|
|
|
57
26
|
const {
|
|
58
27
|
text,
|
|
59
28
|
link
|
|
60
|
-
} = getTxLink(props.method, props.details);
|
|
29
|
+
} = (0, _util.getTxLink)(props.method, props.details);
|
|
61
30
|
if (link) {
|
|
62
31
|
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Link, {
|
|
63
32
|
href: link,
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
module.exports = CustomerInvoiceList;
|
|
7
7
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
8
8
|
var _context = require("@arcblock/ux/lib/Locale/context");
|
|
9
|
+
var _iconsMaterial = require("@mui/icons-material");
|
|
9
10
|
var _material = require("@mui/material");
|
|
10
11
|
var _ahooks = require("ahooks");
|
|
11
12
|
var _ufo = require("ufo");
|
|
@@ -33,6 +34,18 @@ const fetchData = (params = {}) => {
|
|
|
33
34
|
});
|
|
34
35
|
return _api.default.get(`/api/invoices?${search.toString()}`).then(res => res.data);
|
|
35
36
|
};
|
|
37
|
+
const getInvoiceLink = (invoice, action) => {
|
|
38
|
+
if (invoice.id.startsWith("in_")) {
|
|
39
|
+
return {
|
|
40
|
+
external: false,
|
|
41
|
+
url: (0, _ufo.joinURL)(window.location.origin, (0, _util.getPrefix)(), `/customer/invoice/${invoice.id}?action=${invoice.status === "uncollectible" ? action : ""}`)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
external: true,
|
|
46
|
+
url: (0, _util.getTxLink)(invoice.paymentMethod, invoice.metadata?.payment_details).link
|
|
47
|
+
};
|
|
48
|
+
};
|
|
36
49
|
function CustomerInvoiceList({
|
|
37
50
|
customer_id,
|
|
38
51
|
subscription_id,
|
|
@@ -63,14 +76,28 @@ function CustomerInvoiceList({
|
|
|
63
76
|
ignoreZero: true
|
|
64
77
|
});
|
|
65
78
|
}, {
|
|
66
|
-
reloadDeps: [customer_id]
|
|
79
|
+
reloadDeps: [customer_id, subscription_id, status]
|
|
67
80
|
});
|
|
68
81
|
if (loading || !data) {
|
|
69
82
|
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.CircularProgress, {});
|
|
70
83
|
}
|
|
71
84
|
if (data && data.list.length === 0) {
|
|
85
|
+
if (data.subscription && ["active", "trialing"].includes(data.subscription.status)) {
|
|
86
|
+
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
87
|
+
color: "text.secondary",
|
|
88
|
+
sx: {
|
|
89
|
+
my: 0.5
|
|
90
|
+
},
|
|
91
|
+
children: t("payment.customer.invoice.next", {
|
|
92
|
+
date: (0, _util.formatToDatetime)(data.subscription.current_period_end * 1e3)
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
}
|
|
72
96
|
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
73
97
|
color: "text.secondary",
|
|
98
|
+
sx: {
|
|
99
|
+
my: 0.5
|
|
100
|
+
},
|
|
74
101
|
children: t("payment.customer.invoice.empty")
|
|
75
102
|
});
|
|
76
103
|
}
|
|
@@ -91,54 +118,68 @@ function CustomerInvoiceList({
|
|
|
91
118
|
mb: 1
|
|
92
119
|
},
|
|
93
120
|
children: date
|
|
94
|
-
}), invoices.map(invoice =>
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(
|
|
111
|
-
|
|
112
|
-
|
|
121
|
+
}), invoices.map(invoice => {
|
|
122
|
+
const link = getInvoiceLink(invoice, action);
|
|
123
|
+
return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
124
|
+
direction: {
|
|
125
|
+
xs: "column",
|
|
126
|
+
sm: "row"
|
|
127
|
+
},
|
|
128
|
+
sx: {
|
|
129
|
+
my: 1
|
|
130
|
+
},
|
|
131
|
+
gap: {
|
|
132
|
+
xs: 0.5,
|
|
133
|
+
sm: 1.5,
|
|
134
|
+
md: 3
|
|
135
|
+
},
|
|
136
|
+
flexWrap: "nowrap",
|
|
137
|
+
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
138
|
+
flex: 3,
|
|
139
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)("a", {
|
|
140
|
+
href: link.url,
|
|
141
|
+
target: link.external ? "_blank" : target,
|
|
142
|
+
rel: "noreferrer",
|
|
143
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
144
|
+
direction: "row",
|
|
145
|
+
alignItems: "center",
|
|
146
|
+
spacing: 0.5,
|
|
147
|
+
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
148
|
+
component: "span",
|
|
149
|
+
children: invoice.number
|
|
150
|
+
}), link.external && /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.OpenInNewOutlined, {
|
|
151
|
+
fontSize: "small",
|
|
152
|
+
sx: {
|
|
153
|
+
color: "text.secondary"
|
|
154
|
+
}
|
|
155
|
+
})]
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
159
|
+
flex: 3,
|
|
160
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
161
|
+
children: (0, _util.formatToDate)(invoice.created_at)
|
|
162
|
+
})
|
|
163
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
164
|
+
flex: 2,
|
|
165
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
|
|
166
|
+
textAlign: "right",
|
|
167
|
+
children: [(0, _util.formatBNStr)(invoice.total, invoice.paymentCurrency.decimal), "\xA0", invoice.paymentCurrency.symbol]
|
|
168
|
+
})
|
|
169
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
170
|
+
flex: 2,
|
|
171
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_status.default, {
|
|
172
|
+
label: invoice.status,
|
|
173
|
+
color: (0, _util.getInvoiceStatusColor)(invoice.status)
|
|
174
|
+
})
|
|
175
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
176
|
+
flex: 4,
|
|
113
177
|
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
114
|
-
|
|
115
|
-
children: invoice.number
|
|
178
|
+
children: invoice.description || invoice.id
|
|
116
179
|
})
|
|
117
|
-
})
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
121
|
-
children: (0, _util.formatToDate)(invoice.created_at)
|
|
122
|
-
})
|
|
123
|
-
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
124
|
-
flex: 2,
|
|
125
|
-
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
|
|
126
|
-
textAlign: "right",
|
|
127
|
-
children: [(0, _util.formatBNStr)(invoice.total, invoice.paymentCurrency.decimal), "\xA0", invoice.paymentCurrency.symbol]
|
|
128
|
-
})
|
|
129
|
-
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
130
|
-
flex: 2,
|
|
131
|
-
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_status.default, {
|
|
132
|
-
label: invoice.status,
|
|
133
|
-
color: (0, _util.getInvoiceStatusColor)(invoice.status)
|
|
134
|
-
})
|
|
135
|
-
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
136
|
-
flex: 4,
|
|
137
|
-
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
138
|
-
children: invoice.description || invoice.id
|
|
139
|
-
})
|
|
140
|
-
})]
|
|
141
|
-
}, invoice.id))]
|
|
180
|
+
})]
|
|
181
|
+
}, invoice.id);
|
|
182
|
+
})]
|
|
142
183
|
}, date)), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
|
|
143
184
|
children: [hasMore && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Button, {
|
|
144
185
|
variant: "text",
|
|
@@ -175,7 +175,7 @@ function MiniInvoiceList() {
|
|
|
175
175
|
sx: {
|
|
176
176
|
flex: 3
|
|
177
177
|
},
|
|
178
|
-
children: (0, _util.
|
|
178
|
+
children: (0, _util.formatDateTime)(item.created_at, locale)
|
|
179
179
|
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
|
|
180
180
|
component: "span",
|
|
181
181
|
sx: {
|
|
@@ -187,14 +187,19 @@ function MiniInvoiceList() {
|
|
|
187
187
|
component: "span",
|
|
188
188
|
sx: {
|
|
189
189
|
flex: 2,
|
|
190
|
-
textAlign: "
|
|
190
|
+
textAlign: "center"
|
|
191
191
|
},
|
|
192
192
|
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_status.default, {
|
|
193
193
|
label: item.status,
|
|
194
|
-
color: (0, _util.getInvoiceStatusColor)(item.status)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
color: (0, _util.getInvoiceStatusColor)(item.status)
|
|
195
|
+
})
|
|
196
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
197
|
+
component: "span",
|
|
198
|
+
sx: {
|
|
199
|
+
flex: 3
|
|
200
|
+
},
|
|
201
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
202
|
+
children: item.description || item.id
|
|
198
203
|
})
|
|
199
204
|
})]
|
|
200
205
|
}, item.id);
|
|
@@ -222,7 +227,6 @@ function MiniInvoiceList() {
|
|
|
222
227
|
},
|
|
223
228
|
children: x.text[locale] || x.text.en || x.name
|
|
224
229
|
}, x.name)), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Button, {
|
|
225
|
-
target: "_blank",
|
|
226
230
|
variant: "contained",
|
|
227
231
|
sx: {
|
|
228
232
|
color: "#fff!important",
|
package/lib/locales/en.js
CHANGED
|
@@ -238,7 +238,8 @@ module.exports = (0, _flat.default)({
|
|
|
238
238
|
renew: "Renew the subscription",
|
|
239
239
|
renewSuccess: "You have successfully renewed the subscription",
|
|
240
240
|
renewError: "Failed to renew the subscription",
|
|
241
|
-
empty: "There are no invoices"
|
|
241
|
+
empty: "There are no invoices",
|
|
242
|
+
next: "No invoices yet, next invoice will be generated on {date}"
|
|
242
243
|
},
|
|
243
244
|
payment: {
|
|
244
245
|
empty: "There are no payments"
|
package/lib/locales/zh.js
CHANGED
|
@@ -220,7 +220,7 @@ module.exports = (0, _flat.default)({
|
|
|
220
220
|
review: "\u67E5\u770B\u8BA2\u9605\u8BE6\u60C5",
|
|
221
221
|
select: "\u9009\u62E9\u652F\u4ED8\u65B9\u5F0F",
|
|
222
222
|
submit: "\u786E\u8BA4\u53D8\u66F4",
|
|
223
|
-
confirm: "\u786E\u8BA4\u53D8\u66F4\u65B9\u5F0F\u610F\u5473\u7740\u4F60\u5141\u8BB8{payee}\u4F7F\u7528\u65B0\u7684\u652F\u4ED8\u65B9\u5F0F\u652F\u4ED8\u4F60\u7684\u672A\u6765\u8D26\u5355\u3002\u4F60\u53EF\u4EE5\u968F\u65F6\u518D\u6B21\u53D8\u66F4\u652F\u4ED8\u65B9\u5F0F\u3002",
|
|
223
|
+
confirm: "\u786E\u8BA4\u53D8\u66F4\u65B9\u5F0F\u610F\u5473\u7740\u4F60\u5141\u8BB8 {payee} \u4F7F\u7528\u65B0\u7684\u652F\u4ED8\u65B9\u5F0F\u652F\u4ED8\u4F60\u7684\u672A\u6765\u8D26\u5355\u3002\u4F60\u53EF\u4EE5\u968F\u65F6\u518D\u6B21\u53D8\u66F4\u652F\u4ED8\u65B9\u5F0F\u3002",
|
|
224
224
|
completed: "\u4F60\u7684\u652F\u4ED8\u65B9\u5F0F \u5DF2\u7ECF\u66F4\u65B0\u6210\u529F\u3002\u4F60\u53EF\u4EE5\u5728\u4F60\u7684\u8D26\u6237\u4E2D\u67E5\u770B\u6B64\u652F\u4ED8\u65B9\u5F0F\u7684\u8BE6\u7EC6\u4FE1\u606F\u3002"
|
|
225
225
|
},
|
|
226
226
|
invoice: {
|
|
@@ -238,7 +238,8 @@ module.exports = (0, _flat.default)({
|
|
|
238
238
|
renew: "\u6062\u590D\u8BA2\u9605",
|
|
239
239
|
renewSuccess: "\u8BA2\u9605\u6062\u590D\u6210\u529F",
|
|
240
240
|
renewError: "\u8BA2\u9605\u6062\u590D\u5931\u8D25",
|
|
241
|
-
empty: "\u6CA1\u6709\u4EFB\u4F55\u8D26\u5355"
|
|
241
|
+
empty: "\u6CA1\u6709\u4EFB\u4F55\u8D26\u5355",
|
|
242
|
+
next: "\u8FD8\u6CA1\u6709\u8D26\u5355\uFF0C\u4E0B\u6B21\u8D26\u5355\u5C06\u5728 {date} \u751F\u6210"
|
|
242
243
|
},
|
|
243
244
|
payment: {
|
|
244
245
|
empty: "\u6CA1\u6709\u652F\u4ED8\u8BB0\u5F55"
|
|
@@ -248,7 +249,7 @@ module.exports = (0, _flat.default)({
|
|
|
248
249
|
},
|
|
249
250
|
subscriptions: {
|
|
250
251
|
plan: "\u8BA2\u9605",
|
|
251
|
-
nextInvoice: "\u4E0B\
|
|
252
|
+
nextInvoice: "\u4E0B\u6B21\u8D26\u5355",
|
|
252
253
|
title: "\u8BA2\u9605\u7BA1\u7406",
|
|
253
254
|
view: "\u7BA1\u7406\u8BA2\u9605",
|
|
254
255
|
current: "\u5F53\u524D\u8BA2\u9605",
|
package/lib/util.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import type { PriceCurrency, PriceRecurring, TLineItemExpanded, TPaymentCurrency, TPaymentMethodExpanded, TPrice, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
|
|
2
|
+
import type { PaymentDetails, PriceCurrency, PriceRecurring, TLineItemExpanded, TPaymentCurrency, TPaymentMethod, TPaymentMethodExpanded, TPrice, TSubscriptionExpanded, TSubscriptionItemExpanded } from '@blocklet/payment-types';
|
|
3
3
|
export declare const PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
|
|
4
4
|
export declare const getPrefix: () => any;
|
|
5
5
|
export declare function formatToDate(date: Date | string | number, locale?: string): any;
|
|
@@ -62,3 +62,7 @@ export declare const mergeExtraParams: (extra?: Record<string, any>) => string;
|
|
|
62
62
|
export declare const flattenPaymentMethods: (methods?: TPaymentMethodExpanded[]) => import("sequelize").InferAttributes<import("@blocklet/payment-types").PaymentCurrency, {
|
|
63
63
|
omit: never;
|
|
64
64
|
}>[];
|
|
65
|
+
export declare const getTxLink: (method: TPaymentMethod, details: PaymentDetails) => {
|
|
66
|
+
link: string;
|
|
67
|
+
text: string;
|
|
68
|
+
};
|
package/lib/util.js
CHANGED
|
@@ -32,7 +32,7 @@ exports.getRefundStatusColor = getRefundStatusColor;
|
|
|
32
32
|
exports.getStatementDescriptor = getStatementDescriptor;
|
|
33
33
|
exports.getSubscriptionAction = void 0;
|
|
34
34
|
exports.getSubscriptionStatusColor = getSubscriptionStatusColor;
|
|
35
|
-
exports.getSubscriptionTimeSummary = void 0;
|
|
35
|
+
exports.getTxLink = exports.getSubscriptionTimeSummary = void 0;
|
|
36
36
|
exports.getWebhookStatusColor = getWebhookStatusColor;
|
|
37
37
|
exports.isValidCountry = isValidCountry;
|
|
38
38
|
exports.mergeExtraParams = void 0;
|
|
@@ -42,6 +42,7 @@ var _util = require("@ocap/util");
|
|
|
42
42
|
var _trimEnd = _interopRequireDefault(require("lodash/trimEnd"));
|
|
43
43
|
var _numbro = _interopRequireDefault(require("numbro"));
|
|
44
44
|
var _reactInternationalPhone = require("react-international-phone");
|
|
45
|
+
var _ufo = require("ufo");
|
|
45
46
|
var _dayjs = _interopRequireDefault(require("./dayjs"));
|
|
46
47
|
var _locales = require("./locales");
|
|
47
48
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -620,4 +621,36 @@ const flattenPaymentMethods = (methods = []) => {
|
|
|
620
621
|
});
|
|
621
622
|
return out;
|
|
622
623
|
};
|
|
623
|
-
exports.flattenPaymentMethods = flattenPaymentMethods;
|
|
624
|
+
exports.flattenPaymentMethods = flattenPaymentMethods;
|
|
625
|
+
const getTxLink = (method, details) => {
|
|
626
|
+
if (method.type === "arcblock" && details.arcblock?.tx_hash) {
|
|
627
|
+
return {
|
|
628
|
+
link: (0, _ufo.joinURL)(method.settings.arcblock?.explorer_host, "/txs", details.arcblock?.tx_hash),
|
|
629
|
+
text: details.arcblock?.tx_hash
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
if (method.type === "bitcoin" && details.bitcoin?.tx_hash) {
|
|
633
|
+
return {
|
|
634
|
+
link: (0, _ufo.joinURL)(method.settings.bitcoin?.explorer_host, "/tx", details.bitcoin?.tx_hash),
|
|
635
|
+
text: details.bitcoin?.tx_hash
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
if (method.type === "ethereum" && details.ethereum?.tx_hash) {
|
|
639
|
+
return {
|
|
640
|
+
link: (0, _ufo.joinURL)(method.settings.ethereum?.explorer_host, "/tx", details.ethereum?.tx_hash),
|
|
641
|
+
text: details.ethereum?.tx_hash
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
if (method.type === "stripe") {
|
|
645
|
+
const dashboard = method.livemode ? "https://dashboard.stripe.com" : "https://dashboard.stripe.com/test";
|
|
646
|
+
return {
|
|
647
|
+
link: (0, _ufo.joinURL)(method.settings.stripe?.dashboard || dashboard, "payments", details.stripe?.payment_intent_id),
|
|
648
|
+
text: details.stripe?.payment_intent_id
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
return {
|
|
652
|
+
text: "N/A",
|
|
653
|
+
link: ""
|
|
654
|
+
};
|
|
655
|
+
};
|
|
656
|
+
exports.getTxLink = getTxLink;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.200",
|
|
4
4
|
"description": "Reusable react components for payment kit v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"@babel/core": "^7.23.9",
|
|
91
91
|
"@babel/preset-env": "^7.23.9",
|
|
92
92
|
"@babel/preset-react": "^7.23.3",
|
|
93
|
-
"@blocklet/payment-types": "1.13.
|
|
93
|
+
"@blocklet/payment-types": "1.13.200",
|
|
94
94
|
"@storybook/addon-essentials": "^7.6.13",
|
|
95
95
|
"@storybook/addon-interactions": "^7.6.13",
|
|
96
96
|
"@storybook/addon-links": "^7.6.13",
|
|
@@ -119,5 +119,5 @@
|
|
|
119
119
|
"vite-plugin-babel": "^1.2.0",
|
|
120
120
|
"vite-plugin-node-polyfills": "^0.19.0"
|
|
121
121
|
},
|
|
122
|
-
"gitHead": "
|
|
122
|
+
"gitHead": "c57f8e82c4c319183c371393f1bb9891366a36f6"
|
|
123
123
|
}
|
|
@@ -2,41 +2,8 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
|
2
2
|
import type { PaymentDetails, TPaymentMethod } from '@blocklet/payment-types';
|
|
3
3
|
import { OpenInNewOutlined } from '@mui/icons-material';
|
|
4
4
|
import { Link, Stack, Typography } from '@mui/material';
|
|
5
|
-
import { joinURL } from 'ufo';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
if (method.type === 'arcblock' && details.arcblock?.tx_hash) {
|
|
9
|
-
return {
|
|
10
|
-
link: joinURL(method.settings.arcblock?.explorer_host as string, '/txs', details.arcblock?.tx_hash as string),
|
|
11
|
-
text: details.arcblock?.tx_hash as string,
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
if (method.type === 'bitcoin' && details.bitcoin?.tx_hash) {
|
|
15
|
-
return {
|
|
16
|
-
link: joinURL(method.settings.bitcoin?.explorer_host as string, '/tx', details.bitcoin?.tx_hash as string),
|
|
17
|
-
text: details.bitcoin?.tx_hash as string,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
if (method.type === 'ethereum' && details.ethereum?.tx_hash) {
|
|
21
|
-
return {
|
|
22
|
-
link: joinURL(method.settings.ethereum?.explorer_host as string, '/tx', details.ethereum?.tx_hash as string),
|
|
23
|
-
text: details.ethereum?.tx_hash as string,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
if (method.type === 'stripe') {
|
|
27
|
-
const dashboard = method.livemode ? 'https://dashboard.stripe.com' : 'https://dashboard.stripe.com/test';
|
|
28
|
-
return {
|
|
29
|
-
link: joinURL(
|
|
30
|
-
method.settings.stripe?.dashboard || dashboard,
|
|
31
|
-
'payments',
|
|
32
|
-
details.stripe?.payment_intent_id as string
|
|
33
|
-
),
|
|
34
|
-
text: details.stripe?.payment_intent_id as string,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return { text: 'N/A', link: '' };
|
|
39
|
-
};
|
|
6
|
+
import { getTxLink } from '../../util';
|
|
40
7
|
|
|
41
8
|
TxLink.defaultProps = {
|
|
42
9
|
mode: 'dashboard',
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/* eslint-disable react/no-unstable-nested-components */
|
|
2
2
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
|
-
import type { Paginated, TInvoiceExpanded } from '@blocklet/payment-types';
|
|
3
|
+
import type { Paginated, TInvoiceExpanded, TSubscription } from '@blocklet/payment-types';
|
|
4
|
+
import { OpenInNewOutlined } from '@mui/icons-material';
|
|
4
5
|
import { Box, Button, CircularProgress, Stack, Typography } from '@mui/material';
|
|
5
6
|
import { useInfiniteScroll } from 'ahooks';
|
|
6
7
|
import { joinURL } from 'ufo';
|
|
7
8
|
|
|
8
9
|
import api from '../../api';
|
|
9
10
|
import Status from '../../components/status';
|
|
10
|
-
import { formatBNStr, formatToDate, getInvoiceStatusColor, getPrefix } from '../../util';
|
|
11
|
+
import { formatBNStr, formatToDate, formatToDatetime, getInvoiceStatusColor, getPrefix, getTxLink } from '../../util';
|
|
12
|
+
|
|
13
|
+
type Result = Paginated<TInvoiceExpanded> & { subscription: TSubscription };
|
|
11
14
|
|
|
12
15
|
const groupByDate = (items: TInvoiceExpanded[]) => {
|
|
13
16
|
const grouped: { [key: string]: TInvoiceExpanded[] } = {};
|
|
@@ -21,7 +24,7 @@ const groupByDate = (items: TInvoiceExpanded[]) => {
|
|
|
21
24
|
return grouped;
|
|
22
25
|
};
|
|
23
26
|
|
|
24
|
-
const fetchData = (params: Record<string, any> = {}): Promise<
|
|
27
|
+
const fetchData = (params: Record<string, any> = {}): Promise<Result> => {
|
|
25
28
|
const search = new URLSearchParams();
|
|
26
29
|
Object.keys(params).forEach((key) => {
|
|
27
30
|
if (params[key]) {
|
|
@@ -41,6 +44,24 @@ type Props = {
|
|
|
41
44
|
action?: string;
|
|
42
45
|
};
|
|
43
46
|
|
|
47
|
+
const getInvoiceLink = (invoice: TInvoiceExpanded, action?: string) => {
|
|
48
|
+
if (invoice.id.startsWith('in_')) {
|
|
49
|
+
return {
|
|
50
|
+
external: false,
|
|
51
|
+
url: joinURL(
|
|
52
|
+
window.location.origin,
|
|
53
|
+
getPrefix(),
|
|
54
|
+
`/customer/invoice/${invoice.id}?action=${invoice.status === 'uncollectible' ? action : ''}`
|
|
55
|
+
),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
external: true,
|
|
61
|
+
url: getTxLink(invoice.paymentMethod, invoice.metadata?.payment_details).link,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
44
65
|
export default function CustomerInvoiceList({
|
|
45
66
|
customer_id,
|
|
46
67
|
subscription_id,
|
|
@@ -53,13 +74,13 @@ export default function CustomerInvoiceList({
|
|
|
53
74
|
const { t } = useLocaleContext();
|
|
54
75
|
const size = pageSize || 10;
|
|
55
76
|
|
|
56
|
-
const { data, loadMore, loadingMore, loading } = useInfiniteScroll<
|
|
77
|
+
const { data, loadMore, loadingMore, loading } = useInfiniteScroll<Result>(
|
|
57
78
|
(d) => {
|
|
58
79
|
const page = d ? Math.ceil(d.list.length / size) + 1 : 1;
|
|
59
80
|
return fetchData({ page, pageSize: size, status, customer_id, currency_id, subscription_id, ignoreZero: true });
|
|
60
81
|
},
|
|
61
82
|
{
|
|
62
|
-
reloadDeps: [customer_id],
|
|
83
|
+
reloadDeps: [customer_id, subscription_id, status],
|
|
63
84
|
}
|
|
64
85
|
);
|
|
65
86
|
|
|
@@ -68,7 +89,19 @@ export default function CustomerInvoiceList({
|
|
|
68
89
|
}
|
|
69
90
|
|
|
70
91
|
if (data && data.list.length === 0) {
|
|
71
|
-
|
|
92
|
+
if (data.subscription && ['active', 'trialing'].includes(data.subscription.status)) {
|
|
93
|
+
return (
|
|
94
|
+
<Typography color="text.secondary" sx={{ my: 0.5 }}>
|
|
95
|
+
{t('payment.customer.invoice.next', { date: formatToDatetime(data.subscription.current_period_end * 1000) })}
|
|
96
|
+
</Typography>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<Typography color="text.secondary" sx={{ my: 0.5 }}>
|
|
102
|
+
{t('payment.customer.invoice.empty')}
|
|
103
|
+
</Typography>
|
|
104
|
+
);
|
|
72
105
|
}
|
|
73
106
|
|
|
74
107
|
const hasMore = data && data.list.length < data.count;
|
|
@@ -80,48 +113,48 @@ export default function CustomerInvoiceList({
|
|
|
80
113
|
{Object.entries(grouped).map(([date, invoices]) => (
|
|
81
114
|
<Box key={date}>
|
|
82
115
|
<Typography sx={{ fontWeight: 'bold', color: 'text.secondary', mt: 2, mb: 1 }}>{date}</Typography>
|
|
83
|
-
{invoices.map((invoice) =>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
</
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
</
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
</
|
|
123
|
-
|
|
124
|
-
)
|
|
116
|
+
{invoices.map((invoice) => {
|
|
117
|
+
const link = getInvoiceLink(invoice, action);
|
|
118
|
+
return (
|
|
119
|
+
<Stack
|
|
120
|
+
key={invoice.id}
|
|
121
|
+
direction={{
|
|
122
|
+
xs: 'column',
|
|
123
|
+
sm: 'row',
|
|
124
|
+
}}
|
|
125
|
+
sx={{ my: 1 }}
|
|
126
|
+
gap={{
|
|
127
|
+
xs: 0.5,
|
|
128
|
+
sm: 1.5,
|
|
129
|
+
md: 3,
|
|
130
|
+
}}
|
|
131
|
+
flexWrap="nowrap">
|
|
132
|
+
<Box flex={3}>
|
|
133
|
+
<a href={link.url} target={link.external ? '_blank' : target} rel="noreferrer">
|
|
134
|
+
<Stack direction="row" alignItems="center" spacing={0.5}>
|
|
135
|
+
<Typography component="span">{invoice.number}</Typography>
|
|
136
|
+
{link.external && <OpenInNewOutlined fontSize="small" sx={{ color: 'text.secondary' }} />}
|
|
137
|
+
</Stack>
|
|
138
|
+
</a>
|
|
139
|
+
</Box>
|
|
140
|
+
<Box flex={3}>
|
|
141
|
+
<Typography>{formatToDate(invoice.created_at)}</Typography>
|
|
142
|
+
</Box>
|
|
143
|
+
<Box flex={2}>
|
|
144
|
+
<Typography textAlign="right">
|
|
145
|
+
{formatBNStr(invoice.total, invoice.paymentCurrency.decimal)}
|
|
146
|
+
{invoice.paymentCurrency.symbol}
|
|
147
|
+
</Typography>
|
|
148
|
+
</Box>
|
|
149
|
+
<Box flex={2}>
|
|
150
|
+
<Status label={invoice.status} color={getInvoiceStatusColor(invoice.status)} />
|
|
151
|
+
</Box>
|
|
152
|
+
<Box flex={4}>
|
|
153
|
+
<Typography>{invoice.description || invoice.id}</Typography>
|
|
154
|
+
</Box>
|
|
155
|
+
</Stack>
|
|
156
|
+
);
|
|
157
|
+
})}
|
|
125
158
|
</Box>
|
|
126
159
|
))}
|
|
127
160
|
<Box>
|
|
@@ -21,10 +21,10 @@ import api from '../../api';
|
|
|
21
21
|
import Status from '../../components/status';
|
|
22
22
|
import {
|
|
23
23
|
formatBNStr,
|
|
24
|
+
formatDateTime,
|
|
24
25
|
formatError,
|
|
25
26
|
formatSubscriptionProduct,
|
|
26
27
|
formatTime,
|
|
27
|
-
formatToDate,
|
|
28
28
|
getInvoiceStatusColor,
|
|
29
29
|
getPrefix,
|
|
30
30
|
getSubscriptionStatusColor,
|
|
@@ -157,14 +157,17 @@ export default function MiniInvoiceList() {
|
|
|
157
157
|
return (
|
|
158
158
|
<ListItem key={item.id} disableGutters sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
|
159
159
|
<Typography component="span" sx={{ flex: 3 }}>
|
|
160
|
-
{
|
|
160
|
+
{formatDateTime(item.created_at, locale)}
|
|
161
161
|
</Typography>
|
|
162
162
|
<Typography component="span" sx={{ flex: 1, textAlign: 'right' }}>
|
|
163
163
|
{formatBNStr(item.total, item.paymentCurrency.decimal)}
|
|
164
164
|
{item.paymentCurrency.symbol}
|
|
165
165
|
</Typography>
|
|
166
|
-
<Typography component="span" sx={{ flex: 2, textAlign: '
|
|
167
|
-
<Status label={item.status} color={getInvoiceStatusColor(item.status)}
|
|
166
|
+
<Typography component="span" sx={{ flex: 2, textAlign: 'center' }}>
|
|
167
|
+
<Status label={item.status} color={getInvoiceStatusColor(item.status)} />
|
|
168
|
+
</Typography>
|
|
169
|
+
<Typography component="span" sx={{ flex: 3 }}>
|
|
170
|
+
<Typography>{item.description || item.id}</Typography>
|
|
168
171
|
</Typography>
|
|
169
172
|
</ListItem>
|
|
170
173
|
);
|
|
@@ -188,7 +191,6 @@ export default function MiniInvoiceList() {
|
|
|
188
191
|
</Button>
|
|
189
192
|
))}
|
|
190
193
|
<Button
|
|
191
|
-
target="_blank"
|
|
192
194
|
variant="contained"
|
|
193
195
|
sx={{ color: '#fff!important', width: subscription.service_actions?.length ? 'auto' : '100%' }}
|
|
194
196
|
href={joinURL(
|
package/src/locales/en.tsx
CHANGED
|
@@ -241,6 +241,7 @@ export default flat({
|
|
|
241
241
|
renewSuccess: 'You have successfully renewed the subscription',
|
|
242
242
|
renewError: 'Failed to renew the subscription',
|
|
243
243
|
empty: 'There are no invoices',
|
|
244
|
+
next: 'No invoices yet, next invoice will be generated on {date}',
|
|
244
245
|
},
|
|
245
246
|
payment: {
|
|
246
247
|
empty: 'There are no payments',
|
package/src/locales/zh.tsx
CHANGED
|
@@ -215,7 +215,7 @@ export default flat({
|
|
|
215
215
|
review: '查看订阅详情',
|
|
216
216
|
select: '选择支付方式',
|
|
217
217
|
submit: '确认变更',
|
|
218
|
-
confirm: '确认变更方式意味着你允许{payee}使用新的支付方式支付你的未来账单。你可以随时再次变更支付方式。',
|
|
218
|
+
confirm: '确认变更方式意味着你允许 {payee} 使用新的支付方式支付你的未来账单。你可以随时再次变更支付方式。',
|
|
219
219
|
completed: '你的支付方式 已经更新成功。你可以在你的账户中查看此支付方式的详细信息。',
|
|
220
220
|
},
|
|
221
221
|
invoice: {
|
|
@@ -234,6 +234,7 @@ export default flat({
|
|
|
234
234
|
renewSuccess: '订阅恢复成功',
|
|
235
235
|
renewError: '订阅恢复失败',
|
|
236
236
|
empty: '没有任何账单',
|
|
237
|
+
next: '还没有账单,下次账单将在 {date} 生成',
|
|
237
238
|
},
|
|
238
239
|
payment: {
|
|
239
240
|
empty: '没有支付记录',
|
|
@@ -243,7 +244,7 @@ export default flat({
|
|
|
243
244
|
},
|
|
244
245
|
subscriptions: {
|
|
245
246
|
plan: '订阅',
|
|
246
|
-
nextInvoice: '
|
|
247
|
+
nextInvoice: '下次账单',
|
|
247
248
|
title: '订阅管理',
|
|
248
249
|
view: '管理订阅',
|
|
249
250
|
current: '当前订阅',
|
package/src/util.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/* eslint-disable no-nested-ternary */
|
|
2
2
|
/* eslint-disable @typescript-eslint/indent */
|
|
3
3
|
import type {
|
|
4
|
+
PaymentDetails,
|
|
4
5
|
PriceCurrency,
|
|
5
6
|
PriceRecurring,
|
|
6
7
|
TLineItemExpanded,
|
|
7
8
|
TPaymentCurrency,
|
|
9
|
+
TPaymentMethod,
|
|
8
10
|
TPaymentMethodExpanded,
|
|
9
11
|
TPrice,
|
|
10
12
|
TSubscriptionExpanded,
|
|
@@ -14,6 +16,7 @@ import { BN, fromUnitToToken } from '@ocap/util';
|
|
|
14
16
|
import trimEnd from 'lodash/trimEnd';
|
|
15
17
|
import numbro from 'numbro';
|
|
16
18
|
import { defaultCountries } from 'react-international-phone';
|
|
19
|
+
import { joinURL } from 'ufo';
|
|
17
20
|
|
|
18
21
|
import dayjs from './dayjs';
|
|
19
22
|
import { t } from './locales';
|
|
@@ -676,3 +679,37 @@ export const flattenPaymentMethods = (methods: TPaymentMethodExpanded[] = []) =>
|
|
|
676
679
|
|
|
677
680
|
return out;
|
|
678
681
|
};
|
|
682
|
+
|
|
683
|
+
export const getTxLink = (method: TPaymentMethod, details: PaymentDetails) => {
|
|
684
|
+
if (method.type === 'arcblock' && details.arcblock?.tx_hash) {
|
|
685
|
+
return {
|
|
686
|
+
link: joinURL(method.settings.arcblock?.explorer_host as string, '/txs', details.arcblock?.tx_hash as string),
|
|
687
|
+
text: details.arcblock?.tx_hash as string,
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
if (method.type === 'bitcoin' && details.bitcoin?.tx_hash) {
|
|
691
|
+
return {
|
|
692
|
+
link: joinURL(method.settings.bitcoin?.explorer_host as string, '/tx', details.bitcoin?.tx_hash as string),
|
|
693
|
+
text: details.bitcoin?.tx_hash as string,
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
if (method.type === 'ethereum' && details.ethereum?.tx_hash) {
|
|
697
|
+
return {
|
|
698
|
+
link: joinURL(method.settings.ethereum?.explorer_host as string, '/tx', details.ethereum?.tx_hash as string),
|
|
699
|
+
text: details.ethereum?.tx_hash as string,
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
if (method.type === 'stripe') {
|
|
703
|
+
const dashboard = method.livemode ? 'https://dashboard.stripe.com' : 'https://dashboard.stripe.com/test';
|
|
704
|
+
return {
|
|
705
|
+
link: joinURL(
|
|
706
|
+
method.settings.stripe?.dashboard || dashboard,
|
|
707
|
+
'payments',
|
|
708
|
+
details.stripe?.payment_intent_id as string
|
|
709
|
+
),
|
|
710
|
+
text: details.stripe?.payment_intent_id as string,
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return { text: 'N/A', link: '' };
|
|
715
|
+
};
|