@blocklet/payment-react 1.13.127 → 1.13.129
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/es/checkout/form.d.ts +1 -1
- package/es/checkout/form.js +2 -1
- package/es/checkout/table.js +5 -1
- package/es/components/pricing-table.js +1 -0
- package/es/{portal → histroy}/invoice/list.js +1 -1
- package/es/histroy/mini-invoice/list.d.ts +7 -0
- package/es/histroy/mini-invoice/list.js +125 -0
- package/es/{portal → histroy}/payment/list.js +0 -1
- package/es/index.d.ts +4 -3
- package/es/index.js +5 -3
- package/es/locales/en.js +2 -0
- package/es/locales/zh.js +2 -0
- package/es/payment/form/index.js +1 -1
- package/es/payment/index.d.ts +2 -2
- package/es/payment/index.js +65 -45
- package/es/types/index.d.ts +1 -0
- package/es/util.d.ts +2 -1
- package/es/util.js +4 -0
- package/lib/checkout/form.d.ts +1 -1
- package/lib/checkout/form.js +2 -0
- package/lib/checkout/table.js +12 -5
- package/lib/components/pricing-table.js +1 -0
- package/lib/{portal → histroy}/invoice/list.js +1 -1
- package/lib/histroy/mini-invoice/list.d.ts +7 -0
- package/lib/histroy/mini-invoice/list.js +203 -0
- package/lib/{portal → histroy}/payment/list.js +0 -9
- package/lib/index.d.ts +4 -3
- package/lib/index.js +13 -5
- package/lib/locales/en.js +2 -0
- package/lib/locales/zh.js +2 -0
- package/lib/payment/form/index.js +3 -0
- package/lib/payment/index.d.ts +2 -2
- package/lib/payment/index.js +28 -8
- package/lib/types/index.d.ts +1 -0
- package/lib/util.d.ts +2 -1
- package/lib/util.js +5 -0
- package/package.json +3 -3
- package/src/checkout/form.tsx +2 -1
- package/src/checkout/table.tsx +10 -1
- package/src/components/pricing-table.tsx +2 -1
- package/src/{portal → histroy}/invoice/list.tsx +1 -1
- package/src/histroy/mini-invoice/list.tsx +165 -0
- package/src/{portal → histroy}/payment/list.tsx +0 -3
- package/src/index.ts +4 -2
- package/src/locales/en.tsx +2 -0
- package/src/locales/zh.tsx +2 -0
- package/src/payment/form/index.tsx +1 -1
- package/src/payment/index.tsx +23 -4
- package/src/types/index.ts +1 -0
- package/src/util.ts +8 -0
- /package/es/{portal → histroy}/invoice/list.d.ts +0 -0
- /package/es/{portal → histroy}/payment/list.d.ts +0 -0
- /package/lib/{portal → histroy}/invoice/list.d.ts +0 -0
- /package/lib/{portal → histroy}/payment/list.d.ts +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/* eslint-disable react/no-unstable-nested-components */
|
|
2
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
|
+
import type { Paginated, TInvoiceExpanded, TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
4
|
+
import { Box, Button, CircularProgress, Divider, List, ListItem, ListSubheader, Typography } from '@mui/material';
|
|
5
|
+
import { fromUnitToToken } from '@ocap/util';
|
|
6
|
+
import { useInfiniteScroll } from 'ahooks';
|
|
7
|
+
|
|
8
|
+
import api from '../../api';
|
|
9
|
+
import Status from '../../components/status';
|
|
10
|
+
import {
|
|
11
|
+
formatSubscriptionProduct,
|
|
12
|
+
formatTime,
|
|
13
|
+
formatToDate,
|
|
14
|
+
getInvoiceStatusColor,
|
|
15
|
+
getSubscriptionStatusColor,
|
|
16
|
+
} from '../../util';
|
|
17
|
+
|
|
18
|
+
const fetchData = (params: Record<string, any> = {}): Promise<Paginated<TInvoiceExpanded>> => {
|
|
19
|
+
const search = new URLSearchParams();
|
|
20
|
+
Object.keys(params).forEach((key) => {
|
|
21
|
+
search.set(key, String(params[key]));
|
|
22
|
+
});
|
|
23
|
+
return api.get(`/api/invoices?${search.toString()}`).then((res: any) => res.data);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type Props = {
|
|
27
|
+
subscription: TSubscriptionExpanded;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const pageSize = 10;
|
|
31
|
+
|
|
32
|
+
export default function MiniInvoiceList({ subscription }: Props) {
|
|
33
|
+
const { t } = useLocaleContext();
|
|
34
|
+
|
|
35
|
+
const { data, loading } = useInfiniteScroll<Paginated<TInvoiceExpanded>>(
|
|
36
|
+
(d) => {
|
|
37
|
+
const page = d ? Math.ceil(d.list.length / pageSize) + 1 : 1;
|
|
38
|
+
return fetchData({ page, pageSize, status: 'open,paid,uncollectible', subscription_id: subscription.id });
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
reloadDeps: [subscription.id],
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
if (loading || !data) {
|
|
46
|
+
return (
|
|
47
|
+
<Position>
|
|
48
|
+
<CircularProgress />
|
|
49
|
+
</Position>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (data && data.list.length === 0) {
|
|
54
|
+
return (
|
|
55
|
+
<Position>
|
|
56
|
+
<Typography color="text.secondary">{t('payment.customer.invoice.empty')}</Typography>
|
|
57
|
+
</Position>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const infoList = [
|
|
62
|
+
{
|
|
63
|
+
name: t('payment.customer.subscriptions.plan'),
|
|
64
|
+
value: (
|
|
65
|
+
<Typography fontWeight={600} sx={{ marginRight: '10px' }}>
|
|
66
|
+
{formatSubscriptionProduct(subscription.items)}
|
|
67
|
+
</Typography>
|
|
68
|
+
),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: t('payment.common.status'),
|
|
72
|
+
value: <Status label={subscription.status} color={getSubscriptionStatusColor(subscription.status)} />,
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
{
|
|
76
|
+
name: t('payment.customer.subscriptions.nextInvoice'),
|
|
77
|
+
value: (
|
|
78
|
+
<Typography
|
|
79
|
+
sx={{
|
|
80
|
+
color: '#34BE74',
|
|
81
|
+
fontWeight: 'bold',
|
|
82
|
+
}}>
|
|
83
|
+
{formatTime(subscription.current_period_end * 1000)}
|
|
84
|
+
</Typography>
|
|
85
|
+
),
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<Position>
|
|
91
|
+
<Typography title={t('payment.checkout.subscription')} />
|
|
92
|
+
<Box
|
|
93
|
+
sx={{
|
|
94
|
+
display: 'flex',
|
|
95
|
+
flexDirection: 'column',
|
|
96
|
+
alignItem: 'center',
|
|
97
|
+
justifyContent: 'flex-start',
|
|
98
|
+
padding: '16px',
|
|
99
|
+
width: '100%',
|
|
100
|
+
height: '100%',
|
|
101
|
+
}}>
|
|
102
|
+
<Typography component="h3" sx={{ textAlign: 'center' }} variant="h5" gutterBottom>
|
|
103
|
+
{t('payment.customer.subscriptions.current')}
|
|
104
|
+
</Typography>
|
|
105
|
+
<Box sx={{ marginTop: '12px' }}>
|
|
106
|
+
<List>
|
|
107
|
+
{infoList.map(({ name, value }) => {
|
|
108
|
+
return (
|
|
109
|
+
<ListItem key={name} disableGutters sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
|
110
|
+
<Typography component="span">{name}</Typography>
|
|
111
|
+
<Typography component="span">{value}</Typography>
|
|
112
|
+
</ListItem>
|
|
113
|
+
);
|
|
114
|
+
})}
|
|
115
|
+
</List>
|
|
116
|
+
</Box>
|
|
117
|
+
<Divider />
|
|
118
|
+
<Box sx={{ marginTop: '12px' }}>
|
|
119
|
+
<List sx={{ overflow: 'auto', maxHeight: { xs: '240px', md: '360px', padding: 0 } }}>
|
|
120
|
+
<ListSubheader disableGutters sx={{ padding: 0 }}>
|
|
121
|
+
<Typography component="h2" variant="h6" fontSize="16px">
|
|
122
|
+
{t('payment.customer.invoices')}
|
|
123
|
+
</Typography>
|
|
124
|
+
</ListSubheader>
|
|
125
|
+
{(data.list || []).map((item: any) => {
|
|
126
|
+
return (
|
|
127
|
+
<ListItem key={item.id} disableGutters sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
|
128
|
+
<Typography component="span">{formatToDate(item.created_at)}</Typography>
|
|
129
|
+
<Typography component="span">
|
|
130
|
+
{fromUnitToToken(item.total, item.paymentCurrency.decimal)}
|
|
131
|
+
{item.paymentCurrency.symbol}
|
|
132
|
+
</Typography>
|
|
133
|
+
<Status label={item.status} color={getInvoiceStatusColor(item.status)} />
|
|
134
|
+
</ListItem>
|
|
135
|
+
);
|
|
136
|
+
})}
|
|
137
|
+
</List>
|
|
138
|
+
</Box>
|
|
139
|
+
<Button target="_top" variant="contained" sx={{ marginTop: 'auto', width: '100%' }} href="">
|
|
140
|
+
{t('payment.customer.subscriptions.title')}
|
|
141
|
+
</Button>
|
|
142
|
+
</Box>
|
|
143
|
+
</Position>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function Position({ children }: any) {
|
|
148
|
+
return (
|
|
149
|
+
<Box
|
|
150
|
+
className="mini-invoice-box" // 预留 class 用于设置定位
|
|
151
|
+
sx={{
|
|
152
|
+
position: 'absolute',
|
|
153
|
+
right: 0,
|
|
154
|
+
top: '30px',
|
|
155
|
+
justifyContent: 'center',
|
|
156
|
+
padding: '8px',
|
|
157
|
+
minWidth: '400px',
|
|
158
|
+
background: '#fff',
|
|
159
|
+
zIndex: 9,
|
|
160
|
+
boxShadow: '0 4px 8px rgba(0, 0, 0, 20%)',
|
|
161
|
+
}}>
|
|
162
|
+
{children}
|
|
163
|
+
</Box>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
@@ -79,9 +79,6 @@ export default function CustomerPaymentList({ customer_id }: Props) {
|
|
|
79
79
|
md: 3,
|
|
80
80
|
}}
|
|
81
81
|
flexWrap="nowrap">
|
|
82
|
-
<Box flex={3} sx={{ minWidth: '220px' }}>
|
|
83
|
-
<Typography component="span">{item.id}</Typography>
|
|
84
|
-
</Box>
|
|
85
82
|
<Box flex={3}>
|
|
86
83
|
<Typography>{formatToDate(item.created_at)}</Typography>
|
|
87
84
|
</Box>
|
package/src/index.ts
CHANGED
|
@@ -8,12 +8,13 @@ import PricingTable from './components/pricing-table';
|
|
|
8
8
|
import Status from './components/status';
|
|
9
9
|
import Switch from './components/switch-button';
|
|
10
10
|
import dayjs from './dayjs';
|
|
11
|
+
import CustomerInvoiceList from './histroy/invoice/list';
|
|
12
|
+
import MiniInvoiceList from './histroy/mini-invoice/list';
|
|
13
|
+
import CustomerPaymentList from './histroy/payment/list';
|
|
11
14
|
import Amount from './payment/amount';
|
|
12
15
|
import PhoneInput from './payment/form/phone';
|
|
13
16
|
import Payment from './payment/index';
|
|
14
17
|
import ProductSkeleton from './payment/product-skeleton';
|
|
15
|
-
import CustomerInvoiceList from './portal/invoice/list';
|
|
16
|
-
import CustomerPaymentList from './portal/payment/list';
|
|
17
18
|
|
|
18
19
|
export * from './util';
|
|
19
20
|
export * from './contexts/payment';
|
|
@@ -37,4 +38,5 @@ export {
|
|
|
37
38
|
Amount,
|
|
38
39
|
CustomerInvoiceList,
|
|
39
40
|
CustomerPaymentList,
|
|
41
|
+
MiniInvoiceList,
|
|
40
42
|
};
|
package/src/locales/en.tsx
CHANGED
|
@@ -213,6 +213,8 @@ export default flat({
|
|
|
213
213
|
empty: 'Seems you do not have any payment here',
|
|
214
214
|
},
|
|
215
215
|
subscriptions: {
|
|
216
|
+
plan: 'Plan',
|
|
217
|
+
nextInvoice: 'Next Invoice',
|
|
216
218
|
title: 'Manage subscriptions',
|
|
217
219
|
current: 'Current subscriptions',
|
|
218
220
|
empty: 'Seems you do not have any subscriptions here',
|
package/src/locales/zh.tsx
CHANGED
|
@@ -367,7 +367,7 @@ export default function PaymentForm({
|
|
|
367
367
|
<Stack direction="row" alignItems="center">
|
|
368
368
|
<Avatar src={x.logo} alt={x.name} sx={{ width: 30, height: 30, marginRight: '10px' }} />
|
|
369
369
|
<div>
|
|
370
|
-
<Typography variant="h5" component="div">
|
|
370
|
+
<Typography variant="h5" component="div" sx={{ fontSize: '18px' }}>
|
|
371
371
|
{x.symbol}
|
|
372
372
|
</Typography>
|
|
373
373
|
<Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
|
package/src/payment/index.tsx
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
3
|
import Toast from '@arcblock/ux/lib/Toast';
|
|
4
4
|
import type { TCustomer, TPaymentCurrency, TPaymentMethodExpanded } from '@blocklet/payment-types';
|
|
5
|
+
import { ArrowBackOutlined } from '@mui/icons-material';
|
|
5
6
|
import { Box, Fade, Stack } from '@mui/material';
|
|
6
7
|
import { styled } from '@mui/system';
|
|
7
8
|
import { useSetState } from 'ahooks';
|
|
8
|
-
import { useEffect } from 'react';
|
|
9
|
+
import { useEffect, useState } from 'react';
|
|
9
10
|
import { FormProvider, useForm } from 'react-hook-form';
|
|
10
11
|
import { LiteralUnion } from 'type-fest';
|
|
11
12
|
|
|
@@ -40,9 +41,18 @@ export default function Payment({
|
|
|
40
41
|
mode,
|
|
41
42
|
onPaid,
|
|
42
43
|
onError,
|
|
44
|
+
goBack,
|
|
43
45
|
}: Props) {
|
|
44
46
|
const { t } = useLocaleContext();
|
|
45
47
|
const { refresh, livemode, setLivemode } = usePaymentContext();
|
|
48
|
+
const [delay, setDelay] = useState(false);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
setTimeout(() => {
|
|
52
|
+
// 骨架屏 delay
|
|
53
|
+
setDelay(true);
|
|
54
|
+
}, 500);
|
|
55
|
+
}, []);
|
|
46
56
|
|
|
47
57
|
useEffect(() => {
|
|
48
58
|
if (checkoutSession) {
|
|
@@ -59,7 +69,7 @@ export default function Payment({
|
|
|
59
69
|
return <PaymentError title="Oops" description={formatError(error)} />;
|
|
60
70
|
}
|
|
61
71
|
|
|
62
|
-
if (!checkoutSession) {
|
|
72
|
+
if (!checkoutSession || !delay) {
|
|
63
73
|
return (
|
|
64
74
|
<Root mode={mode}>
|
|
65
75
|
<Stack className="cko-container">
|
|
@@ -105,6 +115,7 @@ export default function Payment({
|
|
|
105
115
|
customer={customer as TCustomer}
|
|
106
116
|
onPaid={onPaid}
|
|
107
117
|
onError={onError}
|
|
118
|
+
goBack={goBack}
|
|
108
119
|
mode={mode}
|
|
109
120
|
/>
|
|
110
121
|
);
|
|
@@ -126,6 +137,7 @@ export function PaymentInner({
|
|
|
126
137
|
mode,
|
|
127
138
|
onPaid,
|
|
128
139
|
onError,
|
|
140
|
+
goBack,
|
|
129
141
|
}: MainProps) {
|
|
130
142
|
const { t } = useLocaleContext();
|
|
131
143
|
const { settings, session } = usePaymentContext();
|
|
@@ -204,6 +216,13 @@ export function PaymentInner({
|
|
|
204
216
|
return (
|
|
205
217
|
<FormProvider {...methods}>
|
|
206
218
|
<Root mode={mode}>
|
|
219
|
+
{mode !== 'standalone' ? (
|
|
220
|
+
<ArrowBackOutlined
|
|
221
|
+
sx={{ mr: 0.5, color: 'text.secondary', alignSelf: 'flex-start', margin: '16px 0', cursor: 'pointer' }}
|
|
222
|
+
onClick={goBack}
|
|
223
|
+
fontSize="medium"
|
|
224
|
+
/>
|
|
225
|
+
) : null}
|
|
207
226
|
<Stack className="cko-container" sx={{ gap: { sm: mode === 'standalone' ? 0 : 8 } }}>
|
|
208
227
|
<Fade in>
|
|
209
228
|
<Stack className="cko-overview" direction="column">
|
|
@@ -357,11 +376,11 @@ export const Root = styled(Box)<{ mode: LiteralUnion<'standalone' | 'inline' | '
|
|
|
357
376
|
}
|
|
358
377
|
|
|
359
378
|
.cko-payment-card:nth-child(odd) {
|
|
360
|
-
margin-right:
|
|
379
|
+
margin-right: 8px;
|
|
361
380
|
}
|
|
362
381
|
|
|
363
382
|
.cko-payment-card-unselect:nth-child(odd) {
|
|
364
|
-
margin-right:
|
|
383
|
+
margin-right: 8px;
|
|
365
384
|
}
|
|
366
385
|
|
|
367
386
|
.cko-payment-card::after {
|
package/src/types/index.ts
CHANGED
package/src/util.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
TPaymentMethodExpanded,
|
|
10
10
|
TPrice,
|
|
11
11
|
TSubscriptionExpanded,
|
|
12
|
+
TSubscriptionItemExpanded,
|
|
12
13
|
} from '@blocklet/payment-types';
|
|
13
14
|
import { BN, fromUnitToToken } from '@ocap/util';
|
|
14
15
|
import { defaultCountries } from 'react-international-phone';
|
|
@@ -551,6 +552,13 @@ export function sleep(ms: number) {
|
|
|
551
552
|
});
|
|
552
553
|
}
|
|
553
554
|
|
|
555
|
+
export function formatSubscriptionProduct(items: TSubscriptionItemExpanded[], maxLength = 2) {
|
|
556
|
+
const names = items.map((x) => x.price.product?.name).filter(Boolean);
|
|
557
|
+
return (
|
|
558
|
+
names.slice(0, maxLength).join(', ') + (names.length > maxLength ? ` and ${names.length - maxLength} more` : '')
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
|
|
554
562
|
export const getSubscriptionTimeSummary = (subscription: TSubscriptionExpanded) => {
|
|
555
563
|
const lines = [`Started on ${formatToDate(subscription.start_date * 1000)}`];
|
|
556
564
|
if (subscription.status === 'active' || subscription.status === 'trialing') {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|