@blocklet/payment-react 1.13.287 → 1.13.289

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.
@@ -20,15 +20,24 @@ import {
20
20
  import { styled } from "@mui/system";
21
21
  import { useSetState } from "ahooks";
22
22
  import { useEffect, useMemo, useState } from "react";
23
+ import { BN } from "@ocap/util";
23
24
  import { usePaymentContext } from "../contexts/payment.js";
24
- import { formatError, formatPriceAmount, formatRecurring, getPriceCurrencyOptions } from "../libs/util.js";
25
+ import {
26
+ formatError,
27
+ formatPriceAmount,
28
+ formatRecurring,
29
+ getPriceCurrencyOptions,
30
+ getPriceUintAmountByCurrency
31
+ } from "../libs/util.js";
25
32
  import Amount from "../payment/amount.js";
26
- const groupItemsByRecurring = (items) => {
33
+ const groupItemsByRecurring = (items, currency) => {
27
34
  const grouped = {};
28
35
  const recurring = {};
29
36
  items.forEach((x) => {
30
37
  const key = [x.price.recurring?.interval, x.price.recurring?.interval_count].join("-");
31
- recurring[key] = x.price.recurring;
38
+ if (x.price.currency_options.find((c) => c.currency_id === currency.id)) {
39
+ recurring[key] = x.price.recurring;
40
+ }
32
41
  if (!grouped[key]) {
33
42
  grouped[key] = [];
34
43
  }
@@ -47,7 +56,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
47
56
  settings: { paymentMethods = [] }
48
57
  } = usePaymentContext();
49
58
  const [currency, setCurrency] = useState(table.currency || {});
50
- const { recurring, grouped } = groupItemsByRecurring(table.items);
59
+ const { recurring, grouped } = useMemo(() => groupItemsByRecurring(table.items, currency), [table.items, currency]);
51
60
  const [state, setState] = useSetState({ interval });
52
61
  const currencyMap = useMemo(() => {
53
62
  if (!paymentMethods || paymentMethods.length === 0) {
@@ -76,6 +85,15 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
76
85
  });
77
86
  return Object.keys(visited).map((x) => currencyMap[x]).filter((v) => v);
78
87
  }, [currencyMap, grouped, state.interval]);
88
+ const productList = useMemo(() => {
89
+ return (grouped[state.interval] || []).filter((x) => {
90
+ const price = getPriceUintAmountByCurrency(x.price, currency);
91
+ if (new BN(price).isZero() || !price) {
92
+ return false;
93
+ }
94
+ return true;
95
+ });
96
+ }, [grouped, state.interval, currency]);
79
97
  useEffect(() => {
80
98
  if (table) {
81
99
  if (!state.interval || !grouped[state.interval]) {
@@ -128,7 +146,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
128
146
  },
129
147
  children: [
130
148
  /* @__PURE__ */ jsxs("div", { className: "btn-row", children: [
131
- Object.keys(recurring).length > 1 && /* @__PURE__ */ jsx(
149
+ Object.keys(recurring).length > 0 && /* @__PURE__ */ jsx(
132
150
  ToggleButtonGroup,
133
151
  {
134
152
  size: "small",
@@ -169,7 +187,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
169
187
  ))
170
188
  }
171
189
  ),
172
- currencyList.length > 1 && /* @__PURE__ */ jsx(
190
+ currencyList.length > 0 && /* @__PURE__ */ jsx(
173
191
  Select,
174
192
  {
175
193
  value: currency?.id,
@@ -188,147 +206,145 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
188
206
  gap: "20px",
189
207
  justifyContent: alignItems === "center" ? "center" : "flex-start",
190
208
  className: "price-table-wrap",
191
- children: grouped[state.interval]?.map(
192
- (x) => {
193
- let action = x.subscription_data?.trial_period_days ? t("payment.checkout.try") : t("payment.checkout.subscription");
194
- if (mode === "select") {
195
- action = x.is_selected ? t("payment.checkout.selected") : t("payment.checkout.select");
196
- }
197
- return /* @__PURE__ */ jsxs(
198
- Stack,
199
- {
200
- padding: 4,
201
- spacing: 2,
202
- direction: "column",
203
- alignItems: "flex-start",
204
- className: "price-table-item",
205
- justifyContent: "flex-start",
206
- sx: {
207
- cursor: "pointer",
208
- borderWidth: "1px",
209
- borderStyle: "solid",
210
- borderColor: mode === "select" && x.is_selected ? "primary.main" : "#eee",
211
- borderRadius: 2,
212
- transition: "border-color 0.3s ease 0s, box-shadow 0.3s ease 0s",
213
- boxShadow: "0px 0px 0px 1px rgba(3, 7, 18, 0.08), 0px 1px 2px -1px rgba(3, 7, 18, 0.08), 0px 2px 4px rgba(3, 7, 18, 0.04)",
214
- "&:hover": {
215
- borderColor: mode === "select" && x.is_selected ? "primary.main" : "#ddd",
216
- boxShadow: "0 8px 16px rgba(0, 0, 0, 20%)"
217
- },
218
- width: "320px",
219
- maxWidth: "360px",
220
- padding: "20px",
221
- position: "relative"
209
+ children: productList?.map((x) => {
210
+ let action = x.subscription_data?.trial_period_days ? t("payment.checkout.try") : t("payment.checkout.subscription");
211
+ if (mode === "select") {
212
+ action = x.is_selected ? t("payment.checkout.selected") : t("payment.checkout.select");
213
+ }
214
+ return /* @__PURE__ */ jsxs(
215
+ Stack,
216
+ {
217
+ padding: 4,
218
+ spacing: 2,
219
+ direction: "column",
220
+ alignItems: "flex-start",
221
+ className: "price-table-item",
222
+ justifyContent: "flex-start",
223
+ sx: {
224
+ cursor: "pointer",
225
+ borderWidth: "1px",
226
+ borderStyle: "solid",
227
+ borderColor: mode === "select" && x.is_selected ? "primary.main" : "#eee",
228
+ borderRadius: 2,
229
+ transition: "border-color 0.3s ease 0s, box-shadow 0.3s ease 0s",
230
+ boxShadow: "0px 0px 0px 1px rgba(3, 7, 18, 0.08), 0px 1px 2px -1px rgba(3, 7, 18, 0.08), 0px 2px 4px rgba(3, 7, 18, 0.04)",
231
+ "&:hover": {
232
+ borderColor: mode === "select" && x.is_selected ? "primary.main" : "#ddd",
233
+ boxShadow: "0 8px 16px rgba(0, 0, 0, 20%)"
222
234
  },
223
- children: [
224
- /* @__PURE__ */ jsx(Box, { textAlign: "center", children: /* @__PURE__ */ jsxs(
225
- Stack,
226
- {
227
- direction: "column",
228
- justifyContent: "center",
229
- alignItems: "flex-start",
230
- spacing: 1,
231
- sx: { gap: "12px" },
232
- children: [
233
- /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
234
- /* @__PURE__ */ jsx(
235
- Typography,
236
- {
237
- color: "text.primary",
238
- fontWeight: 600,
239
- sx: {
240
- color: "#4B5563",
241
- fontSize: "18px !important",
242
- fontWeight: "600"
243
- },
244
- children: x.product.name
245
- }
246
- ),
247
- x.is_highlight && /* @__PURE__ */ jsx(
248
- Chip,
249
- {
250
- label: x.highlight_text,
251
- color: "default",
252
- size: "small",
253
- sx: {
254
- position: "absolute",
255
- top: "20px",
256
- right: "20px"
257
- }
258
- }
259
- )
260
- ] }),
235
+ width: "320px",
236
+ maxWidth: "360px",
237
+ padding: "20px",
238
+ position: "relative"
239
+ },
240
+ children: [
241
+ /* @__PURE__ */ jsx(Box, { textAlign: "center", children: /* @__PURE__ */ jsxs(
242
+ Stack,
243
+ {
244
+ direction: "column",
245
+ justifyContent: "center",
246
+ alignItems: "flex-start",
247
+ spacing: 1,
248
+ sx: { gap: "12px" },
249
+ children: [
250
+ /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
261
251
  /* @__PURE__ */ jsx(
262
- Amount,
252
+ Typography,
263
253
  {
264
- amount: formatPriceAmount(x.price, currency, x.product.unit_label),
265
- sx: { my: 0, marginTop: "0px !important", fontSize: "48px", fontWeight: "bold" }
254
+ color: "text.primary",
255
+ fontWeight: 600,
256
+ sx: {
257
+ color: "#4B5563",
258
+ fontSize: "18px !important",
259
+ fontWeight: "600"
260
+ },
261
+ children: x.product.name
266
262
  }
267
263
  ),
268
- /* @__PURE__ */ jsx(
269
- Typography,
264
+ x.is_highlight && /* @__PURE__ */ jsx(
265
+ Chip,
270
266
  {
271
- color: "text.secondary",
267
+ label: x.highlight_text,
268
+ color: "default",
269
+ size: "small",
272
270
  sx: {
273
- marginTop: "0px !important",
274
- color: "#4b5563",
275
- fontWeight: "400",
276
- fontSize: "16px",
277
- textAlign: "left"
278
- },
279
- children: x.product.description
271
+ position: "absolute",
272
+ top: "20px",
273
+ right: "20px"
274
+ }
280
275
  }
281
276
  )
282
- ]
283
- }
284
- ) }),
285
- x.product.features.length > 0 && /* @__PURE__ */ jsx(Box, { sx: { width: "100%" }, children: /* @__PURE__ */ jsxs(List, { dense: true, sx: { display: "flex", flexDirection: "column", gap: "16px", padding: "0px" }, children: [
286
- /* @__PURE__ */ jsx(
287
- Box,
288
- {
289
- sx: {
290
- width: "100%",
291
- position: "relative",
292
- borderTop: "1px solid #e5e7eb",
293
- boxSizing: "border-box",
294
- height: "1px"
295
- }
296
- }
297
- ),
298
- x.product.features.map((f) => /* @__PURE__ */ jsxs(ListItem, { disableGutters: true, disablePadding: true, sx: { fontSize: "16px !important" }, children: [
299
- /* @__PURE__ */ jsx(ListItemIcon, { sx: { minWidth: 25, color: "#059669", fontSize: "64px" }, children: /* @__PURE__ */ jsx(
300
- CheckOutlined,
277
+ ] }),
278
+ /* @__PURE__ */ jsx(
279
+ Amount,
301
280
  {
302
- color: "success",
303
- fontSize: "small",
304
- sx: {
305
- color: "#059669",
306
- fontSize: "18px"
307
- }
281
+ amount: formatPriceAmount(x.price, currency, x.product.unit_label),
282
+ sx: { my: 0, marginTop: "0px !important", fontSize: "48px", fontWeight: "bold" }
308
283
  }
309
- ) }),
284
+ ),
310
285
  /* @__PURE__ */ jsx(
311
- ListItemText,
286
+ Typography,
312
287
  {
288
+ color: "text.secondary",
313
289
  sx: {
314
- ".MuiListItemText-primary": {
315
- fontSize: "16px",
316
- color: "#030712",
317
- fontWeight: "500"
318
- }
290
+ marginTop: "0px !important",
291
+ color: "#4b5563",
292
+ fontWeight: "400",
293
+ fontSize: "16px",
294
+ textAlign: "left"
319
295
  },
320
- primary: f.name
296
+ children: x.product.description
321
297
  }
322
298
  )
323
- ] }, f.name))
324
- ] }) }),
325
- /* @__PURE__ */ jsx(Subscribe, { x, action, onSelect, currencyId: currency?.id })
326
- ]
327
- },
328
- x?.price_id
329
- );
330
- }
331
- )
299
+ ]
300
+ }
301
+ ) }),
302
+ x.product.features.length > 0 && /* @__PURE__ */ jsx(Box, { sx: { width: "100%" }, children: /* @__PURE__ */ jsxs(List, { dense: true, sx: { display: "flex", flexDirection: "column", gap: "16px", padding: "0px" }, children: [
303
+ /* @__PURE__ */ jsx(
304
+ Box,
305
+ {
306
+ sx: {
307
+ width: "100%",
308
+ position: "relative",
309
+ borderTop: "1px solid #e5e7eb",
310
+ boxSizing: "border-box",
311
+ height: "1px"
312
+ }
313
+ }
314
+ ),
315
+ x.product.features.map((f) => /* @__PURE__ */ jsxs(ListItem, { disableGutters: true, disablePadding: true, sx: { fontSize: "16px !important" }, children: [
316
+ /* @__PURE__ */ jsx(ListItemIcon, { sx: { minWidth: 25, color: "#059669", fontSize: "64px" }, children: /* @__PURE__ */ jsx(
317
+ CheckOutlined,
318
+ {
319
+ color: "success",
320
+ fontSize: "small",
321
+ sx: {
322
+ color: "#059669",
323
+ fontSize: "18px"
324
+ }
325
+ }
326
+ ) }),
327
+ /* @__PURE__ */ jsx(
328
+ ListItemText,
329
+ {
330
+ sx: {
331
+ ".MuiListItemText-primary": {
332
+ fontSize: "16px",
333
+ color: "#030712",
334
+ fontWeight: "500"
335
+ }
336
+ },
337
+ primary: f.name
338
+ }
339
+ )
340
+ ] }, f.name))
341
+ ] }) }),
342
+ /* @__PURE__ */ jsx(Subscribe, { x, action, onSelect, currencyId: currency?.id })
343
+ ]
344
+ },
345
+ x?.price_id
346
+ );
347
+ })
332
348
  }
333
349
  )
334
350
  ]
package/es/locales/en.js CHANGED
@@ -81,7 +81,8 @@ export default flat({
81
81
  weeks: "weeks",
82
82
  months: "months",
83
83
  years: "years",
84
- type: "type"
84
+ type: "type",
85
+ donation: "Donation"
85
86
  },
86
87
  payment: {
87
88
  checkout: {
package/es/locales/zh.js CHANGED
@@ -81,7 +81,8 @@ export default flat({
81
81
  weeks: "\u5468",
82
82
  months: "\u6708",
83
83
  years: "\u5E74",
84
- type: "\u7C7B\u578B"
84
+ type: "\u7C7B\u578B",
85
+ donation: "\u6253\u8D4F"
85
86
  },
86
87
  payment: {
87
88
  checkout: {
@@ -13,16 +13,19 @@ var _material = require("@mui/material");
13
13
  var _system = require("@mui/system");
14
14
  var _ahooks = require("ahooks");
15
15
  var _react = require("react");
16
+ var _util = require("@ocap/util");
16
17
  var _payment = require("../contexts/payment");
17
- var _util = require("../libs/util");
18
+ var _util2 = require("../libs/util");
18
19
  var _amount = _interopRequireDefault(require("../payment/amount"));
19
20
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20
- const groupItemsByRecurring = items => {
21
+ const groupItemsByRecurring = (items, currency) => {
21
22
  const grouped = {};
22
23
  const recurring = {};
23
24
  items.forEach(x => {
24
25
  const key = [x.price.recurring?.interval, x.price.recurring?.interval_count].join("-");
25
- recurring[key] = x.price.recurring;
26
+ if (x.price.currency_options.find(c => c.currency_id === currency.id)) {
27
+ recurring[key] = x.price.recurring;
28
+ }
26
29
  if (!grouped[key]) {
27
30
  grouped[key] = [];
28
31
  }
@@ -58,7 +61,7 @@ function PricingTable({
58
61
  const {
59
62
  recurring,
60
63
  grouped
61
- } = groupItemsByRecurring(table.items);
64
+ } = (0, _react.useMemo)(() => groupItemsByRecurring(table.items, currency), [table.items, currency]);
62
65
  const [state, setState] = (0, _ahooks.useSetState)({
63
66
  interval
64
67
  });
@@ -85,12 +88,21 @@ function PricingTable({
85
88
  return [];
86
89
  }
87
90
  grouped[state.interval].forEach(x => {
88
- (0, _util.getPriceCurrencyOptions)(x.price).forEach(c => {
91
+ (0, _util2.getPriceCurrencyOptions)(x.price).forEach(c => {
89
92
  visited[c?.currency_id] = true;
90
93
  });
91
94
  });
92
95
  return Object.keys(visited).map(x => currencyMap[x]).filter(v => v);
93
96
  }, [currencyMap, grouped, state.interval]);
97
+ const productList = (0, _react.useMemo)(() => {
98
+ return (grouped[state.interval] || []).filter(x => {
99
+ const price = (0, _util2.getPriceUintAmountByCurrency)(x.price, currency);
100
+ if (new _util.BN(price).isZero() || !price) {
101
+ return false;
102
+ }
103
+ return true;
104
+ });
105
+ }, [grouped, state.interval, currency]);
94
106
  (0, _react.useEffect)(() => {
95
107
  if (table) {
96
108
  if (!state.interval || !grouped[state.interval]) {
@@ -148,7 +160,7 @@ function PricingTable({
148
160
  },
149
161
  children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)("div", {
150
162
  className: "btn-row",
151
- children: [Object.keys(recurring).length > 1 && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.ToggleButtonGroup, {
163
+ children: [Object.keys(recurring).length > 0 && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.ToggleButtonGroup, {
152
164
  size: "small",
153
165
  value: state.interval,
154
166
  sx: {
@@ -181,9 +193,9 @@ function PricingTable({
181
193
  border: "1px solid #e5e7eb"
182
194
  }
183
195
  },
184
- children: (0, _util.formatRecurring)(recurring[x], true, "", locale)
196
+ children: (0, _util2.formatRecurring)(recurring[x], true, "", locale)
185
197
  }, x))
186
- }), currencyList.length > 1 && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Select, {
198
+ }), currencyList.length > 0 && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Select, {
187
199
  value: currency?.id,
188
200
  onChange: e => setCurrency(currencyList.find(v => v?.id === e.target.value)),
189
201
  size: "small",
@@ -205,7 +217,7 @@ function PricingTable({
205
217
  gap: "20px",
206
218
  justifyContent: alignItems === "center" ? "center" : "flex-start",
207
219
  className: "price-table-wrap",
208
- children: grouped[state.interval]?.map(x => {
220
+ children: productList?.map(x => {
209
221
  let action = x.subscription_data?.trial_period_days ? t("payment.checkout.try") : t("payment.checkout.subscription");
210
222
  if (mode === "select") {
211
223
  action = x.is_selected ? t("payment.checkout.selected") : t("payment.checkout.select");
@@ -270,7 +282,7 @@ function PricingTable({
270
282
  }
271
283
  })]
272
284
  }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_amount.default, {
273
- amount: (0, _util.formatPriceAmount)(x.price, currency, x.product.unit_label),
285
+ amount: (0, _util2.formatPriceAmount)(x.price, currency, x.product.unit_label),
274
286
  sx: {
275
287
  my: 0,
276
288
  marginTop: "0px !important",
@@ -372,7 +384,7 @@ function Subscribe({
372
384
  await onSelect(priceId, currencyId);
373
385
  } catch (err) {
374
386
  console.error(err);
375
- _Toast.default.error((0, _util.formatError)(err));
387
+ _Toast.default.error((0, _util2.formatError)(err));
376
388
  }
377
389
  };
378
390
  return /* @__PURE__ */(0, _jsxRuntime.jsx)(_lab.LoadingButton, {
package/lib/locales/en.js CHANGED
@@ -88,7 +88,8 @@ module.exports = (0, _flat.default)({
88
88
  weeks: "weeks",
89
89
  months: "months",
90
90
  years: "years",
91
- type: "type"
91
+ type: "type",
92
+ donation: "Donation"
92
93
  },
93
94
  payment: {
94
95
  checkout: {
package/lib/locales/zh.js CHANGED
@@ -88,7 +88,8 @@ module.exports = (0, _flat.default)({
88
88
  weeks: "\u5468",
89
89
  months: "\u6708",
90
90
  years: "\u5E74",
91
- type: "\u7C7B\u578B"
91
+ type: "\u7C7B\u578B",
92
+ donation: "\u6253\u8D4F"
92
93
  },
93
94
  payment: {
94
95
  checkout: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.13.287",
3
+ "version": "1.13.289",
4
4
  "description": "Reusable react components for payment kit v2",
5
5
  "keywords": [
6
6
  "react",
@@ -91,7 +91,7 @@
91
91
  "@babel/core": "^7.24.7",
92
92
  "@babel/preset-env": "^7.24.7",
93
93
  "@babel/preset-react": "^7.24.7",
94
- "@blocklet/payment-types": "1.13.287",
94
+ "@blocklet/payment-types": "1.13.289",
95
95
  "@storybook/addon-essentials": "^7.6.19",
96
96
  "@storybook/addon-interactions": "^7.6.19",
97
97
  "@storybook/addon-links": "^7.6.19",
@@ -120,5 +120,5 @@
120
120
  "vite-plugin-babel": "^1.2.0",
121
121
  "vite-plugin-node-polyfills": "^0.21.0"
122
122
  },
123
- "gitHead": "a0dac51aff70028e5996af607181e285ea2bb770"
123
+ "gitHead": "23a533f8752c9ad24d199562ccbae166e992a713"
124
124
  }
@@ -22,18 +22,26 @@ import { styled } from '@mui/system';
22
22
  import { useSetState } from 'ahooks';
23
23
  import { useEffect, useMemo, useState } from 'react';
24
24
 
25
+ import { BN } from '@ocap/util';
25
26
  import { usePaymentContext } from '../contexts/payment';
26
- import { formatError, formatPriceAmount, formatRecurring, getPriceCurrencyOptions } from '../libs/util';
27
+ import {
28
+ formatError,
29
+ formatPriceAmount,
30
+ formatRecurring,
31
+ getPriceCurrencyOptions,
32
+ getPriceUintAmountByCurrency,
33
+ } from '../libs/util';
27
34
  import Amount from '../payment/amount';
28
35
 
29
- const groupItemsByRecurring = (items: TPricingTableItem[]) => {
36
+ const groupItemsByRecurring = (items: TPricingTableItem[], currency: { id: string; symbol: string }) => {
30
37
  const grouped: { [key: string]: TPricingTableItem[] } = {};
31
38
  const recurring: { [key: string]: PriceRecurring } = {};
32
39
 
33
40
  items.forEach((x) => {
34
41
  const key = [x.price.recurring?.interval, x.price.recurring?.interval_count].join('-');
35
- recurring[key] = x.price.recurring as PriceRecurring;
36
-
42
+ if (x.price.currency_options.find((c: PriceCurrency) => c.currency_id === currency.id)) {
43
+ recurring[key] = x.price.recurring as PriceRecurring;
44
+ }
37
45
  if (!grouped[key]) {
38
46
  grouped[key] = [];
39
47
  }
@@ -65,7 +73,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
65
73
  settings: { paymentMethods = [] },
66
74
  } = usePaymentContext();
67
75
  const [currency, setCurrency] = useState(table.currency || {});
68
- const { recurring, grouped } = groupItemsByRecurring(table.items);
76
+ const { recurring, grouped } = useMemo(() => groupItemsByRecurring(table.items, currency), [table.items, currency]);
69
77
  const [state, setState] = useSetState({ interval });
70
78
  const currencyMap = useMemo(() => {
71
79
  if (!paymentMethods || paymentMethods.length === 0) {
@@ -97,6 +105,15 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
97
105
  .map((x) => currencyMap[x])
98
106
  .filter((v) => v);
99
107
  }, [currencyMap, grouped, state.interval]);
108
+ const productList = useMemo(() => {
109
+ return (grouped[state.interval as string] || []).filter((x: TPricingTableItem) => {
110
+ const price = getPriceUintAmountByCurrency(x.price, currency);
111
+ if (new BN(price).isZero() || !price) {
112
+ return false;
113
+ }
114
+ return true;
115
+ });
116
+ }, [grouped, state.interval, currency]);
100
117
 
101
118
  useEffect(() => {
102
119
  if (table) {
@@ -151,7 +168,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
151
168
  },
152
169
  }}>
153
170
  <div className="btn-row">
154
- {Object.keys(recurring).length > 1 && (
171
+ {Object.keys(recurring).length > 0 && (
155
172
  <ToggleButtonGroup
156
173
  size="small"
157
174
  value={state.interval}
@@ -190,7 +207,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
190
207
  ))}
191
208
  </ToggleButtonGroup>
192
209
  )}
193
- {currencyList.length > 1 && (
210
+ {currencyList.length > 0 && (
194
211
  <Select
195
212
  value={currency?.id}
196
213
  onChange={(e) => setCurrency(currencyList.find((v) => v?.id === e.target.value))}
@@ -212,135 +229,132 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
212
229
  gap="20px"
213
230
  justifyContent={alignItems === 'center' ? 'center' : 'flex-start'}
214
231
  className="price-table-wrap">
215
- {grouped[state.interval as string]?.map(
216
- (x: TPricingTableItem & { is_selected?: boolean; is_disabled?: boolean }) => {
217
- let action: string = x.subscription_data?.trial_period_days
218
- ? t('payment.checkout.try')
219
- : t('payment.checkout.subscription');
220
- if (mode === 'select') {
221
- action = x.is_selected ? t('payment.checkout.selected') : t('payment.checkout.select');
222
- }
223
-
224
- return (
225
- <Stack
226
- key={x?.price_id}
227
- padding={4}
228
- spacing={2}
229
- direction="column"
230
- alignItems="flex-start"
231
- className="price-table-item"
232
- justifyContent="flex-start"
233
- sx={{
234
- cursor: 'pointer',
235
- borderWidth: '1px',
236
- borderStyle: 'solid',
237
- borderColor: mode === 'select' && x.is_selected ? 'primary.main' : '#eee',
238
- borderRadius: 2,
239
- transition: 'border-color 0.3s ease 0s, box-shadow 0.3s ease 0s',
240
- boxShadow:
241
- '0px 0px 0px 1px rgba(3, 7, 18, 0.08), 0px 1px 2px -1px rgba(3, 7, 18, 0.08), 0px 2px 4px rgba(3, 7, 18, 0.04)',
242
- '&:hover': {
243
- borderColor: mode === 'select' && x.is_selected ? 'primary.main' : '#ddd',
244
- boxShadow: '0 8px 16px rgba(0, 0, 0, 20%)',
245
- },
246
- width: '320px',
247
- maxWidth: '360px',
232
+ {productList?.map((x: TPricingTableItem & { is_selected?: boolean; is_disabled?: boolean }) => {
233
+ let action: string = x.subscription_data?.trial_period_days
234
+ ? t('payment.checkout.try')
235
+ : t('payment.checkout.subscription');
236
+ if (mode === 'select') {
237
+ action = x.is_selected ? t('payment.checkout.selected') : t('payment.checkout.select');
238
+ }
239
+ return (
240
+ <Stack
241
+ key={x?.price_id}
242
+ padding={4}
243
+ spacing={2}
244
+ direction="column"
245
+ alignItems="flex-start"
246
+ className="price-table-item"
247
+ justifyContent="flex-start"
248
+ sx={{
249
+ cursor: 'pointer',
250
+ borderWidth: '1px',
251
+ borderStyle: 'solid',
252
+ borderColor: mode === 'select' && x.is_selected ? 'primary.main' : '#eee',
253
+ borderRadius: 2,
254
+ transition: 'border-color 0.3s ease 0s, box-shadow 0.3s ease 0s',
255
+ boxShadow:
256
+ '0px 0px 0px 1px rgba(3, 7, 18, 0.08), 0px 1px 2px -1px rgba(3, 7, 18, 0.08), 0px 2px 4px rgba(3, 7, 18, 0.04)',
257
+ '&:hover': {
258
+ borderColor: mode === 'select' && x.is_selected ? 'primary.main' : '#ddd',
259
+ boxShadow: '0 8px 16px rgba(0, 0, 0, 20%)',
260
+ },
261
+ width: '320px',
262
+ maxWidth: '360px',
248
263
 
249
- padding: '20px',
250
- position: 'relative',
251
- }}>
252
- <Box textAlign="center">
253
- <Stack
254
- direction="column"
255
- justifyContent="center"
256
- alignItems="flex-start"
257
- spacing={1}
258
- sx={{ gap: '12px' }}>
259
- <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
260
- <Typography
261
- color="text.primary"
262
- fontWeight={600}
263
- sx={{
264
- color: '#4B5563',
265
- fontSize: '18px !important',
266
- fontWeight: '600',
267
- }}>
268
- {x.product.name}
269
- </Typography>
270
- {x.is_highlight && (
271
- <Chip
272
- label={x.highlight_text}
273
- color="default"
274
- size="small"
275
- sx={{
276
- position: 'absolute',
277
- top: '20px',
278
- right: '20px',
279
- }}
280
- />
281
- )}
282
- </Box>
283
- <Amount
284
- amount={formatPriceAmount(x.price, currency, x.product.unit_label)}
285
- sx={{ my: 0, marginTop: '0px !important', fontSize: '48px', fontWeight: 'bold' }}
286
- />
264
+ padding: '20px',
265
+ position: 'relative',
266
+ }}>
267
+ <Box textAlign="center">
268
+ <Stack
269
+ direction="column"
270
+ justifyContent="center"
271
+ alignItems="flex-start"
272
+ spacing={1}
273
+ sx={{ gap: '12px' }}>
274
+ <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
287
275
  <Typography
288
- color="text.secondary"
276
+ color="text.primary"
277
+ fontWeight={600}
289
278
  sx={{
290
- marginTop: '0px !important',
291
- color: '#4b5563',
292
- fontWeight: '400',
293
- fontSize: '16px',
294
- textAlign: 'left',
279
+ color: '#4B5563',
280
+ fontSize: '18px !important',
281
+ fontWeight: '600',
295
282
  }}>
296
- {x.product.description}
283
+ {x.product.name}
297
284
  </Typography>
298
- </Stack>
299
- </Box>
300
- {x.product.features.length > 0 && (
301
- <Box sx={{ width: '100%' }}>
302
- <List dense sx={{ display: 'flex', flexDirection: 'column', gap: '16px', padding: '0px' }}>
303
- <Box
285
+ {x.is_highlight && (
286
+ <Chip
287
+ label={x.highlight_text}
288
+ color="default"
289
+ size="small"
304
290
  sx={{
305
- width: '100%',
306
- position: 'relative',
307
- borderTop: '1px solid #e5e7eb',
308
- boxSizing: 'border-box',
309
- height: '1px',
291
+ position: 'absolute',
292
+ top: '20px',
293
+ right: '20px',
310
294
  }}
311
295
  />
312
- {x.product.features.map((f: any) => (
313
- <ListItem key={f.name} disableGutters disablePadding sx={{ fontSize: '16px !important' }}>
314
- <ListItemIcon sx={{ minWidth: 25, color: '#059669', fontSize: '64px' }}>
315
- <CheckOutlined
316
- color="success"
317
- fontSize="small"
318
- sx={{
319
- color: '#059669',
320
- fontSize: '18px',
321
- }}
322
- />
323
- </ListItemIcon>
324
- <ListItemText
296
+ )}
297
+ </Box>
298
+ <Amount
299
+ amount={formatPriceAmount(x.price, currency, x.product.unit_label)}
300
+ sx={{ my: 0, marginTop: '0px !important', fontSize: '48px', fontWeight: 'bold' }}
301
+ />
302
+ <Typography
303
+ color="text.secondary"
304
+ sx={{
305
+ marginTop: '0px !important',
306
+ color: '#4b5563',
307
+ fontWeight: '400',
308
+ fontSize: '16px',
309
+ textAlign: 'left',
310
+ }}>
311
+ {x.product.description}
312
+ </Typography>
313
+ </Stack>
314
+ </Box>
315
+ {x.product.features.length > 0 && (
316
+ <Box sx={{ width: '100%' }}>
317
+ <List dense sx={{ display: 'flex', flexDirection: 'column', gap: '16px', padding: '0px' }}>
318
+ <Box
319
+ sx={{
320
+ width: '100%',
321
+ position: 'relative',
322
+ borderTop: '1px solid #e5e7eb',
323
+ boxSizing: 'border-box',
324
+ height: '1px',
325
+ }}
326
+ />
327
+ {x.product.features.map((f: any) => (
328
+ <ListItem key={f.name} disableGutters disablePadding sx={{ fontSize: '16px !important' }}>
329
+ <ListItemIcon sx={{ minWidth: 25, color: '#059669', fontSize: '64px' }}>
330
+ <CheckOutlined
331
+ color="success"
332
+ fontSize="small"
325
333
  sx={{
326
- '.MuiListItemText-primary': {
327
- fontSize: '16px',
328
- color: '#030712',
329
- fontWeight: '500',
330
- },
334
+ color: '#059669',
335
+ fontSize: '18px',
331
336
  }}
332
- primary={f.name}
333
337
  />
334
- </ListItem>
335
- ))}
336
- </List>
337
- </Box>
338
- )}
339
- <Subscribe x={x} action={action} onSelect={onSelect} currencyId={currency?.id} />
340
- </Stack>
341
- );
342
- }
343
- )}
338
+ </ListItemIcon>
339
+ <ListItemText
340
+ sx={{
341
+ '.MuiListItemText-primary': {
342
+ fontSize: '16px',
343
+ color: '#030712',
344
+ fontWeight: '500',
345
+ },
346
+ }}
347
+ primary={f.name}
348
+ />
349
+ </ListItem>
350
+ ))}
351
+ </List>
352
+ </Box>
353
+ )}
354
+ <Subscribe x={x} action={action} onSelect={onSelect} currencyId={currency?.id} />
355
+ </Stack>
356
+ );
357
+ })}
344
358
  </Stack>
345
359
  </Stack>
346
360
  </Root>
@@ -84,6 +84,7 @@ export default flat({
84
84
  months: 'months',
85
85
  years: 'years',
86
86
  type: 'type',
87
+ donation: 'Donation',
87
88
  },
88
89
  payment: {
89
90
  checkout: {
@@ -84,6 +84,7 @@ export default flat({
84
84
  months: '月',
85
85
  years: '年',
86
86
  type: '类型',
87
+ donation: '打赏',
87
88
  },
88
89
  payment: {
89
90
  checkout: {