@blocklet/payment-react 1.19.17 → 1.19.19
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/README.md +313 -0
- package/es/checkout/form.js +2 -2
- package/es/components/auto-topup/index.d.ts +14 -0
- package/es/components/auto-topup/index.js +417 -0
- package/es/components/auto-topup/modal.d.ts +35 -0
- package/es/components/auto-topup/modal.js +734 -0
- package/es/components/auto-topup/product-card.d.ts +13 -0
- package/es/components/auto-topup/product-card.js +173 -0
- package/es/components/collapse.d.ts +13 -0
- package/es/components/collapse.js +76 -0
- package/es/components/input.d.ts +2 -1
- package/es/components/input.js +64 -13
- package/es/components/label.d.ts +2 -1
- package/es/components/label.js +2 -1
- package/es/index.d.ts +4 -1
- package/es/index.js +7 -1
- package/es/libs/util.js +2 -1
- package/es/locales/en.js +56 -0
- package/es/locales/zh.js +56 -0
- package/es/payment/form/index.js +6 -0
- package/es/payment/product-item.js +19 -12
- package/lib/checkout/form.js +2 -2
- package/lib/components/auto-topup/index.d.ts +14 -0
- package/lib/components/auto-topup/index.js +451 -0
- package/lib/components/auto-topup/modal.d.ts +35 -0
- package/lib/components/auto-topup/modal.js +803 -0
- package/lib/components/auto-topup/product-card.d.ts +13 -0
- package/lib/components/auto-topup/product-card.js +149 -0
- package/lib/components/collapse.d.ts +13 -0
- package/lib/components/collapse.js +74 -0
- package/lib/components/input.d.ts +2 -1
- package/lib/components/input.js +66 -24
- package/lib/components/label.d.ts +2 -1
- package/lib/components/label.js +3 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +24 -0
- package/lib/libs/util.js +2 -1
- package/lib/locales/en.js +56 -0
- package/lib/locales/zh.js +56 -0
- package/lib/payment/form/index.js +6 -0
- package/lib/payment/product-item.js +21 -12
- package/package.json +9 -9
- package/src/checkout/form.tsx +2 -2
- package/src/components/auto-topup/index.tsx +449 -0
- package/src/components/auto-topup/modal.tsx +773 -0
- package/src/components/auto-topup/product-card.tsx +156 -0
- package/src/components/collapse.tsx +82 -0
- package/src/components/input.tsx +71 -22
- package/src/components/label.tsx +8 -2
- package/src/index.ts +7 -0
- package/src/libs/util.ts +1 -0
- package/src/locales/en.tsx +59 -0
- package/src/locales/zh.tsx +57 -0
- package/src/payment/form/index.tsx +6 -0
- package/src/payment/product-item.tsx +20 -13
|
@@ -37,7 +37,8 @@ function ProductItem({
|
|
|
37
37
|
locale
|
|
38
38
|
} = (0, _context.useLocaleContext)();
|
|
39
39
|
const {
|
|
40
|
-
settings
|
|
40
|
+
settings,
|
|
41
|
+
setPayable
|
|
41
42
|
} = (0, _payment.usePaymentContext)();
|
|
42
43
|
const pricing = (0, _util.formatLineItemPricing)(item, currency, {
|
|
43
44
|
trialEnd,
|
|
@@ -56,27 +57,34 @@ function ProductItem({
|
|
|
56
57
|
const minQuantity = Math.max(adjustableQuantity.minimum || 1, 1);
|
|
57
58
|
const quantityAvailable = Math.min(item.price.quantity_limit_per_checkout, item.price.quantity_available);
|
|
58
59
|
const maxQuantity = quantityAvailable ? Math.min(adjustableQuantity.maximum || Infinity, quantityAvailable) : adjustableQuantity.maximum || Infinity;
|
|
60
|
+
const localQuantityNum = localQuantity || 0;
|
|
59
61
|
const handleQuantityChange = newQuantity => {
|
|
62
|
+
if (!newQuantity) {
|
|
63
|
+
setLocalQuantity(void 0);
|
|
64
|
+
setPayable(false);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
setPayable(true);
|
|
60
68
|
if (newQuantity >= minQuantity && newQuantity <= maxQuantity) {
|
|
61
|
-
setLocalQuantity(newQuantity);
|
|
62
69
|
if ((0, _util.formatQuantityInventory)(item.price, newQuantity, locale)) {
|
|
63
70
|
return;
|
|
64
71
|
}
|
|
72
|
+
setLocalQuantity(newQuantity);
|
|
65
73
|
onQuantityChange(item.price_id, newQuantity);
|
|
66
74
|
}
|
|
67
75
|
};
|
|
68
76
|
const handleQuantityIncrease = () => {
|
|
69
|
-
if (
|
|
70
|
-
handleQuantityChange(
|
|
77
|
+
if (localQuantityNum < maxQuantity) {
|
|
78
|
+
handleQuantityChange(localQuantityNum + 1);
|
|
71
79
|
}
|
|
72
80
|
};
|
|
73
81
|
const handleQuantityDecrease = () => {
|
|
74
|
-
if (
|
|
75
|
-
handleQuantityChange(
|
|
82
|
+
if (localQuantityNum > minQuantity) {
|
|
83
|
+
handleQuantityChange(localQuantityNum - 1);
|
|
76
84
|
}
|
|
77
85
|
};
|
|
78
86
|
const handleQuantityInputChange = event => {
|
|
79
|
-
const value = parseInt(event.target.value, 10);
|
|
87
|
+
const value = parseInt(event.target.value || "0", 10);
|
|
80
88
|
if (!Number.isNaN(value)) {
|
|
81
89
|
handleQuantityChange(value);
|
|
82
90
|
}
|
|
@@ -84,7 +92,7 @@ function ProductItem({
|
|
|
84
92
|
const formatCreditInfo = () => {
|
|
85
93
|
if (!isCreditProduct) return null;
|
|
86
94
|
const isRecurring = item.price.type === "recurring";
|
|
87
|
-
const totalCredit = (0, _util.formatNumber)(creditAmount * localQuantity);
|
|
95
|
+
const totalCredit = (0, _util.formatNumber)(creditAmount * (localQuantity || 0));
|
|
88
96
|
let message = "";
|
|
89
97
|
if (isRecurring) {
|
|
90
98
|
message = t("payment.checkout.credit.recurringInfo", {
|
|
@@ -114,7 +122,7 @@ function ProductItem({
|
|
|
114
122
|
}
|
|
115
123
|
return pricing.primary;
|
|
116
124
|
}, [trialInDays, trialEnd, pricing, item, locale]);
|
|
117
|
-
const quantityInventoryError = (0, _util.formatQuantityInventory)(item.price,
|
|
125
|
+
const quantityInventoryError = (0, _util.formatQuantityInventory)(item.price, localQuantityNum, locale);
|
|
118
126
|
return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
119
127
|
direction: "column",
|
|
120
128
|
spacing: 1,
|
|
@@ -203,7 +211,7 @@ function ProductItem({
|
|
|
203
211
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.IconButton, {
|
|
204
212
|
size: "small",
|
|
205
213
|
onClick: handleQuantityDecrease,
|
|
206
|
-
disabled:
|
|
214
|
+
disabled: localQuantityNum <= minQuantity,
|
|
207
215
|
sx: {
|
|
208
216
|
minWidth: 32,
|
|
209
217
|
width: 32,
|
|
@@ -223,14 +231,15 @@ function ProductItem({
|
|
|
223
231
|
max: maxQuantity,
|
|
224
232
|
style: {
|
|
225
233
|
textAlign: "center",
|
|
226
|
-
padding: "4px"
|
|
234
|
+
padding: "4px",
|
|
235
|
+
minWidth: 80
|
|
227
236
|
}
|
|
228
237
|
}
|
|
229
238
|
}
|
|
230
239
|
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.IconButton, {
|
|
231
240
|
size: "small",
|
|
232
241
|
onClick: handleQuantityIncrease,
|
|
233
|
-
disabled:
|
|
242
|
+
disabled: localQuantityNum >= maxQuantity,
|
|
234
243
|
sx: {
|
|
235
244
|
minWidth: 32,
|
|
236
245
|
width: 32,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.19",
|
|
4
4
|
"description": "Reusable react components for payment kit v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -54,16 +54,16 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@arcblock/did-connect-react": "^3.1.
|
|
58
|
-
"@arcblock/ux": "^3.1.
|
|
59
|
-
"@arcblock/ws": "^1.
|
|
60
|
-
"@blocklet/theme": "^3.1.
|
|
61
|
-
"@blocklet/ui-react": "^3.1.
|
|
57
|
+
"@arcblock/did-connect-react": "^3.1.31",
|
|
58
|
+
"@arcblock/ux": "^3.1.31",
|
|
59
|
+
"@arcblock/ws": "^1.23.1",
|
|
60
|
+
"@blocklet/theme": "^3.1.31",
|
|
61
|
+
"@blocklet/ui-react": "^3.1.31",
|
|
62
62
|
"@mui/icons-material": "^7.1.2",
|
|
63
63
|
"@mui/lab": "7.0.0-beta.14",
|
|
64
64
|
"@mui/material": "^7.1.2",
|
|
65
65
|
"@mui/system": "^7.1.1",
|
|
66
|
-
"@ocap/util": "^1.
|
|
66
|
+
"@ocap/util": "^1.23.1",
|
|
67
67
|
"@stripe/react-stripe-js": "^2.9.0",
|
|
68
68
|
"@stripe/stripe-js": "^2.4.0",
|
|
69
69
|
"@vitejs/plugin-legacy": "^7.0.0",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"@babel/core": "^7.27.4",
|
|
95
95
|
"@babel/preset-env": "^7.27.2",
|
|
96
96
|
"@babel/preset-react": "^7.27.1",
|
|
97
|
-
"@blocklet/payment-types": "1.19.
|
|
97
|
+
"@blocklet/payment-types": "1.19.19",
|
|
98
98
|
"@storybook/addon-essentials": "^7.6.20",
|
|
99
99
|
"@storybook/addon-interactions": "^7.6.20",
|
|
100
100
|
"@storybook/addon-links": "^7.6.20",
|
|
@@ -125,5 +125,5 @@
|
|
|
125
125
|
"vite-plugin-babel": "^1.3.1",
|
|
126
126
|
"vite-plugin-node-polyfills": "^0.23.0"
|
|
127
127
|
},
|
|
128
|
-
"gitHead": "
|
|
128
|
+
"gitHead": "76facca620eda1132f8c6d5b8f42d8fd9ef78b05"
|
|
129
129
|
}
|
package/src/checkout/form.tsx
CHANGED
|
@@ -67,9 +67,9 @@ export default function CheckoutForm({
|
|
|
67
67
|
}
|
|
68
68
|
}, [type, mode, data, extraParams]);
|
|
69
69
|
|
|
70
|
-
const handlePaid = () => {
|
|
70
|
+
const handlePaid = (result: CheckoutContext) => {
|
|
71
71
|
setState({ completed: true });
|
|
72
|
-
onPaid?.(
|
|
72
|
+
onPaid?.(result as CheckoutContext);
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
const handleError = (err: any) => {
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import React, { useState, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Box,
|
|
4
|
+
Typography,
|
|
5
|
+
Stack,
|
|
6
|
+
Button,
|
|
7
|
+
CircularProgress,
|
|
8
|
+
Card,
|
|
9
|
+
CardContent,
|
|
10
|
+
IconButton,
|
|
11
|
+
Tooltip,
|
|
12
|
+
SxProps,
|
|
13
|
+
Collapse,
|
|
14
|
+
} from '@mui/material';
|
|
15
|
+
import { AddOutlined, CreditCard, SettingsOutlined, AccountBalanceWalletOutlined } from '@mui/icons-material';
|
|
16
|
+
|
|
17
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
18
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
19
|
+
import { useNavigate } from 'react-router-dom';
|
|
20
|
+
import { joinURL } from 'ufo';
|
|
21
|
+
|
|
22
|
+
import type { AutoRechargeConfig } from '@blocklet/payment-types';
|
|
23
|
+
import { useRequest } from 'ahooks';
|
|
24
|
+
|
|
25
|
+
import { getPrefix, formatBNStr, formatNumber, formatPrice } from '../../libs/util';
|
|
26
|
+
import { createLink, handleNavigation } from '../../libs/navigation';
|
|
27
|
+
import { usePaymentContext } from '../../contexts/payment';
|
|
28
|
+
import api from '../../libs/api';
|
|
29
|
+
import AutoTopupModal from './modal';
|
|
30
|
+
|
|
31
|
+
export interface AutoTopupCardProps {
|
|
32
|
+
currencyId: string;
|
|
33
|
+
onConfigChange?: (config: AutoRechargeConfig) => void;
|
|
34
|
+
sx?: SxProps;
|
|
35
|
+
// 渲染模式: default=完整显示, simple=默认收起支持展开, custom=自定义渲染
|
|
36
|
+
mode?: 'default' | 'simple' | 'custom';
|
|
37
|
+
// 自定义渲染函数(custom模式下使用)
|
|
38
|
+
children?: (
|
|
39
|
+
openModal: () => void,
|
|
40
|
+
config: AutoRechargeConfig | null,
|
|
41
|
+
paymentData: { paymentInfo: any; balanceInfo: any } | null,
|
|
42
|
+
loading: boolean
|
|
43
|
+
) => React.ReactNode;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const fetchConfig = async (customerId: string, currencyId: string) => {
|
|
47
|
+
const { data } = await api.get(`/api/auto-recharge-configs/customer/${customerId}`, {
|
|
48
|
+
params: { currency_id: currencyId },
|
|
49
|
+
});
|
|
50
|
+
return data;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const fetchCurrencyBalance = async (currencyId: string, payerAddress: string) => {
|
|
54
|
+
const { data } = await api.get('/api/customers/payer-token', {
|
|
55
|
+
params: { currencyId, payerAddress },
|
|
56
|
+
});
|
|
57
|
+
return data;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const cardStyle = {
|
|
61
|
+
height: '100%',
|
|
62
|
+
width: '100%',
|
|
63
|
+
border: '1px solid',
|
|
64
|
+
borderColor: 'divider',
|
|
65
|
+
boxShadow: 1,
|
|
66
|
+
borderRadius: 1,
|
|
67
|
+
backgroundColor: 'background.default',
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default function AutoTopupCard({
|
|
71
|
+
currencyId,
|
|
72
|
+
onConfigChange = () => {},
|
|
73
|
+
sx = {},
|
|
74
|
+
mode = 'default',
|
|
75
|
+
children = undefined,
|
|
76
|
+
}: AutoTopupCardProps) {
|
|
77
|
+
const { t } = useLocaleContext();
|
|
78
|
+
const navigate = useNavigate();
|
|
79
|
+
const { session } = usePaymentContext();
|
|
80
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
81
|
+
const [paymentData, setPaymentData] = useState<{ paymentInfo: any; balanceInfo: any } | null>(null);
|
|
82
|
+
const [quickSetupMode, setQuickSetupMode] = useState(false); // 是否是快速设置模式
|
|
83
|
+
// simple模式默认收起,default模式默认展开
|
|
84
|
+
const [expanded, setExpanded] = useState(mode === 'default');
|
|
85
|
+
|
|
86
|
+
const customerId = session?.user?.did || '';
|
|
87
|
+
|
|
88
|
+
const {
|
|
89
|
+
data: config,
|
|
90
|
+
loading,
|
|
91
|
+
refresh,
|
|
92
|
+
} = useRequest(() => fetchConfig(customerId, currencyId), {
|
|
93
|
+
refreshDeps: [customerId, currencyId],
|
|
94
|
+
ready: !!customerId && !!currencyId,
|
|
95
|
+
onSuccess: (data) => {
|
|
96
|
+
loadPaymentInfo(data);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const loadPaymentInfo = useCallback(async (data: any) => {
|
|
101
|
+
if (!data?.recharge_currency_id) return;
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const paymentMethodType = data?.paymentMethod?.type;
|
|
105
|
+
const paymentInfo = data?.payment_settings?.payment_method_options?.[paymentMethodType];
|
|
106
|
+
const balanceInfo =
|
|
107
|
+
paymentInfo?.payer && paymentMethodType !== 'stripe'
|
|
108
|
+
? await fetchCurrencyBalance(data.recharge_currency_id, paymentInfo.payer as string)
|
|
109
|
+
: null;
|
|
110
|
+
|
|
111
|
+
setPaymentData({
|
|
112
|
+
paymentInfo,
|
|
113
|
+
balanceInfo,
|
|
114
|
+
});
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.error('Failed to load payment info:', error);
|
|
117
|
+
}
|
|
118
|
+
}, []);
|
|
119
|
+
|
|
120
|
+
const handleRecharge = (e: React.MouseEvent) => {
|
|
121
|
+
if (!paymentData?.paymentInfo?.payer) return;
|
|
122
|
+
const url = joinURL(
|
|
123
|
+
getPrefix(),
|
|
124
|
+
`/customer/recharge/${config?.recharge_currency_id}?rechargeAddress=${paymentData.paymentInfo.payer}`
|
|
125
|
+
);
|
|
126
|
+
const link = createLink(url, true);
|
|
127
|
+
handleNavigation(e, link, navigate);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const handleConfigSuccess = (newConfig: AutoRechargeConfig) => {
|
|
131
|
+
refresh();
|
|
132
|
+
onConfigChange?.(newConfig);
|
|
133
|
+
setModalOpen(false);
|
|
134
|
+
setQuickSetupMode(false); // 重置快速设置模式
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const handleToggleExpanded = () => {
|
|
138
|
+
setExpanded(!expanded);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
if (loading) {
|
|
142
|
+
return (
|
|
143
|
+
<Card sx={{ ...cardStyle, ...sx }}>
|
|
144
|
+
<CardContent>
|
|
145
|
+
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: 80 }}>
|
|
146
|
+
<CircularProgress size={24} />
|
|
147
|
+
</Box>
|
|
148
|
+
</CardContent>
|
|
149
|
+
</Card>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!config) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const renderPurchaseDetails = () => {
|
|
158
|
+
const { paymentInfo, balanceInfo } = paymentData || {};
|
|
159
|
+
|
|
160
|
+
if (!paymentInfo) {
|
|
161
|
+
return (
|
|
162
|
+
<Typography
|
|
163
|
+
variant="body2"
|
|
164
|
+
sx={{
|
|
165
|
+
color: 'text.secondary',
|
|
166
|
+
}}>
|
|
167
|
+
{t('payment.autoTopup.notConfigured')}
|
|
168
|
+
</Typography>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const purchaseAmount = formatPrice(
|
|
173
|
+
config.price,
|
|
174
|
+
config.rechargeCurrency,
|
|
175
|
+
config.price.product?.unit_label,
|
|
176
|
+
config.quantity,
|
|
177
|
+
true
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
if (config?.paymentMethod?.type === 'stripe') {
|
|
181
|
+
const cardBrand =
|
|
182
|
+
(paymentInfo?.card_brand || 'Card').charAt(0).toUpperCase() +
|
|
183
|
+
(paymentInfo?.card_brand || 'Card').slice(1).toLowerCase();
|
|
184
|
+
const last4 = paymentInfo?.card_last4;
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<Stack spacing={1}>
|
|
188
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
|
189
|
+
<Typography
|
|
190
|
+
variant="body2"
|
|
191
|
+
sx={{
|
|
192
|
+
color: 'text.secondary',
|
|
193
|
+
}}>
|
|
194
|
+
{t('payment.autoTopup.purchaseAmount')}:
|
|
195
|
+
</Typography>
|
|
196
|
+
<Typography variant="body2" sx={{ fontWeight: 600, color: 'text.primary' }}>
|
|
197
|
+
{purchaseAmount}
|
|
198
|
+
</Typography>
|
|
199
|
+
</Box>
|
|
200
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
|
201
|
+
<Typography
|
|
202
|
+
variant="body2"
|
|
203
|
+
sx={{
|
|
204
|
+
color: 'text.secondary',
|
|
205
|
+
}}>
|
|
206
|
+
{t('payment.autoTopup.paymentMethod')}:
|
|
207
|
+
</Typography>
|
|
208
|
+
<Stack
|
|
209
|
+
direction="row"
|
|
210
|
+
spacing={1}
|
|
211
|
+
sx={{
|
|
212
|
+
alignItems: 'center',
|
|
213
|
+
}}>
|
|
214
|
+
<CreditCard fontSize="small" sx={{ color: 'text.secondary' }} />
|
|
215
|
+
<Typography variant="body2" sx={{ color: 'text.primary', fontWeight: 500 }}>
|
|
216
|
+
{cardBrand}({last4})
|
|
217
|
+
</Typography>
|
|
218
|
+
</Stack>
|
|
219
|
+
</Box>
|
|
220
|
+
</Stack>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<Stack spacing={1}>
|
|
226
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
|
227
|
+
<Typography
|
|
228
|
+
variant="body2"
|
|
229
|
+
sx={{
|
|
230
|
+
color: 'text.secondary',
|
|
231
|
+
}}>
|
|
232
|
+
{t('payment.autoTopup.purchaseAmount')}:
|
|
233
|
+
</Typography>
|
|
234
|
+
<Typography variant="body2" sx={{ fontWeight: 600, color: 'text.primary' }}>
|
|
235
|
+
{purchaseAmount}
|
|
236
|
+
</Typography>
|
|
237
|
+
</Box>
|
|
238
|
+
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
239
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
|
240
|
+
<Typography
|
|
241
|
+
variant="body2"
|
|
242
|
+
sx={{
|
|
243
|
+
color: 'text.secondary',
|
|
244
|
+
}}>
|
|
245
|
+
{t('payment.autoTopup.walletBalance')}:
|
|
246
|
+
</Typography>
|
|
247
|
+
<Tooltip
|
|
248
|
+
title={paymentInfo?.payer ? `${t('payment.autoTopup.paymentAddress')}: ${paymentInfo.payer}` : ''}
|
|
249
|
+
placement="top">
|
|
250
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
|
251
|
+
<AccountBalanceWalletOutlined sx={{ fontSize: 16, color: 'text.secondary' }} />
|
|
252
|
+
<Typography variant="body2" sx={{ fontWeight: 600, color: 'text.primary' }}>
|
|
253
|
+
{balanceInfo
|
|
254
|
+
? `${formatBNStr(balanceInfo?.token || '0', config?.rechargeCurrency?.decimal || 18)} ${config?.rechargeCurrency?.symbol || ''}`
|
|
255
|
+
: '--'}
|
|
256
|
+
</Typography>
|
|
257
|
+
</Box>
|
|
258
|
+
</Tooltip>
|
|
259
|
+
{balanceInfo && (
|
|
260
|
+
<Button
|
|
261
|
+
size="small"
|
|
262
|
+
variant="text"
|
|
263
|
+
onClick={handleRecharge}
|
|
264
|
+
sx={{
|
|
265
|
+
color: 'primary.main',
|
|
266
|
+
display: 'flex',
|
|
267
|
+
alignItems: 'center',
|
|
268
|
+
}}>
|
|
269
|
+
<AddOutlined fontSize="small" />
|
|
270
|
+
{t('payment.autoTopup.addFunds')}
|
|
271
|
+
</Button>
|
|
272
|
+
)}
|
|
273
|
+
</Box>
|
|
274
|
+
</Box>
|
|
275
|
+
</Stack>
|
|
276
|
+
);
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const openModal = () => setModalOpen(true);
|
|
280
|
+
|
|
281
|
+
const renderInnerView = () => {
|
|
282
|
+
if (mode === 'custom') {
|
|
283
|
+
return children && typeof children === 'function' ? (
|
|
284
|
+
<>{children(openModal, config, paymentData, loading)}</>
|
|
285
|
+
) : (
|
|
286
|
+
<Typography>
|
|
287
|
+
Please provide a valid render function
|
|
288
|
+
<pre>{'(openModal, config, paymentData, loading) => ReactNode'}</pre>
|
|
289
|
+
</Typography>
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return (
|
|
294
|
+
<Card sx={{ ...cardStyle, ...sx }}>
|
|
295
|
+
<CardContent>
|
|
296
|
+
{/* Header */}
|
|
297
|
+
<Stack
|
|
298
|
+
direction="row"
|
|
299
|
+
className="auto-topup-header"
|
|
300
|
+
sx={{
|
|
301
|
+
justifyContent: 'space-between',
|
|
302
|
+
alignItems: 'center',
|
|
303
|
+
borderBottom: '1px solid',
|
|
304
|
+
borderColor: 'divider',
|
|
305
|
+
pb: 1.5,
|
|
306
|
+
}}>
|
|
307
|
+
<Typography variant="subtitle2" sx={{ fontWeight: 600, color: 'text.primary' }}>
|
|
308
|
+
{t('payment.autoTopup.title')}
|
|
309
|
+
</Typography>
|
|
310
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
|
311
|
+
<IconButton
|
|
312
|
+
size="small"
|
|
313
|
+
onClick={openModal}
|
|
314
|
+
sx={{
|
|
315
|
+
p: 0.5,
|
|
316
|
+
color: 'text.secondary',
|
|
317
|
+
'&:hover': {
|
|
318
|
+
bgcolor: 'grey.50',
|
|
319
|
+
color: 'text.primary',
|
|
320
|
+
},
|
|
321
|
+
}}>
|
|
322
|
+
<SettingsOutlined fontSize="small" />
|
|
323
|
+
</IconButton>
|
|
324
|
+
</Box>
|
|
325
|
+
</Stack>
|
|
326
|
+
|
|
327
|
+
{config?.enabled ? (
|
|
328
|
+
<Stack spacing={1.5} className="auto-topup-content" sx={{ pt: 1.5 }}>
|
|
329
|
+
{/* Main Description */}
|
|
330
|
+
{(() => {
|
|
331
|
+
const threshold = `${formatNumber(config.threshold)} ${config.currency?.symbol || ''}`;
|
|
332
|
+
const credits = `${formatNumber(
|
|
333
|
+
Number(config.price.metadata?.credit_config?.credit_amount || 0) * Number(config.quantity)
|
|
334
|
+
)} ${config.currency?.name || ''}`;
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<Typography
|
|
338
|
+
variant="body2"
|
|
339
|
+
sx={{
|
|
340
|
+
color: 'text.secondary',
|
|
341
|
+
}}>
|
|
342
|
+
{t('payment.autoTopup.activeDescriptionWithCredits', { threshold, credits })}
|
|
343
|
+
{/* 展开收起按钮 - 仅在simple模式下显示 */}
|
|
344
|
+
{mode === 'simple' && (
|
|
345
|
+
<Button
|
|
346
|
+
component="span"
|
|
347
|
+
size="small"
|
|
348
|
+
variant="text"
|
|
349
|
+
onClick={handleToggleExpanded}
|
|
350
|
+
sx={{
|
|
351
|
+
color: 'primary.main',
|
|
352
|
+
minWidth: 'auto',
|
|
353
|
+
ml: 1,
|
|
354
|
+
p: 0,
|
|
355
|
+
fontSize: 'inherit',
|
|
356
|
+
textTransform: 'none',
|
|
357
|
+
'&:hover': {
|
|
358
|
+
backgroundColor: 'transparent',
|
|
359
|
+
textDecoration: 'underline',
|
|
360
|
+
},
|
|
361
|
+
}}>
|
|
362
|
+
{expanded ? t('payment.autoTopup.hideDetails') : t('payment.autoTopup.showDetails')}
|
|
363
|
+
</Button>
|
|
364
|
+
)}
|
|
365
|
+
</Typography>
|
|
366
|
+
);
|
|
367
|
+
})()}
|
|
368
|
+
|
|
369
|
+
<Collapse in={mode === 'default' || expanded}>
|
|
370
|
+
<Box
|
|
371
|
+
sx={{
|
|
372
|
+
bgcolor: 'grey.50',
|
|
373
|
+
borderRadius: 1,
|
|
374
|
+
p: 1.5,
|
|
375
|
+
}}>
|
|
376
|
+
{renderPurchaseDetails()}
|
|
377
|
+
</Box>
|
|
378
|
+
</Collapse>
|
|
379
|
+
</Stack>
|
|
380
|
+
) : (
|
|
381
|
+
<Stack
|
|
382
|
+
className="auto-topup-content"
|
|
383
|
+
sx={{
|
|
384
|
+
minHeight: 80,
|
|
385
|
+
display: 'flex',
|
|
386
|
+
flexDirection: 'column',
|
|
387
|
+
alignItems: 'center',
|
|
388
|
+
justifyContent: 'center',
|
|
389
|
+
pt: 1.5,
|
|
390
|
+
gap: 2,
|
|
391
|
+
}}>
|
|
392
|
+
<Typography
|
|
393
|
+
variant="body2"
|
|
394
|
+
sx={{
|
|
395
|
+
color: 'text.secondary',
|
|
396
|
+
textAlign: 'left',
|
|
397
|
+
}}>
|
|
398
|
+
{t('payment.autoTopup.inactiveDescription', {
|
|
399
|
+
name: config?.currency?.name,
|
|
400
|
+
})}
|
|
401
|
+
<Button
|
|
402
|
+
component="span"
|
|
403
|
+
variant="text"
|
|
404
|
+
size="small"
|
|
405
|
+
onClick={() => {
|
|
406
|
+
setQuickSetupMode(true);
|
|
407
|
+
setModalOpen(true);
|
|
408
|
+
}}
|
|
409
|
+
sx={{
|
|
410
|
+
color: 'primary.main',
|
|
411
|
+
minWidth: 'auto',
|
|
412
|
+
ml: 1,
|
|
413
|
+
p: 0,
|
|
414
|
+
fontSize: 'inherit',
|
|
415
|
+
textTransform: 'none',
|
|
416
|
+
'&:hover': {
|
|
417
|
+
backgroundColor: 'transparent',
|
|
418
|
+
textDecoration: 'underline',
|
|
419
|
+
},
|
|
420
|
+
}}>
|
|
421
|
+
{t('payment.autoTopup.setup')}
|
|
422
|
+
</Button>
|
|
423
|
+
</Typography>
|
|
424
|
+
</Stack>
|
|
425
|
+
)}
|
|
426
|
+
</CardContent>
|
|
427
|
+
</Card>
|
|
428
|
+
);
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
return (
|
|
432
|
+
<>
|
|
433
|
+
{renderInnerView()}
|
|
434
|
+
|
|
435
|
+
{modalOpen && (
|
|
436
|
+
<AutoTopupModal
|
|
437
|
+
open={modalOpen}
|
|
438
|
+
onClose={() => {
|
|
439
|
+
setModalOpen(false);
|
|
440
|
+
setQuickSetupMode(false); // 关闭时重置快速设置模式
|
|
441
|
+
}}
|
|
442
|
+
currencyId={currencyId}
|
|
443
|
+
onSuccess={handleConfigSuccess}
|
|
444
|
+
defaultEnabled={quickSetupMode} // 传递默认启用状态
|
|
445
|
+
/>
|
|
446
|
+
)}
|
|
447
|
+
</>
|
|
448
|
+
);
|
|
449
|
+
}
|