payment-kit 1.18.17 → 1.18.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/api/src/libs/subscription.ts +116 -0
- package/api/src/routes/checkout-sessions.ts +28 -1
- package/api/src/routes/customers.ts +5 -1
- package/api/src/store/migrations/20250318-donate-invoice.ts +45 -0
- package/api/tests/libs/subscription.spec.ts +311 -0
- package/blocklet.yml +1 -1
- package/package.json +9 -9
- package/src/components/currency.tsx +11 -4
- package/src/components/customer/link.tsx +54 -14
- package/src/components/customer/overdraft-protection.tsx +36 -2
- package/src/components/info-card.tsx +55 -7
- package/src/components/info-row-group.tsx +122 -0
- package/src/components/info-row.tsx +14 -1
- package/src/components/payouts/portal/list.tsx +7 -2
- package/src/components/subscription/items/index.tsx +1 -1
- package/src/components/subscription/metrics.tsx +14 -6
- package/src/contexts/info-row.tsx +4 -0
- package/src/locales/en.tsx +1 -0
- package/src/locales/zh.tsx +1 -0
- package/src/pages/admin/billing/invoices/detail.tsx +54 -76
- package/src/pages/admin/billing/subscriptions/detail.tsx +34 -71
- package/src/pages/admin/customers/customers/detail.tsx +41 -64
- package/src/pages/admin/payments/intents/detail.tsx +28 -42
- package/src/pages/admin/payments/payouts/detail.tsx +27 -36
- package/src/pages/admin/payments/refunds/detail.tsx +27 -41
- package/src/pages/admin/products/links/detail.tsx +30 -55
- package/src/pages/admin/products/prices/detail.tsx +43 -50
- package/src/pages/admin/products/pricing-tables/detail.tsx +23 -25
- package/src/pages/admin/products/products/detail.tsx +52 -81
- package/src/pages/customer/index.tsx +183 -108
- package/src/pages/customer/invoice/detail.tsx +49 -50
- package/src/pages/customer/payout/detail.tsx +16 -22
- package/src/pages/customer/recharge/account.tsx +92 -34
- package/src/pages/customer/recharge/subscription.tsx +6 -0
- package/src/pages/customer/subscription/detail.tsx +176 -94
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
getPrefix,
|
|
15
15
|
usePaymentContext,
|
|
16
16
|
PaymentBeneficiaries,
|
|
17
|
+
useMobile,
|
|
17
18
|
} from '@blocklet/payment-react';
|
|
18
19
|
import type { TCheckoutSession, TInvoiceExpanded, TPaymentLink } from '@blocklet/payment-types';
|
|
19
20
|
import { ArrowBackOutlined } from '@mui/icons-material';
|
|
@@ -34,6 +35,7 @@ import InvoiceTable from '../../../components/invoice/table';
|
|
|
34
35
|
import { goBackOrFallback } from '../../../libs/util';
|
|
35
36
|
import CustomerRefundList from '../refund/list';
|
|
36
37
|
import InfoMetric from '../../../components/info-metric';
|
|
38
|
+
import InfoRowGroup from '../../../components/info-row-group';
|
|
37
39
|
|
|
38
40
|
const fetchData = (
|
|
39
41
|
id: string
|
|
@@ -43,11 +45,10 @@ const fetchData = (
|
|
|
43
45
|
return api.get(`/api/invoices/${id}`).then((res) => res.data);
|
|
44
46
|
};
|
|
45
47
|
|
|
46
|
-
const InfoDirection = 'column';
|
|
47
|
-
const InfoAlignItems = 'flex-start';
|
|
48
48
|
export default function CustomerInvoiceDetail() {
|
|
49
49
|
const { t, locale } = useLocaleContext();
|
|
50
50
|
const [searchParams] = useSearchParams();
|
|
51
|
+
const { isMobile } = useMobile();
|
|
51
52
|
const { connect } = usePaymentContext();
|
|
52
53
|
const params = useParams<{ id: string }>();
|
|
53
54
|
const [state, setState] = useSetState({
|
|
@@ -138,7 +139,16 @@ export default function CustomerInvoiceDetail() {
|
|
|
138
139
|
</Typography>
|
|
139
140
|
</Stack>
|
|
140
141
|
<Stack direction="row" spacing={1} justifyContent="flex-end" alignItems="center">
|
|
141
|
-
{['open', 'paid', 'uncollectible'].includes(data.status) && <Download data={data} />}
|
|
142
|
+
{['open', 'paid', 'uncollectible'].includes(data.status) && !isDonation && <Download data={data} />}
|
|
143
|
+
{data?.paymentLink?.donation_settings?.reference && (
|
|
144
|
+
<Button
|
|
145
|
+
variant="outlined"
|
|
146
|
+
onClick={() => {
|
|
147
|
+
window.open(data?.paymentLink?.donation_settings?.reference, '_blank');
|
|
148
|
+
}}>
|
|
149
|
+
{t('customer.payout.viewReference')}
|
|
150
|
+
</Button>
|
|
151
|
+
)}
|
|
142
152
|
{['open', 'uncollectible'].includes(data.status) && !hidePayButton && (
|
|
143
153
|
<Button
|
|
144
154
|
variant="outlined"
|
|
@@ -240,51 +250,50 @@ export default function CustomerInvoiceDetail() {
|
|
|
240
250
|
</Stack>
|
|
241
251
|
</Box>
|
|
242
252
|
<Divider />
|
|
243
|
-
<Box className="section">
|
|
253
|
+
<Box className="section" sx={{ containerType: 'inline-size' }}>
|
|
244
254
|
<Typography variant="h3" mb={3} className="section-header">
|
|
245
255
|
{t('payment.customer.invoice.details')}
|
|
246
256
|
</Typography>
|
|
247
|
-
<
|
|
248
|
-
className="invoice-summary-wrapper"
|
|
257
|
+
<InfoRowGroup
|
|
249
258
|
sx={{
|
|
250
259
|
display: 'grid',
|
|
251
260
|
gridTemplateColumns: {
|
|
252
261
|
xs: 'repeat(1, 1fr)',
|
|
253
|
-
|
|
254
|
-
md: 'repeat(2, 1fr)',
|
|
255
|
-
lg: 'repeat(3, 1fr)',
|
|
262
|
+
lg: 'repeat(2, 1fr)',
|
|
256
263
|
},
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
264
|
+
'@container (min-width: 980px)': {
|
|
265
|
+
gridTemplateColumns: 'repeat(2, 1fr)',
|
|
266
|
+
},
|
|
267
|
+
'.info-row-wrapper': {
|
|
268
|
+
gap: 1,
|
|
269
|
+
flexDirection: {
|
|
270
|
+
xs: 'column',
|
|
271
|
+
lg: 'row',
|
|
272
|
+
},
|
|
273
|
+
alignItems: {
|
|
274
|
+
xs: 'flex-start',
|
|
275
|
+
lg: 'center',
|
|
276
|
+
},
|
|
277
|
+
'@container (min-width: 980px)': {
|
|
278
|
+
flexDirection: 'row',
|
|
279
|
+
alignItems: 'center',
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
'.currency-name': {
|
|
283
|
+
color: 'text.secondary',
|
|
260
284
|
},
|
|
261
285
|
}}>
|
|
262
286
|
<InfoRow
|
|
263
|
-
label={t('admin.invoice.
|
|
264
|
-
value={
|
|
265
|
-
direction={InfoDirection}
|
|
266
|
-
alignItems={InfoAlignItems}
|
|
267
|
-
/>
|
|
268
|
-
<InfoRow
|
|
269
|
-
label={t('admin.invoice.from')}
|
|
270
|
-
value={data.statement_descriptor || blocklet.appName}
|
|
271
|
-
direction={InfoDirection}
|
|
272
|
-
alignItems={InfoAlignItems}
|
|
287
|
+
label={t('admin.invoice.billTo')}
|
|
288
|
+
value={<CustomerLink customer={data.customer} linked={false} size={isMobile ? 'default' : 'small'} />}
|
|
273
289
|
/>
|
|
274
|
-
|
|
290
|
+
<InfoRow label={t('admin.invoice.from')} value={data.statement_descriptor || blocklet.appName} />
|
|
275
291
|
<InfoRow
|
|
276
|
-
label={t('admin.invoice.
|
|
277
|
-
value={
|
|
278
|
-
direction={InfoDirection}
|
|
279
|
-
alignItems={InfoAlignItems}
|
|
292
|
+
label={t('admin.invoice.description')}
|
|
293
|
+
value={getInvoiceDescriptionAndReason(data, locale)?.description}
|
|
280
294
|
/>
|
|
281
295
|
{data.status_transitions?.paid_at && (
|
|
282
|
-
<InfoRow
|
|
283
|
-
label={t('admin.invoice.paidAt')}
|
|
284
|
-
value={formatTime(data.status_transitions.paid_at * 1000)}
|
|
285
|
-
direction={InfoDirection}
|
|
286
|
-
alignItems={InfoAlignItems}
|
|
287
|
-
/>
|
|
296
|
+
<InfoRow label={t('admin.invoice.paidAt')} value={formatTime(data.status_transitions.paid_at * 1000)} />
|
|
288
297
|
)}
|
|
289
298
|
<InfoRow
|
|
290
299
|
label={t('admin.paymentCurrency.name')}
|
|
@@ -294,15 +303,17 @@ export default function CustomerInvoiceDetail() {
|
|
|
294
303
|
name={`${data.paymentCurrency.symbol} (${data.paymentMethod.name})`}
|
|
295
304
|
/>
|
|
296
305
|
}
|
|
297
|
-
direction={InfoDirection}
|
|
298
|
-
alignItems={InfoAlignItems}
|
|
299
306
|
/>
|
|
307
|
+
{(isStake || isSlashStake) && (
|
|
308
|
+
<InfoRow
|
|
309
|
+
label={isSlashStake ? t('common.slashStakeAmount') : t('common.stakeAmount')}
|
|
310
|
+
value={`${formatAmount(data.total, data.paymentCurrency.decimal)} ${data.paymentCurrency.symbol}`}
|
|
311
|
+
/>
|
|
312
|
+
)}
|
|
300
313
|
{(!!data.paymentIntent?.payment_details?.ethereum || !!data.paymentIntent?.payment_details?.base) && (
|
|
301
314
|
<InfoRow
|
|
302
315
|
label={t('common.txGas')}
|
|
303
316
|
value={<TxGas details={data.paymentIntent.payment_details as any} method={data.paymentMethod} />}
|
|
304
|
-
direction={InfoDirection}
|
|
305
|
-
alignItems={InfoAlignItems}
|
|
306
317
|
/>
|
|
307
318
|
)}
|
|
308
319
|
{paymentDetails && (
|
|
@@ -311,16 +322,6 @@ export default function CustomerInvoiceDetail() {
|
|
|
311
322
|
isStake ? t('common.stakeTxHash') : t(`common.${paymentDetails?.arcblock?.type || 'transfer'}TxHash`)
|
|
312
323
|
}
|
|
313
324
|
value={<TxLink details={paymentDetails} method={data.paymentMethod} mode="customer" />}
|
|
314
|
-
direction={InfoDirection}
|
|
315
|
-
alignItems={InfoAlignItems}
|
|
316
|
-
/>
|
|
317
|
-
)}
|
|
318
|
-
{(isStake || isSlashStake) && (
|
|
319
|
-
<InfoRow
|
|
320
|
-
label={isSlashStake ? t('common.slashStakeAmount') : t('common.stakeAmount')}
|
|
321
|
-
value={`${formatAmount(data.total, data.paymentCurrency.decimal)} ${data.paymentCurrency.symbol}`}
|
|
322
|
-
direction={InfoDirection}
|
|
323
|
-
alignItems={InfoAlignItems}
|
|
324
325
|
/>
|
|
325
326
|
)}
|
|
326
327
|
{data?.relatedInvoice && (
|
|
@@ -338,11 +339,9 @@ export default function CustomerInvoiceDetail() {
|
|
|
338
339
|
{data.relatedInvoice?.number}
|
|
339
340
|
</Typography>
|
|
340
341
|
}
|
|
341
|
-
direction={InfoDirection}
|
|
342
|
-
alignItems={InfoAlignItems}
|
|
343
342
|
/>
|
|
344
343
|
)}
|
|
345
|
-
</
|
|
344
|
+
</InfoRowGroup>
|
|
346
345
|
</Box>
|
|
347
346
|
{isDonation && !isEmpty(data.paymentIntent?.beneficiaries) && (
|
|
348
347
|
<>
|
|
@@ -25,6 +25,7 @@ import SectionHeader from '../../../components/section/header';
|
|
|
25
25
|
import { getCustomerProfileUrl, goBackOrFallback } from '../../../libs/util';
|
|
26
26
|
import CustomerLink from '../../../components/customer/link';
|
|
27
27
|
import InfoCard from '../../../components/info-card';
|
|
28
|
+
import InfoRowGroup from '../../../components/info-row-group';
|
|
28
29
|
|
|
29
30
|
const fetchData = (
|
|
30
31
|
id: string
|
|
@@ -37,9 +38,6 @@ const fetchData = (
|
|
|
37
38
|
return api.get(`/api/payouts/${id}`).then((res) => res.data);
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
const InfoDirection = 'column';
|
|
41
|
-
const InfoAlignItems = 'flex-start';
|
|
42
|
-
|
|
43
41
|
export default function PayoutDetail() {
|
|
44
42
|
const { t } = useLocaleContext();
|
|
45
43
|
const { isMobile } = useMobile();
|
|
@@ -237,41 +235,37 @@ export default function PayoutDetail() {
|
|
|
237
235
|
<Box flex={1} className="payment-link-column-1" sx={{ gap: 2.5, display: 'flex', flexDirection: 'column' }}>
|
|
238
236
|
<Box className="section">
|
|
239
237
|
<SectionHeader title={t('common.detail')} />
|
|
240
|
-
<
|
|
238
|
+
<InfoRowGroup
|
|
241
239
|
sx={{
|
|
242
240
|
display: 'grid',
|
|
243
241
|
gridTemplateColumns: {
|
|
244
242
|
xs: 'repeat(1, 1fr)',
|
|
245
|
-
|
|
246
|
-
md: 'repeat(2, 1fr)',
|
|
247
|
-
lg: 'repeat(3, 1fr)',
|
|
243
|
+
lg: 'repeat(2, 1fr)',
|
|
248
244
|
},
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
245
|
+
'.info-row-wrapper': {
|
|
246
|
+
gap: 1,
|
|
247
|
+
flexDirection: {
|
|
248
|
+
xs: 'column',
|
|
249
|
+
lg: 'row',
|
|
250
|
+
},
|
|
251
|
+
alignItems: {
|
|
252
|
+
xs: 'flex-start',
|
|
253
|
+
lg: 'center',
|
|
254
|
+
},
|
|
252
255
|
},
|
|
253
256
|
}}>
|
|
254
|
-
<InfoRow
|
|
255
|
-
label={t('common.createdAt')}
|
|
256
|
-
value={formatTime(data.created_at)}
|
|
257
|
-
direction={InfoDirection}
|
|
258
|
-
alignItems={InfoAlignItems}
|
|
259
|
-
/>
|
|
257
|
+
<InfoRow label={t('common.createdAt')} value={formatTime(data.created_at)} />
|
|
260
258
|
{paymentIntent && paymentIntent.payment_details && (
|
|
261
259
|
<InfoRow
|
|
262
260
|
label={t('customer.payout.payTxHash')}
|
|
263
261
|
value={<TxLink details={paymentIntent.payment_details} method={data.paymentMethod} mode="customer" />}
|
|
264
|
-
direction={InfoDirection}
|
|
265
|
-
alignItems={InfoAlignItems}
|
|
266
262
|
/>
|
|
267
263
|
)}
|
|
268
264
|
<InfoRow
|
|
269
265
|
label={t('customer.payout.receiver')}
|
|
270
|
-
value={<CustomerLink customer={data.customer} linked={false} />}
|
|
271
|
-
direction={InfoDirection}
|
|
272
|
-
alignItems={InfoAlignItems}
|
|
266
|
+
value={<CustomerLink customer={data.customer} linked={false} size={isMobile ? 'default' : 'small'} />}
|
|
273
267
|
/>
|
|
274
|
-
</
|
|
268
|
+
</InfoRowGroup>
|
|
275
269
|
</Box>
|
|
276
270
|
</Box>
|
|
277
271
|
</Stack>
|
|
@@ -31,9 +31,11 @@ import type { TPaymentCurrency, TPaymentMethod } from '@blocklet/payment-types';
|
|
|
31
31
|
import { joinURL } from 'ufo';
|
|
32
32
|
import { AccountBalanceWalletOutlined, ArrowBackOutlined, ArrowForwardOutlined } from '@mui/icons-material';
|
|
33
33
|
import Empty from '@arcblock/ux/lib/Empty';
|
|
34
|
+
import { BN } from '@ocap/util';
|
|
34
35
|
import RechargeList from '../../../components/invoice/recharge';
|
|
35
36
|
import { getTokenBalanceLink, goBackOrFallback } from '../../../libs/util';
|
|
36
37
|
import { useSessionContext } from '../../../contexts/session';
|
|
38
|
+
import { formatSmartDuration, TimeUnit } from '../../../libs/dayjs';
|
|
37
39
|
|
|
38
40
|
// 扩展PaymentCurrency类型以包含paymentMethod
|
|
39
41
|
interface ExtendedPaymentCurrency extends TPaymentCurrency {
|
|
@@ -86,7 +88,7 @@ export default function BalanceRechargePage() {
|
|
|
86
88
|
token: string;
|
|
87
89
|
} | null>(null);
|
|
88
90
|
const [customAmount, setCustomAmount] = useState(false);
|
|
89
|
-
const [presetAmounts] = useState<Array<{ amount: string
|
|
91
|
+
const [presetAmounts, setPresetAmounts] = useState<Array<{ amount: string; multiplier: number; label: string }>>([]);
|
|
90
92
|
const { session } = useSessionContext();
|
|
91
93
|
const [currency, setCurrency] = useState<ExtendedPaymentCurrency | null>(null);
|
|
92
94
|
const [relatedSubscriptions, setRelatedSubscriptions] = useState<Subscription[]>([]);
|
|
@@ -105,6 +107,57 @@ export default function BalanceRechargePage() {
|
|
|
105
107
|
if (data.currency) {
|
|
106
108
|
setCurrency(data.currency);
|
|
107
109
|
setRelatedSubscriptions(data.relatedSubscriptions || []);
|
|
110
|
+
|
|
111
|
+
if (data.recommendedRecharge && data.recommendedRecharge.amount) {
|
|
112
|
+
const baseAmount = data.recommendedRecharge.amount;
|
|
113
|
+
const decimal = data.currency.decimal || 0;
|
|
114
|
+
setPresetAmounts([
|
|
115
|
+
{
|
|
116
|
+
amount: Math.ceil(parseFloat(formatBNStr(baseAmount, decimal, 6, true))).toString(),
|
|
117
|
+
multiplier: data.recommendedRecharge.cycle,
|
|
118
|
+
label: t('common.estimatedDuration', {
|
|
119
|
+
duration: formatSmartDuration(1, data.recommendedRecharge.interval as TimeUnit, {
|
|
120
|
+
t,
|
|
121
|
+
}),
|
|
122
|
+
}),
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
amount: Math.ceil(
|
|
126
|
+
parseFloat(formatBNStr(new BN(baseAmount).mul(new BN('4')).toString(), decimal, 6, true))
|
|
127
|
+
).toString(),
|
|
128
|
+
multiplier: data.recommendedRecharge.cycle * 4,
|
|
129
|
+
label: t('common.estimatedDuration', {
|
|
130
|
+
duration: formatSmartDuration(4, data.recommendedRecharge.interval as TimeUnit, {
|
|
131
|
+
t,
|
|
132
|
+
}),
|
|
133
|
+
}),
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
amount: Math.ceil(
|
|
137
|
+
parseFloat(formatBNStr(new BN(baseAmount).mul(new BN('8')).toString(), decimal, 6, true))
|
|
138
|
+
).toString(),
|
|
139
|
+
multiplier: data.recommendedRecharge.cycle * 8,
|
|
140
|
+
label: t('common.estimatedDuration', {
|
|
141
|
+
duration: formatSmartDuration(8, data.recommendedRecharge.interval as TimeUnit, {
|
|
142
|
+
t,
|
|
143
|
+
}),
|
|
144
|
+
}),
|
|
145
|
+
},
|
|
146
|
+
]);
|
|
147
|
+
|
|
148
|
+
setAmount(
|
|
149
|
+
Math.ceil(
|
|
150
|
+
parseFloat(formatBNStr(new BN(baseAmount).mul(new BN('4')).toString(), decimal, 6, true))
|
|
151
|
+
).toString()
|
|
152
|
+
);
|
|
153
|
+
} else {
|
|
154
|
+
setPresetAmounts([
|
|
155
|
+
{ amount: '10', multiplier: 0, label: '' },
|
|
156
|
+
{ amount: '50', multiplier: 0, label: '' },
|
|
157
|
+
{ amount: '100', multiplier: 0, label: '' },
|
|
158
|
+
]);
|
|
159
|
+
}
|
|
160
|
+
|
|
108
161
|
const supportRecharge = data.currency?.paymentMethod?.type === 'arcblock';
|
|
109
162
|
if (supportRecharge) {
|
|
110
163
|
const payerTokenRes = await api.get(`/api/customers/payer-token?currencyId=${currencyId}`);
|
|
@@ -261,7 +314,7 @@ export default function BalanceRechargePage() {
|
|
|
261
314
|
|
|
262
315
|
{currency && (
|
|
263
316
|
<Box ref={rechargeRef}>
|
|
264
|
-
<Stack sx={{ maxWidth: '
|
|
317
|
+
<Stack sx={{ maxWidth: '760px' }}>
|
|
265
318
|
<Box sx={{ mb: 4 }}>
|
|
266
319
|
<BalanceCard elevation={0}>
|
|
267
320
|
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
|
|
@@ -341,7 +394,7 @@ export default function BalanceRechargePage() {
|
|
|
341
394
|
|
|
342
395
|
<Paper elevation={0} sx={{ mb: 3, backgroundColor: 'background.default', borderRadius: '16px' }}>
|
|
343
396
|
<Grid container spacing={2}>
|
|
344
|
-
{presetAmounts.map(({ amount: presetAmount }) => (
|
|
397
|
+
{presetAmounts.map(({ amount: presetAmount, label, multiplier }) => (
|
|
345
398
|
<Grid item xs={6} sm={3} key={presetAmount}>
|
|
346
399
|
<Card
|
|
347
400
|
variant="outlined"
|
|
@@ -365,7 +418,9 @@ export default function BalanceRechargePage() {
|
|
|
365
418
|
}
|
|
366
419
|
: {}),
|
|
367
420
|
}}>
|
|
368
|
-
<CardActionArea
|
|
421
|
+
<CardActionArea
|
|
422
|
+
onClick={() => handleSelect(presetAmount)}
|
|
423
|
+
sx={{ height: '100%', p: 1.5, textAlign: 'center' }}>
|
|
369
424
|
<Typography
|
|
370
425
|
variant="h6"
|
|
371
426
|
align="center"
|
|
@@ -375,6 +430,11 @@ export default function BalanceRechargePage() {
|
|
|
375
430
|
}}>
|
|
376
431
|
{presetAmount} {currency.symbol}
|
|
377
432
|
</Typography>
|
|
433
|
+
{multiplier > 0 && label && (
|
|
434
|
+
<Typography variant="caption" align="center" color="text.secondary">
|
|
435
|
+
{label}
|
|
436
|
+
</Typography>
|
|
437
|
+
)}
|
|
378
438
|
</CardActionArea>
|
|
379
439
|
</Card>
|
|
380
440
|
</Grid>
|
|
@@ -464,39 +524,37 @@ export default function BalanceRechargePage() {
|
|
|
464
524
|
{t('customer.recharge.relatedSubscriptions')}
|
|
465
525
|
</Typography>
|
|
466
526
|
|
|
467
|
-
<
|
|
527
|
+
<Grid container spacing={2}>
|
|
468
528
|
{relatedSubscriptions.map((subscription) => (
|
|
469
|
-
<
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
{subscription.description || subscription.id}
|
|
489
|
-
</Typography>
|
|
490
|
-
</Stack>
|
|
529
|
+
<Grid item xs={12} sm={6} md={4} lg={3} key={subscription.id}>
|
|
530
|
+
<Stack
|
|
531
|
+
onClick={() => handleSubscriptionClick(subscription.id)}
|
|
532
|
+
className="base-card"
|
|
533
|
+
sx={{ height: '100%' }}>
|
|
534
|
+
<Stack direction="row" alignItems="center" spacing={1.5} sx={{ mb: 1 }}>
|
|
535
|
+
<Typography
|
|
536
|
+
variant="subtitle1"
|
|
537
|
+
sx={{
|
|
538
|
+
fontWeight: 'medium',
|
|
539
|
+
overflow: 'hidden',
|
|
540
|
+
textOverflow: 'ellipsis',
|
|
541
|
+
whiteSpace: 'nowrap',
|
|
542
|
+
color: 'text.link',
|
|
543
|
+
cursor: 'pointer',
|
|
544
|
+
}}>
|
|
545
|
+
{subscription.description || subscription.id}
|
|
546
|
+
</Typography>
|
|
547
|
+
</Stack>
|
|
491
548
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
549
|
+
{subscription.items && subscription.items[0] && currency && (
|
|
550
|
+
<Typography variant="body1" sx={{ color: 'text.secondary' }}>
|
|
551
|
+
{formatPrice(subscription.items[0].price, currency)}
|
|
552
|
+
</Typography>
|
|
553
|
+
)}
|
|
554
|
+
</Stack>
|
|
555
|
+
</Grid>
|
|
498
556
|
))}
|
|
499
|
-
</
|
|
557
|
+
</Grid>
|
|
500
558
|
</Box>
|
|
501
559
|
)}
|
|
502
560
|
<Divider sx={{ mb: 3 }} />
|
|
@@ -294,6 +294,12 @@ export default function RechargePage() {
|
|
|
294
294
|
display: 'grid',
|
|
295
295
|
gridTemplateColumns: { xs: 'repeat(1, 1fr)', sm: 'repeat(1, 1fr)', md: 'repeat(1, 1fr)' },
|
|
296
296
|
gap: { xs: 0, md: 2 },
|
|
297
|
+
'.currency-name': {
|
|
298
|
+
color: 'text.secondary',
|
|
299
|
+
},
|
|
300
|
+
'.info-row-label': {
|
|
301
|
+
fontWeight: 500,
|
|
302
|
+
},
|
|
297
303
|
}}>
|
|
298
304
|
<InfoRow
|
|
299
305
|
label={t('common.customer')}
|