@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
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
module.exports = TotalSection;
|
|
7
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
8
|
+
var _context = require("@arcblock/ux/lib/Locale/context");
|
|
9
|
+
var _material = require("@mui/material");
|
|
10
|
+
var _amount = _interopRequireDefault(require("../amount"));
|
|
11
|
+
var _quoteDetailsPanel = _interopRequireDefault(require("../../components/quote-details-panel"));
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
function TotalSection({
|
|
14
|
+
totalAmountText,
|
|
15
|
+
totalUsdDisplay,
|
|
16
|
+
currency,
|
|
17
|
+
hasDynamicPricing,
|
|
18
|
+
rateDisplay,
|
|
19
|
+
rateInfo,
|
|
20
|
+
quoteDetailRows,
|
|
21
|
+
currentSlippagePercent,
|
|
22
|
+
slippageConfig = void 0,
|
|
23
|
+
isPriceLocked,
|
|
24
|
+
isSubscription,
|
|
25
|
+
completed = false,
|
|
26
|
+
onSlippageChange = void 0,
|
|
27
|
+
isStripePayment = false,
|
|
28
|
+
thenInfo = "",
|
|
29
|
+
isRateLoading = false
|
|
30
|
+
}) {
|
|
31
|
+
const {
|
|
32
|
+
t
|
|
33
|
+
} = (0, _context.useLocaleContext)();
|
|
34
|
+
return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
35
|
+
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
36
|
+
sx: {
|
|
37
|
+
display: "flex",
|
|
38
|
+
justifyContent: "space-between",
|
|
39
|
+
flexDirection: "row",
|
|
40
|
+
alignItems: "flex-start",
|
|
41
|
+
width: "100%"
|
|
42
|
+
},
|
|
43
|
+
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
44
|
+
className: "base-label",
|
|
45
|
+
children: t("common.total")
|
|
46
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
47
|
+
sx: {
|
|
48
|
+
alignItems: "flex-end"
|
|
49
|
+
},
|
|
50
|
+
children: [isRateLoading ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Skeleton, {
|
|
51
|
+
variant: "text",
|
|
52
|
+
width: 100,
|
|
53
|
+
height: 24
|
|
54
|
+
}) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_amount.default, {
|
|
55
|
+
amount: totalAmountText,
|
|
56
|
+
sx: {
|
|
57
|
+
fontSize: "16px"
|
|
58
|
+
}
|
|
59
|
+
}), hasDynamicPricing && !isStripePayment && !isRateLoading && (totalUsdDisplay ? /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
|
|
60
|
+
sx: {
|
|
61
|
+
fontSize: "0.7875rem",
|
|
62
|
+
color: "text.lighter"
|
|
63
|
+
},
|
|
64
|
+
children: ["\u2248 $", totalUsdDisplay]
|
|
65
|
+
}) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Tooltip, {
|
|
66
|
+
title: t("payment.checkout.quote.referenceUnavailable"),
|
|
67
|
+
placement: "top",
|
|
68
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
69
|
+
component: "span",
|
|
70
|
+
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
71
|
+
sx: {
|
|
72
|
+
fontSize: "0.7875rem",
|
|
73
|
+
color: "text.lighter"
|
|
74
|
+
},
|
|
75
|
+
children: "\u2248 \u2014"
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
})), hasDynamicPricing && !isStripePayment && /* @__PURE__ */(0, _jsxRuntime.jsx)(_quoteDetailsPanel.default, {
|
|
79
|
+
rateLine: rateDisplay ? t("payment.checkout.quote.rateLine", {
|
|
80
|
+
symbol: currency.symbol,
|
|
81
|
+
rate: rateDisplay
|
|
82
|
+
}) : "",
|
|
83
|
+
rows: quoteDetailRows,
|
|
84
|
+
isSubscription,
|
|
85
|
+
slippageValue: currentSlippagePercent,
|
|
86
|
+
slippageConfig,
|
|
87
|
+
onSlippageChange: !completed && onSlippageChange ? onSlippageChange : void 0,
|
|
88
|
+
exchangeRate: rateInfo.exchangeRate,
|
|
89
|
+
baseCurrency: rateInfo.baseCurrency,
|
|
90
|
+
disabled: isPriceLocked
|
|
91
|
+
})]
|
|
92
|
+
})]
|
|
93
|
+
}), thenInfo && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
94
|
+
sx: {
|
|
95
|
+
display: "flex",
|
|
96
|
+
justifyContent: "space-between",
|
|
97
|
+
flexDirection: "row",
|
|
98
|
+
alignItems: "flex-start",
|
|
99
|
+
width: "100%",
|
|
100
|
+
borderTop: "1px solid",
|
|
101
|
+
borderColor: "divider",
|
|
102
|
+
pt: 1,
|
|
103
|
+
mt: 1
|
|
104
|
+
},
|
|
105
|
+
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
106
|
+
className: "base-label",
|
|
107
|
+
children: t("common.nextCharge")
|
|
108
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
109
|
+
sx: {
|
|
110
|
+
fontSize: "16px",
|
|
111
|
+
color: "text.secondary"
|
|
112
|
+
},
|
|
113
|
+
children: thenInfo
|
|
114
|
+
})]
|
|
115
|
+
})]
|
|
116
|
+
});
|
|
117
|
+
}
|
package/lib/payment/summary.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { DonationSettings, TLineItemExpanded, TPaymentCurrency,
|
|
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,
|
|
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 {};
|
package/lib/payment/summary.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
module.exports = PaymentSummary;
|
|
7
7
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
8
8
|
var _context = require("@arcblock/ux/lib/Locale/context");
|
|
9
|
+
var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
|
|
9
10
|
var _iconsMaterial = require("@mui/icons-material");
|
|
10
11
|
var _material = require("@mui/material");
|
|
11
12
|
var _util = require("@ocap/util");
|
|
@@ -14,17 +15,20 @@ var _noop = _interopRequireDefault(require("lodash/noop"));
|
|
|
14
15
|
var _useBus = _interopRequireDefault(require("use-bus"));
|
|
15
16
|
var _ExpandMore = _interopRequireDefault(require("@mui/icons-material/ExpandMore"));
|
|
16
17
|
var _styles = require("@mui/material/styles");
|
|
18
|
+
var _react = require("react");
|
|
17
19
|
var _status = _interopRequireDefault(require("../components/status"));
|
|
18
20
|
var _api = _interopRequireDefault(require("../libs/api"));
|
|
19
21
|
var _util2 = require("../libs/util");
|
|
20
|
-
var _amount = _interopRequireDefault(require("./amount"));
|
|
21
22
|
var _productDonation = _interopRequireDefault(require("./product-donation"));
|
|
22
23
|
var _productItem = _interopRequireDefault(require("./product-item"));
|
|
23
24
|
var _livemode = _interopRequireDefault(require("../components/livemode"));
|
|
24
25
|
var _payment = require("../contexts/payment");
|
|
25
26
|
var _mobile = require("../hooks/mobile");
|
|
27
|
+
var _dynamicPricing = require("../hooks/dynamic-pricing");
|
|
26
28
|
var _loadingButton = _interopRequireDefault(require("../components/loading-button"));
|
|
27
|
-
var
|
|
29
|
+
var _dynamicPricingUnavailable = _interopRequireDefault(require("../components/dynamic-pricing-unavailable"));
|
|
30
|
+
var _promotionSection = _interopRequireDefault(require("./summary-section/promotion-section"));
|
|
31
|
+
var _totalSection = _interopRequireDefault(require("./summary-section/total-section"));
|
|
28
32
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
29
33
|
const ExpandMore = (0, _styles.styled)(props => {
|
|
30
34
|
const {
|
|
@@ -103,9 +107,23 @@ function PaymentSummary({
|
|
|
103
107
|
trialEnd = 0,
|
|
104
108
|
completed = false,
|
|
105
109
|
checkoutSession = void 0,
|
|
110
|
+
paymentIntent = void 0,
|
|
106
111
|
paymentMethods = [],
|
|
107
112
|
onPromotionUpdate = _noop.default,
|
|
108
113
|
showFeatures = false,
|
|
114
|
+
rateUnavailable = false,
|
|
115
|
+
isRateLoading = false,
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
117
|
+
rateError: _rateError = void 0,
|
|
118
|
+
// Technical errors are logged but not displayed to users
|
|
119
|
+
onQuoteExpired = void 0,
|
|
120
|
+
onRefreshRate = void 0,
|
|
121
|
+
onSlippageChange = void 0,
|
|
122
|
+
slippageConfig: slippageConfigProp = void 0,
|
|
123
|
+
liveRate = void 0,
|
|
124
|
+
liveQuoteSnapshot = void 0,
|
|
125
|
+
isStripePayment = false,
|
|
126
|
+
isSubscription: isSubscriptionProp = void 0,
|
|
109
127
|
...rest
|
|
110
128
|
}) {
|
|
111
129
|
const {
|
|
@@ -132,19 +150,105 @@ function PaymentSummary({
|
|
|
132
150
|
const allowPromotionCodes = !!checkoutSession?.allow_promotion_codes;
|
|
133
151
|
const hasDiscounts = sessionDiscounts?.length > 0;
|
|
134
152
|
const discountCurrency = paymentMethods && checkoutSession ? (0, _util2.findCurrency)(paymentMethods, hasDiscounts ? checkoutSession?.currency_id || currency.id : currency.id) || settings.settings?.baseCurrency : currency;
|
|
153
|
+
const slippageConfig = slippageConfigProp ?? checkoutSession?.metadata?.slippage;
|
|
154
|
+
const {
|
|
155
|
+
hasDynamicPricing,
|
|
156
|
+
isPriceLocked,
|
|
157
|
+
quoteMeta,
|
|
158
|
+
rateInfo,
|
|
159
|
+
quoteLockedAt,
|
|
160
|
+
currentSlippagePercent,
|
|
161
|
+
rateDisplay,
|
|
162
|
+
calculatedTokenAmount,
|
|
163
|
+
calculatedDiscountAmount,
|
|
164
|
+
calculateUsdDisplay,
|
|
165
|
+
buildQuoteDetailRows
|
|
166
|
+
} = (0, _dynamicPricing.useDynamicPricing)({
|
|
167
|
+
items,
|
|
168
|
+
currency: discountCurrency,
|
|
169
|
+
liveRate,
|
|
170
|
+
liveQuoteSnapshot,
|
|
171
|
+
checkoutSession,
|
|
172
|
+
paymentIntent,
|
|
173
|
+
locale,
|
|
174
|
+
isStripePayment,
|
|
175
|
+
isSubscription: isSubscriptionProp,
|
|
176
|
+
slippageConfig,
|
|
177
|
+
trialInDays,
|
|
178
|
+
trialEnd,
|
|
179
|
+
discounts: sessionDiscounts
|
|
180
|
+
});
|
|
135
181
|
const headlines = (0, _util2.formatCheckoutHeadlines)(items, discountCurrency, {
|
|
136
182
|
trialEnd,
|
|
137
183
|
trialInDays
|
|
138
|
-
}, locale
|
|
184
|
+
}, locale, {
|
|
185
|
+
exchangeRate: rateInfo.exchangeRate
|
|
186
|
+
});
|
|
139
187
|
const staking = showStaking ? getStakingSetup(items, discountCurrency, billingThreshold) : "0";
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
188
|
+
const effectiveHasDynamicPricing = hasDynamicPricing && !isStripePayment;
|
|
189
|
+
const hasRecurringItems = items.some(x => (x.upsell_price || x.price)?.type === "recurring");
|
|
190
|
+
const isTrialScenario = headlines.actualAmount === "0" && hasRecurringItems;
|
|
191
|
+
const headlineAmountDisplay = (0, _react.useMemo)(() => {
|
|
192
|
+
if (!effectiveHasDynamicPricing) {
|
|
193
|
+
return headlines.amount;
|
|
194
|
+
}
|
|
195
|
+
if (isTrialScenario || !headlines.amount.includes(discountCurrency.symbol)) {
|
|
196
|
+
return headlines.amount;
|
|
197
|
+
}
|
|
198
|
+
if (calculatedTokenAmount) {
|
|
199
|
+
const displayAmount = (0, _util.fromUnitToToken)(calculatedTokenAmount, discountCurrency?.decimal);
|
|
200
|
+
const formatted2 = (0, _util2.formatDynamicPrice)(displayAmount, true, 6);
|
|
201
|
+
return `${formatted2} ${discountCurrency.symbol}`;
|
|
202
|
+
}
|
|
203
|
+
const formatted = (0, _util2.formatDynamicPrice)(headlines.actualAmount, true, 6);
|
|
204
|
+
return `${formatted} ${discountCurrency.symbol}`;
|
|
205
|
+
}, [headlines.amount, headlines.actualAmount, discountCurrency.symbol, discountCurrency?.decimal, effectiveHasDynamicPricing, calculatedTokenAmount, isTrialScenario]);
|
|
206
|
+
const discountAmount = (0, _react.useMemo)(() => new _util.BN(checkoutSession?.total_details?.amount_discount || "0"), [checkoutSession?.total_details?.amount_discount]);
|
|
207
|
+
const subtotalAmountUnit = new _util.BN((0, _util.fromTokenToUnit)(headlines.actualAmount, discountCurrency?.decimal)).add(new _util.BN(staking)).toString();
|
|
208
|
+
const subtotalAmount = (0, _util.fromUnitToToken)(subtotalAmountUnit, discountCurrency?.decimal);
|
|
209
|
+
const totalAmountUnit = new _util.BN(subtotalAmountUnit).sub(discountAmount).toString();
|
|
210
|
+
const totalAmountValue = (0, _util.fromUnitToToken)(totalAmountUnit, discountCurrency?.decimal);
|
|
211
|
+
const subtotalDisplay = (0, _react.useMemo)(() => {
|
|
212
|
+
if (effectiveHasDynamicPricing && calculatedTokenAmount && !isTrialScenario) {
|
|
213
|
+
const dynamicSubtotalUnit = new _util.BN(calculatedTokenAmount).add(new _util.BN(staking)).toString();
|
|
214
|
+
const displayAmount = (0, _util.fromUnitToToken)(dynamicSubtotalUnit, discountCurrency?.decimal);
|
|
215
|
+
return (0, _util2.formatDynamicPrice)(displayAmount, true, 6);
|
|
216
|
+
}
|
|
217
|
+
return (0, _util2.formatDynamicPrice)(subtotalAmount, effectiveHasDynamicPricing, 6);
|
|
218
|
+
}, [effectiveHasDynamicPricing, calculatedTokenAmount, staking, discountCurrency?.decimal, subtotalAmount, isTrialScenario]);
|
|
219
|
+
const totalAmountDisplay = (0, _react.useMemo)(() => {
|
|
220
|
+
if (effectiveHasDynamicPricing && calculatedTokenAmount && !isTrialScenario) {
|
|
221
|
+
const effectiveDiscount = calculatedDiscountAmount ? new _util.BN(calculatedDiscountAmount) : discountAmount;
|
|
222
|
+
const dynamicTotalUnit = new _util.BN(calculatedTokenAmount).add(new _util.BN(staking)).sub(effectiveDiscount).toString();
|
|
223
|
+
const displayAmount = (0, _util.fromUnitToToken)(dynamicTotalUnit, discountCurrency?.decimal);
|
|
224
|
+
const numericValue = Number(displayAmount);
|
|
225
|
+
if (Number.isFinite(numericValue) && numericValue >= 0) {
|
|
226
|
+
return (0, _util2.formatDynamicPrice)(displayAmount, true, 6);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (isStripePayment && calculatedDiscountAmount && !isTrialScenario) {
|
|
230
|
+
const effectiveDiscount = new _util.BN(calculatedDiscountAmount);
|
|
231
|
+
const adjustedTotalUnit = new _util.BN(subtotalAmountUnit).sub(effectiveDiscount).toString();
|
|
232
|
+
const displayAmount = (0, _util.fromUnitToToken)(adjustedTotalUnit, discountCurrency?.decimal);
|
|
233
|
+
const numericValue = Number(displayAmount);
|
|
234
|
+
if (Number.isFinite(numericValue) && numericValue >= 0) {
|
|
235
|
+
return (0, _util2.formatDynamicPrice)(displayAmount, false, 6);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return (0, _util2.formatDynamicPrice)(totalAmountValue, effectiveHasDynamicPricing, 6);
|
|
239
|
+
}, [effectiveHasDynamicPricing, calculatedTokenAmount, staking, discountAmount, calculatedDiscountAmount, discountCurrency?.decimal, totalAmountValue, isTrialScenario, isStripePayment, subtotalAmountUnit]);
|
|
240
|
+
const totalAmountText = totalAmountDisplay === "\u2014" ? "\u2014" : `${totalAmountDisplay} ${discountCurrency.symbol}`;
|
|
241
|
+
const totalUsdDisplay = (0, _react.useMemo)(() => {
|
|
242
|
+
if (effectiveHasDynamicPricing && calculatedTokenAmount && !isTrialScenario) {
|
|
243
|
+
const effectiveDiscount = calculatedDiscountAmount ? new _util.BN(calculatedDiscountAmount) : discountAmount;
|
|
244
|
+
const dynamicTotalUnit = new _util.BN(calculatedTokenAmount).add(new _util.BN(staking)).sub(effectiveDiscount).toString();
|
|
245
|
+
const dynamicTotalToken = (0, _util.fromUnitToToken)(dynamicTotalUnit, discountCurrency?.decimal);
|
|
246
|
+
return calculateUsdDisplay(dynamicTotalToken);
|
|
247
|
+
}
|
|
248
|
+
return calculateUsdDisplay(totalAmountValue);
|
|
249
|
+
}, [effectiveHasDynamicPricing, calculatedTokenAmount, staking, discountAmount, calculatedDiscountAmount, discountCurrency?.decimal, totalAmountValue, calculateUsdDisplay, isTrialScenario]);
|
|
250
|
+
const quoteDetailRows = buildQuoteDetailRows(t);
|
|
251
|
+
const isSubscription = isSubscriptionProp ?? (checkoutSession?.mode === "subscription" || checkoutSession?.mode === "setup");
|
|
148
252
|
const handlePromotionUpdate = () => {
|
|
149
253
|
onPromotionUpdate?.();
|
|
150
254
|
};
|
|
@@ -159,9 +263,46 @@ function PaymentSummary({
|
|
|
159
263
|
console.error("Failed to remove promotion code:", err);
|
|
160
264
|
}
|
|
161
265
|
};
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
266
|
+
const expiredHandledRef = (0, _react.useRef)(false);
|
|
267
|
+
(0, _react.useEffect)(() => {
|
|
268
|
+
if (completed || expiredHandledRef.current) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (!liveQuoteSnapshot?.expires_at && !quoteMeta?.expiresAt) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const currentTime = Math.floor(Date.now() / 1e3);
|
|
275
|
+
const effectiveExpiresAt = liveQuoteSnapshot?.expires_at ?? quoteMeta?.expiresAt;
|
|
276
|
+
const quoteRemaining = effectiveExpiresAt ? Math.max(0, effectiveExpiresAt - currentTime) : 0;
|
|
277
|
+
const lockRemaining = quoteLockedAt ? Math.max(0, quoteLockedAt + 180 - currentTime) : 0;
|
|
278
|
+
const hasExpiry = !!effectiveExpiresAt;
|
|
279
|
+
const lockActive = lockRemaining > 0;
|
|
280
|
+
if (hasExpiry && !lockActive && quoteRemaining <= 0) {
|
|
281
|
+
expiredHandledRef.current = true;
|
|
282
|
+
onQuoteExpired?.();
|
|
283
|
+
}
|
|
284
|
+
}, [liveQuoteSnapshot?.expires_at, quoteMeta?.expiresAt, quoteLockedAt, completed, onQuoteExpired]);
|
|
285
|
+
const handleSlippageChange = async newSlippageConfig => {
|
|
286
|
+
if (!onSlippageChange) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (!checkoutSessionId) {
|
|
290
|
+
onSlippageChange(newSlippageConfig);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
try {
|
|
294
|
+
await _api.default.put(`/api/checkout-sessions/${checkoutSessionId}/slippage`, {
|
|
295
|
+
slippage_config: newSlippageConfig
|
|
296
|
+
});
|
|
297
|
+
onSlippageChange(newSlippageConfig);
|
|
298
|
+
if (onQuoteExpired) {
|
|
299
|
+
await onQuoteExpired(true);
|
|
300
|
+
}
|
|
301
|
+
} catch (err) {
|
|
302
|
+
console.error("Failed to update slippage", err);
|
|
303
|
+
_Toast.default.error(err.response?.data?.error || (0, _util2.formatError)(err));
|
|
304
|
+
}
|
|
305
|
+
};
|
|
165
306
|
(0, _useBus.default)("error.REQUIRE_CROSS_SELL", () => {
|
|
166
307
|
setState({
|
|
167
308
|
shake: true
|
|
@@ -226,7 +367,7 @@ function PaymentSummary({
|
|
|
226
367
|
xs: 1,
|
|
227
368
|
sm: 2
|
|
228
369
|
},
|
|
229
|
-
children: items.map(x => x.price
|
|
370
|
+
children: items.map(x => x.price?.custom_unit_amount && onChangeAmount && donationSettings ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_productDonation.default, {
|
|
230
371
|
item: x,
|
|
231
372
|
settings: donationSettings,
|
|
232
373
|
onChange: onChangeAmount,
|
|
@@ -237,12 +378,18 @@ function PaymentSummary({
|
|
|
237
378
|
trialInDays,
|
|
238
379
|
trialEnd,
|
|
239
380
|
currency: discountCurrency,
|
|
381
|
+
exchangeRate: rateInfo.exchangeRate,
|
|
382
|
+
isStripePayment,
|
|
383
|
+
isPriceLocked,
|
|
384
|
+
isRateLoading,
|
|
240
385
|
onUpsell: handleUpsell,
|
|
241
386
|
onDownsell: handleDownsell,
|
|
242
387
|
adjustableQuantity: x.adjustable_quantity,
|
|
243
388
|
completed,
|
|
244
389
|
showFeatures,
|
|
245
390
|
onQuantityChange: handleQuantityChange,
|
|
391
|
+
discounts: sessionDiscounts,
|
|
392
|
+
calculatedDiscountAmount: calculatedDiscountAmount || (isStripePayment ? discountAmount.toString() : null),
|
|
246
393
|
children: x.cross_sell && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
247
394
|
direction: "row",
|
|
248
395
|
sx: {
|
|
@@ -279,6 +426,10 @@ function PaymentSummary({
|
|
|
279
426
|
trialInDays,
|
|
280
427
|
currency: discountCurrency,
|
|
281
428
|
trialEnd,
|
|
429
|
+
exchangeRate: rateInfo.exchangeRate,
|
|
430
|
+
isStripePayment,
|
|
431
|
+
isPriceLocked,
|
|
432
|
+
isRateLoading,
|
|
282
433
|
onUpsell: _noop.default,
|
|
283
434
|
onDownsell: _noop.default,
|
|
284
435
|
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
@@ -312,6 +463,9 @@ function PaymentSummary({
|
|
|
312
463
|
})
|
|
313
464
|
})]
|
|
314
465
|
});
|
|
466
|
+
if (!discountCurrency || !items?.length) {
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
315
469
|
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Fade, {
|
|
316
470
|
in: true,
|
|
317
471
|
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
@@ -337,6 +491,11 @@ function PaymentSummary({
|
|
|
337
491
|
},
|
|
338
492
|
children: action || t("payment.checkout.orderSummary")
|
|
339
493
|
}), !settings.livemode && /* @__PURE__ */(0, _jsxRuntime.jsx)(_livemode.default, {})]
|
|
494
|
+
}), effectiveHasDynamicPricing && rateUnavailable && /* @__PURE__ */(0, _jsxRuntime.jsx)(_dynamicPricingUnavailable.default, {
|
|
495
|
+
sx: {
|
|
496
|
+
mb: 2
|
|
497
|
+
},
|
|
498
|
+
onRetry: onRefreshRate
|
|
340
499
|
}), isMobile && !donationSettings ? /* @__PURE__ */(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
341
500
|
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
342
501
|
onClick: () => setState({
|
|
@@ -403,7 +562,7 @@ function PaymentSummary({
|
|
|
403
562
|
})
|
|
404
563
|
})]
|
|
405
564
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
406
|
-
children:
|
|
565
|
+
children: headlineAmountDisplay
|
|
407
566
|
})]
|
|
408
567
|
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
409
568
|
direction: "row",
|
|
@@ -457,122 +616,41 @@ function PaymentSummary({
|
|
|
457
616
|
className: "base-label",
|
|
458
617
|
children: t("common.subtotal")
|
|
459
618
|
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
|
|
460
|
-
children: [
|
|
619
|
+
children: [subtotalDisplay, " ", discountCurrency.symbol]
|
|
461
620
|
})]
|
|
462
|
-
}),
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
children: sessionDiscounts.map(discount => {
|
|
475
|
-
const promotionCodeInfo = discount.promotion_code_details;
|
|
476
|
-
const couponInfo = discount.coupon_details;
|
|
477
|
-
const discountDescription = couponInfo ? (0, _util2.formatCouponTerms)(couponInfo, discountCurrency, locale) : "";
|
|
478
|
-
const notSupported = discountDescription === t("payment.checkout.coupon.noDiscount");
|
|
479
|
-
return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
480
|
-
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
481
|
-
direction: "row",
|
|
482
|
-
spacing: 1,
|
|
483
|
-
sx: {
|
|
484
|
-
justifyContent: "space-between",
|
|
485
|
-
alignItems: "center"
|
|
486
|
-
},
|
|
487
|
-
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
488
|
-
direction: "row",
|
|
489
|
-
spacing: 1,
|
|
490
|
-
sx: {
|
|
491
|
-
alignItems: "center",
|
|
492
|
-
backgroundColor: "grey.100",
|
|
493
|
-
width: "fit-content",
|
|
494
|
-
px: 1,
|
|
495
|
-
py: 1,
|
|
496
|
-
borderRadius: 1
|
|
497
|
-
},
|
|
498
|
-
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
|
|
499
|
-
sx: {
|
|
500
|
-
fontWeight: "medium",
|
|
501
|
-
display: "flex",
|
|
502
|
-
alignItems: "center",
|
|
503
|
-
gap: 0.5
|
|
504
|
-
},
|
|
505
|
-
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.LocalOffer, {
|
|
506
|
-
sx: {
|
|
507
|
-
color: "warning.main",
|
|
508
|
-
fontSize: "small"
|
|
509
|
-
}
|
|
510
|
-
}), promotionCodeInfo?.code || discount.verification_data?.code || t("payment.checkout.discount")]
|
|
511
|
-
}), !completed && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Button, {
|
|
512
|
-
size: "small",
|
|
513
|
-
disabled: paymentState.paying || paymentState.stripePaying,
|
|
514
|
-
onClick: () => handleRemovePromotion(checkoutSessionId),
|
|
515
|
-
sx: {
|
|
516
|
-
minWidth: "auto",
|
|
517
|
-
width: 16,
|
|
518
|
-
height: 16,
|
|
519
|
-
color: "text.secondary",
|
|
520
|
-
"&.Mui-disabled": {
|
|
521
|
-
color: "text.disabled"
|
|
522
|
-
}
|
|
523
|
-
},
|
|
524
|
-
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_iconsMaterial.Close, {
|
|
525
|
-
sx: {
|
|
526
|
-
fontSize: 14
|
|
527
|
-
}
|
|
528
|
-
})
|
|
529
|
-
})]
|
|
530
|
-
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
|
|
531
|
-
sx: {
|
|
532
|
-
color: "text.secondary"
|
|
533
|
-
},
|
|
534
|
-
children: ["-", (0, _util2.formatAmount)(discount.discount_amount || "0", discountCurrency.decimal), " ", discountCurrency.symbol]
|
|
535
|
-
})]
|
|
536
|
-
}), discountDescription && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
537
|
-
sx: {
|
|
538
|
-
fontSize: "small",
|
|
539
|
-
color: notSupported ? "error.main" : "text.secondary",
|
|
540
|
-
mt: 0.5
|
|
541
|
-
},
|
|
542
|
-
children: discountDescription
|
|
543
|
-
})]
|
|
544
|
-
}, discount.promotion_code || discount.coupon || `discount-${discount.discount_amount}`);
|
|
545
|
-
})
|
|
621
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_promotionSection.default, {
|
|
622
|
+
checkoutSessionId: checkoutSession?.id || checkoutSessionId,
|
|
623
|
+
currency: discountCurrency,
|
|
624
|
+
currencyId: currency.id,
|
|
625
|
+
discounts: sessionDiscounts,
|
|
626
|
+
allowPromotionCodes,
|
|
627
|
+
completed,
|
|
628
|
+
disabled: paymentState.paying || paymentState.stripePaying,
|
|
629
|
+
onPromotionUpdate: handlePromotionUpdate,
|
|
630
|
+
onRemovePromotion: handleRemovePromotion,
|
|
631
|
+
calculatedDiscountAmount: calculatedDiscountAmount || (isStripePayment ? discountAmount.toString() : null),
|
|
632
|
+
isRateLoading
|
|
546
633
|
}), hasSubTotal && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Divider, {
|
|
547
634
|
sx: {
|
|
548
635
|
my: 1
|
|
549
636
|
}
|
|
550
|
-
}), /* @__PURE__ */(0, _jsxRuntime.
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
}), headlines.then && headlines.showThen && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
568
|
-
component: "div",
|
|
569
|
-
sx: {
|
|
570
|
-
fontSize: "0.7875rem",
|
|
571
|
-
color: "text.lighter",
|
|
572
|
-
textAlign: "right",
|
|
573
|
-
margin: "-2px 0 8px"
|
|
574
|
-
},
|
|
575
|
-
children: headlines.then
|
|
637
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_totalSection.default, {
|
|
638
|
+
totalAmountText,
|
|
639
|
+
totalUsdDisplay,
|
|
640
|
+
currency: discountCurrency,
|
|
641
|
+
hasDynamicPricing,
|
|
642
|
+
rateDisplay,
|
|
643
|
+
rateInfo,
|
|
644
|
+
quoteDetailRows,
|
|
645
|
+
currentSlippagePercent,
|
|
646
|
+
slippageConfig,
|
|
647
|
+
isPriceLocked,
|
|
648
|
+
isSubscription,
|
|
649
|
+
completed,
|
|
650
|
+
onSlippageChange: onSlippageChange ? handleSlippageChange : void 0,
|
|
651
|
+
isStripePayment,
|
|
652
|
+
isRateLoading,
|
|
653
|
+
thenInfo: headlines.thenValue && headlines.showThen ? headlines.thenValue : void 0
|
|
576
654
|
})]
|
|
577
655
|
})
|
|
578
656
|
});
|
package/lib/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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "Reusable react components for payment kit v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"@babel/core": "^7.27.4",
|
|
97
97
|
"@babel/preset-env": "^7.27.2",
|
|
98
98
|
"@babel/preset-react": "^7.27.1",
|
|
99
|
-
"@blocklet/payment-types": "1.
|
|
99
|
+
"@blocklet/payment-types": "1.25.0",
|
|
100
100
|
"@storybook/addon-essentials": "^7.6.20",
|
|
101
101
|
"@storybook/addon-interactions": "^7.6.20",
|
|
102
102
|
"@storybook/addon-links": "^7.6.20",
|
|
@@ -127,5 +127,5 @@
|
|
|
127
127
|
"vite-plugin-babel": "^1.3.1",
|
|
128
128
|
"vite-plugin-node-polyfills": "^0.23.0"
|
|
129
129
|
},
|
|
130
|
-
"gitHead": "
|
|
130
|
+
"gitHead": "00a94943fea21487c042a7b484f4649add502bc9"
|
|
131
131
|
}
|