payment-kit 1.13.162 → 1.13.163
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.
|
@@ -2,7 +2,6 @@ import { fromTokenToUnit } from '@ocap/util';
|
|
|
2
2
|
import { Router } from 'express';
|
|
3
3
|
import Joi from 'joi';
|
|
4
4
|
import pick from 'lodash/pick';
|
|
5
|
-
import type { WhereOptions } from 'sequelize';
|
|
6
5
|
|
|
7
6
|
import { getWhereFromKvQuery, getWhereFromQuery } from '../libs/api';
|
|
8
7
|
import logger from '../libs/logger';
|
|
@@ -112,22 +111,33 @@ const paginationSchema = Joi.object<{
|
|
|
112
111
|
pageSize: number;
|
|
113
112
|
livemode?: boolean;
|
|
114
113
|
active?: boolean;
|
|
114
|
+
status?: string;
|
|
115
115
|
name?: string;
|
|
116
116
|
description?: string;
|
|
117
|
+
q?: string;
|
|
118
|
+
o?: string;
|
|
117
119
|
}>({
|
|
118
120
|
page: Joi.number().integer().min(1).default(1),
|
|
119
121
|
pageSize: Joi.number().integer().min(1).max(100).default(20),
|
|
120
122
|
livemode: Joi.boolean().empty(''),
|
|
121
123
|
active: Joi.boolean().empty(''),
|
|
124
|
+
status: Joi.string().empty(''),
|
|
122
125
|
name: Joi.string().empty(''),
|
|
123
126
|
description: Joi.string().empty(''),
|
|
127
|
+
q: Joi.string().empty(''), // query
|
|
128
|
+
o: Joi.string().empty(''), // order
|
|
124
129
|
});
|
|
125
130
|
router.get('/', auth, async (req, res) => {
|
|
126
131
|
const { page, pageSize, active, livemode, name, description, ...query } = await paginationSchema.validateAsync(
|
|
127
132
|
req.query,
|
|
128
133
|
{ stripUnknown: false, allowUnknown: true }
|
|
129
134
|
);
|
|
130
|
-
const where
|
|
135
|
+
const where = getWhereFromKvQuery(query.q);
|
|
136
|
+
|
|
137
|
+
if (query.status) {
|
|
138
|
+
// 兼容处理,支持 status
|
|
139
|
+
where.active = query.status === 'active';
|
|
140
|
+
}
|
|
131
141
|
|
|
132
142
|
if (typeof active === 'boolean') {
|
|
133
143
|
where.active = active;
|
|
@@ -151,7 +161,7 @@ router.get('/', auth, async (req, res) => {
|
|
|
151
161
|
|
|
152
162
|
const { rows: list, count } = await Product.findAndCountAll({
|
|
153
163
|
where,
|
|
154
|
-
order: [['created_at', 'DESC']],
|
|
164
|
+
order: [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']],
|
|
155
165
|
offset: (page - 1) * pageSize,
|
|
156
166
|
limit: pageSize,
|
|
157
167
|
include: [{ model: Price, as: 'prices' }],
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.163",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "cross-env COMPONENT_STORE_URL=https://test.store.blocklet.dev blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@arcblock/jwt": "^1.18.110",
|
|
51
51
|
"@arcblock/ux": "^2.9.39",
|
|
52
52
|
"@blocklet/logger": "1.16.23",
|
|
53
|
-
"@blocklet/payment-react": "1.13.
|
|
53
|
+
"@blocklet/payment-react": "1.13.163",
|
|
54
54
|
"@blocklet/sdk": "1.16.23",
|
|
55
55
|
"@blocklet/ui-react": "^2.9.39",
|
|
56
56
|
"@blocklet/uploader": "^0.0.74",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"devDependencies": {
|
|
111
111
|
"@abtnode/types": "1.16.23",
|
|
112
112
|
"@arcblock/eslint-config-ts": "^0.2.4",
|
|
113
|
-
"@blocklet/payment-types": "1.13.
|
|
113
|
+
"@blocklet/payment-types": "1.13.163",
|
|
114
114
|
"@types/cookie-parser": "^1.4.6",
|
|
115
115
|
"@types/cors": "^2.8.17",
|
|
116
116
|
"@types/dotenv-flow": "^3.3.3",
|
|
@@ -149,5 +149,5 @@
|
|
|
149
149
|
"parser": "typescript"
|
|
150
150
|
}
|
|
151
151
|
},
|
|
152
|
-
"gitHead": "
|
|
152
|
+
"gitHead": "2f485afbabe92bb6e63b09c4e69cb2ae06d3d2be"
|
|
153
153
|
}
|
|
@@ -2,6 +2,7 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
|
2
2
|
import { api, usePaymentContext } from '@blocklet/payment-react';
|
|
3
3
|
import type { TCustomer } from '@blocklet/payment-types';
|
|
4
4
|
import { Add, Close } from '@mui/icons-material';
|
|
5
|
+
import { ClickAwayListener, Menu, MenuItem } from '@mui/material';
|
|
5
6
|
import { Box, styled } from '@mui/system';
|
|
6
7
|
import { useEffect, useState } from 'react';
|
|
7
8
|
|
|
@@ -41,6 +42,7 @@ type Props = {
|
|
|
41
42
|
|
|
42
43
|
export default function FilterTooolbar(props: Props) {
|
|
43
44
|
const { setSearch, search, status, currency } = props;
|
|
45
|
+
const isProduct = window.location.pathname.includes('product');
|
|
44
46
|
const handleSearch = (obj: any) => {
|
|
45
47
|
setSearch({
|
|
46
48
|
...search,
|
|
@@ -50,11 +52,15 @@ export default function FilterTooolbar(props: Props) {
|
|
|
50
52
|
|
|
51
53
|
return (
|
|
52
54
|
<Root>
|
|
53
|
-
<
|
|
55
|
+
<Box className="table-toolbar-left">
|
|
54
56
|
<SearchStatus setSearch={handleSearch} status={status} />
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
{isProduct ? null : (
|
|
58
|
+
<>
|
|
59
|
+
<SearchCustomers setSearch={handleSearch} />
|
|
60
|
+
{currency ? <SearchCurrency setSearch={handleSearch} /> : <SearchProducts setSearch={handleSearch} />}
|
|
61
|
+
</>
|
|
62
|
+
)}
|
|
63
|
+
</Box>
|
|
58
64
|
</Root>
|
|
59
65
|
);
|
|
60
66
|
}
|
|
@@ -72,13 +78,13 @@ SearchProducts.defaultProps = defaultProps;
|
|
|
72
78
|
SearchCustomers.defaultProps = defaultProps;
|
|
73
79
|
|
|
74
80
|
function SearchStatus({ status = [], setSearch }: Pick<Props, 'status' | 'setSearch'>) {
|
|
75
|
-
const [show, setShow] = useState(
|
|
81
|
+
const [show, setShow] = useState(null);
|
|
76
82
|
const [display, setDisplay] = useState('');
|
|
77
83
|
const { t } = useLocaleContext();
|
|
78
84
|
return (
|
|
79
85
|
<section
|
|
80
|
-
onClick={() => {
|
|
81
|
-
setShow(
|
|
86
|
+
onClick={(e) => {
|
|
87
|
+
setShow(e.currentTarget as any);
|
|
82
88
|
}}>
|
|
83
89
|
<div className="option-btn">
|
|
84
90
|
{display ? (
|
|
@@ -90,6 +96,7 @@ function SearchStatus({ status = [], setSearch }: Pick<Props, 'status' | 'setSea
|
|
|
90
96
|
status: '',
|
|
91
97
|
});
|
|
92
98
|
setDisplay('');
|
|
99
|
+
setShow(null);
|
|
93
100
|
}}
|
|
94
101
|
/>
|
|
95
102
|
) : (
|
|
@@ -98,20 +105,29 @@ function SearchStatus({ status = [], setSearch }: Pick<Props, 'status' | 'setSea
|
|
|
98
105
|
{t('common.status')}
|
|
99
106
|
<span>{display}</span>
|
|
100
107
|
</div>
|
|
101
|
-
<
|
|
108
|
+
<Menu
|
|
109
|
+
anchorEl={show}
|
|
110
|
+
open={Boolean(show)}
|
|
111
|
+
onClose={(e: any) => {
|
|
112
|
+
e.stopPropagation();
|
|
113
|
+
setShow(null);
|
|
114
|
+
}}
|
|
115
|
+
className="status-options">
|
|
102
116
|
{status.map((x: any) => (
|
|
103
|
-
<
|
|
104
|
-
onClick={() => {
|
|
117
|
+
<MenuItem
|
|
118
|
+
onClick={(e) => {
|
|
119
|
+
e.stopPropagation();
|
|
105
120
|
setSearch({
|
|
106
121
|
status: x,
|
|
107
122
|
});
|
|
108
123
|
setDisplay(x);
|
|
124
|
+
setShow(null);
|
|
109
125
|
}}
|
|
110
126
|
key={x}>
|
|
111
127
|
{x}
|
|
112
|
-
</
|
|
128
|
+
</MenuItem>
|
|
113
129
|
))}
|
|
114
|
-
</
|
|
130
|
+
</Menu>
|
|
115
131
|
</section>
|
|
116
132
|
);
|
|
117
133
|
}
|
|
@@ -128,7 +144,7 @@ function filterCurrency(methods: any) {
|
|
|
128
144
|
}
|
|
129
145
|
|
|
130
146
|
function SearchCurrency({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
131
|
-
const [show, setShow] = useState(
|
|
147
|
+
const [show, setShow] = useState(null);
|
|
132
148
|
const [display, setDisplay] = useState('');
|
|
133
149
|
const { settings } = usePaymentContext();
|
|
134
150
|
const currencies = filterCurrency(settings.paymentMethods);
|
|
@@ -136,8 +152,8 @@ function SearchCurrency({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
136
152
|
|
|
137
153
|
return (
|
|
138
154
|
<section
|
|
139
|
-
onClick={() => {
|
|
140
|
-
setShow(
|
|
155
|
+
onClick={(e) => {
|
|
156
|
+
setShow(e.currentTarget as any);
|
|
141
157
|
}}>
|
|
142
158
|
<div className="option-btn">
|
|
143
159
|
{display ? (
|
|
@@ -149,6 +165,7 @@ function SearchCurrency({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
149
165
|
currency_id: '',
|
|
150
166
|
});
|
|
151
167
|
setDisplay('');
|
|
168
|
+
setShow(null);
|
|
152
169
|
}}
|
|
153
170
|
/>
|
|
154
171
|
) : (
|
|
@@ -157,27 +174,36 @@ function SearchCurrency({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
157
174
|
{t('common.currency')}
|
|
158
175
|
<span>{display}</span>
|
|
159
176
|
</div>
|
|
160
|
-
<
|
|
177
|
+
<Menu
|
|
178
|
+
anchorEl={show}
|
|
179
|
+
open={Boolean(show)}
|
|
180
|
+
onClose={(e: any) => {
|
|
181
|
+
e.stopPropagation();
|
|
182
|
+
setShow(null);
|
|
183
|
+
}}
|
|
184
|
+
className="status-options">
|
|
161
185
|
{Object.keys(currencies).map((k: any) => (
|
|
162
|
-
<
|
|
163
|
-
onClick={() => {
|
|
186
|
+
<MenuItem
|
|
187
|
+
onClick={(e) => {
|
|
188
|
+
e.stopPropagation();
|
|
164
189
|
setSearch({
|
|
165
190
|
currency_id: currencies[k],
|
|
166
191
|
});
|
|
167
192
|
setDisplay(k);
|
|
193
|
+
setShow(null);
|
|
168
194
|
}}
|
|
169
195
|
key={k}>
|
|
170
196
|
{k}
|
|
171
|
-
</
|
|
197
|
+
</MenuItem>
|
|
172
198
|
))}
|
|
173
|
-
</
|
|
199
|
+
</Menu>
|
|
174
200
|
</section>
|
|
175
201
|
);
|
|
176
202
|
}
|
|
177
203
|
|
|
178
204
|
function SearchCustomers({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
179
205
|
const [customers, setCustomers] = useState([]);
|
|
180
|
-
const [show, setShow] = useState(
|
|
206
|
+
const [show, setShow] = useState(null);
|
|
181
207
|
const [text, setText] = useState('');
|
|
182
208
|
const [display, setDisplay] = useState('');
|
|
183
209
|
const { t } = useLocaleContext();
|
|
@@ -199,7 +225,7 @@ function SearchCustomers({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
199
225
|
}, [text]);
|
|
200
226
|
|
|
201
227
|
return (
|
|
202
|
-
<section onClick={() => setShow(
|
|
228
|
+
<section onClick={(e: any) => setShow(e.currentTarget)}>
|
|
203
229
|
<div className="option-btn">
|
|
204
230
|
{display ? (
|
|
205
231
|
<Close
|
|
@@ -210,6 +236,7 @@ function SearchCustomers({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
210
236
|
customer_id: '',
|
|
211
237
|
});
|
|
212
238
|
setDisplay('');
|
|
239
|
+
setShow(null);
|
|
213
240
|
}}
|
|
214
241
|
/>
|
|
215
242
|
) : (
|
|
@@ -218,22 +245,41 @@ function SearchCustomers({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
218
245
|
{t('common.customer')}
|
|
219
246
|
<span>{display}</span>
|
|
220
247
|
</div>
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
248
|
+
|
|
249
|
+
<Menu
|
|
250
|
+
anchorEl={show}
|
|
251
|
+
open={Boolean(show)}
|
|
252
|
+
onClose={(e: any) => {
|
|
253
|
+
e.stopPropagation();
|
|
254
|
+
setShow(null);
|
|
255
|
+
}}>
|
|
256
|
+
<section style={{ padding: '10px 10px 0 10px' }}>
|
|
257
|
+
<input
|
|
258
|
+
style={{
|
|
259
|
+
width: '100%',
|
|
260
|
+
boxSizing: 'border-box',
|
|
261
|
+
border: '1px solid #eee',
|
|
262
|
+
padding: '5px 10px',
|
|
263
|
+
borderRadius: '20px',
|
|
264
|
+
marginBottom: '10px',
|
|
265
|
+
}}
|
|
266
|
+
type="text"
|
|
267
|
+
placeholder="search customers"
|
|
268
|
+
onChange={(e) => {
|
|
269
|
+
setText(e.target.value);
|
|
270
|
+
}}
|
|
271
|
+
/>
|
|
272
|
+
</section>
|
|
229
273
|
{customers.map((x: any) => (
|
|
230
|
-
<
|
|
274
|
+
<MenuItem
|
|
231
275
|
key={x.id}
|
|
232
|
-
onClick={() => {
|
|
276
|
+
onClick={(e) => {
|
|
277
|
+
e.stopPropagation();
|
|
233
278
|
setSearch({
|
|
234
279
|
customer_id: x.id,
|
|
235
280
|
});
|
|
236
281
|
setDisplay(x.name);
|
|
282
|
+
setShow(null);
|
|
237
283
|
}}>
|
|
238
284
|
<InfoCard
|
|
239
285
|
logo={`/.well-known/service/user/avatar/${x.did}?imageFilter=resize&w=48&h=48`}
|
|
@@ -241,9 +287,9 @@ function SearchCustomers({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
241
287
|
key={x.id}
|
|
242
288
|
description={`${x.did.slice(0, 6)}...${x.did.slice(-6)}`}
|
|
243
289
|
/>
|
|
244
|
-
</
|
|
290
|
+
</MenuItem>
|
|
245
291
|
))}
|
|
246
|
-
</
|
|
292
|
+
</Menu>
|
|
247
293
|
</section>
|
|
248
294
|
);
|
|
249
295
|
}
|
|
@@ -275,37 +321,50 @@ function SearchProducts({ setSearch }: Pick<Props, 'setSearch'>) {
|
|
|
275
321
|
}, [price]);
|
|
276
322
|
|
|
277
323
|
return (
|
|
278
|
-
<
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
324
|
+
<ClickAwayListener
|
|
325
|
+
onClickAway={(e) => {
|
|
326
|
+
e.stopPropagation();
|
|
327
|
+
setShow(false);
|
|
328
|
+
}}>
|
|
329
|
+
<section onClick={() => setShow(!show)}>
|
|
330
|
+
<div className="option-btn">
|
|
331
|
+
{display ? (
|
|
332
|
+
<Close
|
|
333
|
+
sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.2rem' }}
|
|
334
|
+
onClick={(e) => {
|
|
335
|
+
e.stopPropagation();
|
|
336
|
+
setSearch({
|
|
337
|
+
q: '',
|
|
338
|
+
});
|
|
339
|
+
setDisplay('');
|
|
340
|
+
setShow(false);
|
|
341
|
+
}}
|
|
342
|
+
/>
|
|
343
|
+
) : (
|
|
344
|
+
<Add sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.2rem' }} />
|
|
345
|
+
)}
|
|
346
|
+
{t('admin.subscription.product')}
|
|
347
|
+
<span>{display}</span>
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
<ul
|
|
351
|
+
className="status-options"
|
|
352
|
+
style={{ display: show ? 'block' : 'none' }}
|
|
353
|
+
onClick={(e) => e.stopPropagation()}>
|
|
354
|
+
<Box sx={{ height: '10px' }} />
|
|
355
|
+
<ProductsProvider>
|
|
356
|
+
<FilterProducts
|
|
357
|
+
hasSelected={() => false}
|
|
358
|
+
onSelect={(p: any) => {
|
|
359
|
+
setPrice(p);
|
|
360
|
+
setDisplay(`${p.productName}(${p.displayPrice})`);
|
|
361
|
+
setShow(false);
|
|
362
|
+
}}
|
|
363
|
+
/>
|
|
364
|
+
</ProductsProvider>
|
|
365
|
+
</ul>
|
|
366
|
+
</section>
|
|
367
|
+
</ClickAwayListener>
|
|
309
368
|
);
|
|
310
369
|
}
|
|
311
370
|
|
|
@@ -343,29 +402,21 @@ const Root = styled(Box)`
|
|
|
343
402
|
|
|
344
403
|
.status-options {
|
|
345
404
|
position: absolute;
|
|
346
|
-
|
|
405
|
+
box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14),
|
|
406
|
+
0px 3px 14px 2px rgba(0, 0, 0, 0.12);
|
|
407
|
+
padding: 0;
|
|
347
408
|
background: #fff;
|
|
348
409
|
border: 1px solid #eee;
|
|
349
|
-
border-radius: 5px;
|
|
350
410
|
z-index: 999999;
|
|
351
|
-
top:
|
|
411
|
+
top: 15px;
|
|
352
412
|
display: block;
|
|
353
413
|
max-height: 500px;
|
|
354
414
|
overflow-y: auto;
|
|
355
415
|
overflow-x: hidden;
|
|
356
416
|
}
|
|
357
417
|
|
|
358
|
-
.status-options input {
|
|
359
|
-
width: 100%;
|
|
360
|
-
border: 1px solid #eee;
|
|
361
|
-
padding: 5px 10px;
|
|
362
|
-
border-radius: 20px;
|
|
363
|
-
margin-bottom: 10px;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
418
|
.status-options li {
|
|
367
419
|
list-style: none;
|
|
368
|
-
padding: 5px;
|
|
369
420
|
line-height: normal;
|
|
370
421
|
}
|
|
371
422
|
|
|
@@ -3,12 +3,11 @@ import { getDurableData } from '@arcblock/ux/lib/Datatable';
|
|
|
3
3
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
4
4
|
import { Status, api, formatTime, usePaymentContext } from '@blocklet/payment-react';
|
|
5
5
|
import type { TProductExpanded } from '@blocklet/payment-types';
|
|
6
|
-
import {
|
|
7
|
-
import { useRequest } from 'ahooks';
|
|
6
|
+
import { CircularProgress } from '@mui/material';
|
|
8
7
|
import { useEffect, useState } from 'react';
|
|
9
8
|
import { useNavigate } from 'react-router-dom';
|
|
10
|
-
import useBus from 'use-bus';
|
|
11
9
|
|
|
10
|
+
import FilterTooolbar from '../../../../components/filter-toolbar';
|
|
12
11
|
import InfoCard from '../../../../components/info-card';
|
|
13
12
|
import ProductActions from '../../../../components/product/actions';
|
|
14
13
|
import Table from '../../../../components/table';
|
|
@@ -17,7 +16,13 @@ import { formatProductPrice } from '../../../../libs/util';
|
|
|
17
16
|
const fetchData = (params: Record<string, any> = {}): Promise<{ list: TProductExpanded[]; count: number }> => {
|
|
18
17
|
const search = new URLSearchParams();
|
|
19
18
|
Object.keys(params).forEach((key) => {
|
|
20
|
-
|
|
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));
|
|
21
26
|
});
|
|
22
27
|
return api.get(`/api/products?${search.toString()}`).then((res) => res.data);
|
|
23
28
|
};
|
|
@@ -29,24 +34,24 @@ export default function ProductsList() {
|
|
|
29
34
|
const { t, locale } = useLocaleContext();
|
|
30
35
|
const navigate = useNavigate();
|
|
31
36
|
const { settings } = usePaymentContext();
|
|
32
|
-
const [search, setSearch] = useState<{ active: string; pageSize: number; page:
|
|
37
|
+
const [search, setSearch] = useState<{ active: string; pageSize: number; page: any; q?: any; o?: any }>({
|
|
33
38
|
active: '',
|
|
34
39
|
pageSize: persisted.rowsPerPage || 20,
|
|
35
40
|
page: persisted.page ? persisted.page + 1 : 1,
|
|
36
41
|
});
|
|
37
42
|
|
|
38
|
-
const
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
refresh();
|
|
41
|
-
}, [search, refresh]);
|
|
43
|
+
const [data, setData] = useState({}) as any;
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
const refresh = () =>
|
|
46
|
+
fetchData(search).then((res: any) => {
|
|
47
|
+
setData(res);
|
|
48
|
+
});
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
refresh();
|
|
52
|
+
}, [search]);
|
|
48
53
|
|
|
49
|
-
if (
|
|
54
|
+
if (!data.list) {
|
|
50
55
|
return <CircularProgress />;
|
|
51
56
|
}
|
|
52
57
|
|
|
@@ -125,30 +130,45 @@ export default function ProductsList() {
|
|
|
125
130
|
<Table
|
|
126
131
|
durable={listKey}
|
|
127
132
|
durableKeys={['page', 'rowsPerPage']}
|
|
128
|
-
title={
|
|
129
|
-
<div className="table-toolbar-left">
|
|
130
|
-
<ToggleButtonGroup
|
|
131
|
-
value={search.active}
|
|
132
|
-
onChange={(_, value) => setSearch((x) => ({ ...x, active: value }))}
|
|
133
|
-
exclusive>
|
|
134
|
-
<ToggleButton value="">All</ToggleButton>
|
|
135
|
-
<ToggleButton value="true">Active</ToggleButton>
|
|
136
|
-
<ToggleButton value="false">Archived</ToggleButton>
|
|
137
|
-
</ToggleButtonGroup>
|
|
138
|
-
</div>
|
|
139
|
-
}
|
|
133
|
+
title={<FilterTooolbar setSearch={setSearch} search={search} status={['active', 'archived']} />}
|
|
140
134
|
data={data.list}
|
|
141
135
|
columns={columns}
|
|
142
136
|
options={{
|
|
143
137
|
count: data.count,
|
|
144
138
|
page: search.page - 1,
|
|
145
139
|
rowsPerPage: search.pageSize,
|
|
140
|
+
onColumnSortChange(_: any, order: any) {
|
|
141
|
+
setSearch({
|
|
142
|
+
...search,
|
|
143
|
+
q: search.q || {},
|
|
144
|
+
o: order,
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
onSearchChange: (text: string) => {
|
|
148
|
+
if (text) {
|
|
149
|
+
setSearch({
|
|
150
|
+
q: {
|
|
151
|
+
'like-description': text,
|
|
152
|
+
'like-name': text,
|
|
153
|
+
},
|
|
154
|
+
active: '',
|
|
155
|
+
pageSize: 100,
|
|
156
|
+
page: 1,
|
|
157
|
+
});
|
|
158
|
+
} else {
|
|
159
|
+
setSearch({
|
|
160
|
+
active: '',
|
|
161
|
+
pageSize: 100,
|
|
162
|
+
page: 1,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
},
|
|
146
166
|
onRowClick: (_: any, { dataIndex }: any) => {
|
|
147
167
|
const item = data.list[dataIndex] as TProductExpanded;
|
|
148
168
|
navigate(`/admin/products/${item.id}`);
|
|
149
169
|
},
|
|
150
170
|
}}
|
|
151
|
-
loading={
|
|
171
|
+
loading={!data.list}
|
|
152
172
|
onChange={onTableChange}
|
|
153
173
|
/>
|
|
154
174
|
);
|