@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.
- 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
|
@@ -16,21 +16,26 @@ import React, { useEffect, useRef, useState } from 'react';
|
|
|
16
16
|
import { useNavigate } from 'react-router-dom';
|
|
17
17
|
|
|
18
18
|
import debounce from 'lodash/debounce';
|
|
19
|
+
import { BN } from '@ocap/util';
|
|
19
20
|
import Status from '../../components/status';
|
|
20
21
|
import { usePaymentContext } from '../../contexts/payment';
|
|
21
22
|
import { useSubscription } from '../../hooks/subscription';
|
|
22
23
|
import api from '../../libs/api';
|
|
23
24
|
import StripePaymentAction from '../../components/stripe-payment-action';
|
|
24
25
|
import {
|
|
25
|
-
formatBNStr,
|
|
26
26
|
formatCreditAmount,
|
|
27
27
|
formatError,
|
|
28
28
|
formatToDate,
|
|
29
29
|
formatToDatetime,
|
|
30
|
+
formatTime,
|
|
31
|
+
formatExchangeRate,
|
|
30
32
|
getInvoiceDescriptionAndReason,
|
|
31
33
|
getInvoiceStatusColor,
|
|
32
34
|
getTxLink,
|
|
33
35
|
isCrossOrigin,
|
|
36
|
+
getUsdAmountFromTokenUnits,
|
|
37
|
+
formatUsdAmount,
|
|
38
|
+
formatAmount,
|
|
34
39
|
} from '../../libs/util';
|
|
35
40
|
import Table from '../../components/table';
|
|
36
41
|
import { createLink, handleNavigation, LinkInfo } from '../../libs/navigation';
|
|
@@ -51,14 +56,26 @@ const groupByDate = (items: TInvoiceExpanded[]) => {
|
|
|
51
56
|
|
|
52
57
|
const fetchData = (params: Record<string, any> = {}): Promise<Result> => {
|
|
53
58
|
const search = new URLSearchParams();
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
const mergedParams: Record<string, any> = { include_quote: true, ...params };
|
|
60
|
+
Object.keys(mergedParams).forEach((key) => {
|
|
61
|
+
if (mergedParams[key]) {
|
|
62
|
+
search.set(key, String(mergedParams[key]));
|
|
57
63
|
}
|
|
58
64
|
});
|
|
59
65
|
return api.get(`/api/invoices?${search.toString()}`).then((res: any) => res.data);
|
|
60
66
|
};
|
|
61
67
|
|
|
68
|
+
const getInvoiceQuoteInfo = (invoice: TInvoiceExpanded) => {
|
|
69
|
+
const lines = (invoice as any).lines || [];
|
|
70
|
+
for (const line of lines) {
|
|
71
|
+
const quote = (line.metadata as any)?.quote;
|
|
72
|
+
if (quote?.exchange_rate) {
|
|
73
|
+
return quote;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
};
|
|
78
|
+
|
|
62
79
|
type Props = {
|
|
63
80
|
customer_id?: string;
|
|
64
81
|
subscription_id?: string;
|
|
@@ -199,12 +216,119 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
|
|
|
199
216
|
customBodyRenderLite: (_: string, index: number) => {
|
|
200
217
|
const invoice = data?.list[index] as TInvoiceExpanded;
|
|
201
218
|
const isVoid = invoice.status === 'void';
|
|
219
|
+
const quoteInfo = getInvoiceQuoteInfo(invoice);
|
|
220
|
+
const providers = quoteInfo?.providers || [];
|
|
221
|
+
const providerNames = providers.map((provider: any) => provider.provider_name).filter(Boolean);
|
|
222
|
+
const providerDisplay =
|
|
223
|
+
providerNames.length > 0
|
|
224
|
+
? providerNames.join(', ')
|
|
225
|
+
: quoteInfo?.rate_provider_name || quoteInfo?.rate_provider_id || '—';
|
|
226
|
+
const providerRates =
|
|
227
|
+
quoteInfo?.providers
|
|
228
|
+
?.map((provider: any) => {
|
|
229
|
+
const name = provider.provider_name || provider.provider_id || '—';
|
|
230
|
+
return provider.rate ? `${name}` : name;
|
|
231
|
+
})
|
|
232
|
+
.filter(Boolean) || [];
|
|
233
|
+
const rateTimestamp = quoteInfo?.rate_timestamp_ms ? formatTime(quoteInfo.rate_timestamp_ms) : '—';
|
|
234
|
+
const formattedRate = formatExchangeRate(quoteInfo?.exchange_rate || null);
|
|
235
|
+
const rateLine = formattedRate
|
|
236
|
+
? (() => {
|
|
237
|
+
const currencyMap = {
|
|
238
|
+
USD: '$',
|
|
239
|
+
CNY: '¥',
|
|
240
|
+
};
|
|
241
|
+
const currencySymbol = currencyMap[quoteInfo?.base_currency as keyof typeof currencyMap];
|
|
242
|
+
return `1 ${invoice.paymentCurrency.symbol} ≈ ${
|
|
243
|
+
currencySymbol
|
|
244
|
+
? `${currencySymbol}${formattedRate}`
|
|
245
|
+
: `${formattedRate} ${quoteInfo?.base_currency || 'USD'}`
|
|
246
|
+
}`;
|
|
247
|
+
})()
|
|
248
|
+
: null;
|
|
249
|
+
|
|
250
|
+
let usdAmount: string | null = null;
|
|
251
|
+
if (quoteInfo?.base_amount) {
|
|
252
|
+
usdAmount = formatUsdAmount(quoteInfo.base_amount, locale);
|
|
253
|
+
} else if (quoteInfo?.exchange_rate && invoice.total) {
|
|
254
|
+
const calculatedUsd = getUsdAmountFromTokenUnits(
|
|
255
|
+
new BN(invoice.total),
|
|
256
|
+
invoice.paymentCurrency.decimal,
|
|
257
|
+
quoteInfo.exchange_rate
|
|
258
|
+
);
|
|
259
|
+
if (calculatedUsd) {
|
|
260
|
+
usdAmount = formatUsdAmount(calculatedUsd, locale);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const tooltipContent = quoteInfo ? (
|
|
265
|
+
<Stack spacing={0.5} sx={{ p: 1 }}>
|
|
266
|
+
<Stack direction="row" justifyContent="space-between" spacing={2}>
|
|
267
|
+
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
268
|
+
{t('payment.customer.invoice.quote.providers')}:
|
|
269
|
+
</Typography>
|
|
270
|
+
<Typography variant="caption" sx={{ color: 'text.primary' }}>
|
|
271
|
+
{(providerRates.length > 0 ? providerRates.join(', ') : providerDisplay) || '—'}
|
|
272
|
+
</Typography>
|
|
273
|
+
</Stack>
|
|
274
|
+
{rateLine && (
|
|
275
|
+
<Stack direction="row" justifyContent="space-between" spacing={2}>
|
|
276
|
+
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
277
|
+
{t('payment.customer.invoice.quote.exchangeRate')}:
|
|
278
|
+
</Typography>
|
|
279
|
+
<Typography variant="caption" sx={{ color: 'text.primary' }}>
|
|
280
|
+
{rateLine}
|
|
281
|
+
</Typography>
|
|
282
|
+
</Stack>
|
|
283
|
+
)}
|
|
284
|
+
<Stack direction="row" justifyContent="space-between" spacing={2}>
|
|
285
|
+
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
286
|
+
{t('payment.customer.invoice.quote.rateTimestamp')}:
|
|
287
|
+
</Typography>
|
|
288
|
+
<Typography variant="caption" sx={{ color: 'text.primary' }}>
|
|
289
|
+
{rateTimestamp}
|
|
290
|
+
</Typography>
|
|
291
|
+
</Stack>
|
|
292
|
+
</Stack>
|
|
293
|
+
) : null;
|
|
294
|
+
|
|
202
295
|
return (
|
|
203
296
|
<Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
|
|
204
|
-
<
|
|
205
|
-
{
|
|
206
|
-
|
|
207
|
-
|
|
297
|
+
<Stack spacing={0.25} alignItems="flex-end">
|
|
298
|
+
<Typography sx={isVoid ? { textDecoration: 'line-through' } : {}}>
|
|
299
|
+
{formatAmount(invoice.total, invoice.paymentCurrency.decimal)}
|
|
300
|
+
{invoice.paymentCurrency.symbol}
|
|
301
|
+
</Typography>
|
|
302
|
+
{(usdAmount || rateLine) && (
|
|
303
|
+
<Tooltip
|
|
304
|
+
title={tooltipContent}
|
|
305
|
+
placement="top"
|
|
306
|
+
arrow
|
|
307
|
+
slotProps={{
|
|
308
|
+
tooltip: {
|
|
309
|
+
sx: {
|
|
310
|
+
backgroundColor: 'background.paper',
|
|
311
|
+
boxShadow: 1,
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
}}>
|
|
315
|
+
<Stack spacing={0.25} alignItems="flex-end">
|
|
316
|
+
{usdAmount && (
|
|
317
|
+
<Typography
|
|
318
|
+
variant="caption"
|
|
319
|
+
sx={{
|
|
320
|
+
color: 'text.secondary',
|
|
321
|
+
fontSize: '0.75rem',
|
|
322
|
+
fontWeight: 400,
|
|
323
|
+
lineHeight: 1.2,
|
|
324
|
+
}}>
|
|
325
|
+
≈ ${usdAmount}
|
|
326
|
+
</Typography>
|
|
327
|
+
)}
|
|
328
|
+
</Stack>
|
|
329
|
+
</Tooltip>
|
|
330
|
+
)}
|
|
331
|
+
</Stack>
|
|
208
332
|
</Box>
|
|
209
333
|
);
|
|
210
334
|
},
|
|
@@ -638,6 +762,11 @@ const InvoiceList = React.memo((props: Props & { onPay: (invoiceId: string) => v
|
|
|
638
762
|
{invoices.map((invoice) => {
|
|
639
763
|
const { link, connect } = getInvoiceLink(invoice, action);
|
|
640
764
|
const isVoid = invoice.status === 'void';
|
|
765
|
+
const quoteInfo = getInvoiceQuoteInfo(invoice);
|
|
766
|
+
const formattedRate = formatExchangeRate(quoteInfo?.exchange_rate || null);
|
|
767
|
+
const rateLine = formattedRate
|
|
768
|
+
? `1 ${invoice.paymentCurrency.symbol} ≈ ${formattedRate} ${quoteInfo?.base_currency || 'USD'}`
|
|
769
|
+
: null;
|
|
641
770
|
return (
|
|
642
771
|
<Stack
|
|
643
772
|
key={invoice.id}
|
|
@@ -687,9 +816,14 @@ const InvoiceList = React.memo((props: Props & { onPay: (invoiceId: string) => v
|
|
|
687
816
|
textAlign: 'right',
|
|
688
817
|
}}>
|
|
689
818
|
<Typography sx={isVoid ? { textDecoration: 'line-through' } : {}}>
|
|
690
|
-
{
|
|
819
|
+
{formatAmount(invoice.total, invoice.paymentCurrency.decimal)}
|
|
691
820
|
{invoice.paymentCurrency.symbol}
|
|
692
821
|
</Typography>
|
|
822
|
+
{rateLine && (
|
|
823
|
+
<Typography variant="caption" sx={{ color: 'text.secondary', display: 'block' }}>
|
|
824
|
+
{rateLine}
|
|
825
|
+
</Typography>
|
|
826
|
+
)}
|
|
693
827
|
</Box>
|
|
694
828
|
<Box
|
|
695
829
|
sx={{
|