@blocklet/payment-react 1.13.202 → 1.13.205

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.
@@ -60,19 +60,18 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
60
60
  }
61
61
  @media (min-width: ${({ theme }) => theme.breakpoints.values.md}px) {
62
62
  .price-table-wrap:has(> div:nth-child(1)) {
63
- width: 300px !important;
63
+ width: 320px !important;
64
64
  }
65
65
  .price-table-wrap:has(> div:nth-child(2)) {
66
- width: 600px !important;
66
+ width: 720px !important;
67
67
  }
68
68
  .price-table-wrap:has(> div:nth-child(3)) {
69
- width: 900px !important;
69
+ width: 960px !important;
70
70
  }
71
71
  .price-table-wrap:has(> div:nth-child(1)) > .price-table-item {
72
72
  width: 90% !important;
73
73
  }
74
74
  .price-table-wrap:has(> div:nth-child(2)) > .price-table-item {
75
- // 当子元素为2的时候,子元素给宽度
76
75
  width: 45% !important;
77
76
  }
78
77
  .price-table-wrap:has(> div:nth-child(3)) > .price-table-item {
@@ -133,7 +132,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
133
132
  direction: "column",
134
133
  alignItems: "center",
135
134
  className: "price-table-item",
136
- justifyContent: "center",
135
+ justifyContent: "flex-start",
137
136
  sx: {
138
137
  cursor: "pointer",
139
138
  borderWidth: "1px",
@@ -149,7 +148,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
149
148
  },
150
149
  children: [
151
150
  /* @__PURE__ */ jsxs(Box, { textAlign: "center", children: [
152
- /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [
151
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: "center", spacing: 1, children: [
153
152
  /* @__PURE__ */ jsx(Typography, { variant: "h5", color: "text.primary", fontWeight: 600, children: x.product.name }),
154
153
  x.is_highlight && /* @__PURE__ */ jsx(Chip, { label: x.highlight_text, color: "default", size: "small" })
155
154
  ] }),
package/es/locales/en.js CHANGED
@@ -98,6 +98,10 @@ export default flat({
98
98
  subscription: "View subscription",
99
99
  invoice: "View invoice"
100
100
  },
101
+ staking: {
102
+ title: "Staking Required",
103
+ tooltip: "Staking is used to ensure that future invoices can be paid normally. Revoking the staking from DID Wallet means canceling the subscription."
104
+ },
101
105
  cardPay: "{action} with card",
102
106
  empty: "No thing to pay",
103
107
  per: "per",
@@ -115,7 +119,7 @@ export default flat({
115
119
  setup: "Thanks for your subscribing",
116
120
  tip: "A payment to {payee} has been completed. You can view the details of this payment in your account."
117
121
  },
118
- confirm: "By confirming your subscription, you allow {payee} to charge your account for this and future payments in accordance with their terms. You can always cancel your subscription.",
122
+ confirm: "By confirming your subscription, you allow {payee} to charge your account or slashing your staking for this and future payments in accordance with their terms. You can always cancel your subscription, or revoking your staking from DID Wallet.",
119
123
  required: "Required",
120
124
  invalid: "Invalid",
121
125
  billing: {
@@ -254,6 +258,7 @@ export default flat({
254
258
  reason: {
255
259
  creation: "Subscription create",
256
260
  cycle: "Subscription cycle",
261
+ staking: "Subscription staking",
257
262
  update: "Subscription update",
258
263
  recover: "Subscription recover",
259
264
  threshold: "Metered usage billing",
package/es/locales/zh.js CHANGED
@@ -98,6 +98,10 @@ export default flat({
98
98
  subscription: "\u67E5\u770B\u8BA2\u9605",
99
99
  invoice: "\u67E5\u770B\u8D26\u5355"
100
100
  },
101
+ staking: {
102
+ title: "\u8D28\u62BC\u6570\u91CF",
103
+ tooltip: "\u8D28\u62BC\u76F8\u5F53\u4E8E\u4FDD\u8BC1\u91D1\uFF0C\u7528\u4E8E\u786E\u4FDD\u672A\u6765\u7684\u8D26\u5355\u80FD\u591F\u6B63\u5E38\u6263\u6B3E\uFF0C\u5982\u679C\u4F60\u4ECE DID Wallet \u64A4\u9500\u8D28\u62BC\uFF0C\u8BA2\u9605\u4E5F\u4F1A\u88AB\u53D6\u6D88\u3002"
104
+ },
101
105
  cardPay: "\u4F7F\u7528\u5361\u7247{action}",
102
106
  empty: "\u6CA1\u6709\u53EF\u652F\u4ED8\u7684\u9879\u76EE",
103
107
  per: "\u6BCF",
@@ -115,7 +119,7 @@ export default flat({
115
119
  setup: "\u611F\u8C22\u60A8\u7684\u8BA2\u9605",
116
120
  tip: "\u5411{payee}\u7684\u4ED8\u6B3E\u5DF2\u5B8C\u6210\u3002\u60A8\u53EF\u4EE5\u5728\u60A8\u7684\u8D26\u6237\u4E2D\u67E5\u770B\u6B64\u4ED8\u6B3E\u7684\u8BE6\u7EC6\u4FE1\u606F\u3002"
117
121
  },
118
- confirm: "\u901A\u8FC7\u786E\u8BA4\u60A8\u7684\u8BA2\u9605\uFF0C\u60A8\u5141\u8BB8{payee}\u6309\u7167\u5176\u6761\u6B3E\u5BF9\u60A8\u7684\u8D26\u6237\u8FDB\u884C\u4ED8\u6B3E\u3002\u60A8\u968F\u65F6\u53EF\u4EE5\u53D6\u6D88\u60A8\u7684\u8BA2\u9605\u3002",
122
+ confirm: "\u901A\u8FC7\u786E\u8BA4\u60A8\u7684\u8BA2\u9605\uFF0C\u60A8\u5141\u8BB8{payee}\u6309\u7167\u5176\u6761\u6B3E\u5BF9\u60A8\u7684\u8D26\u6237\u8FDB\u884C\u4ED8\u6B3E\u6216\u8005\u7F5A\u6CA1\u60A8\u7684\u8D28\u62BC\u3002\u60A8\u968F\u65F6\u53EF\u4EE5\u53D6\u6D88\u60A8\u7684\u8BA2\u9605\uFF0C\u6216\u8005\u64A4\u9500\u8D28\u62BC\u3002",
119
123
  required: "\u5FC5\u586B\u9879",
120
124
  invalid: "\u65E0\u6548",
121
125
  billing: {
@@ -254,6 +258,7 @@ export default flat({
254
258
  reason: {
255
259
  creation: "\u8BA2\u9605\u521B\u5EFA",
256
260
  cycle: "\u81EA\u52A8\u6263\u8D39",
261
+ staking: "\u8BA2\u9605\u521B\u5EFA\uFF08\u8D28\u62BC\uFF09",
257
262
  update: "\u8BA2\u9605\u66F4\u65B0",
258
263
  recover: "\u8BA2\u9605\u6062\u590D",
259
264
  threshold: "\u7528\u91CF\u8D26\u5355",
@@ -143,6 +143,7 @@ export function PaymentInner({
143
143
  });
144
144
  const currencyId = useWatch({ control: methods.control, name: "payment_currency", defaultValue: defaultCurrencyId });
145
145
  const currency = findCurrency(paymentMethods, currencyId) || settings.baseCurrency;
146
+ const method = paymentMethods.find((x) => x.id === currency.payment_method_id);
146
147
  useEffect(() => {
147
148
  if (onChange) {
148
149
  onChange(methods.getValues());
@@ -205,6 +206,8 @@ export function PaymentInner({
205
206
  {
206
207
  items: state.checkoutSession.line_items,
207
208
  trialInDays: state.checkoutSession.subscription_data?.trial_period_days || 0,
209
+ billingThreshold: state.checkoutSession.subscription_data?.billing_threshold_amount || 0,
210
+ showStaking: method.type === "arcblock",
208
211
  currency,
209
212
  onUpsell,
210
213
  onDownsell,
@@ -4,6 +4,8 @@ type Props = {
4
4
  items: TLineItemExpanded[];
5
5
  currency: TPaymentCurrency;
6
6
  trialInDays: number;
7
+ billingThreshold: number;
8
+ showStaking?: boolean;
7
9
  onUpsell?: Function;
8
10
  onDownsell?: Function;
9
11
  onApplyCrossSell?: Function;
@@ -11,7 +13,7 @@ type Props = {
11
13
  checkoutSessionId?: string;
12
14
  crossSellBehavior?: string;
13
15
  };
14
- declare function PaymentSummary({ items, currency, trialInDays, onUpsell, onDownsell, onApplyCrossSell, onCancelCrossSell, checkoutSessionId, crossSellBehavior, ...rest }: Props): import("react").JSX.Element;
16
+ declare function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onApplyCrossSell, onCancelCrossSell, checkoutSessionId, crossSellBehavior, showStaking, ...rest }: Props): import("react").JSX.Element;
15
17
  declare namespace PaymentSummary {
16
18
  var defaultProps: {
17
19
  onUpsell: any;
@@ -20,6 +22,7 @@ declare namespace PaymentSummary {
20
22
  onCancelCrossSell: any;
21
23
  checkoutSessionId: string;
22
24
  crossSellBehavior: string;
25
+ showStaking: boolean;
23
26
  };
24
27
  }
25
28
  export default PaymentSummary;
@@ -1,13 +1,15 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
+ import { InfoOutlined } from "@mui/icons-material";
3
4
  import { LoadingButton } from "@mui/lab";
4
- import { Fade, Grow, Stack, Typography, keyframes } from "@mui/material";
5
+ import { Fade, Grow, Stack, Tooltip, Typography, keyframes } from "@mui/material";
6
+ import { BN, fromTokenToUnit } from "@ocap/util";
5
7
  import { useRequest, useSetState } from "ahooks";
6
8
  import noop from "lodash/noop";
7
9
  import useBus from "use-bus";
8
10
  import api from "../api.js";
9
11
  import Status from "../components/status.js";
10
- import { formatCheckoutHeadlines } from "../util.js";
12
+ import { formatAmount, formatCheckoutHeadlines, getPriceUintAmountByCurrency } from "../util.js";
11
13
  import PaymentAmount from "./amount.js";
12
14
  import ProductItem from "./product-item.js";
13
15
  const shake = keyframes`
@@ -38,24 +40,51 @@ async function fetchCrossSell(id) {
38
40
  return null;
39
41
  }
40
42
  }
43
+ function getStakingSetup(items, currency, billingThreshold = 0) {
44
+ const staking = {
45
+ licensed: new BN(0),
46
+ metered: new BN(0)
47
+ };
48
+ items.forEach((x) => {
49
+ const price = x.upsell_price || x.price;
50
+ const unit = getPriceUintAmountByCurrency(price, currency);
51
+ const amount = new BN(unit).mul(new BN(x.quantity));
52
+ if (price.type === "recurring" && price.recurring) {
53
+ if (price.recurring.usage_type === "licensed") {
54
+ staking.licensed = staking.licensed.add(amount);
55
+ }
56
+ if (price.recurring.usage_type === "metered") {
57
+ if (+billingThreshold) {
58
+ staking.metered = fromTokenToUnit(billingThreshold, currency.decimal);
59
+ } else {
60
+ staking.metered = staking.metered.add(amount);
61
+ }
62
+ }
63
+ }
64
+ });
65
+ return staking.licensed.add(staking.metered).toString();
66
+ }
41
67
  PaymentSummary.defaultProps = {
42
68
  onUpsell: noop,
43
69
  onDownsell: noop,
44
70
  onApplyCrossSell: noop,
45
71
  onCancelCrossSell: noop,
46
72
  checkoutSessionId: "",
47
- crossSellBehavior: ""
73
+ crossSellBehavior: "",
74
+ showStaking: false
48
75
  };
49
76
  export default function PaymentSummary({
50
77
  items,
51
78
  currency,
52
79
  trialInDays,
80
+ billingThreshold,
53
81
  onUpsell,
54
82
  onDownsell,
55
83
  onApplyCrossSell,
56
84
  onCancelCrossSell,
57
85
  checkoutSessionId,
58
86
  crossSellBehavior,
87
+ showStaking,
59
88
  ...rest
60
89
  }) {
61
90
  const { t, locale } = useLocaleContext();
@@ -64,6 +93,7 @@ export default function PaymentSummary({
64
93
  () => checkoutSessionId ? fetchCrossSell(checkoutSessionId) : Promise.resolve(null)
65
94
  );
66
95
  const headlines = formatCheckoutHeadlines(items, currency, trialInDays, locale);
96
+ const staking = showStaking ? getStakingSetup(items, currency, billingThreshold) : "0";
67
97
  useBus(
68
98
  "error.REQUIRE_CROSS_SELL",
69
99
  () => {
@@ -145,10 +175,7 @@ export default function PaymentSummary({
145
175
  borderRadius: 1,
146
176
  padding: 1,
147
177
  animation: state.shake ? `${shake} 0.2s 5 ease-in-out` : "none",
148
- mt: {
149
- xs: 4,
150
- md: 8
151
- }
178
+ mt: 3
152
179
  },
153
180
  children: [
154
181
  /* @__PURE__ */ jsx(
@@ -179,6 +206,32 @@ export default function PaymentSummary({
179
206
  ] })
180
207
  ]
181
208
  }
182
- ) })
209
+ ) }),
210
+ staking > 0 && /* @__PURE__ */ jsxs(
211
+ Stack,
212
+ {
213
+ direction: "row",
214
+ justifyContent: "space-between",
215
+ alignItems: "center",
216
+ spacing: 1,
217
+ sx: {
218
+ border: "1px solid #eee",
219
+ borderRadius: 1,
220
+ padding: 1,
221
+ mt: 3
222
+ },
223
+ children: [
224
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [
225
+ /* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.staking.title") }),
226
+ /* @__PURE__ */ jsx(Tooltip, { title: t("payment.checkout.staking.tooltip"), placement: "top", sx: { maxWidth: "150px" }, children: /* @__PURE__ */ jsx(InfoOutlined, { fontSize: "small", sx: { color: "text.secondary" } }) })
227
+ ] }),
228
+ /* @__PURE__ */ jsxs(Typography, { children: [
229
+ formatAmount(staking, currency.decimal),
230
+ " ",
231
+ currency.symbol
232
+ ] })
233
+ ]
234
+ }
235
+ )
183
236
  ] }) });
184
237
  }
@@ -79,19 +79,18 @@ function PricingTable({
79
79
  theme
80
80
  }) => theme.breakpoints.values.md}px) {
81
81
  .price-table-wrap:has(> div:nth-child(1)) {
82
- width: 300px !important;
82
+ width: 320px !important;
83
83
  }
84
84
  .price-table-wrap:has(> div:nth-child(2)) {
85
- width: 600px !important;
85
+ width: 720px !important;
86
86
  }
87
87
  .price-table-wrap:has(> div:nth-child(3)) {
88
- width: 900px !important;
88
+ width: 960px !important;
89
89
  }
90
90
  .price-table-wrap:has(> div:nth-child(1)) > .price-table-item {
91
91
  width: 90% !important;
92
92
  }
93
93
  .price-table-wrap:has(> div:nth-child(2)) > .price-table-item {
94
- // 当子元素为2的时候,子元素给宽度
95
94
  width: 45% !important;
96
95
  }
97
96
  .price-table-wrap:has(> div:nth-child(3)) > .price-table-item {
@@ -150,7 +149,7 @@ function PricingTable({
150
149
  direction: "column",
151
150
  alignItems: "center",
152
151
  className: "price-table-item",
153
- justifyContent: "center",
152
+ justifyContent: "flex-start",
154
153
  sx: {
155
154
  cursor: "pointer",
156
155
  borderWidth: "1px",
@@ -169,6 +168,7 @@ function PricingTable({
169
168
  children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
170
169
  direction: "row",
171
170
  alignItems: "center",
171
+ justifyContent: "center",
172
172
  spacing: 1,
173
173
  children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
174
174
  variant: "h5",
package/lib/locales/en.js CHANGED
@@ -105,6 +105,10 @@ module.exports = (0, _flat.default)({
105
105
  subscription: "View subscription",
106
106
  invoice: "View invoice"
107
107
  },
108
+ staking: {
109
+ title: "Staking Required",
110
+ tooltip: "Staking is used to ensure that future invoices can be paid normally. Revoking the staking from DID Wallet means canceling the subscription."
111
+ },
108
112
  cardPay: "{action} with card",
109
113
  empty: "No thing to pay",
110
114
  per: "per",
@@ -122,7 +126,7 @@ module.exports = (0, _flat.default)({
122
126
  setup: "Thanks for your subscribing",
123
127
  tip: "A payment to {payee} has been completed. You can view the details of this payment in your account."
124
128
  },
125
- confirm: "By confirming your subscription, you allow {payee} to charge your account for this and future payments in accordance with their terms. You can always cancel your subscription.",
129
+ confirm: "By confirming your subscription, you allow {payee} to charge your account or slashing your staking for this and future payments in accordance with their terms. You can always cancel your subscription, or revoking your staking from DID Wallet.",
126
130
  required: "Required",
127
131
  invalid: "Invalid",
128
132
  billing: {
@@ -261,6 +265,7 @@ module.exports = (0, _flat.default)({
261
265
  reason: {
262
266
  creation: "Subscription create",
263
267
  cycle: "Subscription cycle",
268
+ staking: "Subscription staking",
264
269
  update: "Subscription update",
265
270
  recover: "Subscription recover",
266
271
  threshold: "Metered usage billing",
package/lib/locales/zh.js CHANGED
@@ -105,6 +105,10 @@ module.exports = (0, _flat.default)({
105
105
  subscription: "\u67E5\u770B\u8BA2\u9605",
106
106
  invoice: "\u67E5\u770B\u8D26\u5355"
107
107
  },
108
+ staking: {
109
+ title: "\u8D28\u62BC\u6570\u91CF",
110
+ tooltip: "\u8D28\u62BC\u76F8\u5F53\u4E8E\u4FDD\u8BC1\u91D1\uFF0C\u7528\u4E8E\u786E\u4FDD\u672A\u6765\u7684\u8D26\u5355\u80FD\u591F\u6B63\u5E38\u6263\u6B3E\uFF0C\u5982\u679C\u4F60\u4ECE DID Wallet \u64A4\u9500\u8D28\u62BC\uFF0C\u8BA2\u9605\u4E5F\u4F1A\u88AB\u53D6\u6D88\u3002"
111
+ },
108
112
  cardPay: "\u4F7F\u7528\u5361\u7247{action}",
109
113
  empty: "\u6CA1\u6709\u53EF\u652F\u4ED8\u7684\u9879\u76EE",
110
114
  per: "\u6BCF",
@@ -122,7 +126,7 @@ module.exports = (0, _flat.default)({
122
126
  setup: "\u611F\u8C22\u60A8\u7684\u8BA2\u9605",
123
127
  tip: "\u5411{payee}\u7684\u4ED8\u6B3E\u5DF2\u5B8C\u6210\u3002\u60A8\u53EF\u4EE5\u5728\u60A8\u7684\u8D26\u6237\u4E2D\u67E5\u770B\u6B64\u4ED8\u6B3E\u7684\u8BE6\u7EC6\u4FE1\u606F\u3002"
124
128
  },
125
- confirm: "\u901A\u8FC7\u786E\u8BA4\u60A8\u7684\u8BA2\u9605\uFF0C\u60A8\u5141\u8BB8{payee}\u6309\u7167\u5176\u6761\u6B3E\u5BF9\u60A8\u7684\u8D26\u6237\u8FDB\u884C\u4ED8\u6B3E\u3002\u60A8\u968F\u65F6\u53EF\u4EE5\u53D6\u6D88\u60A8\u7684\u8BA2\u9605\u3002",
129
+ confirm: "\u901A\u8FC7\u786E\u8BA4\u60A8\u7684\u8BA2\u9605\uFF0C\u60A8\u5141\u8BB8{payee}\u6309\u7167\u5176\u6761\u6B3E\u5BF9\u60A8\u7684\u8D26\u6237\u8FDB\u884C\u4ED8\u6B3E\u6216\u8005\u7F5A\u6CA1\u60A8\u7684\u8D28\u62BC\u3002\u60A8\u968F\u65F6\u53EF\u4EE5\u53D6\u6D88\u60A8\u7684\u8BA2\u9605\uFF0C\u6216\u8005\u64A4\u9500\u8D28\u62BC\u3002",
126
130
  required: "\u5FC5\u586B\u9879",
127
131
  invalid: "\u65E0\u6548",
128
132
  billing: {
@@ -261,6 +265,7 @@ module.exports = (0, _flat.default)({
261
265
  reason: {
262
266
  creation: "\u8BA2\u9605\u521B\u5EFA",
263
267
  cycle: "\u81EA\u52A8\u6263\u8D39",
268
+ staking: "\u8BA2\u9605\u521B\u5EFA\uFF08\u8D28\u62BC\uFF09",
264
269
  update: "\u8BA2\u9605\u66F4\u65B0",
265
270
  recover: "\u8BA2\u9605\u6062\u590D",
266
271
  threshold: "\u7528\u91CF\u8D26\u5355",
@@ -176,6 +176,7 @@ function PaymentInner({
176
176
  defaultValue: defaultCurrencyId
177
177
  });
178
178
  const currency = (0, _util.findCurrency)(paymentMethods, currencyId) || settings.baseCurrency;
179
+ const method = paymentMethods.find(x => x.id === currency.payment_method_id);
179
180
  (0, _react.useEffect)(() => {
180
181
  if (onChange) {
181
182
  onChange(methods.getValues());
@@ -277,6 +278,8 @@ function PaymentInner({
277
278
  }) : null, /* @__PURE__ */(0, _jsxRuntime.jsx)(_summary.default, {
278
279
  items: state.checkoutSession.line_items,
279
280
  trialInDays: state.checkoutSession.subscription_data?.trial_period_days || 0,
281
+ billingThreshold: state.checkoutSession.subscription_data?.billing_threshold_amount || 0,
282
+ showStaking: method.type === "arcblock",
280
283
  currency,
281
284
  onUpsell,
282
285
  onDownsell,
@@ -4,6 +4,8 @@ type Props = {
4
4
  items: TLineItemExpanded[];
5
5
  currency: TPaymentCurrency;
6
6
  trialInDays: number;
7
+ billingThreshold: number;
8
+ showStaking?: boolean;
7
9
  onUpsell?: Function;
8
10
  onDownsell?: Function;
9
11
  onApplyCrossSell?: Function;
@@ -11,7 +13,7 @@ type Props = {
11
13
  checkoutSessionId?: string;
12
14
  crossSellBehavior?: string;
13
15
  };
14
- declare function PaymentSummary({ items, currency, trialInDays, onUpsell, onDownsell, onApplyCrossSell, onCancelCrossSell, checkoutSessionId, crossSellBehavior, ...rest }: Props): import("react").JSX.Element;
16
+ declare function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onApplyCrossSell, onCancelCrossSell, checkoutSessionId, crossSellBehavior, showStaking, ...rest }: Props): import("react").JSX.Element;
15
17
  declare namespace PaymentSummary {
16
18
  var defaultProps: {
17
19
  onUpsell: any;
@@ -20,6 +22,7 @@ declare namespace PaymentSummary {
20
22
  onCancelCrossSell: any;
21
23
  checkoutSessionId: string;
22
24
  crossSellBehavior: string;
25
+ showStaking: boolean;
23
26
  };
24
27
  }
25
28
  export default PaymentSummary;
@@ -6,14 +6,16 @@ Object.defineProperty(exports, "__esModule", {
6
6
  module.exports = PaymentSummary;
7
7
  var _jsxRuntime = require("react/jsx-runtime");
8
8
  var _context = require("@arcblock/ux/lib/Locale/context");
9
+ var _iconsMaterial = require("@mui/icons-material");
9
10
  var _lab = require("@mui/lab");
10
11
  var _material = require("@mui/material");
12
+ var _util = require("@ocap/util");
11
13
  var _ahooks = require("ahooks");
12
14
  var _noop = _interopRequireDefault(require("lodash/noop"));
13
15
  var _useBus = _interopRequireDefault(require("use-bus"));
14
16
  var _api = _interopRequireDefault(require("../api"));
15
17
  var _status = _interopRequireDefault(require("../components/status"));
16
- var _util = require("../util");
18
+ var _util2 = require("../util");
17
19
  var _amount = _interopRequireDefault(require("./amount"));
18
20
  var _productItem = _interopRequireDefault(require("./product-item"));
19
21
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -47,24 +49,51 @@ async function fetchCrossSell(id) {
47
49
  return null;
48
50
  }
49
51
  }
52
+ function getStakingSetup(items, currency, billingThreshold = 0) {
53
+ const staking = {
54
+ licensed: new _util.BN(0),
55
+ metered: new _util.BN(0)
56
+ };
57
+ items.forEach(x => {
58
+ const price = x.upsell_price || x.price;
59
+ const unit = (0, _util2.getPriceUintAmountByCurrency)(price, currency);
60
+ const amount = new _util.BN(unit).mul(new _util.BN(x.quantity));
61
+ if (price.type === "recurring" && price.recurring) {
62
+ if (price.recurring.usage_type === "licensed") {
63
+ staking.licensed = staking.licensed.add(amount);
64
+ }
65
+ if (price.recurring.usage_type === "metered") {
66
+ if (+billingThreshold) {
67
+ staking.metered = (0, _util.fromTokenToUnit)(billingThreshold, currency.decimal);
68
+ } else {
69
+ staking.metered = staking.metered.add(amount);
70
+ }
71
+ }
72
+ }
73
+ });
74
+ return staking.licensed.add(staking.metered).toString();
75
+ }
50
76
  PaymentSummary.defaultProps = {
51
77
  onUpsell: _noop.default,
52
78
  onDownsell: _noop.default,
53
79
  onApplyCrossSell: _noop.default,
54
80
  onCancelCrossSell: _noop.default,
55
81
  checkoutSessionId: "",
56
- crossSellBehavior: ""
82
+ crossSellBehavior: "",
83
+ showStaking: false
57
84
  };
58
85
  function PaymentSummary({
59
86
  items,
60
87
  currency,
61
88
  trialInDays,
89
+ billingThreshold,
62
90
  onUpsell,
63
91
  onDownsell,
64
92
  onApplyCrossSell,
65
93
  onCancelCrossSell,
66
94
  checkoutSessionId,
67
95
  crossSellBehavior,
96
+ showStaking,
68
97
  ...rest
69
98
  }) {
70
99
  const {
@@ -79,7 +108,8 @@ function PaymentSummary({
79
108
  data,
80
109
  runAsync
81
110
  } = (0, _ahooks.useRequest)(() => checkoutSessionId ? fetchCrossSell(checkoutSessionId) : Promise.resolve(null));
82
- const headlines = (0, _util.formatCheckoutHeadlines)(items, currency, trialInDays, locale);
111
+ const headlines = (0, _util2.formatCheckoutHeadlines)(items, currency, trialInDays, locale);
112
+ const staking = showStaking ? getStakingSetup(items, currency, billingThreshold) : "0";
83
113
  (0, _useBus.default)("error.REQUIRE_CROSS_SELL", () => {
84
114
  setState({
85
115
  shake: true
@@ -187,10 +217,7 @@ function PaymentSummary({
187
217
  borderRadius: 1,
188
218
  padding: 1,
189
219
  animation: state.shake ? `${shake} 0.2s 5 ease-in-out` : "none",
190
- mt: {
191
- xs: 4,
192
- md: 8
193
- }
220
+ mt: 3
194
221
  },
195
222
  children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_productItem.default, {
196
223
  item: {
@@ -231,6 +258,39 @@ function PaymentSummary({
231
258
  })]
232
259
  })]
233
260
  })
261
+ }), staking > 0 && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
262
+ direction: "row",
263
+ justifyContent: "space-between",
264
+ alignItems: "center",
265
+ spacing: 1,
266
+ sx: {
267
+ border: "1px solid #eee",
268
+ borderRadius: 1,
269
+ padding: 1,
270
+ mt: 3
271
+ },
272
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
273
+ direction: "row",
274
+ alignItems: "center",
275
+ spacing: 0.5,
276
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
277
+ children: t("payment.checkout.staking.title")
278
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Tooltip, {
279
+ title: t("payment.checkout.staking.tooltip"),
280
+ placement: "top",
281
+ sx: {
282
+ maxWidth: "150px"
283
+ },
284
+ children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.InfoOutlined, {
285
+ fontSize: "small",
286
+ sx: {
287
+ color: "text.secondary"
288
+ }
289
+ })
290
+ })]
291
+ }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
292
+ children: [(0, _util2.formatAmount)(staking, currency.decimal), " ", currency.symbol]
293
+ })]
234
294
  })]
235
295
  })
236
296
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.13.202",
3
+ "version": "1.13.205",
4
4
  "description": "Reusable react components for payment kit v2",
5
5
  "keywords": [
6
6
  "react",
@@ -90,7 +90,7 @@
90
90
  "@babel/core": "^7.23.9",
91
91
  "@babel/preset-env": "^7.23.9",
92
92
  "@babel/preset-react": "^7.23.3",
93
- "@blocklet/payment-types": "1.13.202",
93
+ "@blocklet/payment-types": "1.13.205",
94
94
  "@storybook/addon-essentials": "^7.6.13",
95
95
  "@storybook/addon-interactions": "^7.6.13",
96
96
  "@storybook/addon-links": "^7.6.13",
@@ -119,5 +119,5 @@
119
119
  "vite-plugin-babel": "^1.2.0",
120
120
  "vite-plugin-node-polyfills": "^0.19.0"
121
121
  },
122
- "gitHead": "e9c7a403fee7506f92118581d659c91f210714a7"
122
+ "gitHead": "8c16c5d362df5c497c7a95a0ae20e2ef61f747b3"
123
123
  }
@@ -81,19 +81,18 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
81
81
  }
82
82
  @media (min-width: ${({ theme }) => theme.breakpoints.values.md}px) {
83
83
  .price-table-wrap:has(> div:nth-child(1)) {
84
- width: 300px !important;
84
+ width: 320px !important;
85
85
  }
86
86
  .price-table-wrap:has(> div:nth-child(2)) {
87
- width: 600px !important;
87
+ width: 720px !important;
88
88
  }
89
89
  .price-table-wrap:has(> div:nth-child(3)) {
90
- width: 900px !important;
90
+ width: 960px !important;
91
91
  }
92
92
  .price-table-wrap:has(> div:nth-child(1)) > .price-table-item {
93
93
  width: 90% !important;
94
94
  }
95
95
  .price-table-wrap:has(> div:nth-child(2)) > .price-table-item {
96
- // 当子元素为2的时候,子元素给宽度
97
96
  width: 45% !important;
98
97
  }
99
98
  .price-table-wrap:has(> div:nth-child(3)) > .price-table-item {
@@ -157,7 +156,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
157
156
  direction="column"
158
157
  alignItems="center"
159
158
  className="price-table-item"
160
- justifyContent="center"
159
+ justifyContent="flex-start"
161
160
  sx={{
162
161
  cursor: 'pointer',
163
162
  borderWidth: '1px',
@@ -172,7 +171,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
172
171
  },
173
172
  }}>
174
173
  <Box textAlign="center">
175
- <Stack direction="row" alignItems="center" spacing={1}>
174
+ <Stack direction="row" alignItems="center" justifyContent="center" spacing={1}>
176
175
  <Typography variant="h5" color="text.primary" fontWeight={600}>
177
176
  {x.product.name}
178
177
  </Typography>
@@ -99,6 +99,11 @@ export default flat({
99
99
  subscription: 'View subscription',
100
100
  invoice: 'View invoice',
101
101
  },
102
+ staking: {
103
+ title: 'Staking Required',
104
+ tooltip:
105
+ 'Staking is used to ensure that future invoices can be paid normally. Revoking the staking from DID Wallet means canceling the subscription.',
106
+ },
102
107
  cardPay: '{action} with card',
103
108
  empty: 'No thing to pay',
104
109
  per: 'per',
@@ -117,7 +122,7 @@ export default flat({
117
122
  tip: 'A payment to {payee} has been completed. You can view the details of this payment in your account.',
118
123
  },
119
124
  confirm:
120
- 'By confirming your subscription, you allow {payee} to charge your account for this and future payments in accordance with their terms. You can always cancel your subscription.',
125
+ 'By confirming your subscription, you allow {payee} to charge your account or slashing your staking for this and future payments in accordance with their terms. You can always cancel your subscription, or revoking your staking from DID Wallet.',
121
126
  required: 'Required',
122
127
  invalid: 'Invalid',
123
128
  billing: {
@@ -263,6 +268,7 @@ export default flat({
263
268
  reason: {
264
269
  creation: 'Subscription create',
265
270
  cycle: 'Subscription cycle',
271
+ staking: 'Subscription staking',
266
272
  update: 'Subscription update',
267
273
  recover: 'Subscription recover',
268
274
  threshold: 'Metered usage billing',
@@ -99,6 +99,10 @@ export default flat({
99
99
  subscription: '查看订阅',
100
100
  invoice: '查看账单',
101
101
  },
102
+ staking: {
103
+ title: '质押数量',
104
+ tooltip: '质押相当于保证金,用于确保未来的账单能够正常扣款,如果你从 DID Wallet 撤销质押,订阅也会被取消。',
105
+ },
102
106
  cardPay: '使用卡片{action}',
103
107
  empty: '没有可支付的项目',
104
108
  per: '每',
@@ -116,7 +120,8 @@ export default flat({
116
120
  setup: '感谢您的订阅',
117
121
  tip: '向{payee}的付款已完成。您可以在您的账户中查看此付款的详细信息。',
118
122
  },
119
- confirm: '通过确认您的订阅,您允许{payee}按照其条款对您的账户进行付款。您随时可以取消您的订阅。',
123
+ confirm:
124
+ '通过确认您的订阅,您允许{payee}按照其条款对您的账户进行付款或者罚没您的质押。您随时可以取消您的订阅,或者撤销质押。',
120
125
  required: '必填项',
121
126
  invalid: '无效',
122
127
  billing: {
@@ -256,6 +261,7 @@ export default flat({
256
261
  reason: {
257
262
  creation: '订阅创建',
258
263
  cycle: '自动扣费',
264
+ staking: '订阅创建(质押)',
259
265
  update: '订阅更新',
260
266
  recover: '订阅恢复',
261
267
  threshold: '用量账单',
@@ -5,6 +5,7 @@ import type {
5
5
  TCheckoutSessionExpanded,
6
6
  TCustomer,
7
7
  TPaymentCurrency,
8
+ TPaymentMethod,
8
9
  TPaymentMethodExpanded,
9
10
  } from '@blocklet/payment-types';
10
11
  import { ArrowBackOutlined } from '@mui/icons-material';
@@ -180,6 +181,7 @@ export function PaymentInner({
180
181
  const currency =
181
182
  (findCurrency(paymentMethods as TPaymentMethodExpanded[], currencyId as string) as TPaymentCurrency) ||
182
183
  settings.baseCurrency;
184
+ const method = paymentMethods.find((x: any) => x.id === currency.payment_method_id) as TPaymentMethod;
183
185
 
184
186
  useEffect(() => {
185
187
  if (onChange) {
@@ -249,6 +251,8 @@ export function PaymentInner({
249
251
  <PaymentSummary
250
252
  items={state.checkoutSession.line_items}
251
253
  trialInDays={state.checkoutSession.subscription_data?.trial_period_days || 0}
254
+ billingThreshold={state.checkoutSession.subscription_data?.billing_threshold_amount || 0}
255
+ showStaking={method.type === 'arcblock'}
252
256
  currency={currency}
253
257
  onUpsell={onUpsell}
254
258
  onDownsell={onDownsell}
@@ -1,14 +1,16 @@
1
1
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
2
  import type { TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
3
+ import { InfoOutlined } from '@mui/icons-material';
3
4
  import { LoadingButton } from '@mui/lab';
4
- import { Fade, Grow, Stack, Typography, keyframes } from '@mui/material';
5
+ import { Fade, Grow, Stack, Tooltip, Typography, keyframes } from '@mui/material';
6
+ import { BN, fromTokenToUnit } from '@ocap/util';
5
7
  import { useRequest, useSetState } from 'ahooks';
6
8
  import noop from 'lodash/noop';
7
9
  import useBus from 'use-bus';
8
10
 
9
11
  import api from '../api';
10
12
  import Status from '../components/status';
11
- import { formatCheckoutHeadlines } from '../util';
13
+ import { formatAmount, formatCheckoutHeadlines, getPriceUintAmountByCurrency } from '../util';
12
14
  import PaymentAmount from './amount';
13
15
  import ProductItem from './product-item';
14
16
 
@@ -34,6 +36,8 @@ type Props = {
34
36
  items: TLineItemExpanded[];
35
37
  currency: TPaymentCurrency;
36
38
  trialInDays: number;
39
+ billingThreshold: number;
40
+ showStaking?: boolean;
37
41
  onUpsell?: Function;
38
42
  onDownsell?: Function;
39
43
  onApplyCrossSell?: Function;
@@ -55,6 +59,33 @@ async function fetchCrossSell(id: string) {
55
59
  }
56
60
  }
57
61
 
62
+ function getStakingSetup(items: TLineItemExpanded[], currency: TPaymentCurrency, billingThreshold = 0) {
63
+ const staking = {
64
+ licensed: new BN(0),
65
+ metered: new BN(0),
66
+ };
67
+
68
+ items.forEach((x) => {
69
+ const price = x.upsell_price || x.price;
70
+ const unit = getPriceUintAmountByCurrency(price, currency);
71
+ const amount = new BN(unit).mul(new BN(x.quantity));
72
+ if (price.type === 'recurring' && price.recurring) {
73
+ if (price.recurring.usage_type === 'licensed') {
74
+ staking.licensed = staking.licensed.add(amount);
75
+ }
76
+ if (price.recurring.usage_type === 'metered') {
77
+ if (+billingThreshold) {
78
+ staking.metered = fromTokenToUnit(billingThreshold, currency.decimal);
79
+ } else {
80
+ staking.metered = staking.metered.add(amount);
81
+ }
82
+ }
83
+ }
84
+ });
85
+
86
+ return staking.licensed.add(staking.metered).toString();
87
+ }
88
+
58
89
  PaymentSummary.defaultProps = {
59
90
  onUpsell: noop,
60
91
  onDownsell: noop,
@@ -62,18 +93,21 @@ PaymentSummary.defaultProps = {
62
93
  onCancelCrossSell: noop,
63
94
  checkoutSessionId: '',
64
95
  crossSellBehavior: '',
96
+ showStaking: false,
65
97
  };
66
98
 
67
99
  export default function PaymentSummary({
68
100
  items,
69
101
  currency,
70
102
  trialInDays,
103
+ billingThreshold,
71
104
  onUpsell,
72
105
  onDownsell,
73
106
  onApplyCrossSell,
74
107
  onCancelCrossSell,
75
108
  checkoutSessionId,
76
109
  crossSellBehavior,
110
+ showStaking,
77
111
  ...rest
78
112
  }: Props) {
79
113
  const { t, locale } = useLocaleContext();
@@ -82,6 +116,7 @@ export default function PaymentSummary({
82
116
  checkoutSessionId ? fetchCrossSell(checkoutSessionId) : Promise.resolve(null)
83
117
  );
84
118
  const headlines = formatCheckoutHeadlines(items, currency, trialInDays, locale);
119
+ const staking = showStaking ? getStakingSetup(items, currency, billingThreshold) : '0';
85
120
 
86
121
  useBus(
87
122
  'error.REQUIRE_CROSS_SELL',
@@ -175,10 +210,7 @@ export default function PaymentSummary({
175
210
  borderRadius: 1,
176
211
  padding: 1,
177
212
  animation: state.shake ? `${shake} 0.2s 5 ease-in-out` : 'none',
178
- mt: {
179
- xs: 4,
180
- md: 8,
181
- },
213
+ mt: 3,
182
214
  }}>
183
215
  <ProductItem
184
216
  item={{ quantity: 1, price: data, price_id: data.id, cross_sell: true } as TLineItemExpanded}
@@ -207,6 +239,29 @@ export default function PaymentSummary({
207
239
  </Stack>
208
240
  </Grow>
209
241
  )}
242
+ {staking > 0 && (
243
+ <Stack
244
+ direction="row"
245
+ justifyContent="space-between"
246
+ alignItems="center"
247
+ spacing={1}
248
+ sx={{
249
+ border: '1px solid #eee',
250
+ borderRadius: 1,
251
+ padding: 1,
252
+ mt: 3,
253
+ }}>
254
+ <Stack direction="row" alignItems="center" spacing={0.5}>
255
+ <Typography>{t('payment.checkout.staking.title')}</Typography>
256
+ <Tooltip title={t('payment.checkout.staking.tooltip')} placement="top" sx={{ maxWidth: '150px' }}>
257
+ <InfoOutlined fontSize="small" sx={{ color: 'text.secondary' }} />
258
+ </Tooltip>
259
+ </Stack>
260
+ <Typography>
261
+ {formatAmount(staking, currency.decimal)} {currency.symbol}
262
+ </Typography>
263
+ </Stack>
264
+ )}
210
265
  </Stack>
211
266
  </Fade>
212
267
  );