payment-kit 1.14.30 → 1.14.31
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/index.ts +4 -0
- package/api/src/libs/api.ts +23 -0
- package/api/src/libs/subscription.ts +32 -0
- package/api/src/queues/refund.ts +38 -1
- package/api/src/queues/subscription.ts +218 -21
- package/api/src/routes/checkout-sessions.ts +5 -0
- package/api/src/routes/customers.ts +27 -1
- package/api/src/routes/invoices.ts +5 -1
- package/api/src/routes/payment-intents.ts +17 -2
- package/api/src/routes/payment-links.ts +105 -3
- package/api/src/routes/payouts.ts +5 -1
- package/api/src/routes/prices.ts +19 -3
- package/api/src/routes/pricing-table.ts +79 -2
- package/api/src/routes/products.ts +24 -8
- package/api/src/routes/refunds.ts +7 -4
- package/api/src/routes/subscription-items.ts +5 -1
- package/api/src/routes/subscriptions.ts +25 -5
- package/api/src/routes/webhook-endpoints.ts +5 -1
- package/api/src/store/models/subscription.ts +1 -0
- package/api/tests/libs/api.spec.ts +72 -1
- package/api/third.d.ts +2 -0
- package/blocklet.yml +1 -1
- package/package.json +19 -18
- package/src/components/customer/form.tsx +53 -0
- package/src/components/filter-toolbar.tsx +1 -1
- package/src/components/invoice/list.tsx +8 -8
- package/src/components/invoice/table.tsx +42 -36
- package/src/components/metadata/form.tsx +24 -3
- package/src/components/payment-intent/actions.tsx +17 -5
- package/src/components/payment-link/after-pay.tsx +46 -4
- package/src/components/payouts/list.tsx +1 -1
- package/src/components/price/form.tsx +14 -2
- package/src/components/pricing-table/payment-settings.tsx +45 -4
- package/src/components/product/features.tsx +16 -2
- package/src/components/product/form.tsx +28 -4
- package/src/components/subscription/actions/cancel.tsx +10 -0
- package/src/components/subscription/description.tsx +2 -2
- package/src/components/subscription/items/index.tsx +3 -2
- package/src/components/subscription/portal/cancel.tsx +12 -1
- package/src/components/subscription/portal/list.tsx +6 -5
- package/src/locales/en.tsx +6 -1
- package/src/locales/zh.tsx +6 -1
- package/src/pages/admin/billing/invoices/detail.tsx +17 -2
- package/src/pages/admin/billing/subscriptions/detail.tsx +4 -0
- package/src/pages/admin/customers/customers/detail.tsx +4 -0
- package/src/pages/admin/customers/customers/index.tsx +1 -1
- package/src/pages/admin/payments/intents/detail.tsx +4 -0
- package/src/pages/admin/payments/payouts/detail.tsx +4 -0
- package/src/pages/admin/payments/refunds/detail.tsx +4 -0
- package/src/pages/admin/products/links/detail.tsx +4 -0
- package/src/pages/admin/products/prices/detail.tsx +4 -0
- package/src/pages/admin/products/pricing-tables/detail.tsx +4 -0
- package/src/pages/admin/products/products/detail.tsx +4 -0
- package/src/pages/checkout/pricing-table.tsx +9 -3
- package/src/pages/customer/index.tsx +28 -17
- package/src/pages/customer/invoice/detail.tsx +27 -16
- package/src/pages/customer/invoice/past-due.tsx +3 -2
- package/src/pages/customer/subscription/detail.tsx +4 -0
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
2
|
import { AddOutlined, DeleteOutlineOutlined } from '@mui/icons-material';
|
|
3
3
|
import { Box, Button, IconButton, TextField, Typography } from '@mui/material';
|
|
4
|
+
import { get } from 'lodash';
|
|
4
5
|
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
|
|
5
6
|
|
|
6
7
|
export default function MetadataForm() {
|
|
7
8
|
const { t } = useLocaleContext();
|
|
8
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
control,
|
|
11
|
+
formState: { errors },
|
|
12
|
+
} = useFormContext();
|
|
9
13
|
const features = useFieldArray({ control, name: 'features' });
|
|
10
14
|
return (
|
|
11
15
|
<Box sx={{ width: 1 }}>
|
|
@@ -13,7 +17,17 @@ export default function MetadataForm() {
|
|
|
13
17
|
{features.fields.map((feature, index) => (
|
|
14
18
|
<Box key={feature.id} mt={2} sx={{ width: 1 }}>
|
|
15
19
|
<Controller
|
|
16
|
-
render={({ field }) =>
|
|
20
|
+
render={({ field }) => (
|
|
21
|
+
<TextField
|
|
22
|
+
{...field}
|
|
23
|
+
sx={{ width: '80%' }}
|
|
24
|
+
size="small"
|
|
25
|
+
inputProps={{ maxLength: 64 }}
|
|
26
|
+
error={!!get(errors, field.name)}
|
|
27
|
+
helperText={get(errors, field.name)?.message as string}
|
|
28
|
+
/>
|
|
29
|
+
)}
|
|
30
|
+
rules={{ maxLength: { value: 64, message: t('common.maxLength', { len: 64 }) } }}
|
|
17
31
|
name={`features.${index}.name`}
|
|
18
32
|
control={control}
|
|
19
33
|
/>
|
|
@@ -38,16 +38,29 @@ export default function ProductForm(props: Props) {
|
|
|
38
38
|
<Stack spacing={2} flex={2} alignItems="flex-start">
|
|
39
39
|
<FormInput
|
|
40
40
|
name="name"
|
|
41
|
-
rules={{
|
|
41
|
+
rules={{
|
|
42
|
+
required: t('admin.product.name.required'),
|
|
43
|
+
maxLength: {
|
|
44
|
+
value: 64,
|
|
45
|
+
message: t('common.maxLength', { len: 64 }),
|
|
46
|
+
},
|
|
47
|
+
}}
|
|
42
48
|
label={t('admin.product.name.label')}
|
|
43
49
|
placeholder={t('admin.product.name.placeholder')}
|
|
44
50
|
error={!!formState.errors.name}
|
|
45
51
|
helperText={formState.errors.name?.message as string}
|
|
46
52
|
autoFocus
|
|
53
|
+
inputProps={{ maxLength: 64 }}
|
|
47
54
|
/>
|
|
48
55
|
<FormInput
|
|
49
56
|
name="description"
|
|
50
|
-
rules={{
|
|
57
|
+
rules={{
|
|
58
|
+
required: t('admin.product.description.required'),
|
|
59
|
+
maxLength: {
|
|
60
|
+
value: 256,
|
|
61
|
+
message: t('common.maxLength', { len: 256 }),
|
|
62
|
+
},
|
|
63
|
+
}}
|
|
51
64
|
label={t('admin.product.description.label')}
|
|
52
65
|
placeholder={t('admin.product.description.placeholder')}
|
|
53
66
|
error={!!formState.errors.description}
|
|
@@ -55,11 +68,22 @@ export default function ProductForm(props: Props) {
|
|
|
55
68
|
multiline
|
|
56
69
|
minRows={2}
|
|
57
70
|
maxRows={4}
|
|
71
|
+
inputProps={{ maxLength: 256 }}
|
|
58
72
|
/>
|
|
59
73
|
<Collapse trigger={t('admin.product.additional')}>
|
|
60
74
|
<Stack spacing={2} alignItems="flex-start">
|
|
61
|
-
<FormInput
|
|
62
|
-
|
|
75
|
+
<FormInput
|
|
76
|
+
name="statement_descriptor"
|
|
77
|
+
label={t('admin.product.statement_descriptor.label')}
|
|
78
|
+
rules={{ maxLength: { value: 32, message: t('common.maxLength', { len: 32 }) } }}
|
|
79
|
+
inputProps={{ maxLength: 32 }}
|
|
80
|
+
/>
|
|
81
|
+
<FormInput
|
|
82
|
+
name="unit_label"
|
|
83
|
+
label={t('admin.product.unit_label.label')}
|
|
84
|
+
rules={{ maxLength: { value: 32, message: t('common.maxLength', { len: 32 }) } }}
|
|
85
|
+
inputProps={{ maxLength: 32 }}
|
|
86
|
+
/>
|
|
63
87
|
{!props.simple && <ProductFeatures />}
|
|
64
88
|
{!props.simple && <MetadataForm title={t('common.metadata.label')} />}
|
|
65
89
|
</Stack>
|
|
@@ -147,6 +147,16 @@ export default function SubscriptionCancelForm({ data }: { data: TSubscriptionEx
|
|
|
147
147
|
symbol,
|
|
148
148
|
})}
|
|
149
149
|
/>
|
|
150
|
+
<FormControlLabel
|
|
151
|
+
value="slash"
|
|
152
|
+
disabled={loading || !staking}
|
|
153
|
+
onClick={() => !(loading || !staking) && setValue('cancel.staking', 'slash')}
|
|
154
|
+
control={<Radio checked={stakingType === 'slash'} />}
|
|
155
|
+
label={t('admin.subscription.cancel.staking.slash', {
|
|
156
|
+
unused: formatAmount(staking?.return_amount || '0', decimal),
|
|
157
|
+
symbol,
|
|
158
|
+
})}
|
|
159
|
+
/>
|
|
150
160
|
</RadioGroup>
|
|
151
161
|
</Stack>
|
|
152
162
|
</>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatSubscriptionProduct, useMobile } from '@blocklet/payment-react';
|
|
1
|
+
import { formatSubscriptionProduct, TruncatedText, useMobile } from '@blocklet/payment-react';
|
|
2
2
|
import type { TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
3
3
|
import { InfoOutlined } from '@mui/icons-material';
|
|
4
4
|
import { Stack, Tooltip, Typography } from '@mui/material';
|
|
@@ -15,7 +15,7 @@ export default function SubscriptionDescription({ subscription, variant, hideSub
|
|
|
15
15
|
return (
|
|
16
16
|
<Stack direction="row" alignItems="center" spacing={1}>
|
|
17
17
|
<Typography variant={variant} fontWeight={600} className="subscription-description">
|
|
18
|
-
{subscription.description}
|
|
18
|
+
<TruncatedText text={subscription.description} maxLength={80} useWidth />
|
|
19
19
|
</Typography>
|
|
20
20
|
{!hideSubscription && !isMobile && (
|
|
21
21
|
<Tooltip title={formatSubscriptionProduct(subscription.items)}>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable react/no-unstable-nested-components */
|
|
2
2
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
|
-
import { formatPrice, Table } from '@blocklet/payment-react';
|
|
3
|
+
import { formatPrice, Table, TruncatedText, useMobile } from '@blocklet/payment-react';
|
|
4
4
|
import type { TPaymentCurrency, TSubscriptionItemExpanded } from '@blocklet/payment-types';
|
|
5
5
|
import { Avatar, Stack, Typography } from '@mui/material';
|
|
6
6
|
|
|
@@ -22,6 +22,7 @@ const size = { width: 48, height: 48 };
|
|
|
22
22
|
|
|
23
23
|
export default function SubscriptionItemList({ data, currency, mode }: ListProps) {
|
|
24
24
|
const { t } = useLocaleContext();
|
|
25
|
+
const { isMobile } = useMobile();
|
|
25
26
|
const columns = [
|
|
26
27
|
{
|
|
27
28
|
label: t('admin.subscription.product'),
|
|
@@ -53,7 +54,7 @@ export default function SubscriptionItemList({ data, currency, mode }: ListProps
|
|
|
53
54
|
</Avatar>
|
|
54
55
|
)}
|
|
55
56
|
<Typography color="text.primary" fontWeight={600}>
|
|
56
|
-
{item?.price.product.name}
|
|
57
|
+
<TruncatedText text={item?.price.product.name} maxLength={isMobile ? 20 : 50} useWidth />
|
|
57
58
|
{mode === 'customer' ? '' : ` - ${item?.price_id}`}
|
|
58
59
|
</Typography>
|
|
59
60
|
<Typography color="text.secondary" whiteSpace="nowrap">
|
|
@@ -11,7 +11,9 @@ export default function CustomerCancelForm({ data }: { data: TSubscriptionExpand
|
|
|
11
11
|
return (
|
|
12
12
|
<Stack direction="column" spacing={1} alignItems="flex-start">
|
|
13
13
|
<Typography>
|
|
14
|
-
{
|
|
14
|
+
{data.status === 'trialing'
|
|
15
|
+
? t('payment.customer.cancel.trialDescription')
|
|
16
|
+
: t('payment.customer.cancel.description', { date: formatTime(data.current_period_end * 1000) })}
|
|
15
17
|
</Typography>
|
|
16
18
|
<Controller
|
|
17
19
|
name="cancel.feedback"
|
|
@@ -66,6 +68,12 @@ export default function CustomerCancelForm({ data }: { data: TSubscriptionExpand
|
|
|
66
68
|
<Controller
|
|
67
69
|
name="cancel.comment"
|
|
68
70
|
control={control}
|
|
71
|
+
rules={{
|
|
72
|
+
maxLength: {
|
|
73
|
+
value: 200,
|
|
74
|
+
message: t('common.maxLength', { len: 200 }),
|
|
75
|
+
},
|
|
76
|
+
}}
|
|
69
77
|
render={({ field }) => (
|
|
70
78
|
<TextField
|
|
71
79
|
variant="outlined"
|
|
@@ -76,6 +84,9 @@ export default function CustomerCancelForm({ data }: { data: TSubscriptionExpand
|
|
|
76
84
|
maxRows={4}
|
|
77
85
|
placeholder={t('payment.customer.cancel.comment')}
|
|
78
86
|
{...field}
|
|
87
|
+
inputProps={{
|
|
88
|
+
maxLength: 200,
|
|
89
|
+
}}
|
|
79
90
|
/>
|
|
80
91
|
)}
|
|
81
92
|
/>
|
|
@@ -64,7 +64,7 @@ export default function CurrentSubscriptions({
|
|
|
64
64
|
|
|
65
65
|
const showLoadingMore = useDelayedLoading(loadingMore);
|
|
66
66
|
|
|
67
|
-
if (
|
|
67
|
+
if (!data || loading) {
|
|
68
68
|
return <CircularProgress />;
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -75,12 +75,13 @@ export default function CurrentSubscriptions({
|
|
|
75
75
|
<Stack direction="column" spacing={2} sx={{ mt: 2 }}>
|
|
76
76
|
{data.list?.length > 0 ? (
|
|
77
77
|
<>
|
|
78
|
-
<
|
|
78
|
+
<Stack
|
|
79
79
|
ref={listRef}
|
|
80
|
+
spacing={2}
|
|
80
81
|
sx={{
|
|
81
82
|
maxHeight: {
|
|
82
83
|
xs: '100%',
|
|
83
|
-
md: '
|
|
84
|
+
md: '500px',
|
|
84
85
|
},
|
|
85
86
|
overflowY: 'auto',
|
|
86
87
|
}}>
|
|
@@ -98,7 +99,7 @@ export default function CurrentSubscriptions({
|
|
|
98
99
|
padding: 1.5,
|
|
99
100
|
background: 'var(--backgrounds-bg-subtle, #F9FAFB)',
|
|
100
101
|
'&:hover': {
|
|
101
|
-
backgroundColor: '
|
|
102
|
+
backgroundColor: 'var(--backgrounds-bg-highlight, #eff6ff)',
|
|
102
103
|
transition: 'background-color 200ms linear',
|
|
103
104
|
cursor: 'pointer',
|
|
104
105
|
},
|
|
@@ -215,7 +216,7 @@ export default function CurrentSubscriptions({
|
|
|
215
216
|
{t('common.loadingMore', { resource: t('admin.subscriptions') })}
|
|
216
217
|
</Box>
|
|
217
218
|
)}
|
|
218
|
-
</
|
|
219
|
+
</Stack>
|
|
219
220
|
{isMobile && (
|
|
220
221
|
<Box>
|
|
221
222
|
{hasMore && (
|
package/src/locales/en.tsx
CHANGED
|
@@ -16,6 +16,9 @@ export default flat({
|
|
|
16
16
|
add: 'Add',
|
|
17
17
|
fullscreen: 'Fullscreen',
|
|
18
18
|
exit: 'Exit',
|
|
19
|
+
maxLength: 'Max {len} characters',
|
|
20
|
+
minLength: 'Min {len} characters',
|
|
21
|
+
loading: 'Loading...',
|
|
19
22
|
},
|
|
20
23
|
admin: {
|
|
21
24
|
balances: 'Balances',
|
|
@@ -459,8 +462,9 @@ export default flat({
|
|
|
459
462
|
},
|
|
460
463
|
staking: {
|
|
461
464
|
title: 'Stake',
|
|
462
|
-
none: 'No return',
|
|
465
|
+
none: 'No return or slash',
|
|
463
466
|
proration: 'Return Remaining Stake {unused}{symbol}',
|
|
467
|
+
slash: 'Slash Remaining Stake {unused}{symbol}',
|
|
464
468
|
},
|
|
465
469
|
},
|
|
466
470
|
pause: {
|
|
@@ -592,6 +596,7 @@ export default flat({
|
|
|
592
596
|
payments: 'No Payments',
|
|
593
597
|
prices: 'No Prices',
|
|
594
598
|
pricing: 'You haven’t added any prices you can add it',
|
|
599
|
+
summary: 'No Summary',
|
|
595
600
|
},
|
|
596
601
|
customer: {
|
|
597
602
|
subscription: {
|
package/src/locales/zh.tsx
CHANGED
|
@@ -16,6 +16,9 @@ export default flat({
|
|
|
16
16
|
add: '添加',
|
|
17
17
|
fullscreen: '全屏',
|
|
18
18
|
exit: '退出',
|
|
19
|
+
maxLength: '最多输入{len}个字符',
|
|
20
|
+
minLength: '最少输入{len}个字符',
|
|
21
|
+
loading: '加载中...',
|
|
19
22
|
},
|
|
20
23
|
admin: {
|
|
21
24
|
balances: '余额',
|
|
@@ -450,8 +453,9 @@ export default flat({
|
|
|
450
453
|
},
|
|
451
454
|
staking: {
|
|
452
455
|
title: '质押',
|
|
453
|
-
none: '
|
|
456
|
+
none: '不退还 / 罚没质押',
|
|
454
457
|
proration: '退还剩余部分 {unused}{symbol}',
|
|
458
|
+
slash: '罚没剩余部分 {unused}{symbol}',
|
|
455
459
|
},
|
|
456
460
|
},
|
|
457
461
|
pause: {
|
|
@@ -582,6 +586,7 @@ export default flat({
|
|
|
582
586
|
payments: '没有付款记录',
|
|
583
587
|
prices: '没有价格',
|
|
584
588
|
pricing: '您还没有设置定价,您可以添加它',
|
|
589
|
+
summary: '没有摘要',
|
|
585
590
|
},
|
|
586
591
|
customer: {
|
|
587
592
|
subscription: {
|
|
@@ -88,6 +88,17 @@ export default function InvoiceDetail(props: { id: string }) {
|
|
|
88
88
|
const handleEditMetadata = () => {
|
|
89
89
|
setState((prev) => ({ editing: { ...prev.editing, metadata: true } }));
|
|
90
90
|
};
|
|
91
|
+
|
|
92
|
+
const getDescription = (description: string) => {
|
|
93
|
+
let desc = description;
|
|
94
|
+
if (desc.startsWith('Slash stake')) {
|
|
95
|
+
desc = t('payment.invoice.reason.slashStake');
|
|
96
|
+
}
|
|
97
|
+
if (desc.startsWith('Subscription ')) {
|
|
98
|
+
desc = t(`payment.invoice.reason.${desc.replace('Subscription ', '')}`);
|
|
99
|
+
}
|
|
100
|
+
return desc;
|
|
101
|
+
};
|
|
91
102
|
return (
|
|
92
103
|
<Root direction="column" spacing={2.5} sx={{ mb: 4 }}>
|
|
93
104
|
<Box>
|
|
@@ -215,6 +226,10 @@ export default function InvoiceDetail(props: { id: string }) {
|
|
|
215
226
|
md: 'repeat(2, 1fr)',
|
|
216
227
|
lg: 'repeat(3, 1fr)',
|
|
217
228
|
},
|
|
229
|
+
gap: {
|
|
230
|
+
xs: 0,
|
|
231
|
+
md: 2,
|
|
232
|
+
},
|
|
218
233
|
}}>
|
|
219
234
|
<InfoRow
|
|
220
235
|
label={t('admin.invoice.number')}
|
|
@@ -224,7 +239,7 @@ export default function InvoiceDetail(props: { id: string }) {
|
|
|
224
239
|
/>
|
|
225
240
|
<InfoRow
|
|
226
241
|
label={t('admin.invoice.description')}
|
|
227
|
-
value={data.description}
|
|
242
|
+
value={getDescription(data.description || '')}
|
|
228
243
|
direction={InfoDirection}
|
|
229
244
|
alignItems={InfoAlignItems}
|
|
230
245
|
/>
|
|
@@ -325,7 +340,7 @@ export default function InvoiceDetail(props: { id: string }) {
|
|
|
325
340
|
<Box className="section">
|
|
326
341
|
<SectionHeader title={t('admin.summary')} />
|
|
327
342
|
<Box className="section-body">
|
|
328
|
-
<InvoiceTable invoice={data} />
|
|
343
|
+
<InvoiceTable invoice={data} emptyNodeText={t('empty.summary')} />
|
|
329
344
|
</Box>
|
|
330
345
|
</Box>
|
|
331
346
|
<Divider />
|
|
@@ -112,7 +112,7 @@ export default function CustomersList() {
|
|
|
112
112
|
sort: true,
|
|
113
113
|
customBodyRenderLite: (_: string, index: number) => {
|
|
114
114
|
const item = data.list[index] as TCustomer;
|
|
115
|
-
return <Link to={`/admin/customers/${item.id}`}>{formatTime(item.
|
|
115
|
+
return <Link to={`/admin/customers/${item.id}`}>{formatTime(item.created_at)}</Link>;
|
|
116
116
|
},
|
|
117
117
|
},
|
|
118
118
|
},
|
|
@@ -219,6 +219,10 @@ export default function PaymentIntentDetail(props: { id: string }) {
|
|
|
219
219
|
md: 'repeat(2, 1fr)',
|
|
220
220
|
lg: 'repeat(3, 1fr)',
|
|
221
221
|
},
|
|
222
|
+
gap: {
|
|
223
|
+
xs: 0,
|
|
224
|
+
md: 2,
|
|
225
|
+
},
|
|
222
226
|
}}>
|
|
223
227
|
<InfoRow label={t('common.amount')} value={total} direction={InfoDirection} alignItems={InfoAlignItems} />
|
|
224
228
|
<InfoRow
|
|
@@ -216,6 +216,10 @@ export default function PayoutDetail(props: { id: string }) {
|
|
|
216
216
|
md: 'repeat(2, 1fr)',
|
|
217
217
|
lg: 'repeat(3, 1fr)',
|
|
218
218
|
},
|
|
219
|
+
gap: {
|
|
220
|
+
xs: 0,
|
|
221
|
+
md: 2,
|
|
222
|
+
},
|
|
219
223
|
}}>
|
|
220
224
|
<InfoRow label={t('common.amount')} value={total} direction={InfoDirection} alignItems={InfoAlignItems} />
|
|
221
225
|
<InfoRow
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import Center from '@arcblock/ux/lib/Center';
|
|
2
1
|
import { CheckoutTable } from '@blocklet/payment-react';
|
|
3
2
|
import Header from '@blocklet/ui-react/lib/Header';
|
|
4
3
|
import { Box } from '@mui/material';
|
|
@@ -26,9 +25,16 @@ export default function PricingTablePage({ id }: Props) {
|
|
|
26
25
|
hideNavMenu={undefined}
|
|
27
26
|
maxWidth={false}
|
|
28
27
|
/>
|
|
29
|
-
|
|
28
|
+
|
|
29
|
+
<Box
|
|
30
|
+
sx={{
|
|
31
|
+
pt: {
|
|
32
|
+
xs: 0,
|
|
33
|
+
md: '60px',
|
|
34
|
+
},
|
|
35
|
+
}}>
|
|
30
36
|
<CheckoutTable id={id} mode="standalone" />
|
|
31
|
-
</
|
|
37
|
+
</Box>
|
|
32
38
|
</Box>
|
|
33
39
|
);
|
|
34
40
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
formatBNStr,
|
|
7
7
|
formatError,
|
|
8
8
|
getPrefix,
|
|
9
|
+
TruncatedText,
|
|
9
10
|
useMobile,
|
|
10
11
|
usePaymentContext,
|
|
11
12
|
} from '@blocklet/payment-react';
|
|
@@ -91,6 +92,7 @@ export default function CustomerHome() {
|
|
|
91
92
|
const { events } = useSessionContext();
|
|
92
93
|
const { settings } = usePaymentContext();
|
|
93
94
|
const [currency, setCurrency] = useState(settings?.baseCurrency);
|
|
95
|
+
const [subscriptionLoading, setSubscriptionLoading] = useState(false);
|
|
94
96
|
const currencies = flatten(settings.paymentMethods.map((method) => method.payment_currencies));
|
|
95
97
|
|
|
96
98
|
const { livemode, setLivemode } = usePaymentContext();
|
|
@@ -151,7 +153,11 @@ export default function CustomerHome() {
|
|
|
151
153
|
};
|
|
152
154
|
|
|
153
155
|
const onToggleActive = (e: SelectChangeEvent) => {
|
|
156
|
+
setSubscriptionLoading(true);
|
|
154
157
|
setState({ onlyActive: e.target.value === 'active' });
|
|
158
|
+
setTimeout(() => {
|
|
159
|
+
setSubscriptionLoading(false);
|
|
160
|
+
}, 300);
|
|
155
161
|
};
|
|
156
162
|
|
|
157
163
|
const handleCurrencyChange = (e: SelectChangeEvent) => {
|
|
@@ -185,20 +191,24 @@ export default function CustomerHome() {
|
|
|
185
191
|
</FormControl>
|
|
186
192
|
</Box>
|
|
187
193
|
<Box className="section-body">
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
194
|
+
{subscriptionLoading ? (
|
|
195
|
+
<Box>{t('common.loading')}</Box>
|
|
196
|
+
) : (
|
|
197
|
+
<CurrentSubscriptions
|
|
198
|
+
id={data.id}
|
|
199
|
+
onlyActive={state.onlyActive}
|
|
200
|
+
changeActive={(v) => setState({ onlyActive: v })}
|
|
201
|
+
status={state.onlyActive ? 'active,trialing' : 'active,trialing,paused,past_due,canceled'}
|
|
202
|
+
style={{
|
|
203
|
+
cursor: 'pointer',
|
|
204
|
+
}}
|
|
205
|
+
onClickSubscription={(subscription) => {
|
|
206
|
+
startTransition(() => {
|
|
207
|
+
navigate(`/customer/subscription/${subscription.id}`);
|
|
208
|
+
});
|
|
209
|
+
}}
|
|
210
|
+
/>
|
|
211
|
+
)}
|
|
202
212
|
</Box>
|
|
203
213
|
</Box>
|
|
204
214
|
);
|
|
@@ -380,21 +390,22 @@ export default function CustomerHome() {
|
|
|
380
390
|
/>
|
|
381
391
|
<InfoRow
|
|
382
392
|
label={t('admin.customer.address.city')}
|
|
383
|
-
value={data.address?.city}
|
|
393
|
+
value={<TruncatedText text={data.address?.city} maxLength={280} useWidth />}
|
|
394
|
+
// value={data.address?.city}
|
|
384
395
|
sizes={[1, 1]}
|
|
385
396
|
alignItems="normal"
|
|
386
397
|
direction="column"
|
|
387
398
|
/>
|
|
388
399
|
<InfoRow
|
|
389
400
|
label={t('admin.customer.address.line1')}
|
|
390
|
-
value={data.address?.line1}
|
|
401
|
+
value={<TruncatedText text={data.address?.line1} maxLength={280} useWidth />}
|
|
391
402
|
sizes={[1, 1]}
|
|
392
403
|
alignItems="normal"
|
|
393
404
|
direction="column"
|
|
394
405
|
/>
|
|
395
406
|
<InfoRow
|
|
396
407
|
label={t('admin.customer.address.line2')}
|
|
397
|
-
value={data.address?.line2}
|
|
408
|
+
value={<TruncatedText text={data.address?.line2} maxLength={280} useWidth />}
|
|
398
409
|
sizes={[1, 1]}
|
|
399
410
|
alignItems="normal"
|
|
400
411
|
direction="column"
|
|
@@ -101,6 +101,9 @@ export default function CustomerInvoiceDetail() {
|
|
|
101
101
|
return <CircularProgress />;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
const isSlash =
|
|
105
|
+
data.paymentMethod?.type === 'arcblock' && data.paymentIntent?.payment_details?.arcblock?.type === 'slash';
|
|
106
|
+
|
|
104
107
|
return (
|
|
105
108
|
<InvoiceDetailRoot direction="column" spacing={3} sx={{ my: 2 }}>
|
|
106
109
|
<Stack direction="row" justifyContent="space-between">
|
|
@@ -209,6 +212,10 @@ export default function CustomerInvoiceDetail() {
|
|
|
209
212
|
md: 'repeat(2, 1fr)',
|
|
210
213
|
lg: 'repeat(3, 1fr)',
|
|
211
214
|
},
|
|
215
|
+
gap: {
|
|
216
|
+
xs: 0,
|
|
217
|
+
md: 2,
|
|
218
|
+
},
|
|
212
219
|
}}>
|
|
213
220
|
<InfoRow
|
|
214
221
|
label={t('admin.invoice.description')}
|
|
@@ -282,22 +289,26 @@ export default function CustomerInvoiceDetail() {
|
|
|
282
289
|
)}
|
|
283
290
|
</Stack>
|
|
284
291
|
</Box>
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
292
|
+
{!isSlash && (
|
|
293
|
+
<>
|
|
294
|
+
<Divider />
|
|
295
|
+
<Box className="section">
|
|
296
|
+
<Typography variant="h3" mb={1.5} className="section-header">
|
|
297
|
+
{t('payment.customer.products')}
|
|
298
|
+
</Typography>
|
|
299
|
+
<InvoiceTable invoice={data} simple />
|
|
300
|
+
</Box>
|
|
301
|
+
<Divider />
|
|
302
|
+
<Box className="section">
|
|
303
|
+
<Typography variant="h3" className="section-header">
|
|
304
|
+
{t('admin.refunds')}
|
|
305
|
+
</Typography>
|
|
306
|
+
<Box className="section-body">
|
|
307
|
+
<CustomerRefundList invoice_id={data.id} type="table" />
|
|
308
|
+
</Box>
|
|
309
|
+
</Box>
|
|
310
|
+
</>
|
|
311
|
+
)}
|
|
301
312
|
</InvoiceDetailRoot>
|
|
302
313
|
);
|
|
303
314
|
}
|
|
@@ -72,7 +72,7 @@ export default function CustomerInvoicePastDue() {
|
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
return (
|
|
75
|
-
<Stack direction="column" spacing={3} sx={{ my: 2
|
|
75
|
+
<Stack direction="column" spacing={3} sx={{ my: 2 }}>
|
|
76
76
|
<Stack direction="row" alignItems="center" justifyContent="space-between">
|
|
77
77
|
<Stack
|
|
78
78
|
direction="row"
|
|
@@ -100,10 +100,11 @@ export default function CustomerInvoicePastDue() {
|
|
|
100
100
|
customer_id={data.id}
|
|
101
101
|
subscription_id={subscriptionId}
|
|
102
102
|
currency_id={currencyId}
|
|
103
|
-
pageSize={
|
|
103
|
+
pageSize={10}
|
|
104
104
|
status="uncollectible"
|
|
105
105
|
target="_blank"
|
|
106
106
|
action="pay"
|
|
107
|
+
type="table"
|
|
107
108
|
/>
|
|
108
109
|
</Box>
|
|
109
110
|
</Box>
|