payment-kit 1.13.161 → 1.13.162
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/.eslintrc.js +2 -1
- package/api/src/libs/api.ts +18 -29
- package/api/src/routes/customers.ts +12 -7
- package/api/src/routes/invoices.ts +17 -6
- package/api/src/routes/payment-intents.ts +19 -7
- package/api/src/routes/products.ts +2 -2
- package/api/src/routes/refunds.ts +53 -3
- package/api/src/routes/subscription-items.ts +18 -9
- package/api/src/routes/subscriptions.ts +20 -31
- package/api/tests/libs/util.spec.ts +0 -26
- package/blocklet.yml +1 -1
- package/package.json +4 -4
- package/src/components/filter-toolbar.tsx +375 -0
- package/src/components/invoice/list.tsx +17 -46
- package/src/components/payment-intent/list.tsx +17 -41
- package/src/components/payment-link/product-select.tsx +47 -28
- package/src/components/refund/list.tsx +52 -26
- package/src/components/subscription/items/usage-records.tsx +1 -0
- package/src/components/subscription/list.tsx +15 -44
- package/src/components/table.tsx +13 -1
- package/src/global.css +1 -1
- package/src/pages/admin/customers/customers/index.tsx +15 -8
- package/src/pages/admin/payments/links/index.tsx +1 -0
- package/src/pages/admin/products/prices/list.tsx +1 -0
- package/src/pages/admin/products/pricing-tables/index.tsx +1 -0
- package/src/pages/admin/products/products/index.tsx +1 -0
- package/src/pages/customer/index.tsx +1 -13
|
@@ -25,49 +25,68 @@ const filterProducts = (products: TProductExpanded[], hasSelected: (price: any)
|
|
|
25
25
|
return filtered.filter((x) => x.prices.length);
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
export
|
|
29
|
-
const {
|
|
28
|
+
export function FilterProducts({ hasSelected, onSelect }: any) {
|
|
29
|
+
const size = { width: 16, height: 16 };
|
|
30
30
|
const { products } = useProductsContext();
|
|
31
31
|
const { settings } = usePaymentContext();
|
|
32
|
-
const [mode, setMode] = useState(initialMode);
|
|
33
32
|
|
|
33
|
+
return (
|
|
34
|
+
<>
|
|
35
|
+
{filterProducts(products, hasSelected).map((product) => [
|
|
36
|
+
<ListSubheader key={product.id} sx={{ fontSize: '1rem', color: 'text.secondary', lineHeight: '2.5rem' }}>
|
|
37
|
+
<Stack direction="row" alignItems="center" spacing={0.5}>
|
|
38
|
+
{product.images[0] ? (
|
|
39
|
+
<Avatar src={product.images[0]} alt={product.name} variant="square" sx={size} />
|
|
40
|
+
) : (
|
|
41
|
+
<Avatar variant="square" sx={size}>
|
|
42
|
+
{product.name.slice(0, 1)}
|
|
43
|
+
</Avatar>
|
|
44
|
+
)}
|
|
45
|
+
<Typography component="span">{product.name}</Typography>
|
|
46
|
+
</Stack>
|
|
47
|
+
</ListSubheader>,
|
|
48
|
+
...product.prices.map((price) => (
|
|
49
|
+
<MenuItem
|
|
50
|
+
key={price.id}
|
|
51
|
+
sx={{ pl: 4.5 }}
|
|
52
|
+
value={price.id}
|
|
53
|
+
onClick={() => {
|
|
54
|
+
if (onSelect) {
|
|
55
|
+
const wrapPrice: any = price;
|
|
56
|
+
wrapPrice.productName = product.name;
|
|
57
|
+
wrapPrice.displayPrice = formatPrice(price, settings.baseCurrency);
|
|
58
|
+
onSelect(wrapPrice);
|
|
59
|
+
}
|
|
60
|
+
}}>
|
|
61
|
+
<Typography color="text.primary">{formatPrice(price, settings.baseCurrency)}</Typography>
|
|
62
|
+
<Typography color="text.secondary" sx={{ ml: 2 }}>
|
|
63
|
+
{getPriceCurrencyOptions(price).length > 1
|
|
64
|
+
? ` +${getPriceCurrencyOptions(price).length - 1} more currencies`
|
|
65
|
+
: ''}
|
|
66
|
+
</Typography>
|
|
67
|
+
</MenuItem>
|
|
68
|
+
)),
|
|
69
|
+
])}
|
|
70
|
+
</>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default function ProductSelect({ mode: initialMode, hasSelected, onSelect }: Props) {
|
|
75
|
+
const { t } = useLocaleContext();
|
|
76
|
+
const [mode, setMode] = useState(initialMode);
|
|
34
77
|
const handleSelect = (e: any) => {
|
|
35
78
|
setMode('waiting');
|
|
36
79
|
onSelect(e.target.value);
|
|
37
80
|
};
|
|
38
81
|
|
|
39
82
|
if (mode === 'selecting') {
|
|
40
|
-
const size = { width: 16, height: 16 };
|
|
41
83
|
return (
|
|
42
84
|
<Select value="" fullWidth size="small" onChange={handleSelect} MenuProps={{ style: { maxHeight: 480 } }}>
|
|
43
85
|
<MenuItem value="add">
|
|
44
86
|
<AddOutlined />
|
|
45
87
|
{t('admin.product.add')}
|
|
46
88
|
</MenuItem>
|
|
47
|
-
|
|
48
|
-
<ListSubheader key={product.id} sx={{ fontSize: '1rem', color: 'text.secondary', lineHeight: '2.5rem' }}>
|
|
49
|
-
<Stack direction="row" alignItems="center" spacing={0.5}>
|
|
50
|
-
{product.images[0] ? (
|
|
51
|
-
<Avatar src={product.images[0]} alt={product.name} variant="square" sx={size} />
|
|
52
|
-
) : (
|
|
53
|
-
<Avatar variant="square" sx={size}>
|
|
54
|
-
{product.name.slice(0, 1)}
|
|
55
|
-
</Avatar>
|
|
56
|
-
)}
|
|
57
|
-
<Typography component="span">{product.name}</Typography>
|
|
58
|
-
</Stack>
|
|
59
|
-
</ListSubheader>,
|
|
60
|
-
...product.prices.map((price) => (
|
|
61
|
-
<MenuItem key={price.id} sx={{ pl: 4.5 }} value={price.id}>
|
|
62
|
-
<Typography color="text.primary">{formatPrice(price, settings.baseCurrency)}</Typography>
|
|
63
|
-
<Typography color="text.secondary" sx={{ ml: 2 }}>
|
|
64
|
-
{getPriceCurrencyOptions(price).length > 1
|
|
65
|
-
? ` +${getPriceCurrencyOptions(price).length - 1} more currencies`
|
|
66
|
-
: ''}
|
|
67
|
-
</Typography>
|
|
68
|
-
</MenuItem>
|
|
69
|
-
)),
|
|
70
|
-
])}
|
|
89
|
+
<FilterProducts hasSelected={hasSelected} />
|
|
71
90
|
</Select>
|
|
72
91
|
);
|
|
73
92
|
}
|
|
@@ -3,31 +3,39 @@ import { getDurableData } from '@arcblock/ux/lib/Datatable';
|
|
|
3
3
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
4
4
|
import { Status, api, formatTime, getPaymentIntentStatusColor } from '@blocklet/payment-react';
|
|
5
5
|
import type { TRefundExpanded } from '@blocklet/payment-types';
|
|
6
|
-
import {
|
|
6
|
+
import { CircularProgress, Typography } from '@mui/material';
|
|
7
7
|
import { fromUnitToToken } from '@ocap/util';
|
|
8
|
-
import { useRequest } from 'ahooks';
|
|
9
8
|
import { useEffect, useState } from 'react';
|
|
10
9
|
import { useNavigate } from 'react-router-dom';
|
|
11
10
|
|
|
12
11
|
import CustomerLink from '../customer/link';
|
|
12
|
+
import FilterTooolbar from '../filter-toolbar';
|
|
13
13
|
import Table from '../table';
|
|
14
14
|
import RefundActions from './actions';
|
|
15
15
|
|
|
16
16
|
const fetchData = (params: Record<string, any> = {}): Promise<{ list: TRefundExpanded[]; count: number }> => {
|
|
17
17
|
const search = new URLSearchParams();
|
|
18
18
|
Object.keys(params).forEach((key) => {
|
|
19
|
-
|
|
19
|
+
let v = params[key];
|
|
20
|
+
if (key === 'q') {
|
|
21
|
+
v = Object.entries(v)
|
|
22
|
+
.map((x) => x.join(':'))
|
|
23
|
+
.join(' ');
|
|
24
|
+
}
|
|
25
|
+
search.set(key, String(v));
|
|
20
26
|
});
|
|
21
27
|
return api.get(`/api/refunds?${search.toString()}`).then((res) => res.data);
|
|
22
28
|
};
|
|
23
29
|
|
|
24
30
|
type SearchProps = {
|
|
25
|
-
status
|
|
31
|
+
status?: string;
|
|
26
32
|
pageSize: number;
|
|
27
33
|
page: number;
|
|
28
34
|
customer_id?: string;
|
|
29
35
|
invoice_id?: string;
|
|
30
36
|
subscription_id?: string;
|
|
37
|
+
q?: Record<string, string>;
|
|
38
|
+
o?: string;
|
|
31
39
|
};
|
|
32
40
|
|
|
33
41
|
type ListProps = {
|
|
@@ -78,16 +86,18 @@ export default function RefundList({ customer_id, invoice_id, subscription_id, f
|
|
|
78
86
|
page: persisted.page ? persisted.page + 1 : 1,
|
|
79
87
|
});
|
|
80
88
|
|
|
81
|
-
const
|
|
89
|
+
const [data, setData] = useState({}) as any;
|
|
90
|
+
|
|
91
|
+
const refresh = () =>
|
|
92
|
+
fetchData(search).then((res: any) => {
|
|
93
|
+
setData(res);
|
|
94
|
+
});
|
|
95
|
+
|
|
82
96
|
useEffect(() => {
|
|
83
97
|
refresh();
|
|
84
|
-
}, [search
|
|
98
|
+
}, [search]);
|
|
85
99
|
|
|
86
|
-
if (
|
|
87
|
-
return <Alert severity="error">{error.message}</Alert>;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (loading || !data) {
|
|
100
|
+
if (!data.list) {
|
|
91
101
|
return <CircularProgress />;
|
|
92
102
|
}
|
|
93
103
|
|
|
@@ -135,6 +145,7 @@ export default function RefundList({ customer_id, invoice_id, subscription_id, f
|
|
|
135
145
|
label: t('common.createdAt'),
|
|
136
146
|
name: 'created_at',
|
|
137
147
|
options: {
|
|
148
|
+
sort: true,
|
|
138
149
|
customBodyRender: (e: string) => {
|
|
139
150
|
return formatTime(e);
|
|
140
151
|
},
|
|
@@ -179,7 +190,7 @@ export default function RefundList({ customer_id, invoice_id, subscription_id, f
|
|
|
179
190
|
durableKeys={['page', 'rowsPerPage']}
|
|
180
191
|
data={data.list}
|
|
181
192
|
columns={columns}
|
|
182
|
-
loading={
|
|
193
|
+
loading={!data.list}
|
|
183
194
|
onChange={onTableChange}
|
|
184
195
|
options={{
|
|
185
196
|
count: data.count,
|
|
@@ -189,23 +200,38 @@ export default function RefundList({ customer_id, invoice_id, subscription_id, f
|
|
|
189
200
|
const item = data.list[dataIndex] as TRefundExpanded;
|
|
190
201
|
navigate(`/admin/payments/${item.id}`);
|
|
191
202
|
},
|
|
203
|
+
onColumnSortChange(_: any, order: any) {
|
|
204
|
+
setSearch({
|
|
205
|
+
...search,
|
|
206
|
+
q: search.q || {},
|
|
207
|
+
o: order,
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
onSearchChange: (text: string) => {
|
|
211
|
+
if (text) {
|
|
212
|
+
setSearch({
|
|
213
|
+
q: {
|
|
214
|
+
'like-description': text,
|
|
215
|
+
'like-metadata': text,
|
|
216
|
+
},
|
|
217
|
+
status: '',
|
|
218
|
+
pageSize: 100,
|
|
219
|
+
page: 1,
|
|
220
|
+
});
|
|
221
|
+
} else {
|
|
222
|
+
setSearch({
|
|
223
|
+
status: '',
|
|
224
|
+
customer_id,
|
|
225
|
+
invoice_id,
|
|
226
|
+
pageSize: 100,
|
|
227
|
+
page: 1,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
},
|
|
192
231
|
}}
|
|
193
232
|
toolbar={features?.toolbar}
|
|
194
233
|
footer={features?.footer}
|
|
195
|
-
title={
|
|
196
|
-
<div className="table-toolbar-left">
|
|
197
|
-
<ToggleButtonGroup
|
|
198
|
-
value={search.status}
|
|
199
|
-
onChange={(_, value) => setSearch((x) => ({ ...x, status: value }))}
|
|
200
|
-
exclusive>
|
|
201
|
-
<ToggleButton value="">All</ToggleButton>
|
|
202
|
-
<ToggleButton value="succeeded">Succeeded</ToggleButton>
|
|
203
|
-
<ToggleButton value="canceled">Canceled</ToggleButton>
|
|
204
|
-
<ToggleButton value="pending,requires_action">Pending</ToggleButton>
|
|
205
|
-
<ToggleButton value="failed">Failed</ToggleButton>
|
|
206
|
-
</ToggleButtonGroup>
|
|
207
|
-
</div>
|
|
208
|
-
}
|
|
234
|
+
title={<FilterTooolbar setSearch={setSearch} search={search} status={['successed']} currency />}
|
|
209
235
|
/>
|
|
210
236
|
);
|
|
211
237
|
}
|
|
@@ -46,6 +46,7 @@ export function UsageRecordDialog(props: { subscriptionId: string; id: string; o
|
|
|
46
46
|
label: t('common.createdAt'),
|
|
47
47
|
name: 'id',
|
|
48
48
|
options: {
|
|
49
|
+
sort: true,
|
|
49
50
|
customBodyRenderLite: (_: string, index: number) => {
|
|
50
51
|
const item = data.list[index] as TUsageRecord;
|
|
51
52
|
return formatToDatetime(item.timestamp * 1000);
|
|
@@ -3,12 +3,12 @@ import { getDurableData } from '@arcblock/ux/lib/Datatable';
|
|
|
3
3
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
4
4
|
import { Status, api, formatTime } from '@blocklet/payment-react';
|
|
5
5
|
import type { TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
6
|
-
import { CircularProgress
|
|
6
|
+
import { CircularProgress } from '@mui/material';
|
|
7
7
|
import { useEffect, useState } from 'react';
|
|
8
8
|
import { useNavigate } from 'react-router-dom';
|
|
9
9
|
|
|
10
|
-
import { debounce } from '../../libs/util';
|
|
11
10
|
import CustomerLink from '../customer/link';
|
|
11
|
+
import FilterTooolbar from '../filter-toolbar';
|
|
12
12
|
import Table from '../table';
|
|
13
13
|
import SubscriptionActions from './actions';
|
|
14
14
|
import SubscriptionDescription from './description';
|
|
@@ -19,15 +19,13 @@ const fetchData = (params: Record<string, any> = {}): Promise<{ list: TSubscript
|
|
|
19
19
|
Object.keys(params).forEach((key) => {
|
|
20
20
|
let v = params[key];
|
|
21
21
|
if (key === 'q') {
|
|
22
|
-
v = Object.entries(
|
|
22
|
+
v = Object.entries(v)
|
|
23
23
|
.map((x) => x.join(':'))
|
|
24
24
|
.join(' ');
|
|
25
25
|
}
|
|
26
26
|
search.set(key, String(v));
|
|
27
27
|
});
|
|
28
|
-
return
|
|
29
|
-
? api.get(`api/subscriptions/search?${search.toString()}`).then((res) => res.data)
|
|
30
|
-
: api.get(`/api/subscriptions?${search.toString()}`).then((res) => res.data);
|
|
28
|
+
return api.get(`/api/subscriptions?${search.toString()}`).then((res) => res.data);
|
|
31
29
|
};
|
|
32
30
|
|
|
33
31
|
type SearchProps = {
|
|
@@ -36,6 +34,7 @@ type SearchProps = {
|
|
|
36
34
|
page: number;
|
|
37
35
|
customer_id?: string;
|
|
38
36
|
q?: any;
|
|
37
|
+
o?: string;
|
|
39
38
|
};
|
|
40
39
|
|
|
41
40
|
type ListProps = {
|
|
@@ -86,7 +85,7 @@ export default function SubscriptionList({ customer_id, features, status }: List
|
|
|
86
85
|
});
|
|
87
86
|
|
|
88
87
|
useEffect(() => {
|
|
89
|
-
|
|
88
|
+
refresh();
|
|
90
89
|
}, [search]);
|
|
91
90
|
|
|
92
91
|
if (!data.list) {
|
|
@@ -134,6 +133,7 @@ export default function SubscriptionList({ customer_id, features, status }: List
|
|
|
134
133
|
label: t('common.createdAt'),
|
|
135
134
|
name: 'created_at',
|
|
136
135
|
options: {
|
|
136
|
+
sort: true,
|
|
137
137
|
customBodyRender: (e: string) => {
|
|
138
138
|
return formatTime(e);
|
|
139
139
|
},
|
|
@@ -193,35 +193,19 @@ export default function SubscriptionList({ customer_id, features, status }: List
|
|
|
193
193
|
const item = data.list[dataIndex] as TSubscriptionExpanded;
|
|
194
194
|
navigate(`/admin/billing/${item.id}`);
|
|
195
195
|
},
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
page: 1,
|
|
203
|
-
});
|
|
204
|
-
} else if (filterList && filterList[index]) {
|
|
205
|
-
// 这里暂时没有更好的取值方式
|
|
206
|
-
const value = filterList[index][0];
|
|
207
|
-
setSearch({
|
|
208
|
-
q: {
|
|
209
|
-
...search.q,
|
|
210
|
-
[key]: encodeURIComponent(value),
|
|
211
|
-
},
|
|
212
|
-
pageSize: 100,
|
|
213
|
-
page: 1,
|
|
214
|
-
});
|
|
215
|
-
}
|
|
196
|
+
onColumnSortChange(_: any, order: any) {
|
|
197
|
+
setSearch({
|
|
198
|
+
...search,
|
|
199
|
+
q: search.q || {},
|
|
200
|
+
o: order,
|
|
201
|
+
});
|
|
216
202
|
},
|
|
217
203
|
onSearchChange: (text: string) => {
|
|
218
204
|
if (text) {
|
|
219
205
|
setSearch({
|
|
220
206
|
q: {
|
|
221
207
|
'like-metadata': text,
|
|
222
|
-
'like-
|
|
223
|
-
'like-name': text,
|
|
224
|
-
// 'like-product-name': text, // 这个还没实现
|
|
208
|
+
'like-description': text,
|
|
225
209
|
},
|
|
226
210
|
pageSize: 100,
|
|
227
211
|
page: 1,
|
|
@@ -238,20 +222,7 @@ export default function SubscriptionList({ customer_id, features, status }: List
|
|
|
238
222
|
}}
|
|
239
223
|
toolbar={features?.toolbar}
|
|
240
224
|
footer={features?.footer}
|
|
241
|
-
title={
|
|
242
|
-
<div className="table-toolbar-left">
|
|
243
|
-
<ToggleButtonGroup
|
|
244
|
-
value={search.status}
|
|
245
|
-
onChange={(_, value) => setSearch((x) => ({ ...x, status: value }))}
|
|
246
|
-
exclusive>
|
|
247
|
-
<ToggleButton value="active">Active</ToggleButton>
|
|
248
|
-
<ToggleButton value="trialing">Scheduled</ToggleButton>
|
|
249
|
-
<ToggleButton value="canceled">Canceled</ToggleButton>
|
|
250
|
-
<ToggleButton value="incomplete,incomplete_expired">Incomplete</ToggleButton>
|
|
251
|
-
<ToggleButton value="past_due,unpaid">Due</ToggleButton>
|
|
252
|
-
</ToggleButtonGroup>
|
|
253
|
-
</div>
|
|
254
|
-
}
|
|
225
|
+
title={<FilterTooolbar setSearch={setSearch} search={search} status={['active', 'canceled']} />}
|
|
255
226
|
/>
|
|
256
227
|
);
|
|
257
228
|
}
|
package/src/components/table.tsx
CHANGED
|
@@ -14,12 +14,13 @@ export default function Table({ options, columns, toolbar = true, footer = true,
|
|
|
14
14
|
const defaultOptions = {
|
|
15
15
|
print: false,
|
|
16
16
|
download: false,
|
|
17
|
-
filter:
|
|
17
|
+
filter: false,
|
|
18
18
|
selectableRows: 'none',
|
|
19
19
|
rowsPerPage: 10,
|
|
20
20
|
rowsPerPageOptions: [10, 20, 50, 100],
|
|
21
21
|
searchDebounceTime: 300,
|
|
22
22
|
tableBodyHeight: '100%',
|
|
23
|
+
loading: true,
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
const components: any = {};
|
|
@@ -30,6 +31,8 @@ export default function Table({ options, columns, toolbar = true, footer = true,
|
|
|
30
31
|
components.TableFooter = EmptyStub;
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
// components.TableHead = EmptyStub2
|
|
35
|
+
|
|
33
36
|
return (
|
|
34
37
|
<Wrapped
|
|
35
38
|
locale={locale}
|
|
@@ -64,6 +67,15 @@ const Wrapped = styled(Datatable)`
|
|
|
64
67
|
overflow: visible;
|
|
65
68
|
}
|
|
66
69
|
|
|
70
|
+
.custom-toobar-title-inner span {
|
|
71
|
+
overflow: visible !important;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.custom-toobar-title-inner {
|
|
75
|
+
line-height: 30px !important;
|
|
76
|
+
padding: 10px 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
67
79
|
${(props) => {
|
|
68
80
|
if (props.isMobile) {
|
|
69
81
|
return '';
|
package/src/global.css
CHANGED
|
@@ -9,22 +9,19 @@ import { useEffect, useState } from 'react';
|
|
|
9
9
|
import { useNavigate } from 'react-router-dom';
|
|
10
10
|
|
|
11
11
|
import Table from '../../../../components/table';
|
|
12
|
-
import { debounce } from '../../../../libs/util';
|
|
13
12
|
|
|
14
13
|
const fetchData = (params: Record<string, any> = {}): Promise<{ list: TCustomer[]; count: number }> => {
|
|
15
14
|
const search = new URLSearchParams();
|
|
16
15
|
Object.keys(params).forEach((key) => {
|
|
17
16
|
let v = params[key];
|
|
18
17
|
if (key === 'q') {
|
|
19
|
-
v = Object.entries(
|
|
18
|
+
v = Object.entries(v)
|
|
20
19
|
.map((x) => x.join(':'))
|
|
21
20
|
.join(' ');
|
|
22
21
|
}
|
|
23
22
|
search.set(key, String(v));
|
|
24
23
|
});
|
|
25
|
-
return
|
|
26
|
-
? api.get(`api/customers/search?${search.toString()}`).then((res) => res.data)
|
|
27
|
-
: api.get(`/api/customers?${search.toString()}`).then((res) => res.data);
|
|
24
|
+
return api.get(`/api/customers?${search.toString()}`).then((res: any) => res.data);
|
|
28
25
|
};
|
|
29
26
|
|
|
30
27
|
export default function CustomersList() {
|
|
@@ -33,8 +30,9 @@ export default function CustomersList() {
|
|
|
33
30
|
|
|
34
31
|
const { t } = useLocaleContext();
|
|
35
32
|
const navigate = useNavigate();
|
|
36
|
-
const [search, setSearch] = useState<{ active?: string; pageSize: number; page: number; q?: any }>({
|
|
33
|
+
const [search, setSearch] = useState<{ active?: string; pageSize: number; page: number; q?: any; o?: string }>({
|
|
37
34
|
active: '',
|
|
35
|
+
o: 'desc',
|
|
38
36
|
pageSize: persisted.rowsPerPage || 20,
|
|
39
37
|
page: persisted.page ? persisted.page + 1 : 1,
|
|
40
38
|
});
|
|
@@ -47,7 +45,7 @@ export default function CustomersList() {
|
|
|
47
45
|
});
|
|
48
46
|
|
|
49
47
|
useEffect(() => {
|
|
50
|
-
|
|
48
|
+
refresh();
|
|
51
49
|
}, [search]);
|
|
52
50
|
|
|
53
51
|
if (!data.list) {
|
|
@@ -92,6 +90,7 @@ export default function CustomersList() {
|
|
|
92
90
|
label: t('common.createdAt'),
|
|
93
91
|
name: 'created_at',
|
|
94
92
|
options: {
|
|
93
|
+
sort: true,
|
|
95
94
|
customBodyRender: (e: string) => {
|
|
96
95
|
return formatTime(e);
|
|
97
96
|
},
|
|
@@ -121,7 +120,13 @@ export default function CustomersList() {
|
|
|
121
120
|
const item = data.list[dataIndex] as TCustomer;
|
|
122
121
|
navigate(`/admin/customers/${item.id}`);
|
|
123
122
|
},
|
|
124
|
-
|
|
123
|
+
onColumnSortChange(_: any, order: any) {
|
|
124
|
+
setSearch({
|
|
125
|
+
...search,
|
|
126
|
+
q: search.q || {},
|
|
127
|
+
o: order,
|
|
128
|
+
});
|
|
129
|
+
},
|
|
125
130
|
onSearchChange: (text: string) => {
|
|
126
131
|
if (text) {
|
|
127
132
|
setSearch({
|
|
@@ -129,6 +134,8 @@ export default function CustomersList() {
|
|
|
129
134
|
'like-name': text,
|
|
130
135
|
'like-email': text,
|
|
131
136
|
'like-did': text,
|
|
137
|
+
'like-metadata': text,
|
|
138
|
+
'like-phone': text,
|
|
132
139
|
},
|
|
133
140
|
pageSize: 100,
|
|
134
141
|
page: 1,
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import DID from '@arcblock/ux/lib/Address';
|
|
2
2
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
3
|
import Toast from '@arcblock/ux/lib/Toast';
|
|
4
|
-
import {
|
|
5
|
-
CustomerInvoiceList,
|
|
6
|
-
CustomerPaymentList,
|
|
7
|
-
PaymentProvider,
|
|
8
|
-
formatError,
|
|
9
|
-
getPrefix,
|
|
10
|
-
} from '@blocklet/payment-react';
|
|
4
|
+
import { CustomerInvoiceList, PaymentProvider, formatError, getPrefix } from '@blocklet/payment-react';
|
|
11
5
|
import type { GroupedBN, TCustomerExpanded } from '@blocklet/payment-types';
|
|
12
6
|
import { Edit } from '@mui/icons-material';
|
|
13
7
|
import { Alert, Box, Button, CircularProgress, Grid, Stack, Tooltip } from '@mui/material';
|
|
@@ -117,12 +111,6 @@ export default function CustomerHome() {
|
|
|
117
111
|
<CustomerInvoiceList customer_id={data.id} />
|
|
118
112
|
</Box>
|
|
119
113
|
</Box>
|
|
120
|
-
<Box className="section">
|
|
121
|
-
<SectionHeader title={t('payment.customer.payments')} mb={0} />
|
|
122
|
-
<Box className="section-body">
|
|
123
|
-
<CustomerPaymentList customer_id={data.id} />
|
|
124
|
-
</Box>
|
|
125
|
-
</Box>
|
|
126
114
|
</Root>
|
|
127
115
|
</Grid>
|
|
128
116
|
<Grid item xs={12} md={4}>
|