payment-kit 1.17.2 → 1.17.3
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/env.ts +0 -2
- package/api/src/libs/overdraft-protection.ts +4 -1
- package/api/src/libs/subscription.ts +1 -1
- package/api/src/locales/en.ts +2 -2
- package/api/src/locales/zh.ts +2 -2
- package/api/src/queues/notification.ts +1 -1
- package/api/src/queues/subscription.ts +1 -1
- package/api/src/routes/connect/overdraft-protection.ts +4 -1
- package/api/src/routes/connect/shared.ts +12 -7
- package/api/src/routes/invoices.ts +21 -5
- package/api/src/routes/subscriptions.ts +1 -1
- package/blocklet.yml +1 -1
- package/package.json +15 -15
- package/src/components/customer/overdraft-protection.tsx +132 -18
- package/src/components/subscription/metrics.tsx +83 -7
- package/src/components/subscription/portal/actions.tsx +188 -153
- package/src/components/subscription/portal/list.tsx +1 -0
- package/src/libs/dayjs.ts +132 -0
- package/src/locales/en.tsx +18 -11
- package/src/locales/zh.tsx +17 -10
- package/src/pages/admin/billing/subscriptions/detail.tsx +1 -1
- package/src/pages/customer/recharge.tsx +63 -27
- package/src/pages/customer/subscription/detail.tsx +153 -10
- package/src/pages/customer/subscription/embed.tsx +1 -0
- /package/api/src/libs/notification/template/{subscription.overdraft-protection.exhausted.ts → subscription-overdraft-protection-exhausted.ts} +0 -0
|
@@ -3,21 +3,36 @@ import { api, formatBNStr, formatTime } from '@blocklet/payment-react';
|
|
|
3
3
|
import type { TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
4
4
|
import { useRequest } from 'ahooks';
|
|
5
5
|
|
|
6
|
+
import { Button, Stack, Typography, Tooltip, Avatar, Box, CircularProgress, Skeleton } from '@mui/material';
|
|
7
|
+
import { BN } from '@ocap/util';
|
|
8
|
+
import { useNavigate } from 'react-router-dom';
|
|
9
|
+
import { ArrowForward, InfoOutlined } from '@mui/icons-material';
|
|
6
10
|
import InfoMetric from '../info-metric';
|
|
7
11
|
import SubscriptionStatus from './status';
|
|
8
12
|
|
|
9
13
|
type Props = {
|
|
10
14
|
subscription: TSubscriptionExpanded;
|
|
15
|
+
showBalance?: boolean;
|
|
11
16
|
};
|
|
12
17
|
|
|
13
18
|
const fetchUpcoming = (id: string): Promise<{ amount: string }> => {
|
|
14
19
|
return api.get(`/api/subscriptions/${id}/upcoming`).then((res) => res.data);
|
|
15
20
|
};
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
const fetchPayer = (id: string): Promise<{ token: string; paymentAddress: string }> => {
|
|
23
|
+
return api.get(`/api/subscriptions/${id}/payer-token`).then((res) => res.data);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default function SubscriptionMetrics({ subscription, showBalance = true }: Props) {
|
|
18
27
|
const { t } = useLocaleContext();
|
|
19
|
-
const { data: upcoming } = useRequest(() => fetchUpcoming(subscription.id));
|
|
28
|
+
const { data: upcoming, loading: upcomingLoading } = useRequest(() => fetchUpcoming(subscription.id));
|
|
29
|
+
const navigate = useNavigate();
|
|
30
|
+
|
|
31
|
+
const { data: payerValue, loading: payerLoading } = useRequest(() => fetchPayer(subscription.id), {
|
|
32
|
+
ready: showBalance,
|
|
33
|
+
});
|
|
20
34
|
|
|
35
|
+
const supportShowBalance = showBalance && ['arcblock', 'ethereum'].includes(subscription.paymentMethod.type);
|
|
21
36
|
// let scheduleToCancelTime = 0;
|
|
22
37
|
// if (['active', 'trialing', 'past_due'].includes(subscription.status) && subscription.cancel_at) {
|
|
23
38
|
// scheduleToCancelTime = subscription.cancel_at * 1000;
|
|
@@ -25,14 +40,43 @@ export default function SubscriptionMetrics({ subscription }: Props) {
|
|
|
25
40
|
// scheduleToCancelTime = subscription.current_period_end * 1000;
|
|
26
41
|
// }
|
|
27
42
|
|
|
43
|
+
const isInsufficientBalance = new BN(payerValue?.token || '0').lt(new BN(upcoming?.amount || '0'));
|
|
44
|
+
const renderBalanceValue = () => {
|
|
45
|
+
if (upcomingLoading || payerLoading) {
|
|
46
|
+
return <CircularProgress size={16} />;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (isInsufficientBalance) {
|
|
50
|
+
return (
|
|
51
|
+
<Button
|
|
52
|
+
component="a"
|
|
53
|
+
color="error"
|
|
54
|
+
onClick={() => navigate(`/customer/subscription/${subscription.id}/recharge`)}>
|
|
55
|
+
{t('admin.subscription.insufficientBalance')}
|
|
56
|
+
<ArrowForward sx={{ fontSize: '14px' }} />
|
|
57
|
+
</Button>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Stack flexDirection="row" alignItems="center" gap={0.5} sx={{ fontSize: '16px', fontWeight: 500 }}>
|
|
63
|
+
<Avatar
|
|
64
|
+
src={subscription.paymentCurrency?.logo}
|
|
65
|
+
sx={{ width: 16, height: 16 }}
|
|
66
|
+
alt={subscription.paymentCurrency?.name}
|
|
67
|
+
/>
|
|
68
|
+
<Box display="flex" alignItems="baseline">
|
|
69
|
+
{formatBNStr(payerValue?.token, subscription.paymentCurrency.decimal)}
|
|
70
|
+
<Typography sx={{ fontSize: '14px', color: 'text.secondary', ml: 0.5 }}>
|
|
71
|
+
{subscription.paymentCurrency.symbol}
|
|
72
|
+
</Typography>
|
|
73
|
+
</Box>
|
|
74
|
+
</Stack>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
28
77
|
return (
|
|
29
78
|
<>
|
|
30
79
|
<InfoMetric label={t('common.status')} value={<SubscriptionStatus subscription={subscription} />} divider />
|
|
31
|
-
<InfoMetric
|
|
32
|
-
label={t('admin.subscription.startedAt')}
|
|
33
|
-
value={formatTime(subscription.start_date ? subscription.start_date * 1000 : subscription.created_at)}
|
|
34
|
-
divider
|
|
35
|
-
/>
|
|
36
80
|
{subscription.status === 'active' && !subscription.cancel_at && (
|
|
37
81
|
<InfoMetric
|
|
38
82
|
label={t('admin.subscription.nextInvoice')}
|
|
@@ -49,6 +93,34 @@ export default function SubscriptionMetrics({ subscription }: Props) {
|
|
|
49
93
|
divider
|
|
50
94
|
/>
|
|
51
95
|
)}
|
|
96
|
+
{supportShowBalance && ['active', 'trialing'].includes(subscription.status) && (
|
|
97
|
+
<InfoMetric
|
|
98
|
+
label={
|
|
99
|
+
<Stack direction="row" spacing={1} alignItems="center">
|
|
100
|
+
<Typography>{t('admin.subscription.currentBalance')}</Typography>
|
|
101
|
+
<Tooltip
|
|
102
|
+
title={
|
|
103
|
+
<Typography sx={{ fontFamily: 'monospace', fontSize: '13px' }}>
|
|
104
|
+
{t('admin.subscription.paymentAddress')}:
|
|
105
|
+
{payerLoading ? <Skeleton width={120} /> : payerValue?.paymentAddress}
|
|
106
|
+
</Typography>
|
|
107
|
+
}
|
|
108
|
+
arrow>
|
|
109
|
+
<InfoOutlined
|
|
110
|
+
sx={{
|
|
111
|
+
fontSize: '16px',
|
|
112
|
+
color: 'text.secondary',
|
|
113
|
+
cursor: 'pointer',
|
|
114
|
+
'&:hover': { color: 'primary.main' },
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
</Tooltip>
|
|
118
|
+
</Stack>
|
|
119
|
+
}
|
|
120
|
+
value={renderBalanceValue()}
|
|
121
|
+
divider
|
|
122
|
+
/>
|
|
123
|
+
)}
|
|
52
124
|
{/* {scheduleToCancelTime > 0 && (
|
|
53
125
|
<InfoMetric label={t('admin.subscription.cancel.schedule')} value={formatTime(scheduleToCancelTime)} divider />
|
|
54
126
|
)} */}
|
|
@@ -62,3 +134,7 @@ export default function SubscriptionMetrics({ subscription }: Props) {
|
|
|
62
134
|
</>
|
|
63
135
|
);
|
|
64
136
|
}
|
|
137
|
+
|
|
138
|
+
SubscriptionMetrics.defaultProps = {
|
|
139
|
+
showBalance: true,
|
|
140
|
+
};
|
|
@@ -14,7 +14,7 @@ import type { TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
|
14
14
|
import { Button, Link, Stack, Tooltip } from '@mui/material';
|
|
15
15
|
import { useRequest, useSetState } from 'ahooks';
|
|
16
16
|
import isEmpty from 'lodash/isEmpty';
|
|
17
|
-
import { useState } from 'react';
|
|
17
|
+
import { useEffect, useState } from 'react';
|
|
18
18
|
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
|
|
19
19
|
import { useNavigate } from 'react-router-dom';
|
|
20
20
|
import { joinURL } from 'ufo';
|
|
@@ -23,6 +23,22 @@ import OverdraftProtectionDialog from '../../customer/overdraft-protection';
|
|
|
23
23
|
import Actions from '../../actions';
|
|
24
24
|
import { useUnpaidInvoicesCheckForSubscription } from '../../../hooks/subscription';
|
|
25
25
|
|
|
26
|
+
interface ActionConfig {
|
|
27
|
+
key: string;
|
|
28
|
+
show: boolean;
|
|
29
|
+
label: string;
|
|
30
|
+
tooltip?: string;
|
|
31
|
+
onClick: (e?: React.MouseEvent) => void;
|
|
32
|
+
variant?: 'text' | 'outlined' | 'contained';
|
|
33
|
+
color?: 'inherit' | 'primary' | 'secondary' | 'error';
|
|
34
|
+
sx?: any;
|
|
35
|
+
primary?: boolean;
|
|
36
|
+
component?: any;
|
|
37
|
+
href?: string;
|
|
38
|
+
target?: string;
|
|
39
|
+
divider?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
26
42
|
type ActionProps = {
|
|
27
43
|
[key: string]: {
|
|
28
44
|
color?: string;
|
|
@@ -33,6 +49,15 @@ type ActionProps = {
|
|
|
33
49
|
text?: string;
|
|
34
50
|
};
|
|
35
51
|
};
|
|
52
|
+
export interface ProtectionInitValues {
|
|
53
|
+
enabled?: boolean;
|
|
54
|
+
return_stake?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface ActionMethods {
|
|
57
|
+
openOverdraftProtection: (initValues?: ProtectionInitValues) => void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type ActionDisplayMode = 'all-buttons' | 'primary-buttons' | 'menu-only';
|
|
36
61
|
|
|
37
62
|
type Props = {
|
|
38
63
|
subscription: TSubscriptionExpanded;
|
|
@@ -45,9 +70,11 @@ type Props = {
|
|
|
45
70
|
onChange: () => any | Promise<any>;
|
|
46
71
|
};
|
|
47
72
|
showDelegation?: boolean;
|
|
73
|
+
showUnsubscribe?: boolean;
|
|
48
74
|
onChange?: (action?: string) => any | Promise<any>;
|
|
49
75
|
actionProps?: ActionProps;
|
|
50
|
-
mode?:
|
|
76
|
+
mode?: ActionDisplayMode;
|
|
77
|
+
setUp?: (methods: ActionMethods) => void;
|
|
51
78
|
};
|
|
52
79
|
|
|
53
80
|
SubscriptionActions.defaultProps = {
|
|
@@ -57,7 +84,9 @@ SubscriptionActions.defaultProps = {
|
|
|
57
84
|
showDelegation: false,
|
|
58
85
|
onChange: null,
|
|
59
86
|
actionProps: {},
|
|
60
|
-
mode: '
|
|
87
|
+
mode: 'all-buttons',
|
|
88
|
+
setUp: null,
|
|
89
|
+
showUnsubscribe: true,
|
|
61
90
|
};
|
|
62
91
|
const fetchExtraActions = async ({
|
|
63
92
|
id,
|
|
@@ -102,9 +131,11 @@ export function SubscriptionActionsInner({
|
|
|
102
131
|
showRecharge,
|
|
103
132
|
showOverdraftProtection,
|
|
104
133
|
showDelegation,
|
|
134
|
+
showUnsubscribe,
|
|
105
135
|
onChange,
|
|
106
136
|
actionProps,
|
|
107
137
|
mode,
|
|
138
|
+
setUp,
|
|
108
139
|
}: Props) {
|
|
109
140
|
const { t, locale } = useLocaleContext();
|
|
110
141
|
const { reset, getValues } = useFormContext();
|
|
@@ -122,6 +153,7 @@ export function SubscriptionActionsInner({
|
|
|
122
153
|
loading: false,
|
|
123
154
|
openProtection: false,
|
|
124
155
|
protectionLoading: false,
|
|
156
|
+
protectionInitValues: null,
|
|
125
157
|
});
|
|
126
158
|
|
|
127
159
|
const shouldFetchDelegation = showDelegation && ['active', 'trialing', 'past_due'].includes(subscription?.status);
|
|
@@ -146,6 +178,19 @@ export function SubscriptionActionsInner({
|
|
|
146
178
|
refreshDeps: [subscription.id, shouldFetchOverdraftProtection],
|
|
147
179
|
});
|
|
148
180
|
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
if (setUp) {
|
|
183
|
+
setUp({
|
|
184
|
+
openOverdraftProtection: (initValues?: ProtectionInitValues) =>
|
|
185
|
+
setState({
|
|
186
|
+
openProtection: true,
|
|
187
|
+
// @ts-ignore
|
|
188
|
+
protectionInitValues: initValues,
|
|
189
|
+
}),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}, [setUp]);
|
|
193
|
+
|
|
149
194
|
const handleCancel = async () => {
|
|
150
195
|
try {
|
|
151
196
|
const result = await checkUnpaidInvoices();
|
|
@@ -273,162 +318,148 @@ export function SubscriptionActionsInner({
|
|
|
273
318
|
};
|
|
274
319
|
|
|
275
320
|
const renderActions = () => {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
321
|
+
const supportUnsubscribe = action?.action === 'cancel' && showUnsubscribe;
|
|
322
|
+
const supportAction = action && (action?.action !== 'cancel' || supportUnsubscribe);
|
|
323
|
+
|
|
324
|
+
const serviceActions = subscription.service_actions?.filter((x: any) => x?.type !== 'notification') || [];
|
|
325
|
+
const actionConfigs: ActionConfig[] = [
|
|
326
|
+
{
|
|
327
|
+
key: 'delegation',
|
|
328
|
+
show: showDelegation && noDelegation,
|
|
329
|
+
label: t('customer.delegation.btn'),
|
|
330
|
+
tooltip: t('customer.delegation.title'),
|
|
331
|
+
onClick: handleDelegate,
|
|
332
|
+
variant: 'outlined',
|
|
333
|
+
color: 'primary',
|
|
334
|
+
primary: true,
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
key: 'protection',
|
|
338
|
+
show: shouldFetchOverdraftProtection,
|
|
339
|
+
label: t('customer.overdraftProtection.setting'),
|
|
340
|
+
onClick: () => setState({ openProtection: true, protectionInitValues: null }),
|
|
341
|
+
variant: 'outlined',
|
|
342
|
+
color: 'primary',
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
key: 'recharge',
|
|
346
|
+
show: !!(showRecharge && supportRecharge(subscription)),
|
|
347
|
+
label: t('customer.recharge.title'),
|
|
348
|
+
onClick: (e) => {
|
|
349
|
+
e?.stopPropagation();
|
|
350
|
+
navigate(`/customer/subscription/${subscription.id}/recharge`);
|
|
289
351
|
},
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
label: action?.text || t('payment.customer.changePlan.button'),
|
|
314
|
-
handler: () => navigate(`/customer/subscription/${subscription.id}/change-plan`),
|
|
315
|
-
color: 'primary',
|
|
352
|
+
variant: 'outlined',
|
|
353
|
+
color: 'primary',
|
|
354
|
+
primary: true,
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
key: 'changePlan',
|
|
358
|
+
show: !!extraActions?.changePlan,
|
|
359
|
+
label: action?.text || t('payment.customer.changePlan.button'),
|
|
360
|
+
onClick: (e) => {
|
|
361
|
+
e?.stopPropagation();
|
|
362
|
+
navigate(`/customer/subscription/${subscription.id}/change-plan`);
|
|
363
|
+
},
|
|
364
|
+
variant: 'contained',
|
|
365
|
+
color: 'primary',
|
|
366
|
+
sx: action?.sx,
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
key: 'batchPay',
|
|
370
|
+
show: !!extraActions?.batchPay,
|
|
371
|
+
label: action?.text || t('admin.subscription.batchPay.button'),
|
|
372
|
+
onClick: (e) => {
|
|
373
|
+
e?.stopPropagation();
|
|
374
|
+
navigate(`/customer/invoice/past-due?subscription=${subscription.id}¤cy=${extraActions?.batchPay}`);
|
|
316
375
|
},
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
376
|
+
variant: 'outlined',
|
|
377
|
+
color: 'error',
|
|
378
|
+
sx: action?.sx,
|
|
379
|
+
primary: true,
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
key: 'mainAction',
|
|
383
|
+
show: !!(!extraActions?.batchPay && supportAction),
|
|
384
|
+
label: action?.text || t(`payment.customer.${action?.action}.button`),
|
|
385
|
+
onClick: (e) => {
|
|
386
|
+
e?.stopPropagation();
|
|
387
|
+
if (action?.action === 'pastDue') {
|
|
388
|
+
navigate(`/customer/invoice/past-due?subscription=${subscription.id}`);
|
|
389
|
+
} else {
|
|
390
|
+
// @ts-ignore
|
|
391
|
+
setState({ action: action?.action, subscription: subscription.id });
|
|
392
|
+
}
|
|
322
393
|
},
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
394
|
+
// @ts-ignore
|
|
395
|
+
variant: action?.variant || 'outlined',
|
|
396
|
+
// @ts-ignore
|
|
397
|
+
color: action?.color || 'primary',
|
|
398
|
+
sx: action?.sx,
|
|
399
|
+
divider: serviceActions.length > 0,
|
|
400
|
+
},
|
|
401
|
+
// @ts-ignore
|
|
402
|
+
...serviceActions.map((x) => ({
|
|
403
|
+
key: x.name,
|
|
404
|
+
show: true,
|
|
405
|
+
label: x.text[locale] || x.text.en || x.name,
|
|
406
|
+
onClick: () => window.open(x.link, '_blank'),
|
|
407
|
+
variant: x?.variant || 'contained',
|
|
408
|
+
color: x?.color || 'primary',
|
|
409
|
+
component: Link,
|
|
410
|
+
href: x.link,
|
|
411
|
+
target: '_blank',
|
|
412
|
+
sx: { textDecoration: 'none !important' },
|
|
413
|
+
})),
|
|
414
|
+
];
|
|
333
415
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
// @ts-ignore
|
|
337
|
-
actions={actions}
|
|
338
|
-
/>
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
return (
|
|
342
|
-
<>
|
|
343
|
-
{showDelegation && noDelegation && (
|
|
344
|
-
<Tooltip title={t('customer.delegation.title')}>
|
|
345
|
-
<Button variant="outlined" color="primary" onClick={handleDelegate}>
|
|
346
|
-
{t('customer.delegation.btn')}
|
|
347
|
-
</Button>
|
|
348
|
-
</Tooltip>
|
|
349
|
-
)}
|
|
416
|
+
// 过滤出要显示的操作
|
|
417
|
+
const visibleActions = actionConfigs.filter((a) => a.show);
|
|
350
418
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
419
|
+
// 转换为菜单项
|
|
420
|
+
const toMenuItem = (item: any) => ({
|
|
421
|
+
label: item.label,
|
|
422
|
+
handler: item.onClick,
|
|
423
|
+
color: item.color,
|
|
424
|
+
divider: item.divider,
|
|
425
|
+
});
|
|
356
426
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
{
|
|
369
|
-
<
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
onClick={(e) => {
|
|
375
|
-
e.stopPropagation();
|
|
376
|
-
if (action.action === 'pastDue') {
|
|
377
|
-
navigate(`/customer/invoice/past-due?subscription=${subscription.id}`);
|
|
378
|
-
} else {
|
|
379
|
-
setState({
|
|
380
|
-
action: action.action,
|
|
381
|
-
subscription: subscription.id,
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
}}>
|
|
385
|
-
{action?.text || t(`payment.customer.${action.action}.button`)}
|
|
386
|
-
</Button>
|
|
387
|
-
)}
|
|
388
|
-
{extraActions?.changePlan && (
|
|
389
|
-
<Button
|
|
390
|
-
variant="contained"
|
|
391
|
-
color="primary"
|
|
392
|
-
size="small"
|
|
393
|
-
sx={action?.sx as any}
|
|
394
|
-
onClick={(e) => {
|
|
395
|
-
e.stopPropagation();
|
|
396
|
-
navigate(`/customer/subscription/${subscription.id}/change-plan`);
|
|
397
|
-
}}>
|
|
398
|
-
{action?.text || t('payment.customer.changePlan.button')}
|
|
399
|
-
</Button>
|
|
400
|
-
)}
|
|
401
|
-
{!!extraActions?.batchPay && (
|
|
402
|
-
<Button
|
|
403
|
-
variant="outlined"
|
|
404
|
-
color="error"
|
|
405
|
-
size="small"
|
|
406
|
-
sx={action?.sx as any}
|
|
407
|
-
onClick={(e) => {
|
|
408
|
-
e.stopPropagation();
|
|
409
|
-
navigate(`/customer/invoice/past-due?subscription=${subscription.id}¤cy=${extraActions.batchPay}`);
|
|
410
|
-
}}>
|
|
411
|
-
{action?.text || t('admin.subscription.batchPay.button')}
|
|
412
|
-
</Button>
|
|
427
|
+
const toButton = (item: ActionConfig) => (
|
|
428
|
+
<Button
|
|
429
|
+
key={item.key}
|
|
430
|
+
variant={item.variant}
|
|
431
|
+
color={item.color}
|
|
432
|
+
onClick={item.onClick}
|
|
433
|
+
component={item.component}
|
|
434
|
+
href={item.href}
|
|
435
|
+
target={item.target}
|
|
436
|
+
sx={item.sx}
|
|
437
|
+
size="small">
|
|
438
|
+
{item.tooltip ? (
|
|
439
|
+
<Tooltip title={item.tooltip}>
|
|
440
|
+
<span>{item.label}</span>
|
|
441
|
+
</Tooltip>
|
|
442
|
+
) : (
|
|
443
|
+
item.label
|
|
413
444
|
)}
|
|
414
|
-
|
|
415
|
-
?.filter((x: any) => x?.type !== 'notification')
|
|
416
|
-
.map((x) => (
|
|
417
|
-
// @ts-ignore
|
|
418
|
-
<Button
|
|
419
|
-
component={Link}
|
|
420
|
-
key={x.name}
|
|
421
|
-
variant={x?.variant || 'contained'}
|
|
422
|
-
color={x?.color || 'primary'}
|
|
423
|
-
href={x.link}
|
|
424
|
-
size="small"
|
|
425
|
-
target="_blank"
|
|
426
|
-
sx={{ textDecoration: 'none !important' }}>
|
|
427
|
-
{x.text[locale] || x.text.en || x.name}
|
|
428
|
-
</Button>
|
|
429
|
-
))}
|
|
430
|
-
</>
|
|
445
|
+
</Button>
|
|
431
446
|
);
|
|
447
|
+
if (mode === 'menu-only') {
|
|
448
|
+
return <Actions actions={visibleActions.map(toMenuItem)} />;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (mode === 'primary-buttons') {
|
|
452
|
+
const primaryButtons = visibleActions.filter((a) => a.primary);
|
|
453
|
+
const menuItems = visibleActions.filter((a) => !a.primary);
|
|
454
|
+
return (
|
|
455
|
+
<>
|
|
456
|
+
{primaryButtons.map(toButton)}
|
|
457
|
+
{menuItems.length > 0 && <Actions actions={menuItems.map(toMenuItem)} />}
|
|
458
|
+
</>
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return <>{visibleActions.map(toButton)}</>;
|
|
432
463
|
};
|
|
433
464
|
|
|
434
465
|
return (
|
|
@@ -466,11 +497,13 @@ export function SubscriptionActionsInner({
|
|
|
466
497
|
value={overdraftProtection}
|
|
467
498
|
onSave={handleOverdraftProtection}
|
|
468
499
|
open={state.openProtection}
|
|
469
|
-
|
|
500
|
+
payerAddress={subscription.overdraft_protection?.payment_details?.arcblock?.payer}
|
|
501
|
+
stakingAddress={subscription.overdraft_protection?.payment_details?.arcblock?.staking?.address}
|
|
470
502
|
currency={subscription.paymentCurrency}
|
|
471
503
|
subscription={subscription}
|
|
472
504
|
loading={state.protectionLoading}
|
|
473
505
|
onCancel={() => setState({ openProtection: false })}
|
|
506
|
+
initValues={state.protectionInitValues}
|
|
474
507
|
/>
|
|
475
508
|
)}
|
|
476
509
|
</Stack>
|
|
@@ -500,7 +533,9 @@ SubscriptionActionsInner.defaultProps = {
|
|
|
500
533
|
showRecharge: false,
|
|
501
534
|
showOverdraftProtection: false,
|
|
502
535
|
showDelegation: false,
|
|
536
|
+
showUnsubscribe: true,
|
|
503
537
|
onChange: null,
|
|
504
538
|
actionProps: {},
|
|
505
|
-
mode: '
|
|
539
|
+
mode: 'all-buttons',
|
|
540
|
+
setUp: null,
|
|
506
541
|
};
|