@blocklet/payment-react 1.24.4 → 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.
- package/es/components/auto-topup/modal.d.ts +2 -0
- package/es/components/auto-topup/modal.js +48 -6
- package/es/components/auto-topup/product-card.d.ts +16 -1
- package/es/components/auto-topup/product-card.js +97 -15
- package/es/components/dynamic-pricing-unavailable.d.ts +9 -0
- package/es/components/dynamic-pricing-unavailable.js +58 -0
- package/es/components/loading-amount.d.ts +17 -0
- package/es/components/loading-amount.js +46 -0
- package/es/components/price-change-confirm.d.ts +18 -0
- package/es/components/price-change-confirm.js +107 -0
- package/es/components/quote-details-panel.d.ts +21 -0
- package/es/components/quote-details-panel.js +170 -0
- package/es/components/quote-lock-banner.d.ts +7 -0
- package/es/components/quote-lock-banner.js +79 -0
- package/es/components/slippage-config.d.ts +20 -0
- package/es/components/slippage-config.js +261 -0
- package/es/history/invoice/list.js +125 -15
- package/es/hooks/dynamic-pricing.d.ts +102 -0
- package/es/hooks/dynamic-pricing.js +393 -0
- package/es/index.d.ts +6 -1
- package/es/index.js +9 -1
- package/es/libs/util.d.ts +42 -5
- package/es/libs/util.js +345 -57
- package/es/locales/en.js +114 -3
- package/es/locales/zh.js +114 -3
- package/es/payment/form/index.d.ts +4 -1
- package/es/payment/form/index.js +454 -22
- package/es/payment/index.d.ts +1 -1
- package/es/payment/index.js +279 -16
- package/es/payment/product-item.d.ts +26 -1
- package/es/payment/product-item.js +330 -51
- package/es/payment/summary-section/promotion-section.d.ts +32 -0
- package/es/payment/summary-section/promotion-section.js +143 -0
- package/es/payment/summary-section/total-section.d.ts +39 -0
- package/es/payment/summary-section/total-section.js +83 -0
- package/es/payment/summary.d.ts +17 -2
- package/es/payment/summary.js +300 -253
- package/es/types/index.d.ts +11 -0
- package/lib/components/auto-topup/modal.d.ts +2 -0
- package/lib/components/auto-topup/modal.js +54 -6
- package/lib/components/auto-topup/product-card.d.ts +16 -1
- package/lib/components/auto-topup/product-card.js +75 -7
- package/lib/components/dynamic-pricing-unavailable.d.ts +9 -0
- package/lib/components/dynamic-pricing-unavailable.js +81 -0
- package/lib/components/loading-amount.d.ts +17 -0
- package/lib/components/loading-amount.js +53 -0
- package/lib/components/price-change-confirm.d.ts +18 -0
- package/lib/components/price-change-confirm.js +157 -0
- package/lib/components/quote-details-panel.d.ts +21 -0
- package/lib/components/quote-details-panel.js +226 -0
- package/lib/components/quote-lock-banner.d.ts +7 -0
- package/lib/components/quote-lock-banner.js +93 -0
- package/lib/components/slippage-config.d.ts +20 -0
- package/lib/components/slippage-config.js +316 -0
- package/lib/history/invoice/list.js +167 -27
- package/lib/hooks/dynamic-pricing.d.ts +102 -0
- package/lib/hooks/dynamic-pricing.js +390 -0
- package/lib/index.d.ts +6 -1
- package/lib/index.js +32 -0
- package/lib/libs/util.d.ts +42 -5
- package/lib/libs/util.js +367 -49
- package/lib/locales/en.js +114 -3
- package/lib/locales/zh.js +114 -3
- package/lib/payment/form/index.d.ts +4 -1
- package/lib/payment/form/index.js +476 -20
- package/lib/payment/index.d.ts +1 -1
- package/lib/payment/index.js +308 -14
- package/lib/payment/product-item.d.ts +26 -1
- package/lib/payment/product-item.js +270 -35
- package/lib/payment/summary-section/promotion-section.d.ts +32 -0
- package/lib/payment/summary-section/promotion-section.js +133 -0
- package/lib/payment/summary-section/total-section.d.ts +39 -0
- package/lib/payment/summary-section/total-section.js +117 -0
- package/lib/payment/summary.d.ts +17 -2
- package/lib/payment/summary.js +205 -127
- package/lib/types/index.d.ts +11 -0
- package/package.json +3 -3
- package/src/components/auto-topup/modal.tsx +59 -6
- package/src/components/auto-topup/product-card.tsx +118 -11
- package/src/components/dynamic-pricing-unavailable.tsx +69 -0
- package/src/components/loading-amount.tsx +66 -0
- package/src/components/price-change-confirm.tsx +136 -0
- package/src/components/quote-details-panel.tsx +218 -0
- package/src/components/quote-lock-banner.tsx +99 -0
- package/src/components/slippage-config.tsx +336 -0
- package/src/history/invoice/list.tsx +143 -9
- package/src/hooks/dynamic-pricing.ts +617 -0
- package/src/index.ts +9 -0
- package/src/libs/util.ts +473 -58
- package/src/locales/en.tsx +117 -0
- package/src/locales/zh.tsx +111 -0
- package/src/payment/form/index.tsx +561 -19
- package/src/payment/index.tsx +349 -10
- package/src/payment/product-item.tsx +451 -37
- package/src/payment/summary-section/promotion-section.tsx +172 -0
- package/src/payment/summary-section/total-section.tsx +141 -0
- package/src/payment/summary.tsx +334 -192
- package/src/types/index.ts +15 -0
package/es/types/index.d.ts
CHANGED
|
@@ -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
|
|
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: "
|
|
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.
|
|
140
|
-
variant: "h6",
|
|
173
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
141
174
|
sx: {
|
|
142
|
-
|
|
143
|
-
color: "text.primary"
|
|
175
|
+
alignItems: "flex-end"
|
|
144
176
|
},
|
|
145
|
-
children: (0,
|
|
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 {};
|