@blocklet/payment-react 1.13.150 → 1.13.152

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.
@@ -1,9 +1,11 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { useRequest, useSetState } from "ahooks";
3
3
  import noop from "lodash/noop";
4
+ import { useEffect } from "react";
5
+ import { joinURL } from "ufo";
4
6
  import api from "../api.js";
5
7
  import Payment from "../payment/index.js";
6
- import { mergeExtraParams } from "../util.js";
8
+ import { getPrefix, mergeExtraParams } from "../util.js";
7
9
  const startFromPaymentLink = async (id, params) => {
8
10
  const { data } = await api.post(`/api/checkout-sessions/start/${id}?${mergeExtraParams(params)}`);
9
11
  return data;
@@ -21,6 +23,11 @@ export default function CheckoutForm({ id, onPaid, onError, mode, goBack, extraP
21
23
  const { error: apiError, data } = useRequest(
22
24
  () => type === "paymentLink" ? startFromPaymentLink(id, extraParams) : fetchCheckoutSession(id)
23
25
  );
26
+ useEffect(() => {
27
+ if (type === "paymentLink" && mode === "standalone" && data) {
28
+ window.history.replaceState(null, "", joinURL(getPrefix(), `/checkout/pay/${data.checkoutSession.id}`));
29
+ }
30
+ }, [type, mode, data]);
24
31
  const handlePaid = () => {
25
32
  setState({ completed: true });
26
33
  onPaid?.(data);
@@ -1,14 +1,18 @@
1
1
  import type { EventHandler } from 'react';
2
- declare function ConfirmDialog({ onConfirm, onCancel, title, message, loading, }: {
2
+ declare function ConfirmDialog({ onConfirm, onCancel, title, message, confirm, cancel, loading, }: {
3
3
  onConfirm: EventHandler<any>;
4
4
  onCancel: EventHandler<any>;
5
5
  title: string | React.ReactNode;
6
6
  message: string | React.ReactNode;
7
+ confirm?: string | React.ReactNode;
8
+ cancel?: string | React.ReactNode;
7
9
  loading?: boolean;
8
10
  }): import("react").JSX.Element;
9
11
  declare namespace ConfirmDialog {
10
12
  var defaultProps: {
11
13
  loading: boolean;
14
+ confirm: string;
15
+ cancel: string;
12
16
  };
13
17
  }
14
18
  export default ConfirmDialog;
@@ -7,6 +7,8 @@ export default function ConfirmDialog({
7
7
  onCancel,
8
8
  title,
9
9
  message,
10
+ confirm,
11
+ cancel,
10
12
  loading
11
13
  }) {
12
14
  const { t } = useLocaleContext();
@@ -18,14 +20,16 @@ export default function ConfirmDialog({
18
20
  onConfirm,
19
21
  onCancel,
20
22
  confirmButton: {
21
- text: t("common.confirm"),
23
+ text: confirm || t("common.confirm"),
22
24
  props: { color: "error", size: "small", variant: "contained", disabled: !!loading }
23
25
  },
24
- cancelButton: { text: t("common.cancel"), props: { color: "inherit", size: "small" } },
26
+ cancelButton: { text: cancel || t("common.cancel"), props: { color: "inherit", size: "small" } },
25
27
  children: /* @__PURE__ */ jsx(Typography, { children: message })
26
28
  }
27
29
  );
28
30
  }
29
31
  ConfirmDialog.defaultProps = {
30
- loading: false
32
+ loading: false,
33
+ confirm: "",
34
+ cancel: ""
31
35
  };
@@ -2,12 +2,18 @@
2
2
  type Props = {
3
3
  customer_id?: string;
4
4
  subscription_id?: string;
5
+ status?: string;
6
+ pageSize?: number;
7
+ target?: string;
5
8
  };
6
- declare function CustomerInvoiceList({ customer_id, subscription_id }: Props): import("react").JSX.Element;
9
+ declare function CustomerInvoiceList({ customer_id, subscription_id, status, pageSize, target }: Props): import("react").JSX.Element;
7
10
  declare namespace CustomerInvoiceList {
8
11
  var defaultProps: {
9
12
  customer_id: string;
10
13
  subscription_id: string;
14
+ status: string;
15
+ pageSize: number;
16
+ target: string;
11
17
  };
12
18
  }
13
19
  export default CustomerInvoiceList;
@@ -27,13 +27,13 @@ const fetchData = (params = {}) => {
27
27
  });
28
28
  return api.get(`/api/invoices?${search.toString()}`).then((res) => res.data);
29
29
  };
30
- const pageSize = 10;
31
- export default function CustomerInvoiceList({ customer_id, subscription_id }) {
30
+ export default function CustomerInvoiceList({ customer_id, subscription_id, status, pageSize, target }) {
32
31
  const { t } = useLocaleContext();
32
+ const size = pageSize || 10;
33
33
  const { data, loadMore, loadingMore, loading } = useInfiniteScroll(
34
34
  (d) => {
35
- const page = d ? Math.ceil(d.list.length / pageSize) + 1 : 1;
36
- return fetchData({ page, pageSize, status: "open,paid,uncollectible", customer_id, subscription_id });
35
+ const page = d ? Math.ceil(d.list.length / size) + 1 : 1;
36
+ return fetchData({ page, pageSize: size, status, customer_id, subscription_id });
37
37
  },
38
38
  {
39
39
  reloadDeps: [customer_id]
@@ -65,7 +65,14 @@ export default function CustomerInvoiceList({ customer_id, subscription_id }) {
65
65
  },
66
66
  flexWrap: "nowrap",
67
67
  children: [
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
+ /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(
69
+ "a",
70
+ {
71
+ href: joinURL(window.location.origin, getPrefix(), `/customer/invoice/${invoice.id}`),
72
+ target,
73
+ children: /* @__PURE__ */ jsx(Typography, { component: "span", children: invoice.number })
74
+ }
75
+ ) }),
69
76
  /* @__PURE__ */ jsx(Box, { flex: 3, children: /* @__PURE__ */ jsx(Typography, { children: formatToDate(invoice.created_at) }) }),
70
77
  /* @__PURE__ */ jsx(Box, { flex: 2, children: /* @__PURE__ */ jsxs(Typography, { textAlign: "right", children: [
71
78
  fromUnitToToken(invoice.total, invoice.paymentCurrency.decimal),
@@ -81,11 +88,14 @@ export default function CustomerInvoiceList({ customer_id, subscription_id }) {
81
88
  ] }, date)),
82
89
  /* @__PURE__ */ jsxs(Box, { children: [
83
90
  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") }) }),
84
- !hasMore && data.count > pageSize && /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("common.noMore", { resource: t("payment.customer.invoices") }) })
91
+ !hasMore && data.count > size && /* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("common.noMore", { resource: t("payment.customer.invoices") }) })
85
92
  ] })
86
93
  ] });
87
94
  }
88
95
  CustomerInvoiceList.defaultProps = {
89
96
  customer_id: "",
90
- subscription_id: ""
97
+ subscription_id: "",
98
+ status: "open,paid,uncollectible",
99
+ pageSize: 10,
100
+ target: "self"
91
101
  };
package/es/locales/en.js CHANGED
@@ -148,7 +148,8 @@ export default flat({
148
148
  customer: {
149
149
  payments: "Payment History",
150
150
  invoices: "Invoice History",
151
- details: "Billing Details",
151
+ details: "Details",
152
+ summary: "Summary",
152
153
  update: "Update Information",
153
154
  empty: "Seems you do not have any subscriptions or payments here",
154
155
  cancel: {
@@ -168,7 +169,14 @@ export default flat({
168
169
  }
169
170
  },
170
171
  pastDue: {
171
- button: "Pay"
172
+ button: "Pay",
173
+ invoices: "Past Due Invoices",
174
+ warning: "Past due invoices need to be paid immediately, otherwise you can not make new purchases anymore.",
175
+ alert: {
176
+ title: "You have unpaid invoices",
177
+ description: "Seems you have unpaid invoices from previous subscriptions, new purchases are not allowed unless you have paid all past due invoices.",
178
+ confirm: "Pay Now"
179
+ }
172
180
  },
173
181
  recover: {
174
182
  button: "Renew",
package/es/locales/zh.js CHANGED
@@ -148,7 +148,8 @@ export default flat({
148
148
  customer: {
149
149
  payments: "\u652F\u4ED8\u5386\u53F2",
150
150
  invoices: "\u53D1\u7968\u5386\u53F2",
151
- details: "\u8BA1\u8D39\u8BE6\u60C5",
151
+ details: "\u8D26\u6237\u8BE6\u60C5",
152
+ summary: "\u8BA1\u8D39\u6458\u8981",
152
153
  update: "\u66F4\u65B0\u5BA2\u6237\u4FE1\u606F",
153
154
  empty: "\u770B\u8D77\u6765\u60A8\u5728\u8FD9\u91CC\u6CA1\u6709\u4EFB\u4F55\u8BA2\u9605\u6216\u652F\u4ED8",
154
155
  cancel: {
@@ -168,7 +169,14 @@ export default flat({
168
169
  }
169
170
  },
170
171
  pastDue: {
171
- button: "\u7EED\u8D39"
172
+ button: "\u7EED\u8D39",
173
+ invoices: "\u6B20\u8D39\u5E10\u5355",
174
+ warning: "\u8BF7\u5C3D\u5FEB\u652F\u4ED8\u6B20\u8D39\u8D26\u5355\uFF0C\u5426\u5219\u4F60\u5C06\u65E0\u6CD5\u7EE7\u7EED\u4F7F\u7528\u670D\u52A1\u6216\u8D2D\u4E70\u65B0\u670D\u52A1",
175
+ alert: {
176
+ title: "\u4F60\u6709\u6B20\u8D39\u8D26\u5355",
177
+ description: "\u770B\u8D77\u6765\u4F60\u6709\u6B20\u8D39\u7684\u8D26\u5355\uFF0C\u5728\u4F60\u652F\u4ED8\u6240\u6709\u6B20\u8D39\u8D26\u5355\u4E4B\u524D\uFF0C\u65B0\u7684\u8D2D\u4E70\u6216\u8005\u8BA2\u9605\u5C06\u88AB\u7981\u6B62\uFF0C\u8BF7\u4E0D\u8981\u8C03\u76AE\u3002",
178
+ confirm: "\u53BB\u652F\u4ED8"
179
+ }
172
180
  },
173
181
  recover: {
174
182
  button: "\u7EED\u8BA2",
@@ -14,6 +14,7 @@ import { joinURL } from "ufo";
14
14
  import { dispatch } from "use-bus";
15
15
  import isEmail from "validator/es/lib/isEmail";
16
16
  import api from "../../api.js";
17
+ import ConfirmDialog from "../../components/confirm.js";
17
18
  import FormInput from "../../components/input.js";
18
19
  import { usePaymentContext } from "../../contexts/payment.js";
19
20
  import { formatError, getPrefix, getStatementDescriptor } from "../../util.js";
@@ -71,6 +72,7 @@ export default function PaymentForm({
71
72
  paymentIntent,
72
73
  stripeContext: void 0,
73
74
  customer,
75
+ customerLimited: false,
74
76
  stripePaying: false
75
77
  });
76
78
  const currencies = flatPaymentMethods(paymentMethods);
@@ -196,10 +198,17 @@ export default function PaymentForm({
196
198
  }
197
199
  }
198
200
  } catch (err) {
201
+ let shouldToast = true;
199
202
  if (err.response?.data?.code) {
200
203
  dispatch(`error.${err.response?.data?.code}`);
204
+ if (err.response.data.code === "CUSTOMER_LIMITED") {
205
+ shouldToast = false;
206
+ setState({ customerLimited: true });
207
+ }
208
+ }
209
+ if (shouldToast) {
210
+ Toast.error(formatError(err));
201
211
  }
202
- Toast.error(formatError(err));
203
212
  } finally {
204
213
  setState({ submitting: false });
205
214
  }
@@ -353,6 +362,16 @@ export default function PaymentForm({
353
362
  children: t("payment.checkout.confirm", { payee })
354
363
  }
355
364
  )
356
- ] }) })
365
+ ] }) }),
366
+ state.customerLimited && /* @__PURE__ */ jsx(
367
+ ConfirmDialog,
368
+ {
369
+ onConfirm: () => window.open(joinURL(window.location.origin, getPrefix(), "/customer/invoice/past-due"), "_blank"),
370
+ onCancel: () => setState({ customerLimited: false }),
371
+ confirm: t("payment.customer.pastDue.alert.confirm"),
372
+ title: t("payment.customer.pastDue.alert.title"),
373
+ message: t("payment.customer.pastDue.alert.description")
374
+ }
375
+ )
357
376
  ] });
358
377
  }
@@ -7,6 +7,8 @@ module.exports = CheckoutForm;
7
7
  var _jsxRuntime = require("react/jsx-runtime");
8
8
  var _ahooks = require("ahooks");
9
9
  var _noop = _interopRequireDefault(require("lodash/noop"));
10
+ var _react = require("react");
11
+ var _ufo = require("ufo");
10
12
  var _api = _interopRequireDefault(require("../api"));
11
13
  var _payment = _interopRequireDefault(require("../payment"));
12
14
  var _util = require("../util");
@@ -43,6 +45,11 @@ function CheckoutForm({
43
45
  error: apiError,
44
46
  data
45
47
  } = (0, _ahooks.useRequest)(() => type === "paymentLink" ? startFromPaymentLink(id, extraParams) : fetchCheckoutSession(id));
48
+ (0, _react.useEffect)(() => {
49
+ if (type === "paymentLink" && mode === "standalone" && data) {
50
+ window.history.replaceState(null, "", (0, _ufo.joinURL)((0, _util.getPrefix)(), `/checkout/pay/${data.checkoutSession.id}`));
51
+ }
52
+ }, [type, mode, data]);
46
53
  const handlePaid = () => {
47
54
  setState({
48
55
  completed: true
@@ -1,14 +1,18 @@
1
1
  import type { EventHandler } from 'react';
2
- declare function ConfirmDialog({ onConfirm, onCancel, title, message, loading, }: {
2
+ declare function ConfirmDialog({ onConfirm, onCancel, title, message, confirm, cancel, loading, }: {
3
3
  onConfirm: EventHandler<any>;
4
4
  onCancel: EventHandler<any>;
5
5
  title: string | React.ReactNode;
6
6
  message: string | React.ReactNode;
7
+ confirm?: string | React.ReactNode;
8
+ cancel?: string | React.ReactNode;
7
9
  loading?: boolean;
8
10
  }): import("react").JSX.Element;
9
11
  declare namespace ConfirmDialog {
10
12
  var defaultProps: {
11
13
  loading: boolean;
14
+ confirm: string;
15
+ cancel: string;
12
16
  };
13
17
  }
14
18
  export default ConfirmDialog;
@@ -13,6 +13,8 @@ function ConfirmDialog({
13
13
  onCancel,
14
14
  title,
15
15
  message,
16
+ confirm,
17
+ cancel,
16
18
  loading
17
19
  }) {
18
20
  const {
@@ -24,7 +26,7 @@ function ConfirmDialog({
24
26
  onConfirm,
25
27
  onCancel,
26
28
  confirmButton: {
27
- text: t("common.confirm"),
29
+ text: confirm || t("common.confirm"),
28
30
  props: {
29
31
  color: "error",
30
32
  size: "small",
@@ -33,7 +35,7 @@ function ConfirmDialog({
33
35
  }
34
36
  },
35
37
  cancelButton: {
36
- text: t("common.cancel"),
38
+ text: cancel || t("common.cancel"),
37
39
  props: {
38
40
  color: "inherit",
39
41
  size: "small"
@@ -45,5 +47,7 @@ function ConfirmDialog({
45
47
  });
46
48
  }
47
49
  ConfirmDialog.defaultProps = {
48
- loading: false
50
+ loading: false,
51
+ confirm: "",
52
+ cancel: ""
49
53
  };
@@ -2,12 +2,18 @@
2
2
  type Props = {
3
3
  customer_id?: string;
4
4
  subscription_id?: string;
5
+ status?: string;
6
+ pageSize?: number;
7
+ target?: string;
5
8
  };
6
- declare function CustomerInvoiceList({ customer_id, subscription_id }: Props): import("react").JSX.Element;
9
+ declare function CustomerInvoiceList({ customer_id, subscription_id, status, pageSize, target }: Props): import("react").JSX.Element;
7
10
  declare namespace CustomerInvoiceList {
8
11
  var defaultProps: {
9
12
  customer_id: string;
10
13
  subscription_id: string;
14
+ status: string;
15
+ pageSize: number;
16
+ target: string;
11
17
  };
12
18
  }
13
19
  export default CustomerInvoiceList;
@@ -34,25 +34,28 @@ const fetchData = (params = {}) => {
34
34
  });
35
35
  return _api.default.get(`/api/invoices?${search.toString()}`).then(res => res.data);
36
36
  };
37
- const pageSize = 10;
38
37
  function CustomerInvoiceList({
39
38
  customer_id,
40
- subscription_id
39
+ subscription_id,
40
+ status,
41
+ pageSize,
42
+ target
41
43
  }) {
42
44
  const {
43
45
  t
44
46
  } = (0, _context.useLocaleContext)();
47
+ const size = pageSize || 10;
45
48
  const {
46
49
  data,
47
50
  loadMore,
48
51
  loadingMore,
49
52
  loading
50
53
  } = (0, _ahooks.useInfiniteScroll)(d => {
51
- const page = d ? Math.ceil(d.list.length / pageSize) + 1 : 1;
54
+ const page = d ? Math.ceil(d.list.length / size) + 1 : 1;
52
55
  return fetchData({
53
56
  page,
54
- pageSize,
55
- status: "open,paid,uncollectible",
57
+ pageSize: size,
58
+ status,
56
59
  customer_id,
57
60
  subscription_id
58
61
  });
@@ -103,6 +106,7 @@ function CustomerInvoiceList({
103
106
  flex: 3,
104
107
  children: /* @__PURE__ */(0, _jsxRuntime.jsx)("a", {
105
108
  href: (0, _ufo.joinURL)(window.location.origin, (0, _util2.getPrefix)(), `/customer/invoice/${invoice.id}`),
109
+ target,
106
110
  children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
107
111
  component: "span",
108
112
  children: invoice.number
@@ -144,7 +148,7 @@ function CustomerInvoiceList({
144
148
  }) : t("common.loadMore", {
145
149
  resource: t("payment.customer.invoices")
146
150
  })
147
- }), !hasMore && data.count > pageSize && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
151
+ }), !hasMore && data.count > size && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
148
152
  color: "text.secondary",
149
153
  children: t("common.noMore", {
150
154
  resource: t("payment.customer.invoices")
@@ -155,5 +159,8 @@ function CustomerInvoiceList({
155
159
  }
156
160
  CustomerInvoiceList.defaultProps = {
157
161
  customer_id: "",
158
- subscription_id: ""
162
+ subscription_id: "",
163
+ status: "open,paid,uncollectible",
164
+ pageSize: 10,
165
+ target: "self"
159
166
  };
package/lib/locales/en.js CHANGED
@@ -155,7 +155,8 @@ module.exports = (0, _flat.default)({
155
155
  customer: {
156
156
  payments: "Payment History",
157
157
  invoices: "Invoice History",
158
- details: "Billing Details",
158
+ details: "Details",
159
+ summary: "Summary",
159
160
  update: "Update Information",
160
161
  empty: "Seems you do not have any subscriptions or payments here",
161
162
  cancel: {
@@ -175,7 +176,14 @@ module.exports = (0, _flat.default)({
175
176
  }
176
177
  },
177
178
  pastDue: {
178
- button: "Pay"
179
+ button: "Pay",
180
+ invoices: "Past Due Invoices",
181
+ warning: "Past due invoices need to be paid immediately, otherwise you can not make new purchases anymore.",
182
+ alert: {
183
+ title: "You have unpaid invoices",
184
+ description: "Seems you have unpaid invoices from previous subscriptions, new purchases are not allowed unless you have paid all past due invoices.",
185
+ confirm: "Pay Now"
186
+ }
179
187
  },
180
188
  recover: {
181
189
  button: "Renew",
package/lib/locales/zh.js CHANGED
@@ -155,7 +155,8 @@ module.exports = (0, _flat.default)({
155
155
  customer: {
156
156
  payments: "\u652F\u4ED8\u5386\u53F2",
157
157
  invoices: "\u53D1\u7968\u5386\u53F2",
158
- details: "\u8BA1\u8D39\u8BE6\u60C5",
158
+ details: "\u8D26\u6237\u8BE6\u60C5",
159
+ summary: "\u8BA1\u8D39\u6458\u8981",
159
160
  update: "\u66F4\u65B0\u5BA2\u6237\u4FE1\u606F",
160
161
  empty: "\u770B\u8D77\u6765\u60A8\u5728\u8FD9\u91CC\u6CA1\u6709\u4EFB\u4F55\u8BA2\u9605\u6216\u652F\u4ED8",
161
162
  cancel: {
@@ -175,7 +176,14 @@ module.exports = (0, _flat.default)({
175
176
  }
176
177
  },
177
178
  pastDue: {
178
- button: "\u7EED\u8D39"
179
+ button: "\u7EED\u8D39",
180
+ invoices: "\u6B20\u8D39\u5E10\u5355",
181
+ warning: "\u8BF7\u5C3D\u5FEB\u652F\u4ED8\u6B20\u8D39\u8D26\u5355\uFF0C\u5426\u5219\u4F60\u5C06\u65E0\u6CD5\u7EE7\u7EED\u4F7F\u7528\u670D\u52A1\u6216\u8D2D\u4E70\u65B0\u670D\u52A1",
182
+ alert: {
183
+ title: "\u4F60\u6709\u6B20\u8D39\u8D26\u5355",
184
+ description: "\u770B\u8D77\u6765\u4F60\u6709\u6B20\u8D39\u7684\u8D26\u5355\uFF0C\u5728\u4F60\u652F\u4ED8\u6240\u6709\u6B20\u8D39\u8D26\u5355\u4E4B\u524D\uFF0C\u65B0\u7684\u8D2D\u4E70\u6216\u8005\u8BA2\u9605\u5C06\u88AB\u7981\u6B62\uFF0C\u8BF7\u4E0D\u8981\u8C03\u76AE\u3002",
185
+ confirm: "\u53BB\u652F\u4ED8"
186
+ }
179
187
  },
180
188
  recover: {
181
189
  button: "\u7EED\u8BA2",
@@ -20,6 +20,7 @@ var _ufo = require("ufo");
20
20
  var _useBus = require("use-bus");
21
21
  var _isEmail = _interopRequireDefault(require("validator/es/lib/isEmail"));
22
22
  var _api = _interopRequireDefault(require("../../api"));
23
+ var _confirm = _interopRequireDefault(require("../../components/confirm"));
23
24
  var _input = _interopRequireDefault(require("../../components/input"));
24
25
  var _payment = require("../../contexts/payment");
25
26
  var _util = require("../../util");
@@ -90,6 +91,7 @@ function PaymentForm({
90
91
  paymentIntent,
91
92
  stripeContext: void 0,
92
93
  customer,
94
+ customerLimited: false,
93
95
  stripePaying: false
94
96
  });
95
97
  const currencies = flatPaymentMethods(paymentMethods);
@@ -243,10 +245,19 @@ function PaymentForm({
243
245
  }
244
246
  }
245
247
  } catch (err) {
248
+ let shouldToast = true;
246
249
  if (err.response?.data?.code) {
247
250
  (0, _useBus.dispatch)(`error.${err.response?.data?.code}`);
251
+ if (err.response.data.code === "CUSTOMER_LIMITED") {
252
+ shouldToast = false;
253
+ setState({
254
+ customerLimited: true
255
+ });
256
+ }
257
+ }
258
+ if (shouldToast) {
259
+ _Toast.default.error((0, _util.formatError)(err));
248
260
  }
249
- _Toast.default.error((0, _util.formatError)(err));
250
261
  } finally {
251
262
  setState({
252
263
  submitting: false
@@ -450,6 +461,14 @@ function PaymentForm({
450
461
  })
451
462
  })]
452
463
  })
464
+ }), state.customerLimited && /* @__PURE__ */(0, _jsxRuntime.jsx)(_confirm.default, {
465
+ onConfirm: () => window.open((0, _ufo.joinURL)(window.location.origin, (0, _util.getPrefix)(), "/customer/invoice/past-due"), "_blank"),
466
+ onCancel: () => setState({
467
+ customerLimited: false
468
+ }),
469
+ confirm: t("payment.customer.pastDue.alert.confirm"),
470
+ title: t("payment.customer.pastDue.alert.title"),
471
+ message: t("payment.customer.pastDue.alert.description")
453
472
  })]
454
473
  });
455
474
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.13.150",
3
+ "version": "1.13.152",
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.23.9",
90
90
  "@babel/preset-env": "^7.23.9",
91
91
  "@babel/preset-react": "^7.23.3",
92
- "@blocklet/payment-types": "1.13.150",
92
+ "@blocklet/payment-types": "1.13.152",
93
93
  "@storybook/addon-essentials": "^7.6.13",
94
94
  "@storybook/addon-interactions": "^7.6.13",
95
95
  "@storybook/addon-links": "^7.6.13",
@@ -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": "b65548baa2ab6bd40aec35b2a6594bfe6dbb7ee9"
121
+ "gitHead": "5d6d2b6a8c0422e1055ddcec4e3179fd734cdbc5"
122
122
  }
@@ -2,11 +2,13 @@
2
2
  import { TCheckoutSessionExpanded, TPaymentMethodExpanded } from '@blocklet/payment-types';
3
3
  import { useRequest, useSetState } from 'ahooks';
4
4
  import noop from 'lodash/noop';
5
+ import { useEffect } from 'react';
6
+ import { joinURL } from 'ufo';
5
7
 
6
8
  import api from '../api';
7
9
  import Payment from '../payment';
8
10
  import { CheckoutContext, CheckoutProps } from '../types';
9
- import { mergeExtraParams } from '../util';
11
+ import { getPrefix, mergeExtraParams } from '../util';
10
12
 
11
13
  const startFromPaymentLink = async (id: string, params?: Record<string, any>): Promise<CheckoutContext> => {
12
14
  const { data } = await api.post(`/api/checkout-sessions/start/${id}?${mergeExtraParams(params)}`);
@@ -32,6 +34,12 @@ export default function CheckoutForm({ id, onPaid, onError, mode, goBack, extraP
32
34
  type === 'paymentLink' ? startFromPaymentLink(id, extraParams) : fetchCheckoutSession(id)
33
35
  );
34
36
 
37
+ useEffect(() => {
38
+ if (type === 'paymentLink' && mode === 'standalone' && data) {
39
+ window.history.replaceState(null, '', joinURL(getPrefix(), `/checkout/pay/${data.checkoutSession.id}`));
40
+ }
41
+ }, [type, mode, data]);
42
+
35
43
  const handlePaid = () => {
36
44
  setState({ completed: true });
37
45
  onPaid?.(data as CheckoutContext);
@@ -8,12 +8,16 @@ export default function ConfirmDialog({
8
8
  onCancel,
9
9
  title,
10
10
  message,
11
+ confirm,
12
+ cancel,
11
13
  loading,
12
14
  }: {
13
15
  onConfirm: EventHandler<any>;
14
16
  onCancel: EventHandler<any>;
15
17
  title: string | React.ReactNode;
16
18
  message: string | React.ReactNode;
19
+ confirm?: string | React.ReactNode;
20
+ cancel?: string | React.ReactNode;
17
21
  loading?: boolean;
18
22
  }) {
19
23
  const { t } = useLocaleContext();
@@ -25,10 +29,10 @@ export default function ConfirmDialog({
25
29
  onConfirm={onConfirm}
26
30
  onCancel={onCancel}
27
31
  confirmButton={{
28
- text: t('common.confirm'),
32
+ text: confirm || t('common.confirm'),
29
33
  props: { color: 'error', size: 'small', variant: 'contained', disabled: !!loading },
30
34
  }}
31
- cancelButton={{ text: t('common.cancel'), props: { color: 'inherit', size: 'small' } }}>
35
+ cancelButton={{ text: cancel || t('common.cancel'), props: { color: 'inherit', size: 'small' } }}>
32
36
  <Typography>{message}</Typography>
33
37
  </Confirm>
34
38
  );
@@ -36,4 +40,6 @@ export default function ConfirmDialog({
36
40
 
37
41
  ConfirmDialog.defaultProps = {
38
42
  loading: false,
43
+ confirm: '',
44
+ cancel: '',
39
45
  };
@@ -35,17 +35,19 @@ const fetchData = (params: Record<string, any> = {}): Promise<Paginated<TInvoice
35
35
  type Props = {
36
36
  customer_id?: string;
37
37
  subscription_id?: string;
38
+ status?: string;
39
+ pageSize?: number;
40
+ target?: string;
38
41
  };
39
42
 
40
- const pageSize = 10;
41
-
42
- export default function CustomerInvoiceList({ customer_id, subscription_id }: Props) {
43
+ export default function CustomerInvoiceList({ customer_id, subscription_id, status, pageSize, target }: Props) {
43
44
  const { t } = useLocaleContext();
45
+ const size = pageSize || 10;
44
46
 
45
47
  const { data, loadMore, loadingMore, loading } = useInfiniteScroll<Paginated<TInvoiceExpanded>>(
46
48
  (d) => {
47
- const page = d ? Math.ceil(d.list.length / pageSize) + 1 : 1;
48
- return fetchData({ page, pageSize, status: 'open,paid,uncollectible', customer_id, subscription_id });
49
+ const page = d ? Math.ceil(d.list.length / size) + 1 : 1;
50
+ return fetchData({ page, pageSize: size, status, customer_id, subscription_id });
49
51
  },
50
52
  {
51
53
  reloadDeps: [customer_id],
@@ -84,7 +86,9 @@ export default function CustomerInvoiceList({ customer_id, subscription_id }: Pr
84
86
  }}
85
87
  flexWrap="nowrap">
86
88
  <Box flex={3}>
87
- <a href={joinURL(window.location.origin, getPrefix(), `/customer/invoice/${invoice.id}`)}>
89
+ <a
90
+ href={joinURL(window.location.origin, getPrefix(), `/customer/invoice/${invoice.id}`)}
91
+ target={target}>
88
92
  <Typography component="span">{invoice.number}</Typography>
89
93
  </a>
90
94
  </Box>
@@ -115,7 +119,7 @@ export default function CustomerInvoiceList({ customer_id, subscription_id }: Pr
115
119
  : t('common.loadMore', { resource: t('payment.customer.invoices') })}
116
120
  </Button>
117
121
  )}
118
- {!hasMore && data.count > pageSize && (
122
+ {!hasMore && data.count > size && (
119
123
  <Typography color="text.secondary">
120
124
  {t('common.noMore', { resource: t('payment.customer.invoices') })}
121
125
  </Typography>
@@ -128,4 +132,7 @@ export default function CustomerInvoiceList({ customer_id, subscription_id }: Pr
128
132
  CustomerInvoiceList.defaultProps = {
129
133
  customer_id: '',
130
134
  subscription_id: '',
135
+ status: 'open,paid,uncollectible',
136
+ pageSize: 10,
137
+ target: 'self',
131
138
  };
@@ -152,7 +152,8 @@ export default flat({
152
152
  customer: {
153
153
  payments: 'Payment History',
154
154
  invoices: 'Invoice History',
155
- details: 'Billing Details',
155
+ details: 'Details',
156
+ summary: 'Summary',
156
157
  update: 'Update Information',
157
158
  empty: 'Seems you do not have any subscriptions or payments here',
158
159
  cancel: {
@@ -174,6 +175,14 @@ export default flat({
174
175
  },
175
176
  pastDue: {
176
177
  button: 'Pay',
178
+ invoices: 'Past Due Invoices',
179
+ warning: 'Past due invoices need to be paid immediately, otherwise you can not make new purchases anymore.',
180
+ alert: {
181
+ title: 'You have unpaid invoices',
182
+ description:
183
+ 'Seems you have unpaid invoices from previous subscriptions, new purchases are not allowed unless you have paid all past due invoices.',
184
+ confirm: 'Pay Now',
185
+ },
177
186
  },
178
187
  recover: {
179
188
  button: 'Renew',
@@ -149,7 +149,8 @@ export default flat({
149
149
  customer: {
150
150
  payments: '支付历史',
151
151
  invoices: '发票历史',
152
- details: '计费详情',
152
+ details: '账户详情',
153
+ summary: '计费摘要',
153
154
  update: '更新客户信息',
154
155
  empty: '看起来您在这里没有任何订阅或支付',
155
156
  cancel: {
@@ -170,6 +171,13 @@ export default flat({
170
171
  },
171
172
  pastDue: {
172
173
  button: '续费',
174
+ invoices: '欠费帐单',
175
+ warning: '请尽快支付欠费账单,否则你将无法继续使用服务或购买新服务',
176
+ alert: {
177
+ title: '你有欠费账单',
178
+ description: '看起来你有欠费的账单,在你支付所有欠费账单之前,新的购买或者订阅将被禁止,请不要调皮。',
179
+ confirm: '去支付',
180
+ },
173
181
  },
174
182
  recover: {
175
183
  button: '续订',
@@ -16,6 +16,7 @@ import { dispatch } from 'use-bus';
16
16
  import isEmail from 'validator/es/lib/isEmail';
17
17
 
18
18
  import api from '../../api';
19
+ import ConfirmDialog from '../../components/confirm';
19
20
  import FormInput from '../../components/input';
20
21
  import { usePaymentContext } from '../../contexts/payment';
21
22
  import { CheckoutCallbacks, CheckoutContext } from '../../types';
@@ -104,6 +105,7 @@ export default function PaymentForm({
104
105
  status: string;
105
106
  };
106
107
  customer?: TCustomer;
108
+ customerLimited?: boolean;
107
109
  stripePaying: boolean;
108
110
  }>({
109
111
  submitting: false,
@@ -112,6 +114,7 @@ export default function PaymentForm({
112
114
  paymentIntent,
113
115
  stripeContext: undefined,
114
116
  customer,
117
+ customerLimited: false,
115
118
  stripePaying: false,
116
119
  });
117
120
 
@@ -254,10 +257,17 @@ export default function PaymentForm({
254
257
  }
255
258
  }
256
259
  } catch (err: any) {
260
+ let shouldToast = true;
257
261
  if (err.response?.data?.code) {
258
262
  dispatch(`error.${err.response?.data?.code}`);
263
+ if (err.response.data.code === 'CUSTOMER_LIMITED') {
264
+ shouldToast = false;
265
+ setState({ customerLimited: true });
266
+ }
267
+ }
268
+ if (shouldToast) {
269
+ Toast.error(formatError(err));
259
270
  }
260
- Toast.error(formatError(err));
261
271
  } finally {
262
272
  setState({ submitting: false });
263
273
  }
@@ -415,6 +425,17 @@ export default function PaymentForm({
415
425
  )}
416
426
  </Stack>
417
427
  </Fade>
428
+ {state.customerLimited && (
429
+ <ConfirmDialog
430
+ onConfirm={() =>
431
+ window.open(joinURL(window.location.origin, getPrefix(), '/customer/invoice/past-due'), '_blank')
432
+ }
433
+ onCancel={() => setState({ customerLimited: false })}
434
+ confirm={t('payment.customer.pastDue.alert.confirm')}
435
+ title={t('payment.customer.pastDue.alert.title')}
436
+ message={t('payment.customer.pastDue.alert.description')}
437
+ />
438
+ )}
418
439
  </>
419
440
  );
420
441
  }