new-marketplace

Форк
0
382 строки · 15.9 Кб
1
'use client';
2
import { CustomerService } from '../../../demo/service/CustomerService';
3
import { ProductService } from '../../../demo/service/ProductService';
4
import { FilterMatchMode, FilterOperator } from 'primereact/api';
5
import { Button } from 'primereact/button';
6
import { Calendar } from 'primereact/calendar';
7
import { Column, ColumnFilterApplyTemplateOptions, ColumnFilterClearTemplateOptions, ColumnFilterElementTemplateOptions } from 'primereact/column';
8
import { DataTable, DataTableExpandedRows, DataTableFilterMeta } from 'primereact/datatable';
9
import { Dropdown } from 'primereact/dropdown';
10
import { InputNumber } from 'primereact/inputnumber';
11
import { InputText } from 'primereact/inputtext';
12
import { MultiSelect } from 'primereact/multiselect';
13
import { ProgressBar } from 'primereact/progressbar';
14
import { Rating } from 'primereact/rating';
15
import { Slider } from 'primereact/slider';
16
import { ToggleButton } from 'primereact/togglebutton';
17
import { TriStateCheckbox } from 'primereact/tristatecheckbox';
18
import { classNames } from 'primereact/utils';
19
import React, { useEffect, useState } from 'react';
20
import type { Demo } from '@/types';
21

22
const TableDemo = () => {
23
    const [customers1, setCustomers1] = useState<Demo.Customer[]>([]);
24
    const [customers2, setCustomers2] = useState<Demo.Customer[]>([]);
25
    const [customers3, setCustomers3] = useState<Demo.Customer[]>([]);
26
    const [filters1, setFilters1] = useState<DataTableFilterMeta>({});
27
    const [loading1, setLoading1] = useState(true);
28
    const [loading2, setLoading2] = useState(true);
29
    const [idFrozen, setIdFrozen] = useState(false);
30
    const [products, setProducts] = useState<Demo.Product[]>([]);
31
    const [globalFilterValue1, setGlobalFilterValue1] = useState('');
32
    const [expandedRows, setExpandedRows] = useState<any[] | DataTableExpandedRows>([]);
33
    const [allExpanded, setAllExpanded] = useState(false);
34

35
    const representatives = [
36
        { name: 'Amy Elsner', image: 'amyelsner.png' },
37
        { name: 'Anna Fali', image: 'annafali.png' },
38
        { name: 'Asiya Javayant', image: 'asiyajavayant.png' },
39
        { name: 'Bernardo Dominic', image: 'bernardodominic.png' },
40
        { name: 'Elwin Sharvill', image: 'elwinsharvill.png' },
41
        { name: 'Ioni Bowcher', image: 'ionibowcher.png' },
42
        { name: 'Ivan Magalhaes', image: 'ivanmagalhaes.png' },
43
        { name: 'Onyama Limba', image: 'onyamalimba.png' },
44
        { name: 'Stephen Shaw', image: 'stephenshaw.png' },
45
        { name: 'XuXue Feng', image: 'xuxuefeng.png' }
46
    ];
47

48
    const statuses = ['unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal'];
49

50
    const clearFilter1 = () => {
51
        initFilters1();
52
    };
53

54
    const onGlobalFilterChange1 = (e: React.ChangeEvent<HTMLInputElement>) => {
55
        const value = e.target.value;
56
        let _filters1 = { ...filters1 };
57
        (_filters1['global'] as any).value = value;
58

59
        setFilters1(_filters1);
60
        setGlobalFilterValue1(value);
61
    };
62

63
    const renderHeader1 = () => {
64
        return (
65
            <div className="flex justify-content-between">
66
                <Button type="button" icon="pi pi-filter-slash" label="Clear" outlined onClick={clearFilter1} />
67
                <span className="p-input-icon-left">
68
                    <i className="pi pi-search" />
69
                    <InputText value={globalFilterValue1} onChange={onGlobalFilterChange1} placeholder="Keyword Search" />
70
                </span>
71
            </div>
72
        );
73
    };
74

75
    useEffect(() => {
76
        setLoading2(true);
77

78
        CustomerService.getCustomersLarge().then((data) => {
79
            setCustomers1(getCustomers(data));
80
            setLoading1(false);
81
        });
82
        CustomerService.getCustomersLarge().then((data) => {
83
            setCustomers2(getCustomers(data));
84
            setLoading2(false);
85
        });
86
        CustomerService.getCustomersMedium().then((data) => setCustomers3(data));
87
        ProductService.getProductsWithOrdersSmall().then((data) => setProducts(data));
88

89
        initFilters1();
90
    }, []);
91

92
    const balanceTemplate = (rowData: Demo.Customer) => {
93
        return (
94
            <div>
95
                <span className="text-bold">{formatCurrency(rowData.balance as number)}</span>
96
            </div>
97
        );
98
    };
99

100
    const getCustomers = (data: Demo.Customer[]) => {
101
        return [...(data || [])].map((d) => {
102
            d.date = new Date(d.date);
103
            return d;
104
        });
105
    };
106

107
    const formatDate = (value: Date) => {
108
        return value.toLocaleDateString('en-US', {
109
            day: '2-digit',
110
            month: '2-digit',
111
            year: 'numeric'
112
        });
113
    };
114

115
    const formatCurrency = (value: number) => {
116
        return value.toLocaleString('en-US', {
117
            style: 'currency',
118
            currency: 'USD'
119
        });
120
    };
121

122
    const initFilters1 = () => {
123
        setFilters1({
124
            global: { value: null, matchMode: FilterMatchMode.CONTAINS },
125
            name: {
126
                operator: FilterOperator.AND,
127
                constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
128
            },
129
            'country.name': {
130
                operator: FilterOperator.AND,
131
                constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
132
            },
133
            representative: { value: null, matchMode: FilterMatchMode.IN },
134
            date: {
135
                operator: FilterOperator.AND,
136
                constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
137
            },
138
            balance: {
139
                operator: FilterOperator.AND,
140
                constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }]
141
            },
142
            status: {
143
                operator: FilterOperator.OR,
144
                constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }]
145
            },
146
            activity: { value: null, matchMode: FilterMatchMode.BETWEEN },
147
            verified: { value: null, matchMode: FilterMatchMode.EQUALS }
148
        });
149
        setGlobalFilterValue1('');
150
    };
151

152
    const countryBodyTemplate = (rowData: Demo.Customer) => {
153
        return (
154
            <React.Fragment>
155
                <img alt="flag" src={`/demo/images/flag/flag_placeholder.png`} className={`flag flag-${rowData.country.code}`} width={30} />
156
                <span style={{ marginLeft: '.5em', verticalAlign: 'middle' }}>{rowData.country.name}</span>
157
            </React.Fragment>
158
        );
159
    };
160

161
    const filterClearTemplate = (options: ColumnFilterClearTemplateOptions) => {
162
        return <Button type="button" icon="pi pi-times" onClick={options.filterClearCallback} severity="secondary"></Button>;
163
    };
164

165
    const filterApplyTemplate = (options: ColumnFilterApplyTemplateOptions) => {
166
        return <Button type="button" icon="pi pi-check" onClick={options.filterApplyCallback} severity="success"></Button>;
167
    };
168

169
    const representativeBodyTemplate = (rowData: Demo.Customer) => {
170
        const representative = rowData.representative;
171
        return (
172
            <React.Fragment>
173
                <img
174
                    alt={representative.name}
175
                    src={`/demo/images/avatar/${representative.image}`}
176
                    onError={(e) => ((e.target as HTMLImageElement).src = 'https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png')}
177
                    width={32}
178
                    style={{ verticalAlign: 'middle' }}
179
                />
180
                <span style={{ marginLeft: '.5em', verticalAlign: 'middle' }}>{representative.name}</span>
181
            </React.Fragment>
182
        );
183
    };
184

185
    const representativeFilterTemplate = (options: ColumnFilterElementTemplateOptions) => {
186
        return (
187
            <>
188
                <div className="mb-3 text-bold">Agent Picker</div>
189
                <MultiSelect value={options.value} options={representatives} itemTemplate={representativesItemTemplate} onChange={(e) => options.filterCallback(e.value)} optionLabel="name" placeholder="Any" className="p-column-filter" />
190
            </>
191
        );
192
    };
193

194
    const representativesItemTemplate = (option: any) => {
195
        return (
196
            <div className="p-multiselect-representative-option">
197
                <img alt={option.name} src={`/demo/images/avatar/${option.image}`} width={32} style={{ verticalAlign: 'middle' }} />
198
                <span style={{ marginLeft: '.5em', verticalAlign: 'middle' }}>{option.name}</span>
199
            </div>
200
        );
201
    };
202

203
    const dateBodyTemplate = (rowData: Demo.Customer) => {
204
        return formatDate(rowData.date);
205
    };
206

207
    const dateFilterTemplate = (options: ColumnFilterElementTemplateOptions) => {
208
        return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />;
209
    };
210

211
    const balanceBodyTemplate = (rowData: Demo.Customer) => {
212
        return formatCurrency(rowData.balance as number);
213
    };
214

215
    const balanceFilterTemplate = (options: ColumnFilterElementTemplateOptions) => {
216
        return <InputNumber value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} mode="currency" currency="USD" locale="en-US" />;
217
    };
218

219
    const statusBodyTemplate = (rowData: Demo.Customer) => {
220
        return <span className={`customer-badge status-${rowData.status}`}>{rowData.status}</span>;
221
    };
222

223
    const statusFilterTemplate = (options: ColumnFilterElementTemplateOptions) => {
224
        return <Dropdown value={options.value} options={statuses} onChange={(e) => options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder="Select a Status" className="p-column-filter" showClear />;
225
    };
226

227
    const statusItemTemplate = (option: any) => {
228
        return <span className={`customer-badge status-${option}`}>{option}</span>;
229
    };
230

231
    const activityBodyTemplate = (rowData: Demo.Customer) => {
232
        return <ProgressBar value={rowData.activity} showValue={false} style={{ height: '.5rem' }}></ProgressBar>;
233
    };
234

235
    const activityFilterTemplate = (options: ColumnFilterElementTemplateOptions) => {
236
        return (
237
            <React.Fragment>
238
                <Slider value={options.value} onChange={(e) => options.filterCallback(e.value)} range className="m-3"></Slider>
239
                <div className="flex align-items-center justify-content-between px-2">
240
                    <span>{options.value ? options.value[0] : 0}</span>
241
                    <span>{options.value ? options.value[1] : 100}</span>
242
                </div>
243
            </React.Fragment>
244
        );
245
    };
246

247
    const verifiedBodyTemplate = (rowData: Demo.Customer) => {
248
        return (
249
            <i
250
                className={classNames('pi', {
251
                    'text-green-500 pi-check-circle': rowData.verified,
252
                    'text-pink-500 pi-times-circle': !rowData.verified
253
                })}
254
            ></i>
255
        );
256
    };
257

258
    const verifiedFilterTemplate = (options: ColumnFilterElementTemplateOptions) => {
259
        return <TriStateCheckbox value={options.value} onChange={(e) => options.filterCallback(e.value)} />;
260
    };
261

262
    const toggleAll = () => {
263
        if (allExpanded) collapseAll();
264
        else expandAll();
265
    };
266

267
    const expandAll = () => {
268
        let _expandedRows = {} as { [key: string]: boolean };
269
        products.forEach((p) => (_expandedRows[`${p.id}`] = true));
270

271
        setExpandedRows(_expandedRows);
272
        setAllExpanded(true);
273
    };
274

275
    const collapseAll = () => {
276
        setExpandedRows([]);
277
        setAllExpanded(false);
278
    };
279

280
    const amountBodyTemplate = (rowData: Demo.Customer) => {
281
        return formatCurrency(rowData.amount as number);
282
    };
283

284
    const statusOrderBodyTemplate = (rowData: Demo.Customer) => {
285
        return <span className={`order-badge order-${rowData.status?.toLowerCase()}`}>{rowData.status}</span>;
286
    };
287

288
    const searchBodyTemplate = () => {
289
        return <Button icon="pi pi-search" />;
290
    };
291

292
    const imageBodyTemplate = (rowData: Demo.Product) => {
293
        return <img src={`/demo/images/product/${rowData.image}`} onError={(e) => ((e.target as HTMLImageElement).src = 'https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png')} alt={rowData.image} className="shadow-2" width={100} />;
294
    };
295

296
    const priceBodyTemplate = (rowData: Demo.Product) => {
297
        return formatCurrency(rowData.price as number);
298
    };
299

300
    const ratingBodyTemplate = (rowData: Demo.Product) => {
301
        return <Rating value={rowData.rating} readOnly cancel={false} />;
302
    };
303

304
    const statusBodyTemplate2 = (rowData: Demo.Product) => {
305
        return <span className={`product-badge status-${rowData.inventoryStatus?.toLowerCase()}`}>{rowData.inventoryStatus}</span>;
306
    };
307

308
    const rowExpansionTemplate = (data: Demo.Product) => {
309
        return (
310
            <div className="orders-subtable">
311
                <h5>Orders for {data.name}</h5>
312
                <DataTable value={data.orders} responsiveLayout="scroll">
313
                    <Column field="id" header="Id" sortable></Column>
314
                    <Column field="customer" header="Покупатель" sortable></Column>
315
                    <Column field="date" header="Дата" sortable></Column>
316
                    <Column field="amount" header="Количество" body={amountBodyTemplate} sortable></Column>
317
                    <Column field="status" header="Статус" body={statusOrderBodyTemplate} sortable></Column>
318
                    <Column headerStyle={{ width: '4rem' }} body={searchBodyTemplate}></Column>
319
                </DataTable>
320
            </div>
321
        );
322
    };
323

324
    const header = <Button icon={allExpanded ? 'pi pi-minus' : 'pi pi-plus'} label={allExpanded ? 'Свернуть все' : 'Развернуть все'} onClick={toggleAll} className="w-11rem" />;
325

326
    const headerTemplate = (data: Demo.Customer) => {
327
        return (
328
            <React.Fragment>
329
                <img alt={data.representative.name} src={`/demo/images/avatar/${data.representative.image}`} width="32" style={{ verticalAlign: 'middle' }} />
330
                <span className="font-bold ml-2">{data.representative.name}</span>
331
            </React.Fragment>
332
        );
333
    };
334

335
    const footerTemplate = (data: Demo.Customer) => {
336
        return (
337
            <React.Fragment>
338
                <td colSpan={4} style={{ textAlign: 'right' }} className="text-bold pr-6">
339
                    Total Customers
340
                </td>
341
                <td>{calculateCustomerTotal(data.representative.name)}</td>
342
            </React.Fragment>
343
        );
344
    };
345

346
    const calculateCustomerTotal = (name: string) => {
347
        let total = 0;
348

349
        if (customers3) {
350
            for (let customer of customers3) {
351
                if (customer.representative.name === name) {
352
                    total++;
353
                }
354
            }
355
        }
356

357
        return total;
358
    };
359

360
    const header1 = renderHeader1();
361

362
    return (
363
        <div className="grid">
364
            <div className="col-12">
365
                <div className="card">
366
                    <h5>Товары</h5>
367
                    <DataTable value={products} expandedRows={expandedRows} onRowToggle={(e) => setExpandedRows(e.data)} responsiveLayout="scroll" rowExpansionTemplate={rowExpansionTemplate} dataKey="id" header={header}>
368
                        <Column expander style={{ width: '3em' }} />
369
                        <Column field="name" header="Название" sortable />
370
                        <Column header="Изображение" body={imageBodyTemplate} />
371
                        <Column field="price" header="Стоимость" sortable body={priceBodyTemplate} />
372
                        <Column field="category" header="Категория" sortable />
373
                        <Column field="rating" header="Рейтинг" sortable body={ratingBodyTemplate} />
374
                        <Column field="inventoryStatus" header="Статус" sortable body={statusBodyTemplate2} />
375
                    </DataTable>
376
                </div>
377
            </div>
378
		</div>
379
    );
380
};
381

382
export default TableDemo;
383

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.