@blocklet/payment-react 1.13.130 → 1.13.131

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.
@@ -0,0 +1,13 @@
1
+ /// <reference types="react" />
2
+ import type { PaymentDetails, TPaymentMethod } from '@blocklet/payment-types';
3
+ declare function TxLink(props: {
4
+ details: PaymentDetails;
5
+ method: TPaymentMethod;
6
+ mode?: 'customer' | 'dashboard';
7
+ }): import("react").JSX.Element;
8
+ declare namespace TxLink {
9
+ var defaultProps: {
10
+ mode: string;
11
+ };
12
+ }
13
+ export default TxLink;
@@ -0,0 +1,52 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { OpenInNewOutlined } from "@mui/icons-material";
3
+ import { Link, Stack, Typography } from "@mui/material";
4
+ import { joinURL } from "ufo";
5
+ const getTxLink = (method, details) => {
6
+ if (method.type === "arcblock" && details.arcblock?.tx_hash) {
7
+ return {
8
+ link: joinURL(method.settings.arcblock?.explorer_host, "/txs", details.arcblock?.tx_hash),
9
+ text: details.arcblock?.tx_hash
10
+ };
11
+ }
12
+ if (method.type === "bitcoin" && details.bitcoin?.tx_hash) {
13
+ return {
14
+ link: joinURL(method.settings.bitcoin?.explorer_host, "/tx", details.bitcoin?.tx_hash),
15
+ text: details.bitcoin?.tx_hash
16
+ };
17
+ }
18
+ if (method.type === "ethereum" && details.ethereum?.tx_hash) {
19
+ return {
20
+ link: joinURL(method.settings.ethereum?.explorer_host, "/tx", details.ethereum?.tx_hash),
21
+ text: details.ethereum?.tx_hash
22
+ };
23
+ }
24
+ if (method.type === "stripe") {
25
+ const dashboard = method.livemode ? "https://dashboard.stripe.com" : "https://dashboard.stripe.com/test";
26
+ return {
27
+ link: joinURL(
28
+ method.settings.stripe?.dashboard || dashboard,
29
+ "payments",
30
+ details.stripe?.payment_intent_id
31
+ ),
32
+ text: details.stripe?.payment_intent_id
33
+ };
34
+ }
35
+ return { text: "N/A", link: "" };
36
+ };
37
+ TxLink.defaultProps = {
38
+ mode: "dashboard"
39
+ };
40
+ export default function TxLink(props) {
41
+ if (!props.details || props.mode === "customer" && props.method.type === "stripe") {
42
+ return /* @__PURE__ */ jsx(Typography, { component: "small", color: "text.secondary", children: "None" });
43
+ }
44
+ const { text, link } = getTxLink(props.method, props.details);
45
+ if (link) {
46
+ return /* @__PURE__ */ jsx(Link, { href: link, target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsxs(Stack, { component: "span", direction: "row", alignItems: "center", spacing: 1, children: [
47
+ /* @__PURE__ */ jsx(Typography, { component: "span", color: "primary", children: text.length > 40 ? [text.slice(0, 8), text.slice(-8)].join("...") : text }),
48
+ /* @__PURE__ */ jsx(OpenInNewOutlined, { fontSize: "small" })
49
+ ] }) });
50
+ }
51
+ return /* @__PURE__ */ jsx(Typography, { component: "small", color: "text.secondary", children: "None" });
52
+ }
@@ -3,9 +3,10 @@ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
3
  import { Box, Button, CircularProgress, Stack, Typography } from "@mui/material";
4
4
  import { fromUnitToToken } from "@ocap/util";
5
5
  import { useInfiniteScroll } from "ahooks";
6
+ import { joinURL } from "ufo";
6
7
  import api from "../../api.js";
7
8
  import Status from "../../components/status.js";
8
- import { formatToDate, getInvoiceStatusColor } from "../../util.js";
9
+ import { formatToDate, getInvoiceStatusColor, getPrefix } from "../../util.js";
9
10
  const groupByDate = (items) => {
10
11
  const grouped = {};
11
12
  items.forEach((item) => {
@@ -64,7 +65,7 @@ export default function CustomerInvoiceList({ customer_id, subscription_id }) {
64
65
  },
65
66
  flexWrap: "nowrap",
66
67
  children: [
67
- /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx("a", { href: `/customer/invoice/${invoice.id}`, children: /* @__PURE__ */ jsx(Typography, { component: "span", children: invoice.number }) }) }),
68
+ /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx("a", { href: joinURL(window.location.origin, getPrefix(), `/customer/invoice/${invoice.id}`), children: /* @__PURE__ */ jsx(Typography, { component: "span", children: invoice.number }) }) }),
68
69
  /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(Typography, { children: formatToDate(invoice.created_at) }) }),
69
70
  /* @__PURE__ */ jsx(Box, { flex: 2, children: /* @__PURE__ */ jsxs(Typography, { textAlign: "right", children: [
70
71
  fromUnitToToken(invoice.total, invoice.paymentCurrency.decimal),
@@ -3,6 +3,7 @@ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
3
  import { Box, Button, CircularProgress, Divider, List, ListItem, ListSubheader, Typography } from "@mui/material";
4
4
  import { fromUnitToToken } from "@ocap/util";
5
5
  import { useRequest } from "ahooks";
6
+ import { joinURL } from "ufo";
6
7
  import api from "../../api.js";
7
8
  import Status from "../../components/status.js";
8
9
  import {
@@ -10,6 +11,7 @@ import {
10
11
  formatTime,
11
12
  formatToDate,
12
13
  getInvoiceStatusColor,
14
+ getPrefix,
13
15
  getSubscriptionStatusColor
14
16
  } from "../../util.js";
15
17
  const fetchInvoiceData = (params = {}) => {
@@ -29,12 +31,10 @@ export default function MiniInvoiceList() {
29
31
  const { data } = useRequest(
30
32
  () => fetchInvoiceData({ page: 1, pageSize: 10, status: "open,paid,uncollectible", subscription_id: subscriptionId })
31
33
  );
32
- if (!data || !subscription) {
34
+ if (!subscription || !data) {
33
35
  return /* @__PURE__ */ jsx(Position, { children: /* @__PURE__ */ jsx(CircularProgress, {}) });
34
36
  }
35
- if (data && data.list.length === 0) {
36
- return /* @__PURE__ */ jsx(Position, { children: /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("payment.customer.invoice.empty") }) });
37
- }
37
+ const invoices = data.list || [];
38
38
  const infoList = [
39
39
  {
40
40
  name: t("payment.customer.subscriptions.plan"),
@@ -43,8 +43,10 @@ export default function MiniInvoiceList() {
43
43
  {
44
44
  name: t("common.status"),
45
45
  value: /* @__PURE__ */ jsx(Status, { label: subscription.status, color: getSubscriptionStatusColor(subscription.status) })
46
- },
47
- {
46
+ }
47
+ ];
48
+ if (subscription.status === "active" || subscription.status === "trailing") {
49
+ infoList.push({
48
50
  name: t("payment.customer.subscriptions.nextInvoice"),
49
51
  value: /* @__PURE__ */ jsx(
50
52
  Typography,
@@ -57,13 +59,14 @@ export default function MiniInvoiceList() {
57
59
  children: formatTime(subscription.current_period_end * 1e3)
58
60
  }
59
61
  )
60
- }
61
- ];
62
+ });
63
+ }
62
64
  return /* @__PURE__ */ jsxs(Position, { children: [
63
65
  /* @__PURE__ */ jsx(Typography, { title: t("payment.checkout.subscription") }),
64
66
  /* @__PURE__ */ jsxs(
65
67
  Box,
66
68
  {
69
+ className: "mini-invoice-wrap",
67
70
  sx: {
68
71
  display: "flex",
69
72
  flexDirection: "column",
@@ -82,28 +85,30 @@ export default function MiniInvoiceList() {
82
85
  ] }, name);
83
86
  }) }) }),
84
87
  /* @__PURE__ */ jsx(Divider, {}),
85
- /* @__PURE__ */ jsx(Box, { sx: { marginTop: "12px" }, children: /* @__PURE__ */ jsxs(
86
- List,
88
+ /* @__PURE__ */ jsx(Box, { sx: { marginTop: "12px", flex: 1 }, children: /* @__PURE__ */ jsxs(List, { sx: { overflow: "auto" }, className: "mini-invoice-list", children: [
89
+ /* @__PURE__ */ jsx(ListSubheader, { disableGutters: true, sx: { padding: 0 }, children: /* @__PURE__ */ jsx(Typography, { component: "h2", variant: "h6", fontSize: "16px", children: t("payment.customer.invoices") }) }),
90
+ invoices.length === 0 ? /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("payment.customer.invoice.empty") }) : invoices.map((item) => {
91
+ return /* @__PURE__ */ jsxs(ListItem, { disableGutters: true, sx: { display: "flex", justifyContent: "space-between" }, children: [
92
+ /* @__PURE__ */ jsx(Typography, { component: "span", sx: { flex: 3 }, children: formatToDate(item.created_at) }),
93
+ /* @__PURE__ */ jsxs(Typography, { component: "span", sx: { flex: 1, textAlign: "right" }, children: [
94
+ fromUnitToToken(item.total, item.paymentCurrency.decimal),
95
+ "\xA0",
96
+ item.paymentCurrency.symbol
97
+ ] }),
98
+ /* @__PURE__ */ jsx(Typography, { component: "span", sx: { flex: 2, textAlign: "right" }, children: /* @__PURE__ */ jsx(Status, { label: item.status, color: getInvoiceStatusColor(item.status), sx: { flex: 2 } }) })
99
+ ] }, item.id);
100
+ })
101
+ ] }) }),
102
+ /* @__PURE__ */ jsx(
103
+ Button,
87
104
  {
88
- sx: { overflow: "auto", maxHeight: { xs: "240px", md: "360px", padding: 0 } },
89
- className: "mini-invoice-list",
90
- children: [
91
- /* @__PURE__ */ jsx(ListSubheader, { disableGutters: true, sx: { padding: 0 }, children: /* @__PURE__ */ jsx(Typography, { component: "h2", variant: "h6", fontSize: "16px", children: t("payment.customer.invoices") }) }),
92
- (data.list || []).map((item) => {
93
- return /* @__PURE__ */ jsxs(ListItem, { disableGutters: true, sx: { display: "flex", justifyContent: "space-between" }, children: [
94
- /* @__PURE__ */ jsx(Typography, { component: "span", sx: { flex: 3 }, children: formatToDate(item.created_at) }),
95
- /* @__PURE__ */ jsxs(Typography, { component: "span", sx: { flex: 1 }, children: [
96
- fromUnitToToken(item.total, item.paymentCurrency.decimal),
97
- "\xA0",
98
- item.paymentCurrency.symbol
99
- ] }),
100
- /* @__PURE__ */ jsx(Typography, { component: "span", sx: { flex: 2, textAlign: "right" }, children: /* @__PURE__ */ jsx(Status, { label: item.status, color: getInvoiceStatusColor(item.status), sx: { flex: 2 } }) })
101
- ] }, item.id);
102
- })
103
- ]
105
+ target: "_blank",
106
+ variant: "contained",
107
+ sx: { marginTop: "10px 0", width: "100%", color: "#fff!important" },
108
+ href: joinURL(window.location.origin, getPrefix(), `/customer/subscription/${subscription.id}`),
109
+ children: t("payment.customer.subscriptions.title")
104
110
  }
105
- ) }),
106
- /* @__PURE__ */ jsx(Button, { target: "_top", variant: "contained", sx: { marginTop: "10px 0", width: "100%" }, href: "", children: t("payment.customer.subscriptions.title") })
111
+ )
107
112
  ]
108
113
  }
109
114
  )
@@ -115,7 +120,6 @@ function Position({ children }) {
115
120
  {
116
121
  className: "mini-invoice-box",
117
122
  sx: {
118
- justifyContent: "center",
119
123
  padding: "8px",
120
124
  width: "100%",
121
125
  maxWidth: "500px",
@@ -4,6 +4,7 @@ import { Box, Button, CircularProgress, Stack, Typography } from "@mui/material"
4
4
  import { fromUnitToToken } from "@ocap/util";
5
5
  import { useInfiniteScroll } from "ahooks";
6
6
  import api from "../../api.js";
7
+ import TxLink from "../../components/blockchain/tx.js";
7
8
  import Status from "../../components/status.js";
8
9
  import { formatToDate, getPaymentIntentStatusColor } from "../../util.js";
9
10
  const groupByDate = (items) => {
@@ -69,7 +70,15 @@ export default function CustomerPaymentList({ customer_id }) {
69
70
  item.paymentCurrency.symbol
70
71
  ] }) }),
71
72
  /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(Status, { label: item.status, color: getPaymentIntentStatusColor(item.status) }) }),
72
- /* @__PURE__ */ jsx(Box, { flex: 4, children: /* @__PURE__ */ jsx(Typography, { children: item.description || item.id }) })
73
+ /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(Typography, { children: item.description || item.id }) }),
74
+ /* @__PURE__ */ jsx(Box, { flex: 3, sx: { minWidth: "220px" }, children: item.payment_details?.arcblock?.tx_hash && /* @__PURE__ */ jsx(
75
+ TxLink,
76
+ {
77
+ details: item.payment_details,
78
+ method: item.paymentMethod,
79
+ mode: "customer"
80
+ }
81
+ ) })
73
82
  ]
74
83
  },
75
84
  item.id
package/es/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import api from './api';
2
2
  import CheckoutForm from './checkout/form';
3
3
  import CheckoutTable from './checkout/table';
4
+ import TxLink from './components/blockchain/tx';
4
5
  import ConfirmDialog from './components/confirm';
5
6
  import FormInput from './components/input';
6
7
  import Livemode from './components/livemode';
@@ -18,4 +19,4 @@ import ProductSkeleton from './payment/product-skeleton';
18
19
  export * from './util';
19
20
  export * from './contexts/payment';
20
21
  export { translations, createTranslator } from './locales';
21
- export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, Payment, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, MiniInvoiceList, };
22
+ export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, Payment, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, MiniInvoiceList, TxLink, };
package/es/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import api from "./api.js";
2
2
  import CheckoutForm from "./checkout/form.js";
3
3
  import CheckoutTable from "./checkout/table.js";
4
+ import TxLink from "./components/blockchain/tx.js";
4
5
  import ConfirmDialog from "./components/confirm.js";
5
6
  import FormInput from "./components/input.js";
6
7
  import Livemode from "./components/livemode.js";
@@ -35,5 +36,6 @@ export {
35
36
  Amount,
36
37
  CustomerInvoiceList,
37
38
  CustomerPaymentList,
38
- MiniInvoiceList
39
+ MiniInvoiceList,
40
+ TxLink
39
41
  };
package/es/locales/en.js CHANGED
@@ -202,17 +202,17 @@ export default flat({
202
202
  pay: "Pay this invoice",
203
203
  paySuccess: "You have successfully paid the invoice",
204
204
  payError: "Failed to paid the invoice",
205
- empty: "Seems you do not have any invoice here"
205
+ empty: "There are no invoices here"
206
206
  },
207
207
  payment: {
208
- empty: "Seems you do not have any payment here"
208
+ empty: "There are no payments here"
209
209
  },
210
210
  subscriptions: {
211
211
  plan: "Plan",
212
212
  nextInvoice: "Next Invoice",
213
213
  title: "Manage subscriptions",
214
214
  current: "Current subscription",
215
- empty: "Seems you do not have any subscriptions here"
215
+ empty: "There are no subscriptions here"
216
216
  }
217
217
  }
218
218
  }
package/es/locales/zh.js CHANGED
@@ -202,17 +202,17 @@ export default flat({
202
202
  pay: "\u652F\u4ED8\u6B64\u53D1\u7968",
203
203
  paySuccess: "\u652F\u4ED8\u6210\u529F",
204
204
  payError: "\u652F\u4ED8\u5931\u8D25",
205
- empty: "\u4F60\u6CA1\u6709\u4EFB\u4F55\u53D1\u7968"
205
+ empty: "\u6CA1\u6709\u4EFB\u4F55\u53D1\u7968"
206
206
  },
207
207
  payment: {
208
- empty: "\u4F60\u6CA1\u6709\u4EFB\u4F55\u652F\u4ED8"
208
+ empty: "\u6CA1\u6709\u4EFB\u4F55\u652F\u4ED8"
209
209
  },
210
210
  subscriptions: {
211
211
  plan: "\u8BA2\u9605",
212
212
  nextInvoice: "\u4E0B\u4E00\u5F20\u53D1\u7968",
213
213
  title: "\u8BA2\u9605\u7BA1\u7406",
214
214
  current: "\u5F53\u524D\u8BA2\u9605",
215
- empty: "\u4F60\u8FD8\u6CA1\u6709\u4EFB\u4F55\u8BA2\u9605"
215
+ empty: "\u6CA1\u6709\u4EFB\u4F55\u8BA2\u9605"
216
216
  }
217
217
  }
218
218
  }
package/es/util.js CHANGED
@@ -226,9 +226,12 @@ export function getWebhookStatusColor(status) {
226
226
  }
227
227
  export function getCheckoutAmount(items, currency, includeFreeTrial = false, upsell = true) {
228
228
  let renew = new BN(0);
229
- const total = items.reduce((acc, x) => {
229
+ const total = items.filter((x) => {
230
230
  const price = upsell ? x.upsell_price || x.price : x.price;
231
- if (price.type === "recurring") {
231
+ return price != null;
232
+ }).reduce((acc, x) => {
233
+ const price = upsell ? x.upsell_price || x.price : x.price;
234
+ if (price?.type === "recurring") {
232
235
  renew = renew.add(new BN(getPriceUintAmountByCurrency(price, currency)).mul(new BN(x.quantity)));
233
236
  if (includeFreeTrial) {
234
237
  return acc;
@@ -0,0 +1,13 @@
1
+ /// <reference types="react" />
2
+ import type { PaymentDetails, TPaymentMethod } from '@blocklet/payment-types';
3
+ declare function TxLink(props: {
4
+ details: PaymentDetails;
5
+ method: TPaymentMethod;
6
+ mode?: 'customer' | 'dashboard';
7
+ }): import("react").JSX.Element;
8
+ declare namespace TxLink {
9
+ var defaultProps: {
10
+ mode: string;
11
+ };
12
+ }
13
+ export default TxLink;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ module.exports = TxLink;
7
+ var _jsxRuntime = require("react/jsx-runtime");
8
+ var _iconsMaterial = require("@mui/icons-material");
9
+ var _material = require("@mui/material");
10
+ var _ufo = require("ufo");
11
+ const getTxLink = (method, details) => {
12
+ if (method.type === "arcblock" && details.arcblock?.tx_hash) {
13
+ return {
14
+ link: (0, _ufo.joinURL)(method.settings.arcblock?.explorer_host, "/txs", details.arcblock?.tx_hash),
15
+ text: details.arcblock?.tx_hash
16
+ };
17
+ }
18
+ if (method.type === "bitcoin" && details.bitcoin?.tx_hash) {
19
+ return {
20
+ link: (0, _ufo.joinURL)(method.settings.bitcoin?.explorer_host, "/tx", details.bitcoin?.tx_hash),
21
+ text: details.bitcoin?.tx_hash
22
+ };
23
+ }
24
+ if (method.type === "ethereum" && details.ethereum?.tx_hash) {
25
+ return {
26
+ link: (0, _ufo.joinURL)(method.settings.ethereum?.explorer_host, "/tx", details.ethereum?.tx_hash),
27
+ text: details.ethereum?.tx_hash
28
+ };
29
+ }
30
+ if (method.type === "stripe") {
31
+ const dashboard = method.livemode ? "https://dashboard.stripe.com" : "https://dashboard.stripe.com/test";
32
+ return {
33
+ link: (0, _ufo.joinURL)(method.settings.stripe?.dashboard || dashboard, "payments", details.stripe?.payment_intent_id),
34
+ text: details.stripe?.payment_intent_id
35
+ };
36
+ }
37
+ return {
38
+ text: "N/A",
39
+ link: ""
40
+ };
41
+ };
42
+ TxLink.defaultProps = {
43
+ mode: "dashboard"
44
+ };
45
+ function TxLink(props) {
46
+ if (!props.details || props.mode === "customer" && props.method.type === "stripe") {
47
+ return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
48
+ component: "small",
49
+ color: "text.secondary",
50
+ children: "None"
51
+ });
52
+ }
53
+ const {
54
+ text,
55
+ link
56
+ } = getTxLink(props.method, props.details);
57
+ if (link) {
58
+ return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Link, {
59
+ href: link,
60
+ target: "_blank",
61
+ rel: "noopener noreferrer",
62
+ children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
63
+ component: "span",
64
+ direction: "row",
65
+ alignItems: "center",
66
+ spacing: 1,
67
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
68
+ component: "span",
69
+ color: "primary",
70
+ children: text.length > 40 ? [text.slice(0, 8), text.slice(-8)].join("...") : text
71
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.OpenInNewOutlined, {
72
+ fontSize: "small"
73
+ })]
74
+ })
75
+ });
76
+ }
77
+ return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
78
+ component: "small",
79
+ color: "text.secondary",
80
+ children: "None"
81
+ });
82
+ }
@@ -9,6 +9,7 @@ var _context = require("@arcblock/ux/lib/Locale/context");
9
9
  var _material = require("@mui/material");
10
10
  var _util = require("@ocap/util");
11
11
  var _ahooks = require("ahooks");
12
+ var _ufo = require("ufo");
12
13
  var _api = _interopRequireDefault(require("../../api"));
13
14
  var _status = _interopRequireDefault(require("../../components/status"));
14
15
  var _util2 = require("../../util");
@@ -101,7 +102,7 @@ function CustomerInvoiceList({
101
102
  children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
102
103
  flex: 3,
103
104
  children: /* @__PURE__ */(0, _jsxRuntime.jsx)("a", {
104
- href: `/customer/invoice/${invoice.id}`,
105
+ href: (0, _ufo.joinURL)(window.location.origin, (0, _util2.getPrefix)(), `/customer/invoice/${invoice.id}`),
105
106
  children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
106
107
  component: "span",
107
108
  children: invoice.number
@@ -9,6 +9,7 @@ var _context = require("@arcblock/ux/lib/Locale/context");
9
9
  var _material = require("@mui/material");
10
10
  var _util = require("@ocap/util");
11
11
  var _ahooks = require("ahooks");
12
+ var _ufo = require("ufo");
12
13
  var _api = _interopRequireDefault(require("../../api"));
13
14
  var _status = _interopRequireDefault(require("../../components/status"));
14
15
  var _util2 = require("../../util");
@@ -39,19 +40,12 @@ function MiniInvoiceList() {
39
40
  status: "open,paid,uncollectible",
40
41
  subscription_id: subscriptionId
41
42
  }));
42
- if (!data || !subscription) {
43
+ if (!subscription || !data) {
43
44
  return /* @__PURE__ */(0, _jsxRuntime.jsx)(Position, {
44
45
  children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.CircularProgress, {})
45
46
  });
46
47
  }
47
- if (data && data.list.length === 0) {
48
- return /* @__PURE__ */(0, _jsxRuntime.jsx)(Position, {
49
- children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
50
- color: "text.secondary",
51
- children: t("payment.customer.invoice.empty")
52
- })
53
- });
54
- }
48
+ const invoices = data.list || [];
55
49
  const infoList = [{
56
50
  name: t("payment.customer.subscriptions.plan"),
57
51
  value: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
@@ -67,21 +61,25 @@ function MiniInvoiceList() {
67
61
  label: subscription.status,
68
62
  color: (0, _util2.getSubscriptionStatusColor)(subscription.status)
69
63
  })
70
- }, {
71
- name: t("payment.customer.subscriptions.nextInvoice"),
72
- value: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
73
- sx: {
74
- color: "#34BE74",
75
- fontWeight: "bold",
76
- marginRight: "10px"
77
- },
78
- children: (0, _util2.formatTime)(subscription.current_period_end * 1e3)
79
- })
80
64
  }];
65
+ if (subscription.status === "active" || subscription.status === "trailing") {
66
+ infoList.push({
67
+ name: t("payment.customer.subscriptions.nextInvoice"),
68
+ value: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
69
+ sx: {
70
+ color: "#34BE74",
71
+ fontWeight: "bold",
72
+ marginRight: "10px"
73
+ },
74
+ children: (0, _util2.formatTime)(subscription.current_period_end * 1e3)
75
+ })
76
+ });
77
+ }
81
78
  return /* @__PURE__ */(0, _jsxRuntime.jsxs)(Position, {
82
79
  children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
83
80
  title: t("payment.checkout.subscription")
84
81
  }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
82
+ className: "mini-invoice-wrap",
85
83
  sx: {
86
84
  display: "flex",
87
85
  flexDirection: "column",
@@ -126,16 +124,12 @@ function MiniInvoiceList() {
126
124
  })
127
125
  }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Divider, {}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
128
126
  sx: {
129
- marginTop: "12px"
127
+ marginTop: "12px",
128
+ flex: 1
130
129
  },
131
130
  children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.List, {
132
131
  sx: {
133
- overflow: "auto",
134
- maxHeight: {
135
- xs: "240px",
136
- md: "360px",
137
- padding: 0
138
- }
132
+ overflow: "auto"
139
133
  },
140
134
  className: "mini-invoice-list",
141
135
  children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.ListSubheader, {
@@ -149,7 +143,10 @@ function MiniInvoiceList() {
149
143
  fontSize: "16px",
150
144
  children: t("payment.customer.invoices")
151
145
  })
152
- }), (data.list || []).map(item => {
146
+ }), invoices.length === 0 ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
147
+ color: "text.secondary",
148
+ children: t("payment.customer.invoice.empty")
149
+ }) : invoices.map(item => {
153
150
  return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.ListItem, {
154
151
  disableGutters: true,
155
152
  sx: {
@@ -165,7 +162,8 @@ function MiniInvoiceList() {
165
162
  }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
166
163
  component: "span",
167
164
  sx: {
168
- flex: 1
165
+ flex: 1,
166
+ textAlign: "right"
169
167
  },
170
168
  children: [(0, _util.fromUnitToToken)(item.total, item.paymentCurrency.decimal), "\xA0", item.paymentCurrency.symbol]
171
169
  }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
@@ -186,13 +184,14 @@ function MiniInvoiceList() {
186
184
  })]
187
185
  })
188
186
  }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Button, {
189
- target: "_top",
187
+ target: "_blank",
190
188
  variant: "contained",
191
189
  sx: {
192
190
  marginTop: "10px 0",
193
- width: "100%"
191
+ width: "100%",
192
+ color: "#fff!important"
194
193
  },
195
- href: "",
194
+ href: (0, _ufo.joinURL)(window.location.origin, (0, _util2.getPrefix)(), `/customer/subscription/${subscription.id}`),
196
195
  children: t("payment.customer.subscriptions.title")
197
196
  })]
198
197
  })]
@@ -204,7 +203,6 @@ function Position({
204
203
  return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
205
204
  className: "mini-invoice-box",
206
205
  sx: {
207
- justifyContent: "center",
208
206
  padding: "8px",
209
207
  width: "100%",
210
208
  maxWidth: "500px",
@@ -10,6 +10,7 @@ var _material = require("@mui/material");
10
10
  var _util = require("@ocap/util");
11
11
  var _ahooks = require("ahooks");
12
12
  var _api = _interopRequireDefault(require("../../api"));
13
+ var _tx = _interopRequireDefault(require("../../components/blockchain/tx"));
13
14
  var _status = _interopRequireDefault(require("../../components/status"));
14
15
  var _util2 = require("../../util");
15
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -111,10 +112,20 @@ function CustomerPaymentList({
111
112
  color: (0, _util2.getPaymentIntentStatusColor)(item.status)
112
113
  })
113
114
  }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
114
- flex: 4,
115
+ flex: 3,
115
116
  children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
116
117
  children: item.description || item.id
117
118
  })
119
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
120
+ flex: 3,
121
+ sx: {
122
+ minWidth: "220px"
123
+ },
124
+ children: item.payment_details?.arcblock?.tx_hash && /* @__PURE__ */(0, _jsxRuntime.jsx)(_tx.default, {
125
+ details: item.payment_details,
126
+ method: item.paymentMethod,
127
+ mode: "customer"
128
+ })
118
129
  })]
119
130
  }, item.id))]
120
131
  }, date)), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
package/lib/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import api from './api';
2
2
  import CheckoutForm from './checkout/form';
3
3
  import CheckoutTable from './checkout/table';
4
+ import TxLink from './components/blockchain/tx';
4
5
  import ConfirmDialog from './components/confirm';
5
6
  import FormInput from './components/input';
6
7
  import Livemode from './components/livemode';
@@ -18,4 +19,4 @@ import ProductSkeleton from './payment/product-skeleton';
18
19
  export * from './util';
19
20
  export * from './contexts/payment';
20
21
  export { translations, createTranslator } from './locales';
21
- export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, Payment, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, MiniInvoiceList, };
22
+ export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, Payment, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, MiniInvoiceList, TxLink, };
package/lib/index.js CHANGED
@@ -7,6 +7,7 @@ var _exportNames = {
7
7
  api: true,
8
8
  CheckoutForm: true,
9
9
  CheckoutTable: true,
10
+ TxLink: true,
10
11
  ConfirmDialog: true,
11
12
  FormInput: true,
12
13
  Livemode: true,
@@ -114,6 +115,12 @@ Object.defineProperty(exports, "Switch", {
114
115
  return _switchButton.default;
115
116
  }
116
117
  });
118
+ Object.defineProperty(exports, "TxLink", {
119
+ enumerable: true,
120
+ get: function () {
121
+ return _tx.default;
122
+ }
123
+ });
117
124
  Object.defineProperty(exports, "api", {
118
125
  enumerable: true,
119
126
  get: function () {
@@ -141,6 +148,7 @@ Object.defineProperty(exports, "translations", {
141
148
  var _api = _interopRequireDefault(require("./api"));
142
149
  var _form = _interopRequireDefault(require("./checkout/form"));
143
150
  var _table = _interopRequireDefault(require("./checkout/table"));
151
+ var _tx = _interopRequireDefault(require("./components/blockchain/tx"));
144
152
  var _confirm = _interopRequireDefault(require("./components/confirm"));
145
153
  var _input = _interopRequireDefault(require("./components/input"));
146
154
  var _livemode = _interopRequireDefault(require("./components/livemode"));
package/lib/locales/en.js CHANGED
@@ -209,17 +209,17 @@ module.exports = (0, _flat.default)({
209
209
  pay: "Pay this invoice",
210
210
  paySuccess: "You have successfully paid the invoice",
211
211
  payError: "Failed to paid the invoice",
212
- empty: "Seems you do not have any invoice here"
212
+ empty: "There are no invoices here"
213
213
  },
214
214
  payment: {
215
- empty: "Seems you do not have any payment here"
215
+ empty: "There are no payments here"
216
216
  },
217
217
  subscriptions: {
218
218
  plan: "Plan",
219
219
  nextInvoice: "Next Invoice",
220
220
  title: "Manage subscriptions",
221
221
  current: "Current subscription",
222
- empty: "Seems you do not have any subscriptions here"
222
+ empty: "There are no subscriptions here"
223
223
  }
224
224
  }
225
225
  }
package/lib/locales/zh.js CHANGED
@@ -209,17 +209,17 @@ module.exports = (0, _flat.default)({
209
209
  pay: "\u652F\u4ED8\u6B64\u53D1\u7968",
210
210
  paySuccess: "\u652F\u4ED8\u6210\u529F",
211
211
  payError: "\u652F\u4ED8\u5931\u8D25",
212
- empty: "\u4F60\u6CA1\u6709\u4EFB\u4F55\u53D1\u7968"
212
+ empty: "\u6CA1\u6709\u4EFB\u4F55\u53D1\u7968"
213
213
  },
214
214
  payment: {
215
- empty: "\u4F60\u6CA1\u6709\u4EFB\u4F55\u652F\u4ED8"
215
+ empty: "\u6CA1\u6709\u4EFB\u4F55\u652F\u4ED8"
216
216
  },
217
217
  subscriptions: {
218
218
  plan: "\u8BA2\u9605",
219
219
  nextInvoice: "\u4E0B\u4E00\u5F20\u53D1\u7968",
220
220
  title: "\u8BA2\u9605\u7BA1\u7406",
221
221
  current: "\u5F53\u524D\u8BA2\u9605",
222
- empty: "\u4F60\u8FD8\u6CA1\u6709\u4EFB\u4F55\u8BA2\u9605"
222
+ empty: "\u6CA1\u6709\u4EFB\u4F55\u8BA2\u9605"
223
223
  }
224
224
  }
225
225
  }
package/lib/util.js CHANGED
@@ -282,9 +282,12 @@ function getWebhookStatusColor(status) {
282
282
  }
283
283
  function getCheckoutAmount(items, currency, includeFreeTrial = false, upsell = true) {
284
284
  let renew = new _util.BN(0);
285
- const total = items.reduce((acc, x) => {
285
+ const total = items.filter(x => {
286
286
  const price = upsell ? x.upsell_price || x.price : x.price;
287
- if (price.type === "recurring") {
287
+ return price != null;
288
+ }).reduce((acc, x) => {
289
+ const price = upsell ? x.upsell_price || x.price : x.price;
290
+ if (price?.type === "recurring") {
288
291
  renew = renew.add(new _util.BN(getPriceUintAmountByCurrency(price, currency)).mul(new _util.BN(x.quantity)));
289
292
  if (includeFreeTrial) {
290
293
  return acc;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.13.130",
3
+ "version": "1.13.131",
4
4
  "description": "Reusable react components for payment kit v2",
5
5
  "keywords": [
6
6
  "react",
@@ -89,7 +89,7 @@
89
89
  "@babel/core": "^7.19.3",
90
90
  "@babel/preset-env": "^7.19.3",
91
91
  "@babel/preset-react": "^7.18.6",
92
- "@blocklet/payment-types": "1.13.130",
92
+ "@blocklet/payment-types": "1.13.131",
93
93
  "@storybook/addon-essentials": "^7.6.10",
94
94
  "@storybook/addon-interactions": "^7.6.10",
95
95
  "@storybook/addon-links": "^7.6.10",
@@ -118,5 +118,5 @@
118
118
  "vite-plugin-babel": "^1.2.0",
119
119
  "vite-plugin-node-polyfills": "^0.19.0"
120
120
  },
121
- "gitHead": "95aaa56f16ce303e514aa7dde9e542628d7acd2c"
121
+ "gitHead": "a1a5072b1a0c564cce5ba4aee5fc4801cfef4a46"
122
122
  }
@@ -0,0 +1,77 @@
1
+ import type { PaymentDetails, TPaymentMethod } from '@blocklet/payment-types';
2
+ import { OpenInNewOutlined } from '@mui/icons-material';
3
+ import { Link, Stack, Typography } from '@mui/material';
4
+ import { joinURL } from 'ufo';
5
+
6
+ const getTxLink = (method: TPaymentMethod, details: PaymentDetails) => {
7
+ if (method.type === 'arcblock' && details.arcblock?.tx_hash) {
8
+ return {
9
+ link: joinURL(method.settings.arcblock?.explorer_host as string, '/txs', details.arcblock?.tx_hash as string),
10
+ text: details.arcblock?.tx_hash as string,
11
+ };
12
+ }
13
+ if (method.type === 'bitcoin' && details.bitcoin?.tx_hash) {
14
+ return {
15
+ link: joinURL(method.settings.bitcoin?.explorer_host as string, '/tx', details.bitcoin?.tx_hash as string),
16
+ text: details.bitcoin?.tx_hash as string,
17
+ };
18
+ }
19
+ if (method.type === 'ethereum' && details.ethereum?.tx_hash) {
20
+ return {
21
+ link: joinURL(method.settings.ethereum?.explorer_host as string, '/tx', details.ethereum?.tx_hash as string),
22
+ text: details.ethereum?.tx_hash as string,
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 as string
32
+ ),
33
+ text: details.stripe?.payment_intent_id as string,
34
+ };
35
+ }
36
+
37
+ return { text: 'N/A', link: '' };
38
+ };
39
+
40
+ TxLink.defaultProps = {
41
+ mode: 'dashboard',
42
+ };
43
+
44
+ export default function TxLink(props: {
45
+ details: PaymentDetails;
46
+ method: TPaymentMethod;
47
+ mode?: 'customer' | 'dashboard';
48
+ }) {
49
+ if (!props.details || (props.mode === 'customer' && props.method.type === 'stripe')) {
50
+ return (
51
+ <Typography component="small" color="text.secondary">
52
+ None
53
+ </Typography>
54
+ );
55
+ }
56
+
57
+ const { text, link } = getTxLink(props.method, props.details);
58
+
59
+ if (link) {
60
+ return (
61
+ <Link href={link} target="_blank" rel="noopener noreferrer">
62
+ <Stack component="span" direction="row" alignItems="center" spacing={1}>
63
+ <Typography component="span" color="primary">
64
+ {text.length > 40 ? [text.slice(0, 8), text.slice(-8)].join('...') : text}
65
+ </Typography>
66
+ <OpenInNewOutlined fontSize="small" />
67
+ </Stack>
68
+ </Link>
69
+ );
70
+ }
71
+
72
+ return (
73
+ <Typography component="small" color="text.secondary">
74
+ None
75
+ </Typography>
76
+ );
77
+ }
@@ -4,10 +4,11 @@ import type { Paginated, TInvoiceExpanded } from '@blocklet/payment-types';
4
4
  import { Box, Button, CircularProgress, Stack, Typography } from '@mui/material';
5
5
  import { fromUnitToToken } from '@ocap/util';
6
6
  import { useInfiniteScroll } from 'ahooks';
7
+ import { joinURL } from 'ufo';
7
8
 
8
9
  import api from '../../api';
9
10
  import Status from '../../components/status';
10
- import { formatToDate, getInvoiceStatusColor } from '../../util';
11
+ import { formatToDate, getInvoiceStatusColor, getPrefix } from '../../util';
11
12
 
12
13
  const groupByDate = (items: TInvoiceExpanded[]) => {
13
14
  const grouped: { [key: string]: TInvoiceExpanded[] } = {};
@@ -83,7 +84,7 @@ export default function CustomerInvoiceList({ customer_id, subscription_id }: Pr
83
84
  }}
84
85
  flexWrap="nowrap">
85
86
  <Box flex={3}>
86
- <a href={`/customer/invoice/${invoice.id}`}>
87
+ <a href={joinURL(window.location.origin, getPrefix(), `/customer/invoice/${invoice.id}`)}>
87
88
  <Typography component="span">{invoice.number}</Typography>
88
89
  </a>
89
90
  </Box>
@@ -4,6 +4,7 @@ import type { Paginated, TInvoiceExpanded, TSubscriptionExpanded } from '@blockl
4
4
  import { Box, Button, CircularProgress, Divider, List, ListItem, ListSubheader, Typography } from '@mui/material';
5
5
  import { fromUnitToToken } from '@ocap/util';
6
6
  import { useRequest } from 'ahooks';
7
+ import { joinURL } from 'ufo';
7
8
 
8
9
  import api from '../../api';
9
10
  import Status from '../../components/status';
@@ -12,6 +13,7 @@ import {
12
13
  formatTime,
13
14
  formatToDate,
14
15
  getInvoiceStatusColor,
16
+ getPrefix,
15
17
  getSubscriptionStatusColor,
16
18
  } from '../../util';
17
19
 
@@ -37,7 +39,7 @@ export default function MiniInvoiceList() {
37
39
  fetchInvoiceData({ page: 1, pageSize: 10, status: 'open,paid,uncollectible', subscription_id: subscriptionId })
38
40
  );
39
41
 
40
- if (!data || !subscription) {
42
+ if (!subscription || !data) {
41
43
  return (
42
44
  <Position>
43
45
  <CircularProgress />
@@ -45,13 +47,7 @@ export default function MiniInvoiceList() {
45
47
  );
46
48
  }
47
49
 
48
- if (data && data.list.length === 0) {
49
- return (
50
- <Position>
51
- <Typography color="text.secondary">{t('payment.customer.invoice.empty')}</Typography>
52
- </Position>
53
- );
54
- }
50
+ const invoices = data.list || [];
55
51
 
56
52
  const infoList = [
57
53
  {
@@ -66,8 +62,10 @@ export default function MiniInvoiceList() {
66
62
  name: t('common.status'),
67
63
  value: <Status label={subscription.status} color={getSubscriptionStatusColor(subscription.status)} />,
68
64
  },
65
+ ];
69
66
 
70
- {
67
+ if (subscription.status === 'active' || subscription.status === 'trailing') {
68
+ infoList.push({
71
69
  name: t('payment.customer.subscriptions.nextInvoice'),
72
70
  value: (
73
71
  <Typography
@@ -79,13 +77,14 @@ export default function MiniInvoiceList() {
79
77
  {formatTime(subscription.current_period_end * 1000)}
80
78
  </Typography>
81
79
  ),
82
- },
83
- ];
80
+ });
81
+ }
84
82
 
85
83
  return (
86
84
  <Position>
87
85
  <Typography title={t('payment.checkout.subscription')} />
88
86
  <Box
87
+ className="mini-invoice-wrap"
89
88
  sx={{
90
89
  display: 'flex',
91
90
  flexDirection: 'column',
@@ -111,34 +110,40 @@ export default function MiniInvoiceList() {
111
110
  </List>
112
111
  </Box>
113
112
  <Divider />
114
- <Box sx={{ marginTop: '12px' }}>
115
- <List
116
- sx={{ overflow: 'auto', maxHeight: { xs: '240px', md: '360px', padding: 0 } }}
117
- className="mini-invoice-list">
113
+ <Box sx={{ marginTop: '12px', flex: 1 }}>
114
+ <List sx={{ overflow: 'auto' }} className="mini-invoice-list">
118
115
  <ListSubheader disableGutters sx={{ padding: 0 }}>
119
116
  <Typography component="h2" variant="h6" fontSize="16px">
120
117
  {t('payment.customer.invoices')}
121
118
  </Typography>
122
119
  </ListSubheader>
123
- {(data.list || []).map((item: any) => {
124
- return (
125
- <ListItem key={item.id} disableGutters sx={{ display: 'flex', justifyContent: 'space-between' }}>
126
- <Typography component="span" sx={{ flex: 3 }}>
127
- {formatToDate(item.created_at)}
128
- </Typography>
129
- <Typography component="span" sx={{ flex: 1 }}>
130
- {fromUnitToToken(item.total, item.paymentCurrency.decimal)}&nbsp;
131
- {item.paymentCurrency.symbol}
132
- </Typography>
133
- <Typography component="span" sx={{ flex: 2, textAlign: 'right' }}>
134
- <Status label={item.status} color={getInvoiceStatusColor(item.status)} sx={{ flex: 2 }} />
135
- </Typography>
136
- </ListItem>
137
- );
138
- })}
120
+ {(invoices as any).length === 0 ? (
121
+ <Typography color="text.secondary">{t('payment.customer.invoice.empty')}</Typography>
122
+ ) : (
123
+ (invoices as any).map((item: any) => {
124
+ return (
125
+ <ListItem key={item.id} disableGutters sx={{ display: 'flex', justifyContent: 'space-between' }}>
126
+ <Typography component="span" sx={{ flex: 3 }}>
127
+ {formatToDate(item.created_at)}
128
+ </Typography>
129
+ <Typography component="span" sx={{ flex: 1, textAlign: 'right' }}>
130
+ {fromUnitToToken(item.total, item.paymentCurrency.decimal)}&nbsp;
131
+ {item.paymentCurrency.symbol}
132
+ </Typography>
133
+ <Typography component="span" sx={{ flex: 2, textAlign: 'right' }}>
134
+ <Status label={item.status} color={getInvoiceStatusColor(item.status)} sx={{ flex: 2 }} />
135
+ </Typography>
136
+ </ListItem>
137
+ );
138
+ })
139
+ )}
139
140
  </List>
140
141
  </Box>
141
- <Button target="_top" variant="contained" sx={{ marginTop: '10px 0', width: '100%' }} href="">
142
+ <Button
143
+ target="_blank"
144
+ variant="contained"
145
+ sx={{ marginTop: '10px 0', width: '100%', color: '#fff!important' }}
146
+ href={joinURL(window.location.origin, getPrefix(), `/customer/subscription/${subscription.id}`)}>
142
147
  {t('payment.customer.subscriptions.title')}
143
148
  </Button>
144
149
  </Box>
@@ -151,7 +156,6 @@ function Position({ children }: any) {
151
156
  <Box
152
157
  className="mini-invoice-box" // 预留 class 用于设置定位
153
158
  sx={{
154
- justifyContent: 'center',
155
159
  padding: '8px',
156
160
  width: '100%',
157
161
  maxWidth: '500px',
@@ -6,6 +6,7 @@ import { fromUnitToToken } from '@ocap/util';
6
6
  import { useInfiniteScroll } from 'ahooks';
7
7
 
8
8
  import api from '../../api';
9
+ import TxLink from '../../components/blockchain/tx';
9
10
  import Status from '../../components/status';
10
11
  import { formatToDate, getPaymentIntentStatusColor } from '../../util';
11
12
 
@@ -91,9 +92,18 @@ export default function CustomerPaymentList({ customer_id }: Props) {
91
92
  <Box flex={3}>
92
93
  <Status label={item.status} color={getPaymentIntentStatusColor(item.status)} />
93
94
  </Box>
94
- <Box flex={4}>
95
+ <Box flex={3}>
95
96
  <Typography>{item.description || item.id}</Typography>
96
97
  </Box>
98
+ <Box flex={3} sx={{ minWidth: '220px' }}>
99
+ {(item as any).payment_details?.arcblock?.tx_hash && (
100
+ <TxLink
101
+ details={(item as any).payment_details}
102
+ method={(item as any).paymentMethod}
103
+ mode="customer"
104
+ />
105
+ )}
106
+ </Box>
97
107
  </Stack>
98
108
  ))}
99
109
  </Box>
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import api from './api';
2
2
  import CheckoutForm from './checkout/form';
3
3
  import CheckoutTable from './checkout/table';
4
+ import TxLink from './components/blockchain/tx';
4
5
  import ConfirmDialog from './components/confirm';
5
6
  import FormInput from './components/input';
6
7
  import Livemode from './components/livemode';
@@ -39,4 +40,5 @@ export {
39
40
  CustomerInvoiceList,
40
41
  CustomerPaymentList,
41
42
  MiniInvoiceList,
43
+ TxLink,
42
44
  };
@@ -207,17 +207,17 @@ export default flat({
207
207
  pay: 'Pay this invoice',
208
208
  paySuccess: 'You have successfully paid the invoice',
209
209
  payError: 'Failed to paid the invoice',
210
- empty: 'Seems you do not have any invoice here',
210
+ empty: 'There are no invoices here',
211
211
  },
212
212
  payment: {
213
- empty: 'Seems you do not have any payment here',
213
+ empty: 'There are no payments here',
214
214
  },
215
215
  subscriptions: {
216
216
  plan: 'Plan',
217
217
  nextInvoice: 'Next Invoice',
218
218
  title: 'Manage subscriptions',
219
219
  current: 'Current subscription',
220
- empty: 'Seems you do not have any subscriptions here',
220
+ empty: 'There are no subscriptions here',
221
221
  },
222
222
  },
223
223
  },
@@ -203,17 +203,17 @@ export default flat({
203
203
  pay: '支付此发票',
204
204
  paySuccess: '支付成功',
205
205
  payError: '支付失败',
206
- empty: '你没有任何发票',
206
+ empty: '没有任何发票',
207
207
  },
208
208
  payment: {
209
- empty: '你没有任何支付',
209
+ empty: '没有任何支付',
210
210
  },
211
211
  subscriptions: {
212
212
  plan: '订阅',
213
213
  nextInvoice: '下一张发票',
214
214
  title: '订阅管理',
215
215
  current: '当前订阅',
216
- empty: '你还没有任何订阅',
216
+ empty: '没有任何订阅',
217
217
  },
218
218
  },
219
219
  },
package/src/util.ts CHANGED
@@ -324,11 +324,14 @@ export function getCheckoutAmount(
324
324
  upsell = true
325
325
  ) {
326
326
  let renew = new BN(0);
327
-
328
327
  const total = items
328
+ .filter((x) => {
329
+ const price = upsell ? x.upsell_price || x.price : x.price;
330
+ return price != null;
331
+ })
329
332
  .reduce((acc, x) => {
330
333
  const price = upsell ? x.upsell_price || x.price : x.price;
331
- if (price.type === 'recurring') {
334
+ if (price?.type === 'recurring') {
332
335
  renew = renew.add(new BN(getPriceUintAmountByCurrency(price, currency)).mul(new BN(x.quantity)));
333
336
 
334
337
  if (includeFreeTrial) {