@blocklet/payment-react 1.13.123 → 1.13.125

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.
Files changed (47) hide show
  1. package/es/api.js +0 -1
  2. package/es/components/confirm.d.ts +14 -0
  3. package/es/components/confirm.js +31 -0
  4. package/es/components/pricing-table.js +77 -67
  5. package/es/contexts/payment.d.ts +4 -2
  6. package/es/index.d.ts +4 -1
  7. package/es/index.js +7 -1
  8. package/es/locales/en.js +5 -1
  9. package/es/locales/zh.js +4 -0
  10. package/es/payment/form/index.js +2 -2
  11. package/es/payment/index.js +3 -3
  12. package/es/portal/invoice/list.d.ts +6 -0
  13. package/es/portal/invoice/list.js +84 -0
  14. package/es/portal/payment/list.d.ts +6 -0
  15. package/es/portal/payment/list.js +84 -0
  16. package/es/util.d.ts +4 -0
  17. package/es/util.js +56 -0
  18. package/lib/api.js +0 -1
  19. package/lib/components/confirm.d.ts +14 -0
  20. package/lib/components/confirm.js +49 -0
  21. package/lib/components/pricing-table.js +143 -135
  22. package/lib/contexts/payment.d.ts +4 -2
  23. package/lib/index.d.ts +4 -1
  24. package/lib/index.js +24 -0
  25. package/lib/locales/en.js +5 -1
  26. package/lib/locales/zh.js +4 -0
  27. package/lib/payment/form/index.js +2 -2
  28. package/lib/payment/index.js +3 -3
  29. package/lib/portal/invoice/list.d.ts +6 -0
  30. package/lib/portal/invoice/list.js +150 -0
  31. package/lib/portal/payment/list.d.ts +6 -0
  32. package/lib/portal/payment/list.js +149 -0
  33. package/lib/util.d.ts +4 -0
  34. package/lib/util.js +62 -1
  35. package/package.json +3 -3
  36. package/src/api.ts +1 -1
  37. package/src/components/confirm.tsx +39 -0
  38. package/src/components/pricing-table.tsx +125 -113
  39. package/src/contexts/payment.tsx +2 -2
  40. package/src/index.ts +6 -0
  41. package/src/locales/en.tsx +5 -1
  42. package/src/locales/zh.tsx +4 -0
  43. package/src/payment/form/index.tsx +5 -3
  44. package/src/payment/index.tsx +3 -3
  45. package/src/portal/invoice/list.tsx +122 -0
  46. package/src/portal/payment/list.tsx +120 -0
  47. package/src/util.ts +60 -0
package/es/api.js CHANGED
@@ -7,7 +7,6 @@ api.interceptors.request.use(
7
7
  (config) => {
8
8
  const prefix = getPrefix();
9
9
  config.baseURL = prefix || "";
10
- config.timeout = 8e3;
11
10
  const livemode = localStorage.getItem("livemode");
12
11
  const locale = getLocale(window.blocklet?.languages);
13
12
  config.params = { ...config.params || {}, livemode: isNull(livemode) ? true : JSON.parse(livemode), locale };
@@ -0,0 +1,14 @@
1
+ import type { EventHandler } from 'react';
2
+ declare function ConfirmDialog({ onConfirm, onCancel, title, message, loading, }: {
3
+ onConfirm: EventHandler<any>;
4
+ onCancel: EventHandler<any>;
5
+ title: string | React.ReactNode;
6
+ message: string | React.ReactNode;
7
+ loading?: boolean;
8
+ }): import("react").JSX.Element;
9
+ declare namespace ConfirmDialog {
10
+ var defaultProps: {
11
+ loading: boolean;
12
+ };
13
+ }
14
+ export default ConfirmDialog;
@@ -0,0 +1,31 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Confirm } from "@arcblock/ux/lib/Dialog";
3
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
4
+ import { Typography } from "@mui/material";
5
+ export default function ConfirmDialog({
6
+ onConfirm,
7
+ onCancel,
8
+ title,
9
+ message,
10
+ loading
11
+ }) {
12
+ const { t } = useLocaleContext();
13
+ return /* @__PURE__ */ jsx(
14
+ Confirm,
15
+ {
16
+ open: true,
17
+ title,
18
+ onConfirm,
19
+ onCancel,
20
+ confirmButton: {
21
+ text: t("common.confirm"),
22
+ props: { color: "error", size: "small", variant: "contained", disabled: !!loading }
23
+ },
24
+ cancelButton: { text: t("common.cancel"), props: { color: "inherit", size: "small" } },
25
+ children: /* @__PURE__ */ jsx(Typography, { children: message })
26
+ }
27
+ );
28
+ }
29
+ ConfirmDialog.defaultProps = {
30
+ loading: false
31
+ };
@@ -16,6 +16,7 @@ import {
16
16
  ToggleButtonGroup,
17
17
  Typography
18
18
  } from "@mui/material";
19
+ import { styled } from "@mui/system";
19
20
  import { useSetState } from "ahooks";
20
21
  import { useEffect } from "react";
21
22
  import Amount from "../payment/amount.js";
@@ -61,7 +62,14 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
61
62
  Toast.error(formatError(err));
62
63
  }
63
64
  };
64
- return /* @__PURE__ */ jsxs(
65
+ const Root = styled(Box)`
66
+ @media (max-width: ${({ theme }) => theme.breakpoints.values.sm}px) {
67
+ .price-table-item {
68
+ width: 90% !important;
69
+ }
70
+ }
71
+ `;
72
+ return /* @__PURE__ */ jsx(Root, { children: /* @__PURE__ */ jsxs(
65
73
  Stack,
66
74
  {
67
75
  direction: "column",
@@ -96,78 +104,80 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
96
104
  {
97
105
  flexWrap: "wrap",
98
106
  direction: "row",
99
- gap: { xs: 3, sm: 5, md: mode === "checkout" ? 10 : 5 },
107
+ gap: "calc(10px + 3%)",
100
108
  justifyContent: alignItems === "center" ? "center" : "flex-start",
101
- children: grouped[state.interval]?.map((x) => {
102
- let action = x.subscription_data?.trial_period_days ? t("payment.checkout.try") : t("payment.checkout.subscription");
103
- if (mode === "select") {
104
- action = x.is_selected ? t("payment.checkout.selected") : t("payment.checkout.select");
105
- }
106
- return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(
107
- Stack,
108
- {
109
- padding: 4,
110
- spacing: 2,
111
- direction: "column",
112
- alignItems: "center",
113
- sx: {
114
- width: 320,
115
- cursor: "pointer",
116
- borderWidth: "1px",
117
- borderStyle: "solid",
118
- borderColor: mode === "select" && x.is_selected ? "primary.main" : "#eee",
119
- borderRadius: 1,
120
- transition: "border-color 0.3s ease 0s, box-shadow 0.3s ease 0s",
121
- boxShadow: "0 4px 8px rgba(0, 0, 0, 20%)",
122
- "&:hover": {
123
- borderColor: mode === "select" && x.is_selected ? "primary.main" : "#ddd",
124
- boxShadow: "0 8px 16px rgba(0, 0, 0, 20%)"
125
- }
126
- },
127
- children: [
128
- /* @__PURE__ */ jsxs(Box, { textAlign: "center", children: [
109
+ children: grouped[state.interval]?.map(
110
+ (x) => {
111
+ let action = x.subscription_data?.trial_period_days ? t("payment.checkout.try") : t("payment.checkout.subscription");
112
+ if (mode === "select") {
113
+ action = x.is_selected ? t("payment.checkout.selected") : t("payment.checkout.select");
114
+ }
115
+ return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(
116
+ Stack,
117
+ {
118
+ padding: 4,
119
+ spacing: 2,
120
+ direction: "column",
121
+ alignItems: "center",
122
+ className: "price-table-item",
123
+ sx: {
124
+ width: "30%",
125
+ cursor: "pointer",
126
+ borderWidth: "1px",
127
+ borderStyle: "solid",
128
+ borderColor: mode === "select" && x.is_selected ? "primary.main" : "#eee",
129
+ borderRadius: 1,
130
+ transition: "border-color 0.3s ease 0s, box-shadow 0.3s ease 0s",
131
+ boxShadow: "0 4px 8px rgba(0, 0, 0, 20%)",
132
+ "&:hover": {
133
+ borderColor: mode === "select" && x.is_selected ? "primary.main" : "#ddd",
134
+ boxShadow: "0 8px 16px rgba(0, 0, 0, 20%)"
135
+ }
136
+ },
137
+ children: [
138
+ /* @__PURE__ */ jsxs(Box, { textAlign: "center", children: [
139
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [
140
+ /* @__PURE__ */ jsx(Typography, { variant: "h5", color: "text.primary", fontWeight: 600, children: x.product.name }),
141
+ x.is_highlight && /* @__PURE__ */ jsx(Chip, { label: x.highlight_text, color: "default", size: "small" })
142
+ ] }),
143
+ /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: x.product.description })
144
+ ] }),
129
145
  /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [
130
- /* @__PURE__ */ jsx(Typography, { variant: "h5", color: "text.primary", fontWeight: 600, children: x.product.name }),
131
- x.is_highlight && /* @__PURE__ */ jsx(Chip, { label: x.highlight_text, color: "default", size: "small" })
146
+ /* @__PURE__ */ jsx(Amount, { amount: formatPriceAmount(x.price, table.currency, x.product.unit_label) }),
147
+ /* @__PURE__ */ jsxs(Stack, { direction: "column", alignItems: "flex-start", children: [
148
+ /* @__PURE__ */ jsx(Typography, { component: "span", color: "text.secondary", fontSize: "0.8rem", children: t("payment.checkout.per") }),
149
+ /* @__PURE__ */ jsx(Typography, { component: "span", color: "text.secondary", fontSize: "0.8rem", children: formatRecurring(x.price.recurring, false, "", locale) })
150
+ ] })
132
151
  ] }),
133
- /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: x.product.description })
134
- ] }),
135
- /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [
136
- /* @__PURE__ */ jsx(Amount, { amount: formatPriceAmount(x.price, table.currency, x.product.unit_label) }),
137
- /* @__PURE__ */ jsxs(Stack, { direction: "column", alignItems: "flex-start", children: [
138
- /* @__PURE__ */ jsx(Typography, { component: "span", color: "text.secondary", fontSize: "0.8rem", children: t("payment.checkout.per") }),
139
- /* @__PURE__ */ jsx(Typography, { component: "span", color: "text.secondary", fontSize: "0.8rem", children: formatRecurring(x.price.recurring, false, "", locale) })
152
+ /* @__PURE__ */ jsx(
153
+ LoadingButton,
154
+ {
155
+ fullWidth: true,
156
+ size: "large",
157
+ variant: x.is_highlight || x.is_selected ? "contained" : "outlined",
158
+ color: x.is_highlight || x.is_selected ? "primary" : "info",
159
+ sx: { fontSize: "1.2rem" },
160
+ loading: state.loading === x.price_id,
161
+ disabled: x.is_disabled,
162
+ onClick: () => handleSelect(x.price_id),
163
+ children: action
164
+ }
165
+ ),
166
+ x.product.features.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
167
+ /* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.include") }),
168
+ /* @__PURE__ */ jsx(List, { dense: true, children: x.product.features.map((f) => /* @__PURE__ */ jsxs(ListItem, { disableGutters: true, disablePadding: true, children: [
169
+ /* @__PURE__ */ jsx(ListItemIcon, { sx: { minWidth: 25 }, children: /* @__PURE__ */ jsx(CheckOutlined, { color: "success", fontSize: "small" }) }),
170
+ /* @__PURE__ */ jsx(ListItemText, { primary: f.name })
171
+ ] }, f.name)) })
140
172
  ] })
141
- ] }),
142
- /* @__PURE__ */ jsx(
143
- LoadingButton,
144
- {
145
- fullWidth: true,
146
- size: "large",
147
- loadingPosition: "end",
148
- variant: x.is_highlight || x.is_selected ? "contained" : "outlined",
149
- color: x.is_highlight || x.is_selected ? "primary" : "info",
150
- sx: { fontSize: "1.2rem" },
151
- loading: state.loading === x.price_id,
152
- disabled: x.is_disabled,
153
- onClick: () => handleSelect(x.price_id),
154
- children: action
155
- }
156
- ),
157
- x.product.features.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
158
- /* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.include") }),
159
- /* @__PURE__ */ jsx(List, { dense: true, children: x.product.features.map((f) => /* @__PURE__ */ jsxs(ListItem, { disableGutters: true, disablePadding: true, children: [
160
- /* @__PURE__ */ jsx(ListItemIcon, { sx: { minWidth: 25 }, children: /* @__PURE__ */ jsx(CheckOutlined, { color: "success", fontSize: "small" }) }),
161
- /* @__PURE__ */ jsx(ListItemText, { primary: f.name })
162
- ] }, f.name)) })
163
- ] })
164
- ]
165
- }
166
- ) }, x.price_id);
167
- })
173
+ ]
174
+ }
175
+ ) }, x.price_id);
176
+ }
177
+ )
168
178
  }
169
179
  )
170
180
  ]
171
181
  }
172
- );
182
+ ) });
173
183
  }
@@ -7,8 +7,10 @@ export interface Settings {
7
7
  }
8
8
  export type PaymentContextType = {
9
9
  livemode: boolean;
10
- session: any;
11
- connect: any;
10
+ session: import('@arcblock/did-connect/lib/types').SessionContext['session'] & {
11
+ user: any;
12
+ };
13
+ connect: import('@arcblock/did-connect/lib/types').SessionContext['connectApi'];
12
14
  prefix: string;
13
15
  settings: Settings;
14
16
  refresh: () => void;
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 ConfirmDialog from './components/confirm';
4
5
  import FormInput from './components/input';
5
6
  import Livemode from './components/livemode';
6
7
  import PricingTable from './components/pricing-table';
@@ -11,7 +12,9 @@ import Amount from './payment/amount';
11
12
  import PhoneInput from './payment/form/phone';
12
13
  import Payment from './payment/index';
13
14
  import ProductSkeleton from './payment/product-skeleton';
15
+ import CustomerInvoiceList from './portal/invoice/list';
16
+ import CustomerPaymentList from './portal/payment/list';
14
17
  export * from './util';
15
18
  export * from './contexts/payment';
16
19
  export { translations, createTranslator } from './locales';
17
- export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch, CheckoutForm, CheckoutTable, Payment, PricingTable, ProductSkeleton, Amount, };
20
+ export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, Payment, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, };
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 ConfirmDialog from "./components/confirm.js";
4
5
  import FormInput from "./components/input.js";
5
6
  import Livemode from "./components/livemode.js";
6
7
  import PricingTable from "./components/pricing-table.js";
@@ -11,6 +12,8 @@ import Amount from "./payment/amount.js";
11
12
  import PhoneInput from "./payment/form/phone.js";
12
13
  import Payment from "./payment/index.js";
13
14
  import ProductSkeleton from "./payment/product-skeleton.js";
15
+ import CustomerInvoiceList from "./portal/invoice/list.js";
16
+ import CustomerPaymentList from "./portal/payment/list.js";
14
17
  export * from "./util.js";
15
18
  export * from "./contexts/payment.js";
16
19
  export { translations, createTranslator } from "./locales/index.js";
@@ -22,10 +25,13 @@ export {
22
25
  Status,
23
26
  Livemode,
24
27
  Switch,
28
+ ConfirmDialog,
25
29
  CheckoutForm,
26
30
  CheckoutTable,
27
31
  Payment,
28
32
  PricingTable,
29
33
  ProductSkeleton,
30
- Amount
34
+ Amount,
35
+ CustomerInvoiceList,
36
+ CustomerPaymentList
31
37
  };
package/es/locales/en.js CHANGED
@@ -146,6 +146,7 @@ export default flat({
146
146
  }
147
147
  },
148
148
  customer: {
149
+ payments: "Payment History",
149
150
  invoices: "Invoice History",
150
151
  details: "Billing Details",
151
152
  update: "Update Information",
@@ -201,7 +202,10 @@ export default flat({
201
202
  pay: "Pay this invoice",
202
203
  paySuccess: "You have successfully paid the invoice",
203
204
  payError: "Failed to paid the invoice",
204
- empty: "Seems you do not have any payments here"
205
+ empty: "Seems you do not have any invoice here"
206
+ },
207
+ payment: {
208
+ empty: "Seems you do not have any payment here"
205
209
  },
206
210
  subscriptions: {
207
211
  title: "Manage subscriptions",
package/es/locales/zh.js CHANGED
@@ -146,6 +146,7 @@ export default flat({
146
146
  }
147
147
  },
148
148
  customer: {
149
+ payments: "\u652F\u4ED8\u5386\u53F2",
149
150
  invoices: "\u53D1\u7968\u5386\u53F2",
150
151
  details: "\u8BA1\u8D39\u8BE6\u60C5",
151
152
  update: "\u66F4\u65B0\u5BA2\u6237\u4FE1\u606F",
@@ -201,6 +202,9 @@ export default flat({
201
202
  pay: "\u652F\u4ED8\u6B64\u53D1\u7968",
202
203
  paySuccess: "\u652F\u4ED8\u6210\u529F",
203
204
  payError: "\u652F\u4ED8\u5931\u8D25",
205
+ empty: "\u4F60\u6CA1\u6709\u4EFB\u4F55\u53D1\u7968"
206
+ },
207
+ payment: {
204
208
  empty: "\u4F60\u6CA1\u6709\u4EFB\u4F55\u652F\u4ED8"
205
209
  },
206
210
  subscriptions: {
@@ -169,9 +169,9 @@ export default function PaymentForm({
169
169
  await handleConnected();
170
170
  } else {
171
171
  connect.open({
172
+ containerEl: void 0,
172
173
  action: checkoutSession.mode,
173
- prefix: joinURL(getPrefix(), "/api/did"),
174
- timeout: 5 * 60 * 1e3,
174
+ prefix: joinURL(window.location.origin, getPrefix(), "/api/did"),
175
175
  extraParams: { checkoutSessionId: checkoutSession.id },
176
176
  onSuccess: async () => {
177
177
  connect.close();
@@ -305,18 +305,18 @@ export const Root = styled(Box)`
305
305
  }
306
306
 
307
307
  .cko-payment-card-unselect {
308
- border: 2px solid #bbb;
308
+ border: 2px solid #ddd;
309
309
  padding: 5px 10px;
310
310
  margin: 5px 0;
311
311
  cursor: pointer;
312
312
  }
313
313
 
314
314
  .cko-payment-card:nth-child(odd) {
315
- margin-right: 5px;
315
+ margin-right: 16px;
316
316
  }
317
317
 
318
318
  .cko-payment-card-unselect:nth-child(odd) {
319
- margin-right: 5px;
319
+ margin-right: 16px;
320
320
  }
321
321
 
322
322
  .cko-payment-card::after {
@@ -0,0 +1,6 @@
1
+ /// <reference types="react" />
2
+ type Props = {
3
+ customer_id: string;
4
+ };
5
+ export default function CustomerInvoiceList({ customer_id }: Props): import("react").JSX.Element;
6
+ export {};
@@ -0,0 +1,84 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
+ import { Box, Button, CircularProgress, Stack, Typography } from "@mui/material";
4
+ import { fromUnitToToken } from "@ocap/util";
5
+ import { useInfiniteScroll } from "ahooks";
6
+ import api from "../../api.js";
7
+ import Status from "../../components/status.js";
8
+ import { formatToDate, getInvoiceStatusColor } from "../../util.js";
9
+ const groupByDate = (items) => {
10
+ const grouped = {};
11
+ items.forEach((item) => {
12
+ const date = new Date(item.created_at).toLocaleDateString();
13
+ if (!grouped[date]) {
14
+ grouped[date] = [];
15
+ }
16
+ grouped[date]?.push(item);
17
+ });
18
+ return grouped;
19
+ };
20
+ const fetchData = (params = {}) => {
21
+ const search = new URLSearchParams();
22
+ Object.keys(params).forEach((key) => {
23
+ search.set(key, String(params[key]));
24
+ });
25
+ return api.get(`/api/invoices?${search.toString()}`).then((res) => res.data);
26
+ };
27
+ const pageSize = 10;
28
+ export default function CustomerInvoiceList({ customer_id }) {
29
+ const { t } = useLocaleContext();
30
+ const { data, loadMore, loadingMore, loading } = useInfiniteScroll(
31
+ (d) => {
32
+ const page = d ? Math.ceil(d.list.length / pageSize) + 1 : 1;
33
+ return fetchData({ page, pageSize, status: "open,paid,uncollectible", customer_id });
34
+ },
35
+ {
36
+ reloadDeps: [customer_id]
37
+ }
38
+ );
39
+ if (loading || !data) {
40
+ return /* @__PURE__ */ jsx(CircularProgress, {});
41
+ }
42
+ if (data && data.list.length === 0) {
43
+ return /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("payment.customer.invoice.empty") });
44
+ }
45
+ const hasMore = data && data.list.length < data.count;
46
+ const grouped = groupByDate(data.list);
47
+ return /* @__PURE__ */ jsxs(Stack, { direction: "column", gap: 1, sx: { mt: 1 }, children: [
48
+ Object.entries(grouped).map(([date, invoices]) => /* @__PURE__ */ jsxs(Box, { children: [
49
+ /* @__PURE__ */ jsx(Typography, { sx: { fontWeight: "bold", color: "text.secondary", mt: 2, mb: 1 }, children: date }),
50
+ invoices.map((invoice) => /* @__PURE__ */ jsxs(
51
+ Stack,
52
+ {
53
+ direction: {
54
+ xs: "column",
55
+ sm: "row"
56
+ },
57
+ sx: { my: 1 },
58
+ gap: {
59
+ xs: 0.5,
60
+ sm: 1.5,
61
+ md: 3
62
+ },
63
+ flexWrap: "nowrap",
64
+ children: [
65
+ /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx("a", { href: `/customer/invoice/${invoice.id}`, children: /* @__PURE__ */ jsx(Typography, { component: "span", children: invoice.number }) }) }),
66
+ /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(Typography, { children: formatToDate(invoice.created_at) }) }),
67
+ /* @__PURE__ */ jsx(Box, { flex: 2, children: /* @__PURE__ */ jsxs(Typography, { textAlign: "right", children: [
68
+ fromUnitToToken(invoice.total, invoice.paymentCurrency.decimal),
69
+ "\xA0",
70
+ invoice.paymentCurrency.symbol
71
+ ] }) }),
72
+ /* @__PURE__ */ jsx(Box, { flex: 2, children: /* @__PURE__ */ jsx(Status, { label: invoice.status, color: getInvoiceStatusColor(invoice.status) }) }),
73
+ /* @__PURE__ */ jsx(Box, { flex: 4, children: /* @__PURE__ */ jsx(Typography, { children: invoice.description || invoice.id }) })
74
+ ]
75
+ },
76
+ invoice.id
77
+ ))
78
+ ] }, date)),
79
+ /* @__PURE__ */ jsxs(Box, { children: [
80
+ 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("payament.customer.invoices") }) }),
81
+ !hasMore && data.count > pageSize && /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("common.noMore", { resource: t("payment.customer.invoices") }) })
82
+ ] })
83
+ ] });
84
+ }
@@ -0,0 +1,6 @@
1
+ /// <reference types="react" />
2
+ type Props = {
3
+ customer_id: string;
4
+ };
5
+ export default function CustomerPaymentList({ customer_id }: Props): import("react").JSX.Element;
6
+ export {};
@@ -0,0 +1,84 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
+ import { Box, Button, CircularProgress, Stack, Typography } from "@mui/material";
4
+ import { fromUnitToToken } from "@ocap/util";
5
+ import { useInfiniteScroll } from "ahooks";
6
+ import api from "../../api.js";
7
+ import Status from "../../components/status.js";
8
+ import { formatToDate, getPaymentIntentStatusColor } from "../../util.js";
9
+ const groupByDate = (items) => {
10
+ const grouped = {};
11
+ items.forEach((item) => {
12
+ const date = new Date(item.created_at).toLocaleDateString();
13
+ if (!grouped[date]) {
14
+ grouped[date] = [];
15
+ }
16
+ grouped[date]?.push(item);
17
+ });
18
+ return grouped;
19
+ };
20
+ const fetchData = (params = {}) => {
21
+ const search = new URLSearchParams();
22
+ Object.keys(params).forEach((key) => {
23
+ search.set(key, String(params[key]));
24
+ });
25
+ return api.get(`/api/payment-intents?${search.toString()}`).then((res) => res.data);
26
+ };
27
+ const pageSize = 10;
28
+ export default function CustomerPaymentList({ customer_id }) {
29
+ const { t } = useLocaleContext();
30
+ const { data, loadMore, loadingMore, loading } = useInfiniteScroll(
31
+ (d) => {
32
+ const page = d ? Math.ceil(d.list.length / pageSize) + 1 : 1;
33
+ return fetchData({ page, pageSize, customer_id });
34
+ },
35
+ {
36
+ reloadDeps: [customer_id]
37
+ }
38
+ );
39
+ if (loading || !data) {
40
+ return /* @__PURE__ */ jsx(CircularProgress, {});
41
+ }
42
+ if (data && data.list.length === 0) {
43
+ return /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("payment.customer.payment.empty") });
44
+ }
45
+ const hasMore = data && data.list.length < data.count;
46
+ const grouped = groupByDate(data.list);
47
+ return /* @__PURE__ */ jsxs(Stack, { direction: "column", gap: 1, sx: { mt: 1 }, children: [
48
+ Object.entries(grouped).map(([date, payments]) => /* @__PURE__ */ jsxs(Box, { children: [
49
+ /* @__PURE__ */ jsx(Typography, { sx: { fontWeight: "bold", color: "text.secondary", mt: 2, mb: 1 }, children: date }),
50
+ payments.map((item) => /* @__PURE__ */ jsxs(
51
+ Stack,
52
+ {
53
+ direction: {
54
+ xs: "column",
55
+ sm: "row"
56
+ },
57
+ sx: { my: 1 },
58
+ gap: {
59
+ xs: 0.5,
60
+ sm: 1.5,
61
+ md: 3
62
+ },
63
+ flexWrap: "nowrap",
64
+ children: [
65
+ /* @__PURE__ */ jsx(Box, { flex: 3, sx: { minWidth: "220px" }, children: /* @__PURE__ */ jsx(Typography, { component: "span", children: item.id }) }),
66
+ /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(Typography, { children: formatToDate(item.created_at) }) }),
67
+ /* @__PURE__ */ jsx(Box, { flex: 2, children: /* @__PURE__ */ jsxs(Typography, { textAlign: "right", children: [
68
+ fromUnitToToken(item.amount, item.paymentCurrency.decimal),
69
+ "\xA0",
70
+ item.paymentCurrency.symbol
71
+ ] }) }),
72
+ /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(Status, { label: item.status, color: getPaymentIntentStatusColor(item.status) }) }),
73
+ /* @__PURE__ */ jsx(Box, { flex: 4, children: /* @__PURE__ */ jsx(Typography, { children: item.description || item.id }) })
74
+ ]
75
+ },
76
+ item.id
77
+ ))
78
+ ] }, date)),
79
+ /* @__PURE__ */ jsxs(Box, { children: [
80
+ hasMore && /* @__PURE__ */ jsx(Button, { variant: "text", type: "button", color: "inherit", onClick: loadMore, disabled: loadingMore, children: loadingMore ? t("common.loadingMore", { resource: t("payment.customer.payments") }) : t("common.loadMore", { resource: t("payment.customer.payments") }) }),
81
+ !hasMore && data.count > pageSize && /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("common.noMore", { resource: t("payment.customer.payments") }) })
82
+ ] })
83
+ ] });
84
+ }
package/es/util.d.ts CHANGED
@@ -20,6 +20,10 @@ export declare function formatLineItemPricing(item: TLineItemExpanded, currency:
20
20
  secondary?: string;
21
21
  quantity: string;
22
22
  };
23
+ export declare function getSubscriptionStatusColor(status: string): "success" | "primary" | "warning" | "error" | "default";
24
+ export declare function getPaymentIntentStatusColor(status: string): "success" | "warning" | "default";
25
+ export declare function getInvoiceStatusColor(status: string): "success" | "warning" | "default" | "secondary";
26
+ export declare function getWebhookStatusColor(status: string): "success" | "default";
23
27
  export declare function getCheckoutAmount(items: TLineItemExpanded[], currency: TPaymentCurrency, includeFreeTrial?: boolean, upsell?: boolean): {
24
28
  subtotal: any;
25
29
  total: any;
package/es/util.js CHANGED
@@ -168,6 +168,62 @@ export function formatLineItemPricing(item, currency, trial, locale = "en") {
168
168
  quantity
169
169
  };
170
170
  }
171
+ export function getSubscriptionStatusColor(status) {
172
+ switch (status) {
173
+ case "active":
174
+ return "success";
175
+ case "trialing":
176
+ return "primary";
177
+ case "incomplete":
178
+ case "incomplete_expired":
179
+ case "paused":
180
+ return "warning";
181
+ case "past_due":
182
+ case "unpaid":
183
+ return "error";
184
+ case "canceled":
185
+ default:
186
+ return "default";
187
+ }
188
+ }
189
+ export function getPaymentIntentStatusColor(status) {
190
+ switch (status) {
191
+ case "succeeded":
192
+ return "success";
193
+ case "requires_payment_method":
194
+ case "requires_confirmation":
195
+ case "requires_action":
196
+ case "requires_capture":
197
+ return "warning";
198
+ case "canceled":
199
+ case "processing":
200
+ default:
201
+ return "default";
202
+ }
203
+ }
204
+ export function getInvoiceStatusColor(status) {
205
+ switch (status) {
206
+ case "paid":
207
+ return "success";
208
+ case "open":
209
+ return "secondary";
210
+ case "uncollectible":
211
+ return "warning";
212
+ case "draft":
213
+ case "void":
214
+ default:
215
+ return "default";
216
+ }
217
+ }
218
+ export function getWebhookStatusColor(status) {
219
+ switch (status) {
220
+ case "enabled":
221
+ return "success";
222
+ case "disabled":
223
+ default:
224
+ return "default";
225
+ }
226
+ }
171
227
  export function getCheckoutAmount(items, currency, includeFreeTrial = false, upsell = true) {
172
228
  let renew = new BN(0);
173
229
  const total = items.reduce((acc, x) => {
package/lib/api.js CHANGED
@@ -13,7 +13,6 @@ const api = _axios.default.create();
13
13
  api.interceptors.request.use(config => {
14
14
  const prefix = (0, _util.getPrefix)();
15
15
  config.baseURL = prefix || "";
16
- config.timeout = 8e3;
17
16
  const livemode = localStorage.getItem("livemode");
18
17
  const locale = (0, _context.getLocale)(window.blocklet?.languages);
19
18
  config.params = {