@blocklet/payment-react 1.19.0 → 1.19.2

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 (75) 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 +50 -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 +254 -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/address.js +2 -1
  23. package/es/payment/form/index.js +46 -7
  24. package/es/payment/index.js +18 -3
  25. package/es/payment/product-item.d.ts +8 -1
  26. package/es/payment/product-item.js +137 -5
  27. package/es/payment/summary.d.ts +3 -1
  28. package/es/payment/summary.js +9 -0
  29. package/lib/components/blockchain/tx.d.ts +1 -1
  30. package/lib/components/blockchain/tx.js +9 -8
  31. package/lib/components/country-select.d.ts +1 -1
  32. package/lib/components/date-range-picker.d.ts +13 -0
  33. package/lib/components/date-range-picker.js +329 -0
  34. package/lib/components/input.d.ts +5 -2
  35. package/lib/components/input.js +8 -4
  36. package/lib/components/label.d.ts +7 -0
  37. package/lib/components/label.js +62 -0
  38. package/lib/components/loading-button.d.ts +1 -1
  39. package/lib/history/credit/grants-list.d.ts +14 -0
  40. package/lib/history/credit/grants-list.js +277 -0
  41. package/lib/history/credit/transactions-list.d.ts +13 -0
  42. package/lib/history/credit/transactions-list.js +300 -0
  43. package/lib/history/invoice/list.js +24 -0
  44. package/lib/index.d.ts +5 -1
  45. package/lib/index.js +39 -0
  46. package/lib/libs/util.d.ts +2 -0
  47. package/lib/libs/util.js +14 -0
  48. package/lib/locales/en.js +20 -2
  49. package/lib/locales/zh.js +20 -2
  50. package/lib/payment/form/address.js +6 -5
  51. package/lib/payment/form/index.js +49 -9
  52. package/lib/payment/index.js +20 -2
  53. package/lib/payment/product-item.d.ts +8 -1
  54. package/lib/payment/product-item.js +144 -4
  55. package/lib/payment/summary.d.ts +3 -1
  56. package/lib/payment/summary.js +9 -0
  57. package/package.json +3 -3
  58. package/src/components/blockchain/tx.tsx +9 -15
  59. package/src/components/country-select.tsx +2 -2
  60. package/src/components/date-range-picker.tsx +310 -0
  61. package/src/components/input.tsx +14 -3
  62. package/src/components/label.tsx +59 -0
  63. package/src/components/loading-button.tsx +1 -1
  64. package/src/history/credit/grants-list.tsx +276 -0
  65. package/src/history/credit/transactions-list.tsx +316 -0
  66. package/src/history/invoice/list.tsx +18 -1
  67. package/src/index.ts +9 -0
  68. package/src/libs/util.ts +14 -0
  69. package/src/locales/en.tsx +20 -0
  70. package/src/locales/zh.tsx +19 -0
  71. package/src/payment/form/address.tsx +4 -3
  72. package/src/payment/form/index.tsx +112 -53
  73. package/src/payment/index.tsx +17 -1
  74. package/src/payment/product-item.tsx +152 -4
  75. package/src/payment/summary.tsx +13 -2
package/es/locales/zh.js CHANGED
@@ -31,6 +31,10 @@ export default flat({
31
31
  change: "\u66F4\u6362",
32
32
  confirm: "\u786E\u8BA4",
33
33
  cancel: "\u53D6\u6D88",
34
+ clear: "\u6E05\u7A7A",
35
+ selectTimeRange: "\u9009\u62E9\u65F6\u95F4\u8303\u56F4",
36
+ startDate: "\u5F00\u59CB\u65E5\u671F",
37
+ endDate: "\u7ED3\u675F\u65E5\u671F",
34
38
  close: "\u5173\u95ED",
35
39
  back: "\u8FD4\u56DE",
36
40
  every: "\u6BCF",
@@ -100,7 +104,8 @@ export default flat({
100
104
  scan: "\u4F7F\u7528\u4EE5\u4E0B\u65B9\u5F0F\u5B8C\u6210\u672C\u6B21{action}",
101
105
  confirm: "\u786E\u8BA4",
102
106
  cancel: "\u53D6\u6D88"
103
- }
107
+ },
108
+ paymentMethod: "\u652F\u4ED8\u65B9\u5F0F"
104
109
  },
105
110
  payment: {
106
111
  checkout: {
@@ -212,6 +217,11 @@ export default flat({
212
217
  add: "\u6DFB\u52A0\u5230\u8BA2\u5355",
213
218
  remove: "\u4ECE\u8BA2\u5355\u79FB\u9664"
214
219
  },
220
+ credit: {
221
+ oneTimeInfo: "\u4ED8\u6B3E\u5B8C\u6210\u540E\u60A8\u5C06\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
222
+ recurringInfo: "\u60A8\u5C06{period}\u83B7\u5F97 {amount} {symbol} \u989D\u5EA6",
223
+ expiresIn: "\u989D\u5EA6\u6709\u6548\u671F\u4E3A {duration} {unit}"
224
+ },
215
225
  emptyItems: {
216
226
  title: "\u6CA1\u6709\u4EFB\u4F55\u8D2D\u4E70\u9879\u76EE",
217
227
  description: "\u53EF\u80FD\u8FD9\u4E2A\u4ED8\u6B3E\u94FE\u63A5\u6CA1\u6709\u6B63\u786E\u914D\u7F6E"
@@ -232,7 +242,15 @@ export default flat({
232
242
  payer: "\u8D26\u6237\u5730\u5740",
233
243
  amount: "\u652F\u4ED8\u91D1\u989D",
234
244
  failed: "\u8D26\u6237\u53D1\u751F\u53D8\u5316\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5B8C\u6210\u652F\u4ED8\uFF0C\u8BF7\u624B\u52A8\u652F\u4ED8\u3002",
235
- balanceLink: "\u67E5\u770B\u4F59\u989D"
245
+ balanceLink: "\u67E5\u770B\u4F59\u989D",
246
+ credit: {
247
+ title: "\u786E\u8BA4\u989D\u5EA6\u652F\u4ED8",
248
+ availableAmount: "\u53EF\u7528\u989D\u5EA6\uFF1A{amount}",
249
+ confirmMessage: "\u60A8\u5C06\u4F7F\u7528 {amount} \u989D\u5EA6\u6765\u8BA2\u9605\u6B64\u670D\u52A1\u3002",
250
+ 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",
251
+ insufficientTitle: "\u989D\u5EA6\u4E0D\u8DB3",
252
+ 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"
253
+ }
236
254
  }
237
255
  },
238
256
  customer: {
@@ -1,8 +1,9 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
- import { Fade, FormLabel, InputAdornment, Stack } from "@mui/material";
3
+ import { Fade, InputAdornment, Stack } from "@mui/material";
4
4
  import { Controller, useFormContext, useWatch } from "react-hook-form";
5
5
  import FormInput from "../../components/input.js";
6
+ import FormLabel from "../../components/label.js";
6
7
  import CountrySelect from "../../components/country-select.js";
7
8
  import { getFieldValidation, validatePostalCode } from "../../libs/validator.js";
8
9
  export default function AddressForm({ mode, stripe, sx = {}, fieldValidation = {}, errorPosition = "right" }) {
@@ -2,7 +2,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import "react-international-phone/style.css";
3
3
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
4
4
  import Toast from "@arcblock/ux/lib/Toast";
5
- import { Box, Button, CircularProgress, Divider, Fade, FormLabel, Stack, Tooltip, Typography } from "@mui/material";
5
+ import { Box, Button, CircularProgress, Divider, Fade, Stack, Tooltip, Typography } from "@mui/material";
6
6
  import { useMemoizedFn, useSetState } from "ahooks";
7
7
  import pWaitFor from "p-wait-for";
8
8
  import { useEffect, useMemo, useRef } from "react";
@@ -15,6 +15,7 @@ import DID from "@arcblock/ux/lib/DID";
15
15
  import isEmpty from "lodash/isEmpty";
16
16
  import { HelpOutline, OpenInNew } from "@mui/icons-material";
17
17
  import FormInput from "../../components/input.js";
18
+ import FormLabel from "../../components/label.js";
18
19
  import { usePaymentContext } from "../../contexts/payment.js";
19
20
  import { useSubscription } from "../../hooks/subscription.js";
20
21
  import api from "../../libs/api.js";
@@ -131,7 +132,8 @@ export default function PaymentForm({
131
132
  customer,
132
133
  customerLimited: false,
133
134
  stripePaying: false,
134
- fastCheckoutInfo: null
135
+ fastCheckoutInfo: null,
136
+ creditInsufficientInfo: null
135
137
  });
136
138
  const currencies = flattenPaymentMethods(paymentMethods);
137
139
  const onCheckoutComplete = useMemoizedFn(async ({ response }) => {
@@ -300,6 +302,9 @@ export default function PaymentForm({
300
302
  const handleFastCheckoutCancel = () => {
301
303
  setState({ fastCheckoutInfo: null });
302
304
  };
305
+ const handleCreditInsufficientClose = () => {
306
+ setState({ creditInsufficientInfo: null });
307
+ };
303
308
  const openConnect = () => {
304
309
  try {
305
310
  if (!["arcblock", "ethereum", "base"].includes(method.type)) {
@@ -355,7 +360,27 @@ export default function PaymentForm({
355
360
  customerLimited: false
356
361
  });
357
362
  if (["arcblock", "ethereum", "base"].includes(method.type)) {
358
- if ((result.data.balance?.sufficient || result.data.delegation?.sufficient) && !isDonationMode && result.data.fastPayInfo) {
363
+ if (paymentCurrency?.type === "credit") {
364
+ if (result.data.creditSufficient === true) {
365
+ setState({
366
+ fastCheckoutInfo: {
367
+ open: true,
368
+ loading: false,
369
+ sourceType: "credit",
370
+ amount: result.data.fastPayInfo?.amount || "0",
371
+ payer: result.data.fastPayInfo?.payer,
372
+ availableCredit: result.data.fastPayInfo?.amount || "0",
373
+ balance: result.data.fastPayInfo?.token?.balance || "0"
374
+ }
375
+ });
376
+ } else {
377
+ setState({
378
+ creditInsufficientInfo: {
379
+ open: true
380
+ }
381
+ });
382
+ }
383
+ } else if ((result.data.balance?.sufficient || result.data.delegation?.sufficient) && !isDonationMode && result.data.fastPayInfo) {
359
384
  setState({
360
385
  fastCheckoutInfo: {
361
386
  open: true,
@@ -445,8 +470,10 @@ export default function PaymentForm({
445
470
  {
446
471
  onConfirm: handleFastCheckoutConfirm,
447
472
  onCancel: handleFastCheckoutCancel,
448
- title: t("payment.checkout.fastPay.title"),
449
- message: /* @__PURE__ */ jsxs(Stack, { children: [
473
+ title: state.fastCheckoutInfo.sourceType === "credit" ? t("payment.checkout.fastPay.credit.title") : t("payment.checkout.fastPay.title"),
474
+ message: state.fastCheckoutInfo.sourceType === "credit" ? /* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.fastPay.credit.meteringSubscriptionMessage", {
475
+ available: `${fromUnitToToken(state.fastCheckoutInfo?.balance || "0", paymentCurrency?.decimal || 18).toString()} ${paymentCurrency?.symbol}`
476
+ }) }) : /* @__PURE__ */ jsxs(Stack, { children: [
450
477
  /* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.fastPay.autoPaymentReason") }),
451
478
  /* @__PURE__ */ jsx(Divider, { sx: { mt: 1.5, mb: 1.5 } }),
452
479
  /* @__PURE__ */ jsxs(Stack, { spacing: 1, children: [
@@ -521,6 +548,16 @@ export default function PaymentForm({
521
548
  color: "primary"
522
549
  }
523
550
  );
551
+ const CreditInsufficientDialog = state.creditInsufficientInfo && /* @__PURE__ */ jsx(
552
+ ConfirmDialog,
553
+ {
554
+ onConfirm: handleCreditInsufficientClose,
555
+ onCancel: handleCreditInsufficientClose,
556
+ title: t("payment.checkout.fastPay.credit.insufficientTitle"),
557
+ message: /* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.fastPay.credit.insufficientMessage") }),
558
+ confirm: t("common.confirm")
559
+ }
560
+ );
524
561
  if (onlyShowBtn) {
525
562
  return /* @__PURE__ */ jsxs(Fragment, { children: [
526
563
  /* @__PURE__ */ jsx(Box, { className: "cko-payment-submit-btn", children: /* @__PURE__ */ jsxs(
@@ -573,7 +610,8 @@ export default function PaymentForm({
573
610
  }
574
611
  }
575
612
  ),
576
- FastCheckoutConfirmDialog
613
+ FastCheckoutConfirmDialog,
614
+ CreditInsufficientDialog
577
615
  ] });
578
616
  }
579
617
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -768,6 +806,7 @@ export default function PaymentForm({
768
806
  }
769
807
  }
770
808
  ),
771
- FastCheckoutConfirmDialog
809
+ FastCheckoutConfirmDialog,
810
+ CreditInsufficientDialog
772
811
  ] });
773
812
  }
@@ -18,7 +18,8 @@ import {
18
18
  getQueryParams,
19
19
  getStatementDescriptor,
20
20
  isMobileSafari,
21
- isValidCountry
21
+ isValidCountry,
22
+ showStaking
22
23
  } from "../libs/util.js";
23
24
  import PaymentError from "./error.js";
24
25
  import CheckoutFooter from "./footer.js";
@@ -166,6 +167,18 @@ function PaymentInner({
166
167
  Toast.error(formatError(err));
167
168
  }
168
169
  };
170
+ const onQuantityChange = async (itemId, quantity) => {
171
+ try {
172
+ const { data } = await api.put(`/api/checkout-sessions/${state.checkoutSession.id}/adjust-quantity`, {
173
+ itemId,
174
+ quantity
175
+ });
176
+ setState({ checkoutSession: data });
177
+ } catch (err) {
178
+ console.error(err);
179
+ Toast.error(formatError(err));
180
+ }
181
+ };
169
182
  const onCancelCrossSell = async () => {
170
183
  try {
171
184
  const { data } = await api.delete(`/api/checkout-sessions/${state.checkoutSession.id}/cross-sell`);
@@ -211,17 +224,19 @@ function PaymentInner({
211
224
  // @ts-ignore
212
225
  state.checkoutSession.subscription_data?.min_stake_amount || 0
213
226
  ),
214
- showStaking: method.type === "arcblock" && !state.checkoutSession.subscription_data?.no_stake,
227
+ showStaking: showStaking(method, currency, !!state.checkoutSession.subscription_data?.no_stake),
215
228
  currency,
216
229
  onUpsell,
217
230
  onDownsell,
231
+ onQuantityChange,
218
232
  onApplyCrossSell,
219
233
  onCancelCrossSell,
220
234
  onChangeAmount,
221
235
  checkoutSessionId: state.checkoutSession.id,
222
236
  crossSellBehavior: state.checkoutSession.cross_sell_behavior,
223
237
  donationSettings: paymentLink?.donation_settings,
224
- action
238
+ action,
239
+ completed
225
240
  }
226
241
  ),
227
242
  mode === "standalone" && !isMobile && /* @__PURE__ */ jsx(CheckoutFooter, { className: "cko-footer", sx: { color: "text.lighter" } })
@@ -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 {};
@@ -1,10 +1,12 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
- import { Box, Stack, Typography } from "@mui/material";
4
- import { useMemo } from "react";
3
+ import { Box, Stack, Typography, IconButton, TextField, Alert } from "@mui/material";
4
+ import { Add, Remove } from "@mui/icons-material";
5
+ import { useMemo, useState } from "react";
5
6
  import Status from "../components/status.js";
6
7
  import Switch from "../components/switch-button.js";
7
8
  import {
9
+ findCurrency,
8
10
  formatLineItemPricing,
9
11
  formatPrice,
10
12
  formatQuantityInventory,
@@ -13,6 +15,7 @@ import {
13
15
  } from "../libs/util.js";
14
16
  import ProductCard from "./product-card.js";
15
17
  import dayjs from "../libs/dayjs.js";
18
+ import { usePaymentContext } from "../contexts/payment.js";
16
19
  export default function ProductItem({
17
20
  item,
18
21
  items,
@@ -22,13 +25,77 @@ export default function ProductItem({
22
25
  mode = "normal",
23
26
  children = null,
24
27
  onUpsell,
25
- onDownsell
28
+ onDownsell,
29
+ completed = false,
30
+ adjustableQuantity = { enabled: false },
31
+ onQuantityChange = () => {
32
+ }
26
33
  }) {
27
34
  const { t, locale } = useLocaleContext();
35
+ const { settings } = usePaymentContext();
28
36
  const pricing = formatLineItemPricing(item, currency, { trialEnd, trialInDays }, locale);
29
37
  const saving = formatUpsellSaving(items, currency);
30
38
  const metered = item.price?.recurring?.usage_type === "metered" ? t("common.metered") : "";
31
39
  const canUpsell = mode === "normal" && items.length === 1;
40
+ const isCreditProduct = item.price.product?.type === "credit" && item.price.metadata?.credit_config?.credit_amount;
41
+ const creditAmount = isCreditProduct ? Number(item.price.metadata.credit_config.credit_amount) : 0;
42
+ const creditCurrency = isCreditProduct ? findCurrency(settings.paymentMethods, item.price.metadata?.credit_config?.currency_id ?? "") : null;
43
+ const validDuration = item.price.metadata?.credit_config?.valid_duration_value;
44
+ const validDurationUnit = item.price.metadata?.credit_config?.valid_duration_unit || "days";
45
+ const [localQuantity, setLocalQuantity] = useState(item.quantity);
46
+ const canAdjustQuantity = adjustableQuantity.enabled && mode === "normal";
47
+ const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
48
+ const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
49
+ const maxQuantity = Math.min(adjustableQuantity.maximum || 999, quantityAvailable || 999);
50
+ const handleQuantityChange = (newQuantity) => {
51
+ if (newQuantity >= minQuantity && newQuantity <= maxQuantity) {
52
+ setLocalQuantity(newQuantity);
53
+ if (formatQuantityInventory(item.price, newQuantity, locale)) {
54
+ return;
55
+ }
56
+ onQuantityChange(item.price_id, newQuantity);
57
+ }
58
+ };
59
+ const handleQuantityIncrease = () => {
60
+ if (localQuantity < maxQuantity) {
61
+ handleQuantityChange(localQuantity + 1);
62
+ }
63
+ };
64
+ const handleQuantityDecrease = () => {
65
+ if (localQuantity > minQuantity) {
66
+ handleQuantityChange(localQuantity - 1);
67
+ }
68
+ };
69
+ const handleQuantityInputChange = (event) => {
70
+ const value = parseInt(event.target.value, 10);
71
+ if (!Number.isNaN(value)) {
72
+ handleQuantityChange(value);
73
+ }
74
+ };
75
+ const formatCreditInfo = () => {
76
+ if (!isCreditProduct) return null;
77
+ const isRecurring = item.price.type === "recurring";
78
+ const totalCredit = creditAmount * localQuantity;
79
+ let message = "";
80
+ if (isRecurring) {
81
+ message = t("payment.checkout.credit.recurringInfo", {
82
+ amount: totalCredit,
83
+ period: formatRecurring(item.price.recurring, true, "per", locale)
84
+ });
85
+ } else {
86
+ message = t("payment.checkout.credit.oneTimeInfo", {
87
+ amount: totalCredit,
88
+ symbol: creditCurrency?.symbol || "Credits"
89
+ });
90
+ }
91
+ if (validDuration && validDuration > 0) {
92
+ message += `\uFF0C${t("payment.checkout.credit.expiresIn", {
93
+ duration: validDuration,
94
+ unit: t(`common.${validDurationUnit}`)
95
+ })}`;
96
+ }
97
+ return message;
98
+ };
32
99
  const primaryText = useMemo(() => {
33
100
  const price = item.upsell_price || item.price || {};
34
101
  const isRecurring = price?.type === "recurring" && price?.recurring;
@@ -38,6 +105,7 @@ export default function ProductItem({
38
105
  }
39
106
  return pricing.primary;
40
107
  }, [trialInDays, trialEnd, pricing, item, locale]);
108
+ const quantityInventoryError = formatQuantityInventory(item.price, localQuantity, locale);
41
109
  return /* @__PURE__ */ jsxs(
42
110
  Stack,
43
111
  {
@@ -105,10 +173,10 @@ export default function ProductItem({
105
173
  ]
106
174
  }
107
175
  ),
108
- formatQuantityInventory(item.price, item.quantity, locale) ? /* @__PURE__ */ jsx(
176
+ quantityInventoryError ? /* @__PURE__ */ jsx(
109
177
  Status,
110
178
  {
111
- label: formatQuantityInventory(item.price, item.quantity, locale),
179
+ label: quantityInventoryError,
112
180
  variant: "outlined",
113
181
  sx: {
114
182
  mt: 1,
@@ -118,6 +186,70 @@ export default function ProductItem({
118
186
  }
119
187
  }
120
188
  ) : null,
189
+ canAdjustQuantity && !completed && /* @__PURE__ */ jsx(Box, { sx: { mt: 1, p: 1 }, children: /* @__PURE__ */ jsxs(
190
+ Stack,
191
+ {
192
+ direction: "row",
193
+ spacing: 1,
194
+ sx: {
195
+ alignItems: "center"
196
+ },
197
+ children: [
198
+ /* @__PURE__ */ jsxs(
199
+ Typography,
200
+ {
201
+ variant: "body2",
202
+ sx: {
203
+ color: "text.secondary",
204
+ minWidth: "fit-content"
205
+ },
206
+ children: [
207
+ t("common.quantity"),
208
+ ":"
209
+ ]
210
+ }
211
+ ),
212
+ /* @__PURE__ */ jsx(
213
+ IconButton,
214
+ {
215
+ size: "small",
216
+ onClick: handleQuantityDecrease,
217
+ disabled: localQuantity <= minQuantity,
218
+ sx: { minWidth: 32, width: 32, height: 32 },
219
+ children: /* @__PURE__ */ jsx(Remove, { fontSize: "small" })
220
+ }
221
+ ),
222
+ /* @__PURE__ */ jsx(
223
+ TextField,
224
+ {
225
+ size: "small",
226
+ value: localQuantity,
227
+ onChange: handleQuantityInputChange,
228
+ sx: { width: 60 },
229
+ type: "number",
230
+ slotProps: {
231
+ htmlInput: {
232
+ min: minQuantity,
233
+ max: maxQuantity,
234
+ style: { textAlign: "center", padding: "4px" }
235
+ }
236
+ }
237
+ }
238
+ ),
239
+ /* @__PURE__ */ jsx(
240
+ IconButton,
241
+ {
242
+ size: "small",
243
+ onClick: handleQuantityIncrease,
244
+ disabled: localQuantity >= maxQuantity,
245
+ sx: { minWidth: 32, width: 32, height: 32 },
246
+ children: /* @__PURE__ */ jsx(Add, { fontSize: "small" })
247
+ }
248
+ )
249
+ ]
250
+ }
251
+ ) }),
252
+ isCreditProduct && /* @__PURE__ */ jsx(Alert, { severity: "info", sx: { mt: 1, fontSize: "0.875rem" }, icon: false, children: formatCreditInfo() }),
121
253
  children
122
254
  ]
123
255
  }
@@ -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 {};
@@ -73,6 +73,7 @@ export default function PaymentSummary({
73
73
  billingThreshold,
74
74
  onUpsell = noop,
75
75
  onDownsell = noop,
76
+ onQuantityChange = noop,
76
77
  onApplyCrossSell = noop,
77
78
  onCancelCrossSell = noop,
78
79
  onChangeAmount = noop,
@@ -82,6 +83,7 @@ export default function PaymentSummary({
82
83
  donationSettings = void 0,
83
84
  action = "",
84
85
  trialEnd = 0,
86
+ completed = false,
85
87
  ...rest
86
88
  }) {
87
89
  const { t, locale } = useLocaleContext();
@@ -111,6 +113,10 @@ export default function PaymentSummary({
111
113
  await onUpsell(from, to);
112
114
  runAsync();
113
115
  };
116
+ const handleQuantityChange = async (itemId, quantity) => {
117
+ await onQuantityChange(itemId, quantity);
118
+ runAsync();
119
+ };
114
120
  const handleDownsell = async (from) => {
115
121
  await onDownsell(from);
116
122
  runAsync();
@@ -166,6 +172,9 @@ export default function PaymentSummary({
166
172
  currency,
167
173
  onUpsell: handleUpsell,
168
174
  onDownsell: handleDownsell,
175
+ adjustableQuantity: x.adjustable_quantity,
176
+ completed,
177
+ onQuantityChange: handleQuantityChange,
169
178
  children: x.cross_sell && /* @__PURE__ */ jsxs(
170
179
  Stack,
171
180
  {
@@ -1,5 +1,5 @@
1
1
  import type { PaymentDetails, TPaymentMethod } from '@blocklet/payment-types';
2
- export default function TxLink(rawProps: {
2
+ export default function TxLink({ details, method, mode, align, }: {
3
3
  details: PaymentDetails;
4
4
  method: TPaymentMethod;
5
5
  mode?: 'customer' | 'dashboard';
@@ -10,15 +10,16 @@ var _iconsMaterial = require("@mui/icons-material");
10
10
  var _material = require("@mui/material");
11
11
  var _system = require("@mui/system");
12
12
  var _util = require("../../libs/util");
13
- function TxLink(rawProps) {
14
- const props = Object.assign({
15
- mode: "dashboard",
16
- align: "left"
17
- }, rawProps);
13
+ function TxLink({
14
+ details,
15
+ method,
16
+ mode = "dashboard",
17
+ align = "left"
18
+ }) {
18
19
  const {
19
20
  t
20
21
  } = (0, _context.useLocaleContext)();
21
- if (!props.details || props.mode === "customer" && props.method.type === "stripe") {
22
+ if (!details || mode === "customer" && method.type === "stripe") {
22
23
  return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
23
24
  component: "small",
24
25
  sx: {
@@ -30,7 +31,7 @@ function TxLink(rawProps) {
30
31
  const {
31
32
  text,
32
33
  link
33
- } = (0, _util.getTxLink)(props.method, props.details);
34
+ } = (0, _util.getTxLink)(method, details);
34
35
  if (link && text) {
35
36
  return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Link, {
36
37
  href: link,
@@ -39,7 +40,7 @@ function TxLink(rawProps) {
39
40
  children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(Root, {
40
41
  direction: "row",
41
42
  alignItems: "center",
42
- justifyContent: props.align === "left" ? "flex-start" : "flex-end",
43
+ justifyContent: align === "left" ? "flex-start" : "flex-end",
43
44
  sx: {
44
45
  color: "text.link"
45
46
  },
@@ -8,5 +8,5 @@ export type CountrySelectProps = {
8
8
  showDialCode?: boolean;
9
9
  };
10
10
  export default function CountrySelect({ ref, value, onChange, name, sx, showDialCode, }: CountrySelectProps & {
11
- ref?: React.RefObject<HTMLDivElement>;
11
+ ref?: React.RefObject<HTMLDivElement | null>;
12
12
  }): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ export interface DateRangeValue {
2
+ start: number | undefined;
3
+ end: number | undefined;
4
+ }
5
+ export interface DateRangePickerProps {
6
+ value: DateRangeValue;
7
+ onChange: (value: DateRangeValue) => void;
8
+ label?: string;
9
+ size?: 'small' | 'medium';
10
+ fullWidth?: boolean;
11
+ disabled?: boolean;
12
+ }
13
+ export default function DateRangePicker({ value, onChange, label, size, fullWidth, disabled, }: DateRangePickerProps): import("react").JSX.Element;