@blocklet/payment-react 1.19.18 → 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.
Files changed (55) hide show
  1. package/README.md +313 -0
  2. package/es/checkout/form.js +2 -2
  3. package/es/components/auto-topup/index.d.ts +14 -0
  4. package/es/components/auto-topup/index.js +417 -0
  5. package/es/components/auto-topup/modal.d.ts +35 -0
  6. package/es/components/auto-topup/modal.js +734 -0
  7. package/es/components/auto-topup/product-card.d.ts +13 -0
  8. package/es/components/auto-topup/product-card.js +173 -0
  9. package/es/components/collapse.d.ts +13 -0
  10. package/es/components/collapse.js +76 -0
  11. package/es/components/input.d.ts +2 -1
  12. package/es/components/input.js +64 -13
  13. package/es/components/label.d.ts +2 -1
  14. package/es/components/label.js +2 -1
  15. package/es/index.d.ts +4 -1
  16. package/es/index.js +7 -1
  17. package/es/libs/util.js +2 -1
  18. package/es/locales/en.js +56 -0
  19. package/es/locales/zh.js +56 -0
  20. package/es/payment/form/index.js +6 -0
  21. package/es/payment/product-item.js +17 -10
  22. package/lib/checkout/form.js +2 -2
  23. package/lib/components/auto-topup/index.d.ts +14 -0
  24. package/lib/components/auto-topup/index.js +451 -0
  25. package/lib/components/auto-topup/modal.d.ts +35 -0
  26. package/lib/components/auto-topup/modal.js +803 -0
  27. package/lib/components/auto-topup/product-card.d.ts +13 -0
  28. package/lib/components/auto-topup/product-card.js +149 -0
  29. package/lib/components/collapse.d.ts +13 -0
  30. package/lib/components/collapse.js +74 -0
  31. package/lib/components/input.d.ts +2 -1
  32. package/lib/components/input.js +66 -24
  33. package/lib/components/label.d.ts +2 -1
  34. package/lib/components/label.js +3 -1
  35. package/lib/index.d.ts +4 -1
  36. package/lib/index.js +24 -0
  37. package/lib/libs/util.js +2 -1
  38. package/lib/locales/en.js +56 -0
  39. package/lib/locales/zh.js +56 -0
  40. package/lib/payment/form/index.js +6 -0
  41. package/lib/payment/product-item.js +18 -10
  42. package/package.json +9 -9
  43. package/src/checkout/form.tsx +2 -2
  44. package/src/components/auto-topup/index.tsx +449 -0
  45. package/src/components/auto-topup/modal.tsx +773 -0
  46. package/src/components/auto-topup/product-card.tsx +156 -0
  47. package/src/components/collapse.tsx +82 -0
  48. package/src/components/input.tsx +71 -22
  49. package/src/components/label.tsx +8 -2
  50. package/src/index.ts +7 -0
  51. package/src/libs/util.ts +1 -0
  52. package/src/locales/en.tsx +59 -0
  53. package/src/locales/zh.tsx +57 -0
  54. package/src/payment/form/index.tsx +6 -0
  55. package/src/payment/product-item.tsx +18 -11
@@ -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,7 +57,14 @@ 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
69
  if ((0, _util.formatQuantityInventory)(item.price, newQuantity, locale)) {
62
70
  return;
@@ -66,17 +74,17 @@ function ProductItem({
66
74
  }
67
75
  };
68
76
  const handleQuantityIncrease = () => {
69
- if (localQuantity < maxQuantity) {
70
- handleQuantityChange(localQuantity + 1);
77
+ if (localQuantityNum < maxQuantity) {
78
+ handleQuantityChange(localQuantityNum + 1);
71
79
  }
72
80
  };
73
81
  const handleQuantityDecrease = () => {
74
- if (localQuantity > minQuantity) {
75
- handleQuantityChange(localQuantity - 1);
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, localQuantity, locale);
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: localQuantity <= minQuantity,
214
+ disabled: localQuantityNum <= minQuantity,
207
215
  sx: {
208
216
  minWidth: 32,
209
217
  width: 32,
@@ -231,7 +239,7 @@ function ProductItem({
231
239
  }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.IconButton, {
232
240
  size: "small",
233
241
  onClick: handleQuantityIncrease,
234
- disabled: localQuantity >= maxQuantity,
242
+ disabled: localQuantityNum >= maxQuantity,
235
243
  sx: {
236
244
  minWidth: 32,
237
245
  width: 32,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.19.18",
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.18",
58
- "@arcblock/ux": "^3.1.18",
59
- "@arcblock/ws": "^1.21.3",
60
- "@blocklet/theme": "^3.1.18",
61
- "@blocklet/ui-react": "^3.1.18",
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.21.3",
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.18",
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": "b57baf21f22ae453247bc31444673aa01e35e6dc"
128
+ "gitHead": "76facca620eda1132f8c6d5b8f42d8fd9ef78b05"
129
129
  }
@@ -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?.(data as CheckoutContext);
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
+ }