@blocklet/payment-react 1.24.3 → 1.25.0

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 (101) hide show
  1. package/es/components/auto-topup/modal.d.ts +2 -0
  2. package/es/components/auto-topup/modal.js +48 -6
  3. package/es/components/auto-topup/product-card.d.ts +16 -1
  4. package/es/components/auto-topup/product-card.js +97 -15
  5. package/es/components/dynamic-pricing-unavailable.d.ts +9 -0
  6. package/es/components/dynamic-pricing-unavailable.js +58 -0
  7. package/es/components/loading-amount.d.ts +17 -0
  8. package/es/components/loading-amount.js +46 -0
  9. package/es/components/price-change-confirm.d.ts +18 -0
  10. package/es/components/price-change-confirm.js +107 -0
  11. package/es/components/quote-details-panel.d.ts +21 -0
  12. package/es/components/quote-details-panel.js +170 -0
  13. package/es/components/quote-lock-banner.d.ts +7 -0
  14. package/es/components/quote-lock-banner.js +79 -0
  15. package/es/components/slippage-config.d.ts +20 -0
  16. package/es/components/slippage-config.js +261 -0
  17. package/es/history/credit/transactions-list.js +11 -1
  18. package/es/history/invoice/list.js +125 -15
  19. package/es/hooks/dynamic-pricing.d.ts +102 -0
  20. package/es/hooks/dynamic-pricing.js +393 -0
  21. package/es/index.d.ts +6 -1
  22. package/es/index.js +9 -1
  23. package/es/libs/util.d.ts +42 -5
  24. package/es/libs/util.js +345 -57
  25. package/es/locales/en.js +114 -3
  26. package/es/locales/zh.js +114 -3
  27. package/es/payment/form/index.d.ts +4 -1
  28. package/es/payment/form/index.js +454 -22
  29. package/es/payment/index.d.ts +1 -1
  30. package/es/payment/index.js +279 -16
  31. package/es/payment/product-item.d.ts +26 -1
  32. package/es/payment/product-item.js +330 -51
  33. package/es/payment/summary-section/promotion-section.d.ts +32 -0
  34. package/es/payment/summary-section/promotion-section.js +143 -0
  35. package/es/payment/summary-section/total-section.d.ts +39 -0
  36. package/es/payment/summary-section/total-section.js +83 -0
  37. package/es/payment/summary.d.ts +17 -2
  38. package/es/payment/summary.js +300 -253
  39. package/es/types/index.d.ts +11 -0
  40. package/lib/components/auto-topup/modal.d.ts +2 -0
  41. package/lib/components/auto-topup/modal.js +54 -6
  42. package/lib/components/auto-topup/product-card.d.ts +16 -1
  43. package/lib/components/auto-topup/product-card.js +75 -7
  44. package/lib/components/dynamic-pricing-unavailable.d.ts +9 -0
  45. package/lib/components/dynamic-pricing-unavailable.js +81 -0
  46. package/lib/components/loading-amount.d.ts +17 -0
  47. package/lib/components/loading-amount.js +53 -0
  48. package/lib/components/price-change-confirm.d.ts +18 -0
  49. package/lib/components/price-change-confirm.js +157 -0
  50. package/lib/components/quote-details-panel.d.ts +21 -0
  51. package/lib/components/quote-details-panel.js +226 -0
  52. package/lib/components/quote-lock-banner.d.ts +7 -0
  53. package/lib/components/quote-lock-banner.js +93 -0
  54. package/lib/components/slippage-config.d.ts +20 -0
  55. package/lib/components/slippage-config.js +316 -0
  56. package/lib/history/credit/transactions-list.js +11 -1
  57. package/lib/history/invoice/list.js +167 -27
  58. package/lib/hooks/dynamic-pricing.d.ts +102 -0
  59. package/lib/hooks/dynamic-pricing.js +390 -0
  60. package/lib/index.d.ts +6 -1
  61. package/lib/index.js +32 -0
  62. package/lib/libs/util.d.ts +42 -5
  63. package/lib/libs/util.js +367 -49
  64. package/lib/locales/en.js +114 -3
  65. package/lib/locales/zh.js +114 -3
  66. package/lib/payment/form/index.d.ts +4 -1
  67. package/lib/payment/form/index.js +476 -20
  68. package/lib/payment/index.d.ts +1 -1
  69. package/lib/payment/index.js +308 -14
  70. package/lib/payment/product-item.d.ts +26 -1
  71. package/lib/payment/product-item.js +270 -35
  72. package/lib/payment/summary-section/promotion-section.d.ts +32 -0
  73. package/lib/payment/summary-section/promotion-section.js +133 -0
  74. package/lib/payment/summary-section/total-section.d.ts +39 -0
  75. package/lib/payment/summary-section/total-section.js +117 -0
  76. package/lib/payment/summary.d.ts +17 -2
  77. package/lib/payment/summary.js +205 -127
  78. package/lib/types/index.d.ts +11 -0
  79. package/package.json +3 -3
  80. package/src/components/auto-topup/modal.tsx +59 -6
  81. package/src/components/auto-topup/product-card.tsx +118 -11
  82. package/src/components/dynamic-pricing-unavailable.tsx +69 -0
  83. package/src/components/loading-amount.tsx +66 -0
  84. package/src/components/price-change-confirm.tsx +136 -0
  85. package/src/components/quote-details-panel.tsx +218 -0
  86. package/src/components/quote-lock-banner.tsx +99 -0
  87. package/src/components/slippage-config.tsx +336 -0
  88. package/src/history/credit/transactions-list.tsx +14 -1
  89. package/src/history/invoice/list.tsx +143 -9
  90. package/src/hooks/dynamic-pricing.ts +617 -0
  91. package/src/index.ts +9 -0
  92. package/src/libs/util.ts +473 -58
  93. package/src/locales/en.tsx +117 -0
  94. package/src/locales/zh.tsx +111 -0
  95. package/src/payment/form/index.tsx +561 -19
  96. package/src/payment/index.tsx +349 -10
  97. package/src/payment/product-item.tsx +451 -37
  98. package/src/payment/summary-section/promotion-section.tsx +172 -0
  99. package/src/payment/summary-section/total-section.tsx +141 -0
  100. package/src/payment/summary.tsx +334 -192
  101. package/src/types/index.ts +15 -0
@@ -0,0 +1,143 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
+ import { Close, LocalOffer } from "@mui/icons-material";
4
+ import { Box, Button, Stack, Typography } from "@mui/material";
5
+ import PromotionCode from "../../components/promotion-code.js";
6
+ import { formatAmount, formatCouponTerms } from "../../libs/util.js";
7
+ export default function PromotionSection({
8
+ checkoutSessionId,
9
+ currency,
10
+ currencyId,
11
+ discounts,
12
+ allowPromotionCodes,
13
+ completed = false,
14
+ disabled = false,
15
+ onPromotionUpdate,
16
+ onRemovePromotion,
17
+ calculatedDiscountAmount = null,
18
+ isRateLoading = false
19
+ }) {
20
+ const { t, locale } = useLocaleContext();
21
+ const hasDiscounts = discounts?.length > 0;
22
+ const getAppliedPromotionCodes = () => {
23
+ if (!discounts?.length) return [];
24
+ return discounts.filter((discount) => discount.promotion_code || discount.coupon).map((discount) => ({
25
+ id: discount.promotion_code || discount.coupon,
26
+ code: discount.verification_data?.code || "APPLIED",
27
+ discount_amount: discount.discount_amount
28
+ }));
29
+ };
30
+ if (allowPromotionCodes && !hasDiscounts) {
31
+ return /* @__PURE__ */ jsx(Box, { sx: { mt: 1 }, children: /* @__PURE__ */ jsx(
32
+ PromotionCode,
33
+ {
34
+ checkoutSessionId,
35
+ initialAppliedCodes: getAppliedPromotionCodes(),
36
+ disabled: completed,
37
+ onUpdate: onPromotionUpdate,
38
+ currencyId
39
+ }
40
+ ) });
41
+ }
42
+ if (!hasDiscounts) {
43
+ return null;
44
+ }
45
+ return /* @__PURE__ */ jsx(Box, { children: discounts.map((discount) => {
46
+ const promotionCodeInfo = discount.promotion_code_details;
47
+ const couponInfo = discount.coupon_details;
48
+ const discountDescription = couponInfo ? formatCouponTerms(couponInfo, currency, locale) : "";
49
+ const notSupported = discountDescription === t("payment.checkout.coupon.noDiscount");
50
+ return /* @__PURE__ */ jsxs(Stack, { children: [
51
+ /* @__PURE__ */ jsxs(
52
+ Stack,
53
+ {
54
+ direction: "row",
55
+ spacing: 1,
56
+ sx: {
57
+ justifyContent: "space-between",
58
+ alignItems: "center"
59
+ },
60
+ children: [
61
+ /* @__PURE__ */ jsxs(
62
+ Stack,
63
+ {
64
+ direction: "row",
65
+ spacing: 1,
66
+ sx: {
67
+ alignItems: "center",
68
+ backgroundColor: "grey.100",
69
+ width: "fit-content",
70
+ px: 1,
71
+ py: 1,
72
+ borderRadius: 1
73
+ },
74
+ children: [
75
+ /* @__PURE__ */ jsxs(
76
+ Typography,
77
+ {
78
+ sx: {
79
+ fontWeight: "medium",
80
+ display: "flex",
81
+ alignItems: "center",
82
+ gap: 0.5
83
+ },
84
+ children: [
85
+ /* @__PURE__ */ jsx(LocalOffer, { sx: { color: "warning.main", fontSize: "small" } }),
86
+ promotionCodeInfo?.code || discount.verification_data?.code || t("payment.checkout.discount")
87
+ ]
88
+ }
89
+ ),
90
+ !completed && /* @__PURE__ */ jsx(
91
+ Button,
92
+ {
93
+ size: "small",
94
+ disabled,
95
+ onClick: () => onRemovePromotion(checkoutSessionId),
96
+ sx: {
97
+ minWidth: "auto",
98
+ width: 16,
99
+ height: 16,
100
+ color: "text.secondary",
101
+ "&.Mui-disabled": {
102
+ color: "text.disabled"
103
+ }
104
+ },
105
+ children: /* @__PURE__ */ jsx(Close, { sx: { fontSize: 14 } })
106
+ }
107
+ )
108
+ ]
109
+ }
110
+ ),
111
+ /* @__PURE__ */ jsxs(
112
+ Typography,
113
+ {
114
+ sx: {
115
+ color: "text.secondary",
116
+ opacity: isRateLoading ? 0 : 1,
117
+ transition: "opacity 300ms ease-in-out"
118
+ },
119
+ children: [
120
+ "-",
121
+ formatAmount(calculatedDiscountAmount || "0", currency.decimal),
122
+ " ",
123
+ currency.symbol
124
+ ]
125
+ }
126
+ )
127
+ ]
128
+ }
129
+ ),
130
+ discountDescription && /* @__PURE__ */ jsx(
131
+ Typography,
132
+ {
133
+ sx: {
134
+ fontSize: "small",
135
+ color: notSupported ? "error.main" : "text.secondary",
136
+ mt: 0.5
137
+ },
138
+ children: discountDescription
139
+ }
140
+ )
141
+ ] }, discount.promotion_code || discount.coupon || `discount-${discount.discount_amount}`);
142
+ }) });
143
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * TotalSection Component
3
+ *
4
+ * Displays total amount, USD equivalent, exchange rate details,
5
+ * and quote information for dynamic pricing.
6
+ */
7
+ import type { TPaymentCurrency } from '@blocklet/payment-types';
8
+ import type { SlippageConfigValue } from '../../components/slippage-config';
9
+ export interface RateInfo {
10
+ exchangeRate: string | null;
11
+ baseCurrency: string;
12
+ providerName?: string | null;
13
+ providerId?: string | null;
14
+ timestampMs?: number | null;
15
+ }
16
+ export interface QuoteDetailRow {
17
+ label: string;
18
+ value: string | React.ReactNode;
19
+ isSlippage?: boolean;
20
+ }
21
+ export interface TotalSectionProps {
22
+ totalAmountText: string;
23
+ totalUsdDisplay: string | null;
24
+ currency: TPaymentCurrency;
25
+ hasDynamicPricing: boolean;
26
+ rateDisplay: string | null;
27
+ rateInfo: RateInfo;
28
+ quoteDetailRows: QuoteDetailRow[];
29
+ currentSlippagePercent: number;
30
+ slippageConfig?: SlippageConfigValue;
31
+ isPriceLocked: boolean;
32
+ isSubscription: boolean;
33
+ completed?: boolean;
34
+ onSlippageChange?: (slippageConfig: SlippageConfigValue) => void;
35
+ isStripePayment?: boolean;
36
+ thenInfo?: string;
37
+ isRateLoading?: boolean;
38
+ }
39
+ export default function TotalSection({ totalAmountText, totalUsdDisplay, currency, hasDynamicPricing, rateDisplay, rateInfo, quoteDetailRows, currentSlippagePercent, slippageConfig, isPriceLocked, isSubscription, completed, onSlippageChange, isStripePayment, thenInfo, isRateLoading, }: TotalSectionProps): import("react").JSX.Element;
@@ -0,0 +1,83 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
+ import { Box, Skeleton, Stack, Tooltip, Typography } from "@mui/material";
4
+ import PaymentAmount from "../amount.js";
5
+ import QuoteDetailsPanel from "../../components/quote-details-panel.js";
6
+ export default function TotalSection({
7
+ totalAmountText,
8
+ totalUsdDisplay,
9
+ currency,
10
+ hasDynamicPricing,
11
+ rateDisplay,
12
+ rateInfo,
13
+ quoteDetailRows,
14
+ currentSlippagePercent,
15
+ slippageConfig = void 0,
16
+ isPriceLocked,
17
+ isSubscription,
18
+ completed = false,
19
+ onSlippageChange = void 0,
20
+ isStripePayment = false,
21
+ thenInfo = "",
22
+ isRateLoading = false
23
+ }) {
24
+ const { t } = useLocaleContext();
25
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
26
+ /* @__PURE__ */ jsxs(
27
+ Stack,
28
+ {
29
+ sx: {
30
+ display: "flex",
31
+ justifyContent: "space-between",
32
+ flexDirection: "row",
33
+ alignItems: "flex-start",
34
+ width: "100%"
35
+ },
36
+ children: [
37
+ /* @__PURE__ */ jsx(Box, { className: "base-label", children: t("common.total") }),
38
+ /* @__PURE__ */ jsxs(Stack, { sx: { alignItems: "flex-end" }, children: [
39
+ isRateLoading ? /* @__PURE__ */ jsx(Skeleton, { variant: "text", width: 100, height: 24 }) : /* @__PURE__ */ jsx(PaymentAmount, { amount: totalAmountText, sx: { fontSize: "16px" } }),
40
+ hasDynamicPricing && !isStripePayment && !isRateLoading && (totalUsdDisplay ? /* @__PURE__ */ jsxs(Typography, { sx: { fontSize: "0.7875rem", color: "text.lighter" }, children: [
41
+ "\u2248 $",
42
+ totalUsdDisplay
43
+ ] }) : /* @__PURE__ */ jsx(Tooltip, { title: t("payment.checkout.quote.referenceUnavailable"), placement: "top", children: /* @__PURE__ */ jsx(Box, { component: "span", children: /* @__PURE__ */ jsx(Typography, { sx: { fontSize: "0.7875rem", color: "text.lighter" }, children: "\u2248 \u2014" }) }) })),
44
+ hasDynamicPricing && !isStripePayment && /* @__PURE__ */ jsx(
45
+ QuoteDetailsPanel,
46
+ {
47
+ rateLine: rateDisplay ? t("payment.checkout.quote.rateLine", { symbol: currency.symbol, rate: rateDisplay }) : "",
48
+ rows: quoteDetailRows,
49
+ isSubscription,
50
+ slippageValue: currentSlippagePercent,
51
+ slippageConfig,
52
+ onSlippageChange: !completed && onSlippageChange ? onSlippageChange : void 0,
53
+ exchangeRate: rateInfo.exchangeRate,
54
+ baseCurrency: rateInfo.baseCurrency,
55
+ disabled: isPriceLocked
56
+ }
57
+ )
58
+ ] })
59
+ ]
60
+ }
61
+ ),
62
+ thenInfo && /* @__PURE__ */ jsxs(
63
+ Stack,
64
+ {
65
+ sx: {
66
+ display: "flex",
67
+ justifyContent: "space-between",
68
+ flexDirection: "row",
69
+ alignItems: "flex-start",
70
+ width: "100%",
71
+ borderTop: "1px solid",
72
+ borderColor: "divider",
73
+ pt: 1,
74
+ mt: 1
75
+ },
76
+ children: [
77
+ /* @__PURE__ */ jsx(Box, { className: "base-label", children: t("common.nextCharge") }),
78
+ /* @__PURE__ */ jsx(Typography, { sx: { fontSize: "16px", color: "text.secondary" }, children: thenInfo })
79
+ ]
80
+ }
81
+ )
82
+ ] });
83
+ }
@@ -1,4 +1,6 @@
1
- import type { DonationSettings, TLineItemExpanded, TPaymentCurrency, TCheckoutSession, TPaymentMethodExpanded } from '@blocklet/payment-types';
1
+ import type { DonationSettings, TCheckoutSession, TLineItemExpanded, TPaymentCurrency, TPaymentIntent, TPaymentMethodExpanded } from '@blocklet/payment-types';
2
+ import { type LiveRateInfo, type LiveQuoteSnapshot } from '../hooks/dynamic-pricing';
3
+ import type { SlippageConfigValue } from '../components/slippage-config';
2
4
  type Props = {
3
5
  items: TLineItemExpanded[];
4
6
  currency: TPaymentCurrency;
@@ -18,9 +20,22 @@ type Props = {
18
20
  action?: string;
19
21
  completed?: boolean;
20
22
  checkoutSession?: TCheckoutSession;
23
+ paymentIntent?: TPaymentIntent | null;
21
24
  onPromotionUpdate?: () => void;
22
25
  paymentMethods?: TPaymentMethodExpanded[];
23
26
  showFeatures?: boolean;
27
+ rateUnavailable?: boolean;
28
+ rateError?: string;
29
+ isRateLoading?: boolean;
30
+ onQuoteExpired?: (forceRefresh?: boolean) => void;
31
+ onRefreshRate?: () => Promise<void>;
32
+ onSlippageChange?: (slippageConfig: SlippageConfigValue) => void;
33
+ slippageConfig?: SlippageConfigValue;
34
+ liveRate?: LiveRateInfo;
35
+ liveQuoteSnapshot?: LiveQuoteSnapshot;
36
+ isStripePayment?: boolean;
37
+ isSubscription?: boolean;
24
38
  };
25
- export default function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onQuantityChange, onApplyCrossSell, onCancelCrossSell, onChangeAmount, checkoutSessionId, crossSellBehavior, showStaking, donationSettings, action, trialEnd, completed, checkoutSession, paymentMethods, onPromotionUpdate, showFeatures, ...rest }: Props): import("react").JSX.Element;
39
+ export default function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onQuantityChange, onApplyCrossSell, onCancelCrossSell, onChangeAmount, checkoutSessionId, crossSellBehavior, showStaking, donationSettings, action, trialEnd, completed, checkoutSession, paymentIntent, paymentMethods, onPromotionUpdate, showFeatures, rateUnavailable, isRateLoading, rateError: _rateError, // Technical errors are logged but not displayed to users
40
+ onQuoteExpired, onRefreshRate, onSlippageChange, slippageConfig: slippageConfigProp, liveRate, liveQuoteSnapshot, isStripePayment, isSubscription: isSubscriptionProp, ...rest }: Props): import("react").JSX.Element | null;
26
41
  export {};