@blocklet/payment-react 1.24.4 → 1.25.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 (98) 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/invoice/list.js +125 -15
  18. package/es/hooks/dynamic-pricing.d.ts +102 -0
  19. package/es/hooks/dynamic-pricing.js +393 -0
  20. package/es/index.d.ts +6 -1
  21. package/es/index.js +9 -1
  22. package/es/libs/util.d.ts +42 -5
  23. package/es/libs/util.js +345 -57
  24. package/es/locales/en.js +114 -3
  25. package/es/locales/zh.js +114 -3
  26. package/es/payment/form/index.d.ts +4 -1
  27. package/es/payment/form/index.js +454 -22
  28. package/es/payment/index.d.ts +1 -1
  29. package/es/payment/index.js +279 -16
  30. package/es/payment/product-item.d.ts +26 -1
  31. package/es/payment/product-item.js +330 -51
  32. package/es/payment/summary-section/promotion-section.d.ts +32 -0
  33. package/es/payment/summary-section/promotion-section.js +143 -0
  34. package/es/payment/summary-section/total-section.d.ts +39 -0
  35. package/es/payment/summary-section/total-section.js +83 -0
  36. package/es/payment/summary.d.ts +17 -2
  37. package/es/payment/summary.js +300 -253
  38. package/es/types/index.d.ts +11 -0
  39. package/lib/components/auto-topup/modal.d.ts +2 -0
  40. package/lib/components/auto-topup/modal.js +54 -6
  41. package/lib/components/auto-topup/product-card.d.ts +16 -1
  42. package/lib/components/auto-topup/product-card.js +75 -7
  43. package/lib/components/dynamic-pricing-unavailable.d.ts +9 -0
  44. package/lib/components/dynamic-pricing-unavailable.js +81 -0
  45. package/lib/components/loading-amount.d.ts +17 -0
  46. package/lib/components/loading-amount.js +53 -0
  47. package/lib/components/price-change-confirm.d.ts +18 -0
  48. package/lib/components/price-change-confirm.js +157 -0
  49. package/lib/components/quote-details-panel.d.ts +21 -0
  50. package/lib/components/quote-details-panel.js +226 -0
  51. package/lib/components/quote-lock-banner.d.ts +7 -0
  52. package/lib/components/quote-lock-banner.js +93 -0
  53. package/lib/components/slippage-config.d.ts +20 -0
  54. package/lib/components/slippage-config.js +316 -0
  55. package/lib/history/invoice/list.js +167 -27
  56. package/lib/hooks/dynamic-pricing.d.ts +102 -0
  57. package/lib/hooks/dynamic-pricing.js +390 -0
  58. package/lib/index.d.ts +6 -1
  59. package/lib/index.js +32 -0
  60. package/lib/libs/util.d.ts +42 -5
  61. package/lib/libs/util.js +367 -49
  62. package/lib/locales/en.js +114 -3
  63. package/lib/locales/zh.js +114 -3
  64. package/lib/payment/form/index.d.ts +4 -1
  65. package/lib/payment/form/index.js +476 -20
  66. package/lib/payment/index.d.ts +1 -1
  67. package/lib/payment/index.js +308 -14
  68. package/lib/payment/product-item.d.ts +26 -1
  69. package/lib/payment/product-item.js +270 -35
  70. package/lib/payment/summary-section/promotion-section.d.ts +32 -0
  71. package/lib/payment/summary-section/promotion-section.js +133 -0
  72. package/lib/payment/summary-section/total-section.d.ts +39 -0
  73. package/lib/payment/summary-section/total-section.js +117 -0
  74. package/lib/payment/summary.d.ts +17 -2
  75. package/lib/payment/summary.js +205 -127
  76. package/lib/types/index.d.ts +11 -0
  77. package/package.json +3 -3
  78. package/src/components/auto-topup/modal.tsx +59 -6
  79. package/src/components/auto-topup/product-card.tsx +118 -11
  80. package/src/components/dynamic-pricing-unavailable.tsx +69 -0
  81. package/src/components/loading-amount.tsx +66 -0
  82. package/src/components/price-change-confirm.tsx +136 -0
  83. package/src/components/quote-details-panel.tsx +218 -0
  84. package/src/components/quote-lock-banner.tsx +99 -0
  85. package/src/components/slippage-config.tsx +336 -0
  86. package/src/history/invoice/list.tsx +143 -9
  87. package/src/hooks/dynamic-pricing.ts +617 -0
  88. package/src/index.ts +9 -0
  89. package/src/libs/util.ts +473 -58
  90. package/src/locales/en.tsx +117 -0
  91. package/src/locales/zh.tsx +111 -0
  92. package/src/payment/form/index.tsx +561 -19
  93. package/src/payment/index.tsx +349 -10
  94. package/src/payment/product-item.tsx +451 -37
  95. package/src/payment/summary-section/promotion-section.tsx +172 -0
  96. package/src/payment/summary-section/total-section.tsx +141 -0
  97. package/src/payment/summary.tsx +334 -192
  98. package/src/types/index.ts +15 -0
@@ -11,6 +11,16 @@ export type CheckoutContext = {
11
11
  action?: string;
12
12
  showCheckoutSummary?: boolean;
13
13
  currencyId?: string;
14
+ quotes?: Record<string, {
15
+ quote_id: string;
16
+ expires_at: number;
17
+ quoted_amount: string;
18
+ exchange_rate?: string;
19
+ rate_provider_name?: string;
20
+ rate_provider_id?: string;
21
+ }>;
22
+ rateUnavailable?: boolean;
23
+ rateError?: string;
14
24
  };
15
25
  export type CheckoutFormData = {
16
26
  customer_name: string;
@@ -44,6 +54,7 @@ export type CheckoutCallbacks = {
44
54
  onError: (err: Error) => void;
45
55
  onChange?: (data: CheckoutFormData) => void;
46
56
  goBack?: () => void;
57
+ onRefreshQuote?: () => Promise<boolean>;
47
58
  };
48
59
  export type PricingRenderProps = {
49
60
  totalPrice: string;
@@ -1,4 +1,5 @@
1
1
  import type { AutoRechargeConfig } from '@blocklet/payment-types';
2
+ import type { SlippageConfigValue } from '../slippage-config';
2
3
  export interface AutoTopupFormData {
3
4
  enabled: boolean;
4
5
  threshold: string;
@@ -21,6 +22,7 @@ export interface AutoTopupFormData {
21
22
  city?: string;
22
23
  postal_code?: string;
23
24
  };
25
+ slippage_config?: SlippageConfigValue | null;
24
26
  }
25
27
  export interface AutoTopupModalProps {
26
28
  open: boolean;
@@ -58,7 +58,16 @@ const DEFAULT_VALUES = {
58
58
  recharge_currency_id: "",
59
59
  price_id: "",
60
60
  daily_max_amount: 0,
61
- daily_max_attempts: 0
61
+ daily_max_attempts: 0,
62
+ slippage_config: null
63
+ };
64
+ const fetchExchangeRate = async currencyId => {
65
+ const {
66
+ data
67
+ } = await _api.default.post("/api/exchange-rates/validate", {
68
+ currency: currencyId
69
+ });
70
+ return data;
62
71
  };
63
72
  const waitForAutoRechargeComplete = async configId => {
64
73
  let result;
@@ -281,6 +290,8 @@ function AutoTopup({
281
290
  settings
282
291
  } = (0, _payment.usePaymentContext)();
283
292
  const [changePaymentMethod, setChangePaymentMethod] = (0, _react.useState)(false);
293
+ const [slippagePercent, setSlippagePercent] = (0, _react.useState)(0.5);
294
+ const [slippageConfig, setSlippageConfig] = (0, _react.useState)(null);
284
295
  const [state, setState] = (0, _ahooks.useSetState)({
285
296
  loading: false,
286
297
  submitting: false,
@@ -316,6 +327,10 @@ function AutoTopup({
316
327
  const enabled = watch("enabled");
317
328
  const quantity = watch("quantity");
318
329
  const rechargeCurrencyId = watch("recharge_currency_id");
330
+ const selectedMethod = settings.paymentMethods.find(method => {
331
+ return method.payment_currencies.find(c => c.id === rechargeCurrencyId);
332
+ });
333
+ const isStripePayment = selectedMethod?.type === "stripe";
319
334
  const handleClose = () => {
320
335
  setState({
321
336
  loading: false,
@@ -343,6 +358,24 @@ function AutoTopup({
343
358
  max_amount: data.daily_limits?.max_amount || 0,
344
359
  max_attempts: data.daily_limits?.max_attempts || 0
345
360
  });
361
+ if (data.slippage_config) {
362
+ setSlippageConfig(data.slippage_config);
363
+ setSlippagePercent(data.slippage_config.percent ?? 0.5);
364
+ }
365
+ }
366
+ });
367
+ const isDynamicPricing = config?.price?.pricing_type === "dynamic";
368
+ const {
369
+ data: exchangeRateData
370
+ } = (0, _ahooks.useRequest)(() => fetchExchangeRate(rechargeCurrencyId), {
371
+ refreshDeps: [rechargeCurrencyId],
372
+ ready: !!rechargeCurrencyId && isDynamicPricing && enabled && !isStripePayment,
373
+ pollingInterval: 3e4,
374
+ // Refresh every 30 seconds
375
+ pollingWhenHidden: false,
376
+ // Stop polling when tab is hidden
377
+ onError: error => {
378
+ console.warn("Failed to fetch exchange rate:", error.message);
346
379
  }
347
380
  });
348
381
  const filterCurrencies = (0, _react.useMemo)(() => {
@@ -477,6 +510,12 @@ function AutoTopup({
477
510
  },
478
511
  change_payment_method: changePaymentMethod
479
512
  };
513
+ if (isDynamicPricing && slippageConfig) {
514
+ submitData.slippage_config = {
515
+ ...slippageConfig,
516
+ updated_at_ms: Date.now()
517
+ };
518
+ }
480
519
  const {
481
520
  data
482
521
  } = await _api.default.post("/api/auto-recharge-configs/submit", submitData);
@@ -508,10 +547,7 @@ function AutoTopup({
508
547
  handleFormSubmit(formData);
509
548
  };
510
549
  const rechargeCurrency = filterCurrencies.find(c => c.id === rechargeCurrencyId);
511
- const selectedMethod = settings.paymentMethods.find(method => {
512
- return method.payment_currencies.find(c => c.id === rechargeCurrencyId);
513
- });
514
- const showStripeForm = state.authorizationRequired && selectedMethod?.type === "stripe";
550
+ const showStripeForm = state.authorizationRequired && isStripePayment;
515
551
  const onStripeConfirm = async () => {
516
552
  await handleConnected();
517
553
  };
@@ -713,7 +749,19 @@ function AutoTopup({
713
749
  quantity,
714
750
  onQuantityChange: newQuantity => setValue("quantity", newQuantity),
715
751
  maxQuantity: 9999,
716
- minQuantity: 1
752
+ minQuantity: 1,
753
+ exchangeRate: exchangeRateData?.rate,
754
+ isDynamicPricing: isDynamicPricing && !isStripePayment,
755
+ exchangeRateData,
756
+ slippageConfig,
757
+ slippagePercent,
758
+ onSlippageChange: newSlippageConfig => {
759
+ setSlippageConfig(newSlippageConfig);
760
+ if (newSlippageConfig.percent !== void 0) {
761
+ setSlippagePercent(newSlippageConfig.percent);
762
+ }
763
+ },
764
+ disabled: state.submitting
717
765
  }), config && rechargeCurrency && /* @__PURE__ */(0, _jsxRuntime.jsx)(PaymentMethodDisplay, {
718
766
  config,
719
767
  onChangePaymentMethod: setChangePaymentMethod,
@@ -1,4 +1,12 @@
1
1
  import type { TPaymentCurrency } from '@blocklet/payment-types';
2
+ import type { SlippageConfigValue } from '../slippage-config';
3
+ interface ExchangeRateData {
4
+ rate?: string;
5
+ provider_name?: string;
6
+ provider_id?: string;
7
+ provider_display?: string;
8
+ timestamp_ms?: number;
9
+ }
2
10
  interface AutoTopupProductCardProps {
3
11
  product: any;
4
12
  price: any;
@@ -8,6 +16,13 @@ interface AutoTopupProductCardProps {
8
16
  maxQuantity?: number;
9
17
  minQuantity?: number;
10
18
  creditCurrency: TPaymentCurrency;
19
+ exchangeRate?: string | null;
20
+ isDynamicPricing?: boolean;
21
+ exchangeRateData?: ExchangeRateData | null;
22
+ slippageConfig?: SlippageConfigValue | null;
23
+ slippagePercent?: number;
24
+ onSlippageChange?: (config: SlippageConfigValue) => void;
25
+ disabled?: boolean;
11
26
  }
12
- export default function AutoTopupProductCard({ product, price, currency, quantity, onQuantityChange, maxQuantity, minQuantity, creditCurrency, }: AutoTopupProductCardProps): import("react").JSX.Element;
27
+ export default function AutoTopupProductCard({ product, price, currency, quantity, onQuantityChange, maxQuantity, minQuantity, creditCurrency, exchangeRate, isDynamicPricing, exchangeRateData, slippageConfig, slippagePercent, onSlippageChange, disabled, }: AutoTopupProductCardProps): import("react").JSX.Element;
13
28
  export {};
@@ -10,6 +10,7 @@ var _context = require("@arcblock/ux/lib/Locale/context");
10
10
  var _react = require("react");
11
11
  var _productCard = _interopRequireDefault(require("../../payment/product-card"));
12
12
  var _util = require("../../libs/util");
13
+ var _quoteDetailsPanel = _interopRequireDefault(require("../quote-details-panel"));
13
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
15
  function AutoTopupProductCard({
15
16
  product,
@@ -19,7 +20,14 @@ function AutoTopupProductCard({
19
20
  onQuantityChange,
20
21
  maxQuantity = 99,
21
22
  minQuantity = 1,
22
- creditCurrency
23
+ creditCurrency,
24
+ exchangeRate = null,
25
+ isDynamicPricing = false,
26
+ exchangeRateData = null,
27
+ slippageConfig = null,
28
+ slippagePercent = 0.5,
29
+ onSlippageChange = void 0,
30
+ disabled = false
23
31
  }) {
24
32
  const {
25
33
  t,
@@ -27,6 +35,32 @@ function AutoTopupProductCard({
27
35
  } = (0, _context.useLocaleContext)();
28
36
  const [localQuantity, setLocalQuantity] = (0, _react.useState)(quantity);
29
37
  const localQuantityNum = Number(localQuantity) || 0;
38
+ const {
39
+ paymentAmount,
40
+ usdReferenceDisplay
41
+ } = (0, _react.useMemo)(() => {
42
+ if (!isDynamicPricing || !exchangeRate || !price?.base_amount) {
43
+ return {
44
+ paymentAmount: (0, _util.formatPrice)(price, currency, product?.unit_label, localQuantity, true),
45
+ usdReferenceDisplay: null
46
+ };
47
+ }
48
+ const baseAmount = Number(price.base_amount) * localQuantityNum;
49
+ const rate = Number(exchangeRate);
50
+ if (rate <= 0 || !Number.isFinite(baseAmount)) {
51
+ return {
52
+ paymentAmount: (0, _util.formatPrice)(price, currency, product?.unit_label, localQuantity, true),
53
+ usdReferenceDisplay: null
54
+ };
55
+ }
56
+ const tokenAmount = baseAmount / rate;
57
+ const formattedToken = (0, _util.formatDynamicPrice)(tokenAmount, true, 6);
58
+ const formattedUsd = (0, _util.formatUsdAmount)(baseAmount.toString(), locale);
59
+ return {
60
+ paymentAmount: `${formattedToken} ${currency.symbol}`,
61
+ usdReferenceDisplay: formattedUsd ? `\u2248 $${formattedUsd}` : null
62
+ };
63
+ }, [isDynamicPricing, exchangeRate, price, currency, product?.unit_label, localQuantity, localQuantityNum, locale]);
30
64
  const handleQuantityChange = newQuantity => {
31
65
  if (!newQuantity) {
32
66
  setLocalQuantity(void 0);
@@ -124,7 +158,7 @@ function AutoTopupProductCard({
124
158
  direction: "row",
125
159
  sx: {
126
160
  justifyContent: "space-between",
127
- alignItems: "center",
161
+ alignItems: "flex-start",
128
162
  mt: 2,
129
163
  pt: 2,
130
164
  borderTop: "1px solid",
@@ -136,13 +170,47 @@ function AutoTopupProductCard({
136
170
  color: "text.secondary"
137
171
  },
138
172
  children: t("payment.autoTopup.rechargeAmount")
139
- }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
140
- variant: "h6",
173
+ }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
141
174
  sx: {
142
- fontWeight: 600,
143
- color: "text.primary"
175
+ alignItems: "flex-end"
144
176
  },
145
- children: (0, _util.formatPrice)(price, currency, product?.unit_label, localQuantity, true)
177
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
178
+ variant: "h6",
179
+ sx: {
180
+ fontWeight: 600,
181
+ color: "text.primary"
182
+ },
183
+ children: paymentAmount
184
+ }), usdReferenceDisplay && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
185
+ sx: {
186
+ fontSize: "0.7875rem",
187
+ color: "text.lighter"
188
+ },
189
+ children: usdReferenceDisplay
190
+ }), isDynamicPricing && exchangeRateData?.rate && /* @__PURE__ */(0, _jsxRuntime.jsx)(_quoteDetailsPanel.default, {
191
+ rateLine: t("payment.checkout.quote.rateLine", {
192
+ symbol: currency.symbol,
193
+ rate: `$${(0, _util.formatExchangeRate)(exchangeRateData.rate) || exchangeRateData.rate}`
194
+ }),
195
+ rows: [{
196
+ label: t("payment.checkout.quote.detailProvider"),
197
+ value: exchangeRateData?.provider_display || exchangeRateData?.provider_name || "\u2014"
198
+ }, {
199
+ label: t("payment.checkout.quote.detailUpdatedAt"),
200
+ value: exchangeRateData?.timestamp_ms ? (0, _util.formatToDatetime)(exchangeRateData.timestamp_ms, locale) : "\u2014"
201
+ }, {
202
+ label: t("payment.checkout.quote.detailSlippage"),
203
+ value: slippageConfig?.mode === "rate" && slippageConfig.min_acceptable_rate ? `$${(0, _util.formatExchangeRate)(slippageConfig.min_acceptable_rate) || slippageConfig.min_acceptable_rate}` : `${slippageConfig?.percent ?? slippagePercent}%`,
204
+ isSlippage: true
205
+ }],
206
+ isSubscription: true,
207
+ slippageValue: slippageConfig?.percent ?? slippagePercent,
208
+ slippageConfig: slippageConfig || void 0,
209
+ onSlippageChange,
210
+ exchangeRate: exchangeRateData?.rate,
211
+ baseCurrency: "USD",
212
+ disabled
213
+ })]
146
214
  })]
147
215
  })]
148
216
  });
@@ -0,0 +1,9 @@
1
+ import { type SxProps } from '@mui/material';
2
+ interface DynamicPricingUnavailableProps {
3
+ error?: string;
4
+ onRetry?: () => void | Promise<void>;
5
+ showRetry?: boolean;
6
+ sx?: SxProps;
7
+ }
8
+ export default function DynamicPricingUnavailable({ error, onRetry, showRetry, sx, }: DynamicPricingUnavailableProps): import("react").JSX.Element;
9
+ export {};
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ module.exports = DynamicPricingUnavailable;
7
+ var _jsxRuntime = require("react/jsx-runtime");
8
+ var _material = require("@mui/material");
9
+ var _iconsMaterial = require("@mui/icons-material");
10
+ var _context = require("@arcblock/ux/lib/Locale/context");
11
+ var _react = require("react");
12
+ function DynamicPricingUnavailable({
13
+ error = void 0,
14
+ onRetry = void 0,
15
+ showRetry = true,
16
+ sx = void 0
17
+ }) {
18
+ const {
19
+ t
20
+ } = (0, _context.useLocaleContext)();
21
+ const [retrying, setRetrying] = (0, _react.useState)(false);
22
+ if (error) {
23
+ console.error("[Dynamic Pricing Error]", error);
24
+ }
25
+ const handleRetry = async () => {
26
+ if (!onRetry || retrying) return;
27
+ setRetrying(true);
28
+ try {
29
+ await onRetry();
30
+ } finally {
31
+ setRetrying(false);
32
+ }
33
+ };
34
+ return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Alert, {
35
+ severity: "warning",
36
+ icon: /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.ErrorOutline, {}),
37
+ sx: {
38
+ borderRadius: 2,
39
+ "& .MuiAlert-message": {
40
+ width: "100%"
41
+ },
42
+ ...sx
43
+ },
44
+ children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
45
+ sx: {
46
+ display: "flex",
47
+ justifyContent: "space-between",
48
+ alignItems: "flex-start",
49
+ width: "100%"
50
+ },
51
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
52
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.AlertTitle, {
53
+ sx: {
54
+ fontWeight: 600
55
+ },
56
+ children: t("payment.dynamicPricing.unavailable.title")
57
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
58
+ variant: "body2",
59
+ sx: {
60
+ color: "text.secondary",
61
+ mt: 0.5
62
+ },
63
+ children: t("payment.dynamicPricing.unavailable.message")
64
+ })]
65
+ }), showRetry && onRetry && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Button, {
66
+ size: "small",
67
+ variant: "outlined",
68
+ onClick: handleRetry,
69
+ disabled: retrying,
70
+ startIcon: retrying ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.CircularProgress, {
71
+ size: 16
72
+ }) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.Refresh, {}),
73
+ sx: {
74
+ ml: 2,
75
+ flexShrink: 0
76
+ },
77
+ children: t("payment.dynamicPricing.unavailable.retry")
78
+ })]
79
+ })
80
+ });
81
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * LoadingAmount Component
3
+ *
4
+ * Displays amount with skeleton loading state during currency switch.
5
+ * Only shows skeleton when isRateLoading is true (currency switch scenario).
6
+ */
7
+ import type { SxProps, Theme } from '@mui/material';
8
+ export interface LoadingAmountProps {
9
+ value: string;
10
+ loading?: boolean;
11
+ skeletonWidth?: number;
12
+ height?: number;
13
+ sx?: SxProps<Theme>;
14
+ animateValueChange?: boolean;
15
+ transitionDuration?: number;
16
+ }
17
+ export default function LoadingAmount({ value, loading, skeletonWidth, height, sx, animateValueChange, transitionDuration, }: LoadingAmountProps): import("react").JSX.Element;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ module.exports = LoadingAmount;
7
+ var _jsxRuntime = require("react/jsx-runtime");
8
+ var _material = require("@mui/material");
9
+ var _react = require("react");
10
+ function LoadingAmount({
11
+ value,
12
+ loading = false,
13
+ skeletonWidth = 80,
14
+ height = 24,
15
+ sx = {},
16
+ animateValueChange = false,
17
+ transitionDuration = 300
18
+ }) {
19
+ const [displayValue, setDisplayValue] = (0, _react.useState)(value);
20
+ const [isTransitioning, setIsTransitioning] = (0, _react.useState)(false);
21
+ const prevValueRef = (0, _react.useRef)(value);
22
+ (0, _react.useEffect)(() => {
23
+ if (value !== prevValueRef.current) {
24
+ prevValueRef.current = value;
25
+ if (animateValueChange && !loading) {
26
+ setIsTransitioning(true);
27
+ const timer = setTimeout(() => {
28
+ setDisplayValue(value);
29
+ setIsTransitioning(false);
30
+ }, transitionDuration / 2);
31
+ return () => clearTimeout(timer);
32
+ }
33
+ setDisplayValue(value);
34
+ }
35
+ return void 0;
36
+ }, [value, loading, animateValueChange, transitionDuration]);
37
+ if (loading) {
38
+ return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Skeleton, {
39
+ variant: "text",
40
+ width: skeletonWidth,
41
+ height
42
+ });
43
+ }
44
+ return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
45
+ component: "span",
46
+ sx: {
47
+ ...sx,
48
+ opacity: isTransitioning ? 0 : 1,
49
+ transition: animateValueChange ? `opacity ${transitionDuration / 2}ms ease-in-out` : void 0
50
+ },
51
+ children: displayValue
52
+ });
53
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Price Change Confirmation Dialog (Final Freeze Architecture)
3
+ *
4
+ * Displayed when the price changes between Preview and Submit
5
+ * beyond the user's configured slippage threshold.
6
+ *
7
+ * @see Intent: blocklets/core/ai/intent/20260112-dynamic-price.md
8
+ */
9
+ export interface PriceChangeConfirmProps {
10
+ open: boolean;
11
+ previewRate?: string;
12
+ submitRate?: string;
13
+ changePercent: number;
14
+ onConfirm: () => void;
15
+ onCancel: () => void;
16
+ loading?: boolean;
17
+ }
18
+ export default function PriceChangeConfirm({ open, previewRate, submitRate, changePercent, onConfirm, onCancel, loading, }: PriceChangeConfirmProps): import("react").JSX.Element;
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ module.exports = PriceChangeConfirm;
7
+ var _jsxRuntime = require("react/jsx-runtime");
8
+ var _material = require("@mui/material");
9
+ var _WarningAmber = _interopRequireDefault(require("@mui/icons-material/WarningAmber"));
10
+ var _context = require("@arcblock/ux/lib/Locale/context");
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ function PriceChangeConfirm({
13
+ open,
14
+ previewRate = void 0,
15
+ submitRate = void 0,
16
+ changePercent,
17
+ onConfirm,
18
+ onCancel,
19
+ loading = false
20
+ }) {
21
+ const {
22
+ t
23
+ } = (0, _context.useLocaleContext)();
24
+ const changeDirection = changePercent > 0 ? "increased" : "decreased";
25
+ const absChangePercent = Math.abs(changePercent);
26
+ return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Dialog, {
27
+ open,
28
+ onClose: loading ? void 0 : onCancel,
29
+ maxWidth: "sm",
30
+ fullWidth: true,
31
+ PaperProps: {
32
+ sx: {
33
+ borderRadius: 2
34
+ }
35
+ },
36
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.DialogTitle, {
37
+ sx: {
38
+ display: "flex",
39
+ alignItems: "center",
40
+ gap: 1,
41
+ pb: 1
42
+ },
43
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_WarningAmber.default, {
44
+ color: "warning"
45
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
46
+ variant: "h6",
47
+ component: "span",
48
+ children: t("payment.checkout.priceChange.title", {
49
+ fallback: "Price Changed"
50
+ })
51
+ })]
52
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.DialogContent, {
53
+ children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
54
+ spacing: 2,
55
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
56
+ variant: "body1",
57
+ color: "text.secondary",
58
+ children: t("payment.checkout.priceChange.description", {
59
+ fallback: `The exchange rate has ${changeDirection} by ${absChangePercent.toFixed(2)}% since you started this checkout.`,
60
+ direction: changeDirection,
61
+ percent: absChangePercent.toFixed(2)
62
+ })
63
+ }), (previewRate || submitRate) && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
64
+ sx: {
65
+ bgcolor: "action.hover",
66
+ borderRadius: 1,
67
+ p: 2
68
+ },
69
+ children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
70
+ spacing: 1,
71
+ children: [previewRate && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
72
+ sx: {
73
+ display: "flex",
74
+ justifyContent: "space-between"
75
+ },
76
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
77
+ variant: "body2",
78
+ color: "text.secondary",
79
+ children: [t("payment.checkout.priceChange.previewRate", {
80
+ fallback: "Preview Rate"
81
+ }), ":"]
82
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
83
+ variant: "body2",
84
+ fontFamily: "monospace",
85
+ children: previewRate
86
+ })]
87
+ }), submitRate && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
88
+ sx: {
89
+ display: "flex",
90
+ justifyContent: "space-between"
91
+ },
92
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
93
+ variant: "body2",
94
+ color: "text.secondary",
95
+ children: [t("payment.checkout.priceChange.currentRate", {
96
+ fallback: "Current Rate"
97
+ }), ":"]
98
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
99
+ variant: "body2",
100
+ fontFamily: "monospace",
101
+ children: submitRate
102
+ })]
103
+ }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
104
+ sx: {
105
+ display: "flex",
106
+ justifyContent: "space-between"
107
+ },
108
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
109
+ variant: "body2",
110
+ color: "text.secondary",
111
+ children: [t("payment.checkout.priceChange.change", {
112
+ fallback: "Change"
113
+ }), ":"]
114
+ }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
115
+ variant: "body2",
116
+ fontWeight: "bold",
117
+ color: changePercent > 0 ? "error.main" : "success.main",
118
+ children: [changePercent > 0 ? "+" : "", changePercent.toFixed(2), "%"]
119
+ })]
120
+ })]
121
+ })
122
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
123
+ variant: "body2",
124
+ color: "text.secondary",
125
+ children: t("payment.checkout.priceChange.confirm", {
126
+ fallback: "Do you want to continue with the new price?"
127
+ })
128
+ })]
129
+ })
130
+ }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.DialogActions, {
131
+ sx: {
132
+ px: 3,
133
+ pb: 2
134
+ },
135
+ children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Button, {
136
+ onClick: onCancel,
137
+ disabled: loading,
138
+ variant: "outlined",
139
+ color: "inherit",
140
+ children: t("payment.checkout.priceChange.cancel", {
141
+ fallback: "Cancel"
142
+ })
143
+ }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Button, {
144
+ onClick: onConfirm,
145
+ disabled: loading,
146
+ variant: "contained",
147
+ color: "primary",
148
+ autoFocus: true,
149
+ children: loading ? t("payment.checkout.priceChange.confirming", {
150
+ fallback: "Confirming..."
151
+ }) : t("payment.checkout.priceChange.accept", {
152
+ fallback: "Accept & Continue"
153
+ })
154
+ })]
155
+ })]
156
+ });
157
+ }
@@ -0,0 +1,21 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { SlippageConfigValue } from './slippage-config';
3
+ type QuoteDetailRow = {
4
+ label: string;
5
+ value: ReactNode;
6
+ isSlippage?: boolean;
7
+ tooltip?: string;
8
+ };
9
+ type QuoteDetailsPanelProps = {
10
+ rateLine: string;
11
+ rows: QuoteDetailRow[];
12
+ isSubscription?: boolean;
13
+ slippageValue?: number;
14
+ onSlippageChange?: (value: SlippageConfigValue) => void | Promise<void>;
15
+ slippageConfig?: SlippageConfigValue;
16
+ exchangeRate?: string | null;
17
+ baseCurrency?: string;
18
+ disabled?: boolean;
19
+ };
20
+ export default function QuoteDetailsPanel({ rateLine, rows, isSubscription, slippageValue, onSlippageChange, slippageConfig, exchangeRate, baseCurrency, disabled, }: QuoteDetailsPanelProps): import("react").JSX.Element | null;
21
+ export {};