@blocklet/payment-react 1.19.0 → 1.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/es/components/blockchain/tx.d.ts +1 -1
  2. package/es/components/blockchain/tx.js +9 -11
  3. package/es/components/country-select.d.ts +1 -1
  4. package/es/components/date-range-picker.d.ts +13 -0
  5. package/es/components/date-range-picker.js +279 -0
  6. package/es/components/input.d.ts +5 -2
  7. package/es/components/input.js +6 -2
  8. package/es/components/label.d.ts +7 -0
  9. package/es/components/label.js +49 -0
  10. package/es/components/loading-button.d.ts +1 -1
  11. package/es/history/credit/grants-list.d.ts +14 -0
  12. package/es/history/credit/grants-list.js +215 -0
  13. package/es/history/credit/transactions-list.d.ts +13 -0
  14. package/es/history/credit/transactions-list.js +255 -0
  15. package/es/history/invoice/list.js +21 -1
  16. package/es/index.d.ts +5 -1
  17. package/es/index.js +10 -1
  18. package/es/libs/util.d.ts +2 -0
  19. package/es/libs/util.js +12 -0
  20. package/es/locales/en.js +20 -2
  21. package/es/locales/zh.js +20 -2
  22. package/es/payment/form/index.js +44 -6
  23. package/es/payment/index.js +18 -3
  24. package/es/payment/product-item.d.ts +8 -1
  25. package/es/payment/product-item.js +137 -5
  26. package/es/payment/summary.d.ts +3 -1
  27. package/es/payment/summary.js +9 -0
  28. package/lib/components/blockchain/tx.d.ts +1 -1
  29. package/lib/components/blockchain/tx.js +9 -8
  30. package/lib/components/country-select.d.ts +1 -1
  31. package/lib/components/date-range-picker.d.ts +13 -0
  32. package/lib/components/date-range-picker.js +329 -0
  33. package/lib/components/input.d.ts +5 -2
  34. package/lib/components/input.js +8 -4
  35. package/lib/components/label.d.ts +7 -0
  36. package/lib/components/label.js +60 -0
  37. package/lib/components/loading-button.d.ts +1 -1
  38. package/lib/history/credit/grants-list.d.ts +14 -0
  39. package/lib/history/credit/grants-list.js +277 -0
  40. package/lib/history/credit/transactions-list.d.ts +13 -0
  41. package/lib/history/credit/transactions-list.js +301 -0
  42. package/lib/history/invoice/list.js +24 -0
  43. package/lib/index.d.ts +5 -1
  44. package/lib/index.js +39 -0
  45. package/lib/libs/util.d.ts +2 -0
  46. package/lib/libs/util.js +14 -0
  47. package/lib/locales/en.js +20 -2
  48. package/lib/locales/zh.js +20 -2
  49. package/lib/payment/form/index.js +45 -6
  50. package/lib/payment/index.js +20 -2
  51. package/lib/payment/product-item.d.ts +8 -1
  52. package/lib/payment/product-item.js +144 -4
  53. package/lib/payment/summary.d.ts +3 -1
  54. package/lib/payment/summary.js +9 -0
  55. package/package.json +3 -3
  56. package/src/components/blockchain/tx.tsx +9 -15
  57. package/src/components/country-select.tsx +2 -2
  58. package/src/components/date-range-picker.tsx +310 -0
  59. package/src/components/input.tsx +14 -3
  60. package/src/components/label.tsx +58 -0
  61. package/src/components/loading-button.tsx +1 -1
  62. package/src/history/credit/grants-list.tsx +276 -0
  63. package/src/history/credit/transactions-list.tsx +317 -0
  64. package/src/history/invoice/list.tsx +18 -1
  65. package/src/index.ts +9 -0
  66. package/src/libs/util.ts +14 -0
  67. package/src/locales/en.tsx +20 -0
  68. package/src/locales/zh.tsx +19 -0
  69. package/src/payment/form/address.tsx +2 -2
  70. package/src/payment/form/index.tsx +110 -52
  71. package/src/payment/index.tsx +17 -1
  72. package/src/payment/product-item.tsx +152 -4
  73. package/src/payment/summary.tsx +13 -2
package/lib/index.js CHANGED
@@ -12,6 +12,7 @@ var _exportNames = {
12
12
  TxLink: true,
13
13
  ConfirmDialog: true,
14
14
  FormInput: true,
15
+ FormLabel: true,
15
16
  Livemode: true,
16
17
  PricingTable: true,
17
18
  Table: true,
@@ -20,6 +21,9 @@ var _exportNames = {
20
21
  Switch: true,
21
22
  CustomerInvoiceList: true,
22
23
  CustomerPaymentList: true,
24
+ CreditGrantsList: true,
25
+ CreditStatusChip: true,
26
+ CreditTransactionsList: true,
23
27
  api: true,
24
28
  dayjs: true,
25
29
  Amount: true,
@@ -39,6 +43,7 @@ var _exportNames = {
39
43
  PaymentBeneficiaries: true,
40
44
  LoadingButton: true,
41
45
  ResumeSubscription: true,
46
+ DateRangePicker: true,
42
47
  PaymentThemeProvider: true,
43
48
  translations: true,
44
49
  createTranslator: true
@@ -85,6 +90,24 @@ Object.defineProperty(exports, "CountrySelect", {
85
90
  return _countrySelect.default;
86
91
  }
87
92
  });
93
+ Object.defineProperty(exports, "CreditGrantsList", {
94
+ enumerable: true,
95
+ get: function () {
96
+ return _grantsList.default;
97
+ }
98
+ });
99
+ Object.defineProperty(exports, "CreditStatusChip", {
100
+ enumerable: true,
101
+ get: function () {
102
+ return _grantsList.StatusChip;
103
+ }
104
+ });
105
+ Object.defineProperty(exports, "CreditTransactionsList", {
106
+ enumerable: true,
107
+ get: function () {
108
+ return _transactionsList.default;
109
+ }
110
+ });
88
111
  Object.defineProperty(exports, "CurrencySelector", {
89
112
  enumerable: true,
90
113
  get: function () {
@@ -103,6 +126,12 @@ Object.defineProperty(exports, "CustomerPaymentList", {
103
126
  return _list2.default;
104
127
  }
105
128
  });
129
+ Object.defineProperty(exports, "DateRangePicker", {
130
+ enumerable: true,
131
+ get: function () {
132
+ return _dateRangePicker.default;
133
+ }
134
+ });
106
135
  Object.defineProperty(exports, "DonateDetails", {
107
136
  enumerable: true,
108
137
  get: function () {
@@ -115,6 +144,12 @@ Object.defineProperty(exports, "FormInput", {
115
144
  return _input.default;
116
145
  }
117
146
  });
147
+ Object.defineProperty(exports, "FormLabel", {
148
+ enumerable: true,
149
+ get: function () {
150
+ return _label.default;
151
+ }
152
+ });
118
153
  Object.defineProperty(exports, "Link", {
119
154
  enumerable: true,
120
155
  get: function () {
@@ -278,6 +313,7 @@ var _gas = _interopRequireDefault(require("./components/blockchain/gas"));
278
313
  var _tx = _interopRequireDefault(require("./components/blockchain/tx"));
279
314
  var _confirm = _interopRequireDefault(require("./components/confirm"));
280
315
  var _input = _interopRequireDefault(require("./components/input"));
316
+ var _label = _interopRequireDefault(require("./components/label"));
281
317
  var _livemode = _interopRequireDefault(require("./components/livemode"));
282
318
  var _pricingTable = _interopRequireDefault(require("./components/pricing-table"));
283
319
  var _table2 = _interopRequireDefault(require("./components/table"));
@@ -286,6 +322,8 @@ var _status = _interopRequireDefault(require("./components/status"));
286
322
  var _switchButton = _interopRequireDefault(require("./components/switch-button"));
287
323
  var _list = _interopRequireDefault(require("./history/invoice/list"));
288
324
  var _list2 = _interopRequireDefault(require("./history/payment/list"));
325
+ var _grantsList = _interopRequireWildcard(require("./history/credit/grants-list"));
326
+ var _transactionsList = _interopRequireDefault(require("./history/credit/transactions-list"));
289
327
  var _api = _interopRequireDefault(require("./libs/api"));
290
328
  var _dayjs = _interopRequireDefault(require("./libs/dayjs"));
291
329
  var _amount = _interopRequireDefault(require("./payment/amount"));
@@ -305,6 +343,7 @@ var _overDueInvoicePayment = _interopRequireDefault(require("./components/over-d
305
343
  var _paymentBeneficiaries = _interopRequireDefault(require("./components/payment-beneficiaries"));
306
344
  var _loadingButton = _interopRequireDefault(require("./components/loading-button"));
307
345
  var _resumeSubscription = _interopRequireDefault(require("./components/resume-subscription"));
346
+ var _dateRangePicker = _interopRequireDefault(require("./components/date-range-picker"));
308
347
  var _theme = require("./theme");
309
348
  var _util = require("./libs/util");
310
349
  Object.keys(_util).forEach(function (key) {
@@ -129,3 +129,5 @@ export declare function parseMarkedText(text: string): Array<{
129
129
  content: string;
130
130
  }>;
131
131
  export declare function getTokenBalanceLink(method: TPaymentMethod, address: string): string;
132
+ export declare function isCreditMetered(price: TPrice): boolean;
133
+ export declare function showStaking(method: TPaymentMethod, currency: TPaymentCurrency, noStake: boolean): boolean;
package/lib/libs/util.js CHANGED
@@ -53,6 +53,7 @@ exports.getWebhookStatusColor = getWebhookStatusColor;
53
53
  exports.getWordBreakStyle = getWordBreakStyle;
54
54
  exports.hasDelegateTxHash = hasDelegateTxHash;
55
55
  exports.hasMultipleRecurringIntervals = hasMultipleRecurringIntervals;
56
+ exports.isCreditMetered = isCreditMetered;
56
57
  exports.isCrossOrigin = isCrossOrigin;
57
58
  exports.isMobileSafari = isMobileSafari;
58
59
  exports.isPaymentKitMounted = void 0;
@@ -61,6 +62,7 @@ exports.lazyLoad = lazyLoad;
61
62
  exports.mergeExtraParams = void 0;
62
63
  exports.openDonationSettings = openDonationSettings;
63
64
  exports.parseMarkedText = parseMarkedText;
65
+ exports.showStaking = showStaking;
64
66
  exports.sleep = sleep;
65
67
  exports.stopEvent = stopEvent;
66
68
  exports.truncateText = truncateText;
@@ -1232,4 +1234,16 @@ function getTokenBalanceLink(method, address) {
1232
1234
  return (0, _ufo.joinURL)(explorerHost, "address", address);
1233
1235
  }
1234
1236
  return "";
1237
+ }
1238
+ function isCreditMetered(price) {
1239
+ return !!(price.type === "recurring" && price.recurring?.usage_type === "metered" && price.recurring?.meter_id);
1240
+ }
1241
+ function showStaking(method, currency, noStake) {
1242
+ if (noStake) {
1243
+ return false;
1244
+ }
1245
+ if (method.type === "arcblock") {
1246
+ return currency.type !== "credit";
1247
+ }
1248
+ return true;
1235
1249
  }
package/lib/locales/en.js CHANGED
@@ -35,6 +35,10 @@ module.exports = (0, _flat.default)({
35
35
  remove: "Remove",
36
36
  removed: "Resource removed",
37
37
  confirm: "Confirm",
38
+ clear: "Clear",
39
+ selectTimeRange: "Select time range",
40
+ startDate: "Start date",
41
+ endDate: "End date",
38
42
  upload: "Upload",
39
43
  change: "Change",
40
44
  cancel: "Cancel",
@@ -107,7 +111,8 @@ module.exports = (0, _flat.default)({
107
111
  scan: "Use following methods to complete this {action}",
108
112
  confirm: "Confirm",
109
113
  cancel: "Cancel"
110
- }
114
+ },
115
+ paymentMethod: "Payment Method"
111
116
  },
112
117
  payment: {
113
118
  checkout: {
@@ -211,6 +216,11 @@ module.exports = (0, _flat.default)({
211
216
  add: "Add to order",
212
217
  remove: "Remove from order"
213
218
  },
219
+ credit: {
220
+ oneTimeInfo: "You will receive {amount} {symbol} credits after payment",
221
+ recurringInfo: "You will receive {amount} {symbol} credits {period}",
222
+ expiresIn: "credits have a validity period of {duration} {unit}"
223
+ },
214
224
  expired: {
215
225
  title: "Expired Link",
216
226
  description: "This link has expired. This means that your payment has already been processed or your session has expired."
@@ -239,7 +249,15 @@ module.exports = (0, _flat.default)({
239
249
  payer: "Account",
240
250
  amount: "Amount",
241
251
  failed: "Account changed, please pay manually.",
242
- balanceLink: "View Balance"
252
+ balanceLink: "View Balance",
253
+ credit: {
254
+ title: "Confirm Credit Payment",
255
+ availableAmount: "Available Credit: {amount}",
256
+ confirmMessage: "You will use {amount} credits to subscribe to this service.",
257
+ meteringSubscriptionMessage: "This subscription service will deduct credits in real-time based on actual usage. You currently have {available} credits available. Confirm to continue?",
258
+ insufficientTitle: "Insufficient Credit",
259
+ insufficientMessage: "This subscription service will deduct credits in real-time based on actual usage. You currently have insufficient credits. Please top up your credits first."
260
+ }
243
261
  }
244
262
  },
245
263
  customer: {
package/lib/locales/zh.js CHANGED
@@ -38,6 +38,10 @@ module.exports = (0, _flat.default)({
38
38
  change: "\u66F4\u6362",
39
39
  confirm: "\u786E\u8BA4",
40
40
  cancel: "\u53D6\u6D88",
41
+ clear: "\u6E05\u7A7A",
42
+ selectTimeRange: "\u9009\u62E9\u65F6\u95F4\u8303\u56F4",
43
+ startDate: "\u5F00\u59CB\u65E5\u671F",
44
+ endDate: "\u7ED3\u675F\u65E5\u671F",
41
45
  close: "\u5173\u95ED",
42
46
  back: "\u8FD4\u56DE",
43
47
  every: "\u6BCF",
@@ -107,7 +111,8 @@ module.exports = (0, _flat.default)({
107
111
  scan: "\u4F7F\u7528\u4EE5\u4E0B\u65B9\u5F0F\u5B8C\u6210\u672C\u6B21{action}",
108
112
  confirm: "\u786E\u8BA4",
109
113
  cancel: "\u53D6\u6D88"
110
- }
114
+ },
115
+ paymentMethod: "\u652F\u4ED8\u65B9\u5F0F"
111
116
  },
112
117
  payment: {
113
118
  checkout: {
@@ -219,6 +224,11 @@ module.exports = (0, _flat.default)({
219
224
  add: "\u6DFB\u52A0\u5230\u8BA2\u5355",
220
225
  remove: "\u4ECE\u8BA2\u5355\u79FB\u9664"
221
226
  },
227
+ credit: {
228
+ oneTimeInfo: "\u4ED8\u6B3E\u5B8C\u6210\u540E\u60A8\u5C06\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
229
+ recurringInfo: "\u60A8\u5C06{period}\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
230
+ expiresIn: "\u989D\u5EA6\u6709\u6548\u671F\u4E3A {duration} {unit}"
231
+ },
222
232
  emptyItems: {
223
233
  title: "\u6CA1\u6709\u4EFB\u4F55\u8D2D\u4E70\u9879\u76EE",
224
234
  description: "\u53EF\u80FD\u8FD9\u4E2A\u4ED8\u6B3E\u94FE\u63A5\u6CA1\u6709\u6B63\u786E\u914D\u7F6E"
@@ -239,7 +249,15 @@ module.exports = (0, _flat.default)({
239
249
  payer: "\u8D26\u6237\u5730\u5740",
240
250
  amount: "\u652F\u4ED8\u91D1\u989D",
241
251
  failed: "\u8D26\u6237\u53D1\u751F\u53D8\u5316\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5B8C\u6210\u652F\u4ED8\uFF0C\u8BF7\u624B\u52A8\u652F\u4ED8\u3002",
242
- balanceLink: "\u67E5\u770B\u4F59\u989D"
252
+ balanceLink: "\u67E5\u770B\u4F59\u989D",
253
+ credit: {
254
+ title: "\u786E\u8BA4\u989D\u5EA6\u652F\u4ED8",
255
+ availableAmount: "\u53EF\u7528\u989D\u5EA6\uFF1A{amount}",
256
+ confirmMessage: "\u60A8\u5C06\u4F7F\u7528 {amount} \u989D\u5EA6\u6765\u8BA2\u9605\u6B64\u670D\u52A1\u3002",
257
+ meteringSubscriptionMessage: "\u6B64\u8BA2\u9605\u670D\u52A1\u5C06\u6839\u636E\u5B9E\u9645\u4F7F\u7528\u60C5\u51B5\u5B9E\u65F6\u6263\u9664\u989D\u5EA6\u3002\u60A8\u5F53\u524D\u53EF\u7528\u989D\u5EA6\u4E3A {available}\uFF0C\u786E\u8BA4\u662F\u5426\u7EE7\u7EED\uFF1F",
258
+ insufficientTitle: "\u989D\u5EA6\u4E0D\u8DB3",
259
+ insufficientMessage: "\u6B64\u8BA2\u9605\u670D\u52A1\u5C06\u6839\u636E\u5B9E\u9645\u4F7F\u7528\u60C5\u51B5\u5B9E\u65F6\u6263\u9664\u989D\u5EA6\u3002\u60A8\u5F53\u524D\u53EF\u7528\u989D\u5EA6\u4E0D\u8DB3\uFF0C\u8BF7\u5148\u5145\u503C\u989D\u5EA6\u3002"
260
+ }
243
261
  }
244
262
  },
245
263
  customer: {
@@ -154,7 +154,8 @@ function PaymentForm({
154
154
  customer,
155
155
  customerLimited: false,
156
156
  stripePaying: false,
157
- fastCheckoutInfo: null
157
+ fastCheckoutInfo: null,
158
+ creditInsufficientInfo: null
158
159
  });
159
160
  const currencies = (0, _util2.flattenPaymentMethods)(paymentMethods);
160
161
  const onCheckoutComplete = (0, _ahooks.useMemoizedFn)(async ({
@@ -346,6 +347,11 @@ function PaymentForm({
346
347
  fastCheckoutInfo: null
347
348
  });
348
349
  };
350
+ const handleCreditInsufficientClose = () => {
351
+ setState({
352
+ creditInsufficientInfo: null
353
+ });
354
+ };
349
355
  const openConnect = () => {
350
356
  try {
351
357
  if (!["arcblock", "ethereum", "base"].includes(method.type)) {
@@ -416,7 +422,27 @@ function PaymentForm({
416
422
  customerLimited: false
417
423
  });
418
424
  if (["arcblock", "ethereum", "base"].includes(method.type)) {
419
- if ((result.data.balance?.sufficient || result.data.delegation?.sufficient) && !isDonationMode && result.data.fastPayInfo) {
425
+ if (paymentCurrency?.type === "credit") {
426
+ if (result.data.creditSufficient === true) {
427
+ setState({
428
+ fastCheckoutInfo: {
429
+ open: true,
430
+ loading: false,
431
+ sourceType: "credit",
432
+ amount: result.data.fastPayInfo?.amount || "0",
433
+ payer: result.data.fastPayInfo?.payer,
434
+ availableCredit: result.data.fastPayInfo?.amount || "0",
435
+ balance: result.data.fastPayInfo?.token?.balance || "0"
436
+ }
437
+ });
438
+ } else {
439
+ setState({
440
+ creditInsufficientInfo: {
441
+ open: true
442
+ }
443
+ });
444
+ }
445
+ } else if ((result.data.balance?.sufficient || result.data.delegation?.sufficient) && !isDonationMode && result.data.fastPayInfo) {
420
446
  setState({
421
447
  fastCheckoutInfo: {
422
448
  open: true,
@@ -525,8 +551,12 @@ function PaymentForm({
525
551
  const FastCheckoutConfirmDialog = state.fastCheckoutInfo && /* @__PURE__ */(0, _jsxRuntime.jsx)(_confirm.default, {
526
552
  onConfirm: handleFastCheckoutConfirm,
527
553
  onCancel: handleFastCheckoutCancel,
528
- title: t("payment.checkout.fastPay.title"),
529
- message: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
554
+ title: state.fastCheckoutInfo.sourceType === "credit" ? t("payment.checkout.fastPay.credit.title") : t("payment.checkout.fastPay.title"),
555
+ message: state.fastCheckoutInfo.sourceType === "credit" ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
556
+ children: t("payment.checkout.fastPay.credit.meteringSubscriptionMessage", {
557
+ available: `${(0, _util.fromUnitToToken)(state.fastCheckoutInfo?.balance || "0", paymentCurrency?.decimal || 18).toString()} ${paymentCurrency?.symbol}`
558
+ })
559
+ }) : /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
530
560
  children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
531
561
  children: t("payment.checkout.fastPay.autoPaymentReason")
532
562
  }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Divider, {
@@ -596,6 +626,15 @@ function PaymentForm({
596
626
  loading: state.fastCheckoutInfo.loading,
597
627
  color: "primary"
598
628
  });
629
+ const CreditInsufficientDialog = state.creditInsufficientInfo && /* @__PURE__ */(0, _jsxRuntime.jsx)(_confirm.default, {
630
+ onConfirm: handleCreditInsufficientClose,
631
+ onCancel: handleCreditInsufficientClose,
632
+ title: t("payment.checkout.fastPay.credit.insufficientTitle"),
633
+ message: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
634
+ children: t("payment.checkout.fastPay.credit.insufficientMessage")
635
+ }),
636
+ confirm: t("common.confirm")
637
+ });
599
638
  if (onlyShowBtn) {
600
639
  return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
601
640
  children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
@@ -646,7 +685,7 @@ function PaymentForm({
646
685
  }),
647
686
  title: t("payment.customer.pastDue.alert.title")
648
687
  }
649
- }), FastCheckoutConfirmDialog]
688
+ }), FastCheckoutConfirmDialog, CreditInsufficientDialog]
650
689
  });
651
690
  }
652
691
  return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
@@ -852,6 +891,6 @@ function PaymentForm({
852
891
  }),
853
892
  title: t("payment.customer.pastDue.alert.title")
854
893
  }
855
- }), FastCheckoutConfirmDialog]
894
+ }), FastCheckoutConfirmDialog, CreditInsufficientDialog]
856
895
  });
857
896
  }
@@ -196,6 +196,22 @@ function PaymentInner({
196
196
  _Toast.default.error((0, _util2.formatError)(err));
197
197
  }
198
198
  };
199
+ const onQuantityChange = async (itemId, quantity) => {
200
+ try {
201
+ const {
202
+ data
203
+ } = await _api.default.put(`/api/checkout-sessions/${state.checkoutSession.id}/adjust-quantity`, {
204
+ itemId,
205
+ quantity
206
+ });
207
+ setState({
208
+ checkoutSession: data
209
+ });
210
+ } catch (err) {
211
+ console.error(err);
212
+ _Toast.default.error((0, _util2.formatError)(err));
213
+ }
214
+ };
199
215
  const onCancelCrossSell = async () => {
200
216
  try {
201
217
  const {
@@ -262,17 +278,19 @@ function PaymentInner({
262
278
  billingThreshold: Math.max(state.checkoutSession.subscription_data?.billing_threshold_amount || 0,
263
279
  // @ts-ignore
264
280
  state.checkoutSession.subscription_data?.min_stake_amount || 0),
265
- showStaking: method.type === "arcblock" && !state.checkoutSession.subscription_data?.no_stake,
281
+ showStaking: (0, _util2.showStaking)(method, currency, !!state.checkoutSession.subscription_data?.no_stake),
266
282
  currency,
267
283
  onUpsell,
268
284
  onDownsell,
285
+ onQuantityChange,
269
286
  onApplyCrossSell,
270
287
  onCancelCrossSell,
271
288
  onChangeAmount,
272
289
  checkoutSessionId: state.checkoutSession.id,
273
290
  crossSellBehavior: state.checkoutSession.cross_sell_behavior,
274
291
  donationSettings: paymentLink?.donation_settings,
275
- action
292
+ action,
293
+ completed
276
294
  }), mode === "standalone" && !isMobile && /* @__PURE__ */(0, _jsxRuntime.jsx)(_footer.default, {
277
295
  className: "cko-footer",
278
296
  sx: {
@@ -10,6 +10,13 @@ type Props = {
10
10
  onDownsell: Function;
11
11
  mode?: 'normal' | 'cross-sell';
12
12
  children?: React.ReactNode;
13
+ adjustableQuantity?: {
14
+ enabled: boolean;
15
+ minimum?: number;
16
+ maximum?: number;
17
+ };
18
+ onQuantityChange?: (itemId: string, quantity: number) => void;
19
+ completed?: boolean;
13
20
  };
14
- export default function ProductItem({ item, items, trialInDays, trialEnd, currency, mode, children, onUpsell, onDownsell, }: Props): JSX.Element;
21
+ export default function ProductItem({ item, items, trialInDays, trialEnd, currency, mode, children, onUpsell, onDownsell, completed, adjustableQuantity, onQuantityChange, }: Props): JSX.Element;
15
22
  export {};
@@ -7,12 +7,14 @@ module.exports = ProductItem;
7
7
  var _jsxRuntime = require("react/jsx-runtime");
8
8
  var _context = require("@arcblock/ux/lib/Locale/context");
9
9
  var _material = require("@mui/material");
10
+ var _iconsMaterial = require("@mui/icons-material");
10
11
  var _react = require("react");
11
12
  var _status = _interopRequireDefault(require("../components/status"));
12
13
  var _switchButton = _interopRequireDefault(require("../components/switch-button"));
13
14
  var _util = require("../libs/util");
14
15
  var _productCard = _interopRequireDefault(require("./product-card"));
15
16
  var _dayjs = _interopRequireDefault(require("../libs/dayjs"));
17
+ var _payment = require("../contexts/payment");
16
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
19
  function ProductItem({
18
20
  item,
@@ -23,12 +25,20 @@ function ProductItem({
23
25
  mode = "normal",
24
26
  children = null,
25
27
  onUpsell,
26
- onDownsell
28
+ onDownsell,
29
+ completed = false,
30
+ adjustableQuantity = {
31
+ enabled: false
32
+ },
33
+ onQuantityChange = () => {}
27
34
  }) {
28
35
  const {
29
36
  t,
30
37
  locale
31
38
  } = (0, _context.useLocaleContext)();
39
+ const {
40
+ settings
41
+ } = (0, _payment.usePaymentContext)();
32
42
  const pricing = (0, _util.formatLineItemPricing)(item, currency, {
33
43
  trialEnd,
34
44
  trialInDays
@@ -36,6 +46,65 @@ function ProductItem({
36
46
  const saving = (0, _util.formatUpsellSaving)(items, currency);
37
47
  const metered = item.price?.recurring?.usage_type === "metered" ? t("common.metered") : "";
38
48
  const canUpsell = mode === "normal" && items.length === 1;
49
+ const isCreditProduct = item.price.product?.type === "credit" && item.price.metadata?.credit_config?.credit_amount;
50
+ const creditAmount = isCreditProduct ? Number(item.price.metadata.credit_config.credit_amount) : 0;
51
+ const creditCurrency = isCreditProduct ? (0, _util.findCurrency)(settings.paymentMethods, item.price.metadata?.credit_config?.currency_id ?? "") : null;
52
+ const validDuration = item.price.metadata?.credit_config?.valid_duration_value;
53
+ const validDurationUnit = item.price.metadata?.credit_config?.valid_duration_unit || "days";
54
+ const [localQuantity, setLocalQuantity] = (0, _react.useState)(item.quantity);
55
+ const canAdjustQuantity = adjustableQuantity.enabled && mode === "normal";
56
+ const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
57
+ const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
58
+ const maxQuantity = Math.min(adjustableQuantity.maximum || 999, quantityAvailable || 999);
59
+ const handleQuantityChange = newQuantity => {
60
+ if (newQuantity >= minQuantity && newQuantity <= maxQuantity) {
61
+ setLocalQuantity(newQuantity);
62
+ if ((0, _util.formatQuantityInventory)(item.price, newQuantity, locale)) {
63
+ return;
64
+ }
65
+ onQuantityChange(item.price_id, newQuantity);
66
+ }
67
+ };
68
+ const handleQuantityIncrease = () => {
69
+ if (localQuantity < maxQuantity) {
70
+ handleQuantityChange(localQuantity + 1);
71
+ }
72
+ };
73
+ const handleQuantityDecrease = () => {
74
+ if (localQuantity > minQuantity) {
75
+ handleQuantityChange(localQuantity - 1);
76
+ }
77
+ };
78
+ const handleQuantityInputChange = event => {
79
+ const value = parseInt(event.target.value, 10);
80
+ if (!Number.isNaN(value)) {
81
+ handleQuantityChange(value);
82
+ }
83
+ };
84
+ const formatCreditInfo = () => {
85
+ if (!isCreditProduct) return null;
86
+ const isRecurring = item.price.type === "recurring";
87
+ const totalCredit = creditAmount * localQuantity;
88
+ let message = "";
89
+ if (isRecurring) {
90
+ message = t("payment.checkout.credit.recurringInfo", {
91
+ amount: totalCredit,
92
+ period: (0, _util.formatRecurring)(item.price.recurring, true, "per", locale)
93
+ });
94
+ } else {
95
+ message = t("payment.checkout.credit.oneTimeInfo", {
96
+ amount: totalCredit,
97
+ symbol: creditCurrency?.symbol || "Credits"
98
+ });
99
+ }
100
+ if (validDuration && validDuration > 0) {
101
+ message += `\uFF0C${t("payment.checkout.credit.expiresIn", {
102
+ duration: validDuration,
103
+ unit: t(`common.${validDurationUnit}`)
104
+ })}`;
105
+ }
106
+ return message;
107
+ };
39
108
  const primaryText = (0, _react.useMemo)(() => {
40
109
  const price = item.upsell_price || item.price || {};
41
110
  const isRecurring = price?.type === "recurring" && price?.recurring;
@@ -45,6 +114,7 @@ function ProductItem({
45
114
  }
46
115
  return pricing.primary;
47
116
  }, [trialInDays, trialEnd, pricing, item, locale]);
117
+ const quantityInventoryError = (0, _util.formatQuantityInventory)(item.price, localQuantity, locale);
48
118
  return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
49
119
  direction: "column",
50
120
  spacing: 1,
@@ -103,8 +173,8 @@ function ProductItem({
103
173
  children: pricing.secondary
104
174
  })]
105
175
  })]
106
- }), (0, _util.formatQuantityInventory)(item.price, item.quantity, locale) ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_status.default, {
107
- label: (0, _util.formatQuantityInventory)(item.price, item.quantity, locale),
176
+ }), quantityInventoryError ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_status.default, {
177
+ label: quantityInventoryError,
108
178
  variant: "outlined",
109
179
  sx: {
110
180
  mt: 1,
@@ -112,7 +182,77 @@ function ProductItem({
112
182
  backgroundColor: "chip.error.background",
113
183
  color: "chip.error.text"
114
184
  }
115
- }) : null, children]
185
+ }) : null, canAdjustQuantity && !completed && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
186
+ sx: {
187
+ mt: 1,
188
+ p: 1
189
+ },
190
+ children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
191
+ direction: "row",
192
+ spacing: 1,
193
+ sx: {
194
+ alignItems: "center"
195
+ },
196
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
197
+ variant: "body2",
198
+ sx: {
199
+ color: "text.secondary",
200
+ minWidth: "fit-content"
201
+ },
202
+ children: [t("common.quantity"), ":"]
203
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.IconButton, {
204
+ size: "small",
205
+ onClick: handleQuantityDecrease,
206
+ disabled: localQuantity <= minQuantity,
207
+ sx: {
208
+ minWidth: 32,
209
+ width: 32,
210
+ height: 32
211
+ },
212
+ children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.Remove, {
213
+ fontSize: "small"
214
+ })
215
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.TextField, {
216
+ size: "small",
217
+ value: localQuantity,
218
+ onChange: handleQuantityInputChange,
219
+ sx: {
220
+ width: 60
221
+ },
222
+ type: "number",
223
+ slotProps: {
224
+ htmlInput: {
225
+ min: minQuantity,
226
+ max: maxQuantity,
227
+ style: {
228
+ textAlign: "center",
229
+ padding: "4px"
230
+ }
231
+ }
232
+ }
233
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.IconButton, {
234
+ size: "small",
235
+ onClick: handleQuantityIncrease,
236
+ disabled: localQuantity >= maxQuantity,
237
+ sx: {
238
+ minWidth: 32,
239
+ width: 32,
240
+ height: 32
241
+ },
242
+ children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.Add, {
243
+ fontSize: "small"
244
+ })
245
+ })]
246
+ })
247
+ }), isCreditProduct && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Alert, {
248
+ severity: "info",
249
+ sx: {
250
+ mt: 1,
251
+ fontSize: "0.875rem"
252
+ },
253
+ icon: false,
254
+ children: formatCreditInfo()
255
+ }), children]
116
256
  }), canUpsell && !item.upsell_price_id && item.price.upsell?.upsells_to && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
117
257
  direction: "row",
118
258
  className: "product-item-upsell",
@@ -8,6 +8,7 @@ type Props = {
8
8
  showStaking?: boolean;
9
9
  onUpsell?: Function;
10
10
  onDownsell?: Function;
11
+ onQuantityChange?: Function;
11
12
  onChangeAmount?: Function;
12
13
  onApplyCrossSell?: Function;
13
14
  onCancelCrossSell?: Function;
@@ -15,6 +16,7 @@ type Props = {
15
16
  crossSellBehavior?: string;
16
17
  donationSettings?: DonationSettings;
17
18
  action?: string;
19
+ completed?: boolean;
18
20
  };
19
- export default function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onApplyCrossSell, onCancelCrossSell, onChangeAmount, checkoutSessionId, crossSellBehavior, showStaking, donationSettings, action, trialEnd, ...rest }: Props): import("react").JSX.Element;
21
+ export default function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onQuantityChange, onApplyCrossSell, onCancelCrossSell, onChangeAmount, checkoutSessionId, crossSellBehavior, showStaking, donationSettings, action, trialEnd, completed, ...rest }: Props): import("react").JSX.Element;
20
22
  export {};
@@ -90,6 +90,7 @@ function PaymentSummary({
90
90
  billingThreshold,
91
91
  onUpsell = _noop.default,
92
92
  onDownsell = _noop.default,
93
+ onQuantityChange = _noop.default,
93
94
  onApplyCrossSell = _noop.default,
94
95
  onCancelCrossSell = _noop.default,
95
96
  onChangeAmount = _noop.default,
@@ -99,6 +100,7 @@ function PaymentSummary({
99
100
  donationSettings = void 0,
100
101
  action = "",
101
102
  trialEnd = 0,
103
+ completed = false,
102
104
  ...rest
103
105
  }) {
104
106
  const {
@@ -138,6 +140,10 @@ function PaymentSummary({
138
140
  await onUpsell(from, to);
139
141
  runAsync();
140
142
  };
143
+ const handleQuantityChange = async (itemId, quantity) => {
144
+ await onQuantityChange(itemId, quantity);
145
+ runAsync();
146
+ };
141
147
  const handleDownsell = async from => {
142
148
  await onDownsell(from);
143
149
  runAsync();
@@ -196,6 +202,9 @@ function PaymentSummary({
196
202
  currency,
197
203
  onUpsell: handleUpsell,
198
204
  onDownsell: handleDownsell,
205
+ adjustableQuantity: x.adjustable_quantity,
206
+ completed,
207
+ onQuantityChange: handleQuantityChange,
199
208
  children: x.cross_sell && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
200
209
  direction: "row",
201
210
  sx: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.19.0",
3
+ "version": "1.19.1",
4
4
  "description": "Reusable react components for payment kit v2",
5
5
  "keywords": [
6
6
  "react",
@@ -94,7 +94,7 @@
94
94
  "@babel/core": "^7.27.4",
95
95
  "@babel/preset-env": "^7.27.2",
96
96
  "@babel/preset-react": "^7.27.1",
97
- "@blocklet/payment-types": "1.19.0",
97
+ "@blocklet/payment-types": "1.19.1",
98
98
  "@storybook/addon-essentials": "^7.6.20",
99
99
  "@storybook/addon-interactions": "^7.6.20",
100
100
  "@storybook/addon-links": "^7.6.20",
@@ -125,5 +125,5 @@
125
125
  "vite-plugin-babel": "^1.3.1",
126
126
  "vite-plugin-node-polyfills": "^0.23.0"
127
127
  },
128
- "gitHead": "2810263174bb900ebb5a431dc53930b08b4a8d6d"
128
+ "gitHead": "48d5719c8ce4e89a16f8dd576ff8f72072e3909e"
129
129
  }