@visns-studio/visns-components 2.2.9 → 2.2.11

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.
@@ -1,1429 +1,1431 @@
1
- import React, { useCallback, useEffect, useState } from "react";
2
- import { useNavigate } from "react-router-dom";
3
- import axios from "axios";
4
- import debounce from "lodash.debounce";
5
- import moment from "moment";
6
- import numeral from "numeral";
7
- import Popup from "reactjs-popup";
8
- import parse from "html-react-parser";
9
- import NumberFilter from "@inovua/reactdatagrid-community/NumberFilter";
10
- import SelectFilter from "@inovua/reactdatagrid-community/SelectFilter";
11
- import DateFilter from "@inovua/reactdatagrid-community/DateFilter";
12
- import ReactDataGrid from "@inovua/reactdatagrid-community";
13
- import { confirmAlert } from "react-confirm-alert";
14
- import { toast } from "react-toastify";
15
- import Toggle from "react-toggle";
1
+ import React, { useCallback, useEffect, useState } from 'react';
2
+ import { useNavigate } from 'react-router-dom';
3
+ import axios from 'axios';
4
+ import debounce from 'lodash.debounce';
5
+ import moment from 'moment';
6
+ import numeral from 'numeral';
7
+ import Popup from 'reactjs-popup';
8
+ import parse from 'html-react-parser';
9
+ import NumberFilter from '@inovua/reactdatagrid-community/NumberFilter';
10
+ import SelectFilter from '@inovua/reactdatagrid-community/SelectFilter';
11
+ import DateFilter from '@inovua/reactdatagrid-community/DateFilter';
12
+ import ReactDataGrid from '@inovua/reactdatagrid-community';
13
+ import { confirmAlert } from 'react-confirm-alert';
14
+ import { toast } from 'react-toastify';
15
+ import Toggle from 'react-toggle';
16
16
  import {
17
- Backspace,
18
- Check,
19
- Clock,
20
- CloudDownload,
21
- Copy,
22
- Edit,
23
- Folder,
24
- Inbox,
25
- Network,
26
- Ribbon,
27
- Search,
28
- ShippingBoxV1,
29
- ToggleOff,
30
- ToggleOnFill,
31
- TriangleAlert,
32
- } from "akar-icons";
33
-
34
- import "@inovua/reactdatagrid-community/index.css";
35
- import "react-confirm-alert/src/react-confirm-alert.css";
36
- import "react-toggle/style.css";
37
-
38
- import CustomFetch from "../crm/Fetch";
39
- import Form from "./Form";
17
+ Backspace,
18
+ Check,
19
+ Clock,
20
+ CloudDownload,
21
+ Copy,
22
+ Edit,
23
+ Folder,
24
+ Inbox,
25
+ Network,
26
+ Ribbon,
27
+ Search,
28
+ ShippingBoxV1,
29
+ ToggleOff,
30
+ ToggleOnFill,
31
+ TriangleAlert,
32
+ } from 'akar-icons';
33
+
34
+ import '@inovua/reactdatagrid-community/index.css';
35
+ import 'react-confirm-alert/src/react-confirm-alert.css';
36
+ import 'react-toggle/style.css';
37
+
38
+ import CustomFetch from '../crm/Fetch';
39
+ import Form from './Form';
40
40
 
41
41
  const loadData = async (
42
- { skip, limit, sortInfo, currentData, filterValue, groupBy },
43
- search,
44
- ajaxSetting
42
+ { skip, limit, sortInfo, currentData, filterValue, groupBy },
43
+ search,
44
+ ajaxSetting
45
45
  ) => {
46
- const url = ajaxSetting.url;
47
- const page = Math.floor(skip / limit) + 1;
48
- const params = { page, sortInfo, take: limit, search: search, where: [] };
49
-
50
- if (sortInfo) {
51
- params.sortBy = sortInfo.name;
52
- params.sort = sortInfo.dir === 1 ? "asc" : "desc";
53
- }
54
-
55
- if (ajaxSetting && ajaxSetting.where) {
56
- params.where = ajaxSetting.where;
57
- }
58
-
59
- if (filterValue) {
60
- filterValue.forEach((fv) => {
61
- const identifier = fv.key ? fv.key : fv.name;
62
- const existingIndex = params.where.findIndex(
63
- (w) => w.id === identifier
64
- );
65
-
66
- if (fv.value !== null && fv.value !== "") {
67
- if (existingIndex !== -1) {
68
- params.where[existingIndex].value = fv.value;
69
- } else {
70
- params.where.push({
71
- id: identifier,
72
- value: fv.value,
73
- operator: fv.operator,
74
- });
75
- }
76
- } else {
77
- if (existingIndex !== -1) {
78
- params.where.splice(existingIndex, 1);
79
- }
80
- }
81
- });
82
- }
83
-
84
- try {
85
- const response = await axios.post(url, params);
86
- const { data, total } = response.data;
87
- return { data, count: total };
88
- } catch (error) {
89
- console.error("Error fetching data:", error);
90
- return { data: [], count: 0 };
91
- }
46
+ const url = ajaxSetting.url;
47
+ const page = Math.floor(skip / limit) + 1;
48
+ const params = { page, sortInfo, take: limit, search: search, where: [] };
49
+
50
+ if (sortInfo) {
51
+ params.sortBy = sortInfo.name;
52
+ params.sort = sortInfo.dir === 1 ? 'asc' : 'desc';
53
+ }
54
+
55
+ if (ajaxSetting && ajaxSetting.where) {
56
+ params.where = ajaxSetting.where;
57
+ }
58
+
59
+ if (filterValue) {
60
+ filterValue.forEach((fv) => {
61
+ const identifier = fv.key ? fv.key : fv.name;
62
+ const existingIndex = params.where.findIndex(
63
+ (w) => w.id === identifier
64
+ );
65
+
66
+ if (fv.value !== null && fv.value !== '') {
67
+ if (existingIndex !== -1) {
68
+ params.where[existingIndex].value = fv.value;
69
+ } else {
70
+ params.where.push({
71
+ id: identifier,
72
+ value: fv.value,
73
+ operator: fv.operator,
74
+ });
75
+ }
76
+ } else {
77
+ if (existingIndex !== -1) {
78
+ params.where.splice(existingIndex, 1);
79
+ }
80
+ }
81
+ });
82
+ }
83
+
84
+ try {
85
+ const response = await axios.post(url, params);
86
+ const { data, total } = response.data;
87
+ return { data, count: total };
88
+ } catch (error) {
89
+ console.error('Error fetching data:', error);
90
+ return { data: [], count: 0 };
91
+ }
92
92
  };
93
93
 
94
94
  const DataGrid = ({
95
- ajaxSetting,
96
- form,
97
- columns,
98
- settings,
99
- setFilterData,
100
- style,
101
- tableFilters,
102
- historySearch,
103
- historyUrl,
95
+ ajaxSetting,
96
+ form,
97
+ columns,
98
+ settings,
99
+ setFilterData,
100
+ style,
101
+ tableFilters,
102
+ historySearch,
103
+ historyUrl,
104
104
  }) => {
105
- const navigate = useNavigate();
106
-
107
- /** Modal States */
108
- const [formData, setFormData] = useState(form);
109
- const [formType, setFormType] = useState("");
110
- const [formId, setFormId] = useState(0);
111
- const [modalShow, setModalShow] = useState(false);
112
-
113
- /** Modal Functions */
114
- const childDropdownCallback = (data) => {
115
- let _form = { ...formData };
116
-
117
- if (formData.fields.length > 0) {
118
- formData.fields.forEach((a, b) => {
119
- if (a.id === data.id) {
120
- _form.fields[b].options = data.data;
121
- }
122
- });
123
- }
124
-
125
- setFormData(_form);
126
- };
127
-
128
- const modalOpen = (formType, formId) => {
129
- setModalShow(true);
130
- setFormType(formType);
131
- setFormId(formId);
132
- };
133
-
134
- const modalClose = () => {
135
- setModalShow(false);
136
- };
137
-
138
- /** Table States */
139
- const [dataReload, setDataReload] = useState(0);
140
- const [dSearch, setDSearch] = useState("");
141
- const data = useCallback(
142
- (params) => {
143
- const sqlResult = loadData(params, dSearch, ajaxSetting);
144
-
145
- sqlResult.then((res) => {
146
- setDataCount(res.count);
147
- });
148
-
149
- return sqlResult;
150
- },
151
- [ajaxSetting, dataReload, dSearch]
152
- );
153
- const [filterDataSource, setFilterDataSource] = useState([]);
154
- const [filterValue, setFilterValue] = useState([]);
155
- const [gridColumns, setGridColumns] = useState([]);
156
- const [limit, setLimit] = useState(ajaxSetting.take || 10);
157
- const [search, setSearch] = useState("");
158
- const sortInfo =
159
- ajaxSetting.sortBy && ajaxSetting.sort
160
- ? {
161
- name: ajaxSetting.sortBy,
162
- dir: ajaxSetting.sort === "asc" ? 1 : -1,
163
- }
164
- : null;
165
-
166
- /** Table Functions */
167
- const handleChangeSearch = (e) => {
168
- const { value } = e.target;
169
- setSearch(value);
170
- };
171
-
172
- const handleSettingClick = (s, d) => {
173
- switch (s.id) {
174
- case "update":
175
- modalOpen("update", d.id);
176
- break;
177
- case "delete":
178
- confirmAlert({
179
- title: "Delete Item",
180
- message: `Are you sure you want to delete ${
181
- d.name ? d.name : d.label ? d.label : "this item"
182
- }?`,
183
- buttons: [
184
- {
185
- label: "Yes",
186
- onClick: () =>
187
- CustomFetch(
188
- form.url + "/" + d[form.primaryKey],
189
- "DELETE",
190
- {},
191
- (result) => {
192
- if (result.error === "") {
193
- const min = 0;
194
- const max = 999999999;
195
- const randomNumber = Math.floor(
196
- Math.random() *
197
- (max - min + 1) +
198
- min
199
- );
200
-
201
- setDataReload(randomNumber);
202
-
203
- toast.success(
204
- `The selected item has been deleted.`
205
- );
206
- } else {
207
- toast.error(String(result.error));
208
- }
209
- }
210
- ),
211
- },
212
- {
213
- label: "No",
214
- onClick: () => close(),
215
- },
216
- ],
217
- });
218
- break;
219
- default:
220
- confirmAlert({
221
- title: s.title,
222
- message: "",
223
- buttons: [
224
- {
225
- label: "Yes",
226
- onClick: () =>
227
- CustomFetch(
228
- s.url + "/" + d[form.primaryKey],
229
- s.method,
230
- {},
231
- function (result) {
232
- if (result.error === "") {
233
- const min = 0;
234
- const max = 999999999;
235
- const randomNumber = Math.floor(
236
- Math.random() *
237
- (max - min + 1) +
238
- min
239
- );
240
-
241
- setDataReload(randomNumber);
242
-
243
- toast.success(String(s.title));
244
- } else {
245
- toast.error(String(result.error));
246
- }
247
- }
248
- ),
249
- },
250
- {
251
- label: "No",
252
- onClick: () => close(),
253
- },
254
- ],
255
- });
256
- break;
257
- }
258
- };
259
-
260
- const handleReload = () => {
261
- const min = 0;
262
- const max = 999999999;
263
- const randomNumber = Math.floor(Math.random() * (max - min + 1) + min);
264
-
265
- setDataReload(randomNumber);
266
- };
267
-
268
- const onRowClick = useCallback((rowProps, event) => {
269
- const cellElement = event.target.closest(".InovuaReactDataGrid__cell");
270
- const columnIndex = Array.from(cellElement.parentNode.children).indexOf(
271
- cellElement
272
- );
273
-
274
- let proceed = true;
275
-
276
- columns.forEach((a, b) => {
277
- if (
278
- a.id === rowProps.columns[columnIndex].id &&
279
- a.type === "toggle"
280
- ) {
281
- proceed = false;
282
- }
283
- });
284
-
285
- if (proceed) {
286
- if (
287
- rowProps.columns[columnIndex].link &&
288
- rowProps.columns[columnIndex].link.url
289
- ) {
290
- if (rowProps.columns[columnIndex].link.folder) {
291
- window.location.href =
292
- rowProps.columns[columnIndex].link.url +
293
- rowProps.data[rowProps.columns[columnIndex].link.key] +
294
- "/" +
295
- rowProps.columns[columnIndex].link.folder;
296
- } else {
297
- navigate(
298
- `${rowProps.columns[columnIndex].link.url}${
299
- rowProps.data[
300
- rowProps.columns[columnIndex].link.key
301
- ]
302
- }`,
303
- {
304
- state: {
305
- form: form,
306
- },
307
- }
308
- );
309
- }
310
- } else {
311
- modalOpen("update", rowProps.data[form.primaryKey]);
312
- }
313
- }
314
- }, []);
315
-
316
- const onRenderRow = useCallback((rowProps) => {
317
- // save the original handlers to be called later
318
- const { onClick } = rowProps;
319
-
320
- rowProps.onClick = (event) => {
321
- onRowClick(rowProps, event);
322
- if (onClick) {
323
- onClick(event);
324
- }
325
- };
326
- }, []);
327
-
328
- const sortTrigger = () => {
329
- const url = form.url.replace("/ajax", "");
330
- console.info(url);
331
- const newState = {
332
- form: form,
333
- };
334
-
335
- navigate(`${url}/sort`, {
336
- state: newState,
337
- });
338
- };
339
-
340
- /** Table Hooks */
341
- useEffect(() => {
342
- const delayedSetDSearch = debounce(() => {
343
- setDSearch(search);
344
- }, 300); // Adjust the delay (in milliseconds) according to your needs
345
-
346
- delayedSetDSearch();
347
-
348
- return delayedSetDSearch.cancel; // Cleanup the debounce timer on unmount
349
- }, [search, setDSearch]);
350
-
351
- const renderSetting = (s, d) => {
352
- let iconStyle = {};
353
-
354
- if (s.active) {
355
- if (
356
- d.hasOwnProperty(s.active.id) &&
357
- !s.active.hasOwnProperty("type") &&
358
- d[s.active.id] === s.active.value
359
- ) {
360
- iconStyle = {
361
- color: s.active.colour,
362
- };
363
- } else if (s.active.hasOwnProperty("type")) {
364
- switch (s.active.type) {
365
- case "greater":
366
- if (d[s.active.id] > s.active.value) {
367
- iconStyle = {
368
- color: s.active.colour,
369
- };
370
- }
371
- break;
372
- case "not null":
373
- if (d[s.active.id] !== null) {
374
- iconStyle = {
375
- color: s.active.colour,
376
- };
377
- }
378
- break;
379
- default:
380
- break;
381
- }
382
- }
383
- }
384
-
385
- const getIconComponent = (IconComponent) => (
386
- <IconComponent
387
- data-tooltip-id="system-tooltip"
388
- data-tooltip-content={
389
- iconStyle && iconStyle.color ? s.active.title : s.title
390
- }
391
- strokeWidth={2}
392
- size={18}
393
- className="tdaction"
394
- style={iconStyle}
395
- />
396
- );
397
-
398
- switch (s.id) {
399
- case "complete":
400
- return getIconComponent(Check);
401
- case "delete":
402
- return getIconComponent(Backspace);
403
- case "primary":
404
- return getIconComponent(Ribbon);
405
- case "ssa":
406
- return getIconComponent(Clock);
407
- case "update":
408
- return getIconComponent(Edit);
409
- default:
410
- return null;
411
- }
412
- };
413
-
414
- const renderColumnContextMenu = useCallback((menuProps, { cellProps }) => {
415
- const filteredItems = menuProps.items
416
- .map((item, key) => {
417
- if (key >= 6 && key <= 9) {
418
- return null; // Skip items with keys 6-9 [lock columns setting]
419
- }
420
- return item;
421
- })
422
- .filter(Boolean); // Filter out any null items
423
-
424
- menuProps.items = filteredItems;
425
- }, []);
426
-
427
- useEffect(() => {
428
- const renderColumn = (column) => {
429
- let childValue;
430
- let date;
431
- let filterEditor = null;
432
- let filterEditorProps = null;
433
- let fileUrl = null;
434
- let icons = [];
435
- let relationName;
436
- let selectedDataSource = null;
437
- let stage;
438
- let style;
439
- let value;
440
-
441
- const commonProps = {
442
- header: column.label,
443
- defaultFlex: 1,
444
- link: column.link ? column.link : {},
445
- minWidth:
446
- column.minWidth && column.minWidth > 0
447
- ? column.minWidth
448
- : undefined,
449
- maxWidth:
450
- column.maxWidth && column.maxWidth > 0
451
- ? column.maxWidth
452
- : undefined,
453
- };
454
-
455
- switch (column.type) {
456
- case "address":
457
- return {
458
- ...commonProps,
459
- name: `${column.type}.${column.id}`,
460
- render: ({ data }) => {
461
- if (data.address1) {
462
- value += `${data.address1} `;
463
- }
464
-
465
- if (data.address2) {
466
- value += `${data.address2} `;
467
- }
468
-
469
- if (data.suburb) {
470
- value += `${data.suburb} `;
471
- }
472
-
473
- if (data.postcode) {
474
- value += `${data.postcode} `;
475
- }
476
- },
477
- };
478
- case "age":
479
- return {
480
- ...commonProps,
481
- name: `${column.type}.${column.id}`,
482
- render: ({ data }) => {
483
- value = column.id.reduce((acc, id) => {
484
- if (acc === "") {
485
- return data[id];
486
- } else {
487
- return acc[id];
488
- }
489
- }, "");
490
-
491
- if (value !== "" && value !== null) {
492
- date = moment(value);
493
-
494
- return (
495
- <span>
496
- {moment().diff(
497
- date,
498
- column.duration
499
- ? column.duration
500
- : "years"
501
- )}
502
- </span>
503
- );
504
- } else {
505
- return null;
506
- }
507
- },
508
- };
509
- case "arrayCount":
510
- return {
511
- ...commonProps,
512
- name: `${column.type}.${column.id}`,
513
- sortable: false,
514
- render: ({ data }) => {
515
- if (data && data[column.id]) {
516
- return data[column.id].length;
517
- } else {
518
- return null;
519
- }
520
- },
521
- };
522
- case "coding":
523
- return {
524
- ...commonProps,
525
- name: "audits.name",
526
- sortable: false,
527
- render: ({ data }) => {
528
- if (data) {
529
- return handleCoding(column, data);
530
- } else {
531
- return null;
532
- }
533
- },
534
- };
535
- case "created_by":
536
- return {
537
- ...commonProps,
538
- name: "audits.name",
539
- sortable: false,
540
- render: ({ data }) => {
541
- if (
542
- data.audits[0] &&
543
- data.audits[0].user &&
544
- data.audits[0].user.name
545
- ) {
546
- value = data.audits[0].user.name;
547
-
548
- return <span>{value}</span>;
549
- } else {
550
- return null;
551
- }
552
- },
553
- };
554
- case "currency":
555
- return {
556
- ...commonProps,
557
- name: column.id,
558
- render: ({ data }) => {
559
- if (data) {
560
- data = numeral(data[column.id]).format(
561
- "$0,0.00"
562
- );
563
-
564
- return <span>{data}</span>;
565
- } else {
566
- return null;
567
- }
568
- },
569
- };
570
- case "date":
571
- if (column.filter && column.filter.type) {
572
- filterEditor = DateFilter;
573
- filterEditorProps = (props, { index }) => {
574
- return {
575
- dateFormat: "DD-MM-YYYY",
576
- placeholder: "All Dates",
577
- };
578
- };
579
- } else {
580
- filterEditor = null;
581
- filterEditorProps = null;
582
- }
583
-
584
- return {
585
- ...commonProps,
586
- name: column.id,
587
- filterEditor: filterEditor,
588
- filterEditorProps: filterEditorProps,
589
- render: ({ data }) => {
590
- if (
591
- data &&
592
- data[column.id] &&
593
- moment(data[column.id]).isValid() &&
594
- moment(data[column.id]).format("YYYY-MM-DD") !==
595
- "1970-01-01"
596
- ) {
597
- const value = moment(data[column.id]).format(
598
- column.format || "DD-MM-YYYY"
599
- );
600
- style = {};
601
-
602
- if (
603
- column.active &&
604
- column.active.id &&
605
- column.active.value === "expired"
606
- ) {
607
- if (
608
- data[column.active.id] &&
609
- moment(data[column.active.id]).isBefore(
610
- moment()
611
- )
612
- ) {
613
- style = {
614
- color: column.active.colour,
615
- };
616
- }
617
- }
618
-
619
- return <span style={style}>{value}</span>;
620
- } else {
621
- return null;
622
- }
623
- },
624
- };
625
- case "datetime":
626
- if (column.filter && column.filter.type) {
627
- filterEditor = DateFilter;
628
- filterEditorProps = (props, { index }) => {
629
- return {
630
- dateFormat: "DD-MM-YYYY",
631
- placeholder: "All Dates",
632
- };
633
- };
634
- } else {
635
- filterEditor = null;
636
- filterEditorProps = null;
637
- }
638
-
639
- return {
640
- ...commonProps,
641
- name: column.id,
642
- filterEditor: filterEditor,
643
- filterEditorProps: filterEditorProps,
644
- render: ({ data }) => {
645
- if (
646
- data &&
647
- data[column.id] &&
648
- moment(data[column.id]).isValid() &&
649
- moment(data[column.id]).format("YYYY-MM-DD") !==
650
- "1970-01-01"
651
- ) {
652
- data = moment(data[column.id]).format(
653
- column.format
654
- ? column.format
655
- : "DD-MM-YYYY hh:mm A"
656
- );
657
-
658
- return <span>{data}</span>;
659
- } else {
660
- return null;
661
- }
662
- },
663
- };
664
- case "file":
665
- return {
666
- ...commonProps,
667
- name: column.id,
668
- sortable: false,
669
- render: ({ data }) => {
670
- if (data) {
671
- return (
672
- <span>
673
- <CloudDownload
674
- data-tooltip-id="system-tooltip"
675
- data-tooltip-content="Download File"
676
- strokeWidth={2}
677
- size={18}
678
- className="tdaction"
679
- />
680
- </span>
681
- );
682
- } else {
683
- return null;
684
- }
685
- },
686
- };
687
- case "icons":
688
- return {
689
- ...commonProps,
690
- name: column.id,
691
- sortable: false,
692
- render: ({ data }) => {
693
- icons = [];
694
-
695
- if (column.icons && column.icons.length > 0) {
696
- column.icons.forEach((icon) => {
697
- icons.push(
698
- <img
699
- src={icon.url}
700
- alt={icon.name}
701
- data-tooltip-id="system-tooltip"
702
- data-tooltip-content={icon.name}
703
- />
704
- );
705
- });
706
- }
707
-
708
- if (data) {
709
- return <span>{icons}</span>;
710
- } else {
711
- return null;
712
- }
713
- },
714
- };
715
- case "image":
716
- return {
717
- ...commonProps,
718
- name: column.id,
719
- render: ({ data }) => {
720
- if (data && data[column.id]) {
721
- const fileUrl =
722
- data[column.id][0]?.file_url ||
723
- data[column.id]?.file_url;
724
-
725
- if (fileUrl) {
726
- return (
727
- <span>
728
- {parse(
729
- `<img width="150" src="${fileUrl}" />`
730
- )}
731
- </span>
732
- );
733
- }
734
- }
735
-
736
- return null;
737
- },
738
- };
739
- case "json":
740
- return {
741
- ...commonProps,
742
- name: column.id,
743
- render: ({ data }) => {
744
- if (
745
- data &&
746
- data[column.id] &&
747
- data[column.id][column.jsonData]
748
- ) {
749
- data = data[column.id][column.jsonData];
750
-
751
- return <span>{data}</span>;
752
- } else {
753
- return null;
754
- }
755
- },
756
- };
757
- case "number":
758
- return {
759
- ...commonProps,
760
- name: column.id,
761
- type: "number",
762
- };
763
- case "option":
764
- selectedDataSource = filterDataSource.reduce((acc, fds) => {
765
- if (fds.id === column.id) {
766
- return fds.dataset;
767
- }
768
- return acc;
769
- }, null);
770
-
771
- if (
772
- column.filter &&
773
- column.filter.type &&
774
- column.filter.type === "select"
775
- ) {
776
- filterEditor = SelectFilter;
777
- filterEditorProps = {
778
- placeholder: column.filter.placeholder
779
- ? column.filter.placeholder
780
- : "All Options",
781
- dataSource: selectedDataSource,
782
- };
783
- } else {
784
- filterEditor = null;
785
- filterEditorProps = null;
786
- }
787
-
788
- return {
789
- ...commonProps,
790
- name: column.id,
791
- filterEditor: filterEditor,
792
- filterEditorProps: filterEditorProps,
793
- render: ({ data }) => {
794
- if (
795
- data &&
796
- column.options &&
797
- column.options[data[column.id]]
798
- ) {
799
- data = column.options[data[column.id]];
800
-
801
- return <span>{data}</span>;
802
- } else {
803
- return null;
804
- }
805
- },
806
- };
807
- case "placeholder":
808
- return {
809
- ...commonProps,
810
- name: column.id,
811
- sortable: false,
812
- render: ({ data }) => {
813
- if (data) {
814
- return <span>{column.placeholder}</span>;
815
- } else {
816
- return null;
817
- }
818
- },
819
- };
820
- case "relation":
821
- relationName = column.id.reduce(
822
- (acc, id) => acc + `${id}.`,
823
- ""
824
- );
825
- relationName += column.nameFrom;
826
-
827
- selectedDataSource = filterDataSource.reduce((acc, fds) => {
828
- if (fds.id === relationName) {
829
- return fds.dataset;
830
- }
831
- return acc;
832
- }, null);
833
-
834
- if (
835
- column.filter &&
836
- column.filter.type &&
837
- column.filter.type === "select"
838
- ) {
839
- filterEditor = SelectFilter;
840
- filterEditorProps = {
841
- placeholder: column.filter.placeholder
842
- ? column.filter.placeholder
843
- : "All Options",
844
- dataSource: selectedDataSource,
845
- };
846
- } else {
847
- filterEditor = null;
848
- filterEditorProps = null;
849
- }
850
-
851
- return {
852
- ...commonProps,
853
- name: relationName,
854
- sortable: false,
855
- filterEditor: filterEditor,
856
- filterEditorProps: filterEditorProps,
857
- render: ({ data }) => {
858
- value = column.id.reduce((acc, id) => {
859
- if (acc === "") {
860
- return data[id];
861
- } else {
862
- if (acc && acc[id]) {
863
- return acc[id];
864
- } else {
865
- return "";
866
- }
867
- }
868
- }, "");
869
-
870
- if (value) {
871
- if (Array.isArray(column.nameFrom)) {
872
- value = column.nameFrom
873
- .map((nf) => value[nf])
874
- .join(" ");
875
- } else {
876
- value = value[column.nameFrom];
877
- }
878
-
879
- if (
880
- column.placeholder &&
881
- column.placeholder !== ""
882
- ) {
883
- return <span>{column.placeholder}</span>;
884
- } else {
885
- return <span>{value}</span>;
886
- }
887
- } else {
888
- return null;
889
- }
890
- },
891
- };
892
- case "relationArray":
893
- relationName =
894
- column.id.reduce((acc, id) => acc + `${id}.`, "") +
895
- column.nameFrom;
896
-
897
- selectedDataSource = filterDataSource.reduce((acc, fds) => {
898
- if (fds.id === relationName) {
899
- return fds.dataset;
900
- }
901
- return acc;
902
- }, null);
903
-
904
- if (
905
- column.filter &&
906
- column.filter.type &&
907
- column.filter.type === "select"
908
- ) {
909
- filterEditor = SelectFilter;
910
- filterEditorProps = {
911
- placeholder: column.filter.placeholder
912
- ? column.filter.placeholder
913
- : "All Options",
914
- dataSource: selectedDataSource,
915
- };
916
- } else {
917
- filterEditor = null;
918
- filterEditorProps = null;
919
- }
920
-
921
- return {
922
- ...commonProps,
923
- name: relationName,
924
- sortable: false,
925
- filterEditor: filterEditor,
926
- filterEditorProps: filterEditorProps,
927
- render: ({ data }) => {
928
- const relationValue = column.id.reduce(
929
- (acc, id) =>
930
- acc === ""
931
- ? data[id]
932
- : acc && acc[id]
933
- ? acc[id]
934
- : "",
935
- ""
936
- );
937
-
938
- if (relationValue && Array.isArray(relationValue)) {
939
- const nameProperties = Array.isArray(
940
- column.nameFrom
941
- )
942
- ? column.nameFrom
943
- : [column.nameFrom];
944
-
945
- const values = relationValue
946
- .map((rv) => {
947
- if (
948
- column.childId &&
949
- Array.isArray(column.childId)
950
- ) {
951
- childValue = rv;
952
-
953
- column.childId.forEach((a) => {
954
- if (childValue[a]) {
955
- childValue = childValue[a];
956
- }
957
- });
958
-
959
- if (childValue) {
960
- const propertyValues =
961
- nameProperties
962
- .map(
963
- (prop) =>
964
- childValue[prop]
965
- )
966
- .filter(
967
- (value) =>
968
- value !==
969
- undefined &&
970
- value !== null
971
- );
972
- return propertyValues.join(" ");
973
- }
974
- } else {
975
- const propertyValues =
976
- nameProperties
977
- .map((prop) => rv[prop])
978
- .filter(
979
- (value) =>
980
- value !==
981
- undefined &&
982
- value !== null
983
- );
984
- return propertyValues.join(" ");
985
- }
986
- })
987
- .filter((value) => value !== "");
988
-
989
- if (values.length > 0) {
990
- let result = "";
991
-
992
- if (
993
- column.relation?.id &&
994
- column.relation?.key
995
- ) {
996
- const relationValue =
997
- column.relation.key.reduce(
998
- (acc, id) =>
999
- acc === ""
1000
- ? data[id]
1001
- : acc && acc[id]
1002
- ? acc[id]
1003
- : "",
1004
- ""
1005
- );
1006
-
1007
- result = `${
1008
- relationValue[column.relation.id]
1009
- }<br />`;
1010
- }
1011
-
1012
- if (
1013
- column.where &&
1014
- column.where.id &&
1015
- column.where.value
1016
- ) {
1017
- if (
1018
- data[column.where.id] ===
1019
- column.where.value
1020
- ) {
1021
- result += values.join("<br />");
1022
- }
1023
- } else {
1024
- result += values.join("<br />");
1025
- }
1026
-
1027
- return <span>{parse(result)}</span>;
1028
- }
1029
- }
1030
-
1031
- return null;
1032
- },
1033
- };
1034
- case "richtext":
1035
- return {
1036
- ...commonProps,
1037
- name: column.id,
1038
- render: ({ data }) => {
1039
- if (data && data[column.id]) {
1040
- return <span>{parse(data[column.id])}</span>;
1041
- } else {
1042
- return null;
1043
- }
1044
- },
1045
- };
1046
- case "stage":
1047
- return {
1048
- ...commonProps,
1049
- name: column.id,
1050
- sortable: false,
1051
- render: ({ data }) => {
1052
- stage = "";
1053
-
1054
- column.keyIds.forEach((a, b) => {
1055
- if (data[a] === 1) {
1056
- stage = column.valueIds[b];
1057
- }
1058
- });
1059
-
1060
- return <span>{stage}</span>;
1061
- },
1062
- };
1063
- case "time":
1064
- return {
1065
- ...commonProps,
1066
- name: column.id,
1067
- render: ({ data }) => {
1068
- if (
1069
- data &&
1070
- data[column.id] &&
1071
- moment(data[column.id]).isValid() &&
1072
- moment(data[column.id]).format("YYYY-MM-DD") !==
1073
- "1970-01-01"
1074
- ) {
1075
- data = moment(data[column.id]).format(
1076
- column.format ? column.format : "hh:mm A"
1077
- );
1078
-
1079
- return <span>{data}</span>;
1080
- } else {
1081
- return null;
1082
- }
1083
- },
1084
- };
1085
- case "toggle":
1086
- return {
1087
- ...commonProps,
1088
- name: column.id,
1089
- render: ({ data }) => {
1090
- return (
1091
- <Toggle
1092
- name={column.id}
1093
- checked={
1094
- data[column.id] === 1 ? true : false
1095
- }
1096
- onChange={() => {
1097
- CustomFetch(
1098
- `${column.url}/${data.id}`,
1099
- "POST",
1100
- {
1101
- [column.id]:
1102
- data[column.id] === 1
1103
- ? 0
1104
- : 1,
1105
- },
1106
- (res) => {
1107
- if (res.error === "") {
1108
- handleReload();
1109
- } else {
1110
- toast.error(res.error);
1111
- }
1112
- }
1113
- );
1114
- }}
1115
- />
1116
- );
1117
- },
1118
- };
1119
- case "url":
1120
- return {
1121
- ...commonProps,
1122
- name: column.id,
1123
- render: ({ data }) => {
1124
- if (data && data[column.id]) {
1125
- return (
1126
- <span>
1127
- <a
1128
- href={data[column.id]}
1129
- target="_blank"
1130
- >
1131
- Link
1132
- </a>
1133
- </span>
1134
- );
1135
- } else {
1136
- return null;
1137
- }
1138
- },
1139
- };
1140
- default:
1141
- selectedDataSource = filterDataSource.reduce((acc, fds) => {
1142
- if (fds.id === column.id) {
1143
- return fds.dataset;
1144
- }
1145
- return acc;
1146
- }, null);
1147
-
1148
- if (column.filter && column.filter.type) {
1149
- switch (column.filter.type) {
1150
- case "select":
1151
- filterEditor = SelectFilter;
1152
- filterEditorProps = {
1153
- placeholder: column.filter.placeholder
1154
- ? column.filter.placeholder
1155
- : "All Options",
1156
- dataSource: selectedDataSource,
1157
- };
1158
- break;
1159
- default:
1160
- filterEditor = null;
1161
- filterEditorProps = null;
1162
- break;
1163
- }
1164
- } else {
1165
- filterEditor = null;
1166
- filterEditorProps = null;
1167
- }
1168
-
1169
- return {
1170
- ...commonProps,
1171
- name: column.id,
1172
- filterEditor: filterEditor,
1173
- filterEditorProps: filterEditorProps,
1174
- };
1175
- }
1176
- };
1177
-
1178
- const newColumns = columns.map(renderColumn);
1179
-
1180
- if (settings.length > 0) {
1181
- newColumns.push({
1182
- name: "setting",
1183
- header: "Action",
1184
- defaultWidth: 100,
1185
- textAlign: "center",
1186
- render: ({ data }) => {
1187
- return (
1188
- <div className="tdactions">
1189
- {settings.map((setting) => (
1190
- <span
1191
- key={`setting-${setting.id}`}
1192
- onClick={(e) => {
1193
- e.preventDefault();
1194
- e.stopPropagation();
1195
- handleSettingClick(setting, data);
1196
- }}
1197
- >
1198
- {renderSetting(setting, data)}
1199
- </span>
1200
- ))}
1201
- </div>
1202
- );
1203
- },
1204
- });
1205
- }
1206
-
1207
- setGridColumns(newColumns);
1208
-
1209
- const newFilterValue = columns
1210
- .filter((column) => column.filter && column.filter.type) // Only consider columns with a filter type
1211
- .map((column) => {
1212
- // Map these filtered columns to a new object array
1213
- const filterName = Array.isArray(column.id)
1214
- ? column.id.reduce((acc, id) => acc + `${id}.`, "") +
1215
- column.nameFrom
1216
- : column.id;
1217
-
1218
- return {
1219
- key: column.filter.key ? column.filter.key : null,
1220
- name: filterName,
1221
- operator: column.filter.operator,
1222
- type: column.filter.type,
1223
- value: column.filter.value ? column.filter.value : "",
1224
- };
1225
- });
1226
-
1227
- setFilterValue(newFilterValue);
1228
- }, [columns, filterDataSource]);
1229
-
1230
- useEffect(() => {
1231
- if (setFilterData) {
1232
- setFilterData(filterValue);
1233
- }
1234
- }, [filterValue]);
1235
-
1236
- useEffect(() => {
1237
- columns.forEach((column) => {
1238
- if (column.filter && column.filter.url) {
1239
- CustomFetch(
1240
- column.filter.url,
1241
- "POST",
1242
- column.filter.where ? { where: column.filter.where } : {},
1243
- (res) => {
1244
- const filterName = Array.isArray(column.id)
1245
- ? column.id.reduce(
1246
- (acc, id) => acc + `${id}.`,
1247
- ""
1248
- ) + column.nameFrom
1249
- : column.id;
1250
-
1251
- const filterIndex = filterDataSource.findIndex(
1252
- (filter) => filter.id === filterName
1253
- );
1254
-
1255
- if (filterIndex >= 0) {
1256
- const updatedFilter = {
1257
- ...filterDataSource[filterIndex],
1258
- dataset: res.data,
1259
- };
1260
- const updatedDataSource = [
1261
- ...filterDataSource.slice(0, filterIndex),
1262
- updatedFilter,
1263
- ...filterDataSource.slice(filterIndex + 1),
1264
- ];
1265
- setFilterDataSource(updatedDataSource);
1266
- } else {
1267
- const newFilter = {
1268
- id: filterName,
1269
- dataset: res.data,
1270
- };
1271
- setFilterDataSource((prevState) => [
1272
- ...prevState,
1273
- newFilter,
1274
- ]);
1275
- }
1276
- }
1277
- );
1278
- } else if (column.filter && column.filter.options) {
1279
- const filterName = Array.isArray(column.id)
1280
- ? column.id.reduce((acc, id) => acc + `${id}.`, "") +
1281
- column.nameFrom
1282
- : column.id;
1283
-
1284
- const newFilter = {
1285
- id: filterName,
1286
- dataset: column.filter.options,
1287
- };
1288
-
1289
- setFilterDataSource((prevState) => [...prevState, newFilter]);
1290
- }
1291
- });
1292
- }, []);
1293
-
1294
- // Data Grid Styling
1295
- const [windowHeight, setWindowHeight] = useState(window.innerHeight);
1296
- const [dataCount, setDataCount] = useState(0);
1297
- const [gridStyle, setGridStyle] = useState({
1298
- minHeight:
1299
- dataCount > 5
1300
- ? dataCount > 8
1301
- ? windowHeight * 0.7 > 550
1302
- ? windowHeight * 0.7
1303
- : 550
1304
- : 450
1305
- : 400,
1306
- boxShadow: "none",
1307
- });
1308
- const headerProps = {
1309
- style: style ? style : {},
1310
- };
1311
-
1312
- useEffect(() => {
1313
- setGridStyle((prevState) => ({
1314
- ...prevState,
1315
- minHeight:
1316
- dataCount > 5
1317
- ? dataCount > 8
1318
- ? windowHeight * 0.7 > 550
1319
- ? windowHeight * 0.7
1320
- : 550
1321
- : 450
1322
- : 400,
1323
- }));
1324
-
1325
- let dgHeight =
1326
- dataCount > 5
1327
- ? dataCount > 8
1328
- ? windowHeight * 0.7 > 550
1329
- ? windowHeight * 0.7
1330
- : 550
1331
- : 450
1332
- : 400;
1333
-
1334
- let rowCount = Math.floor((dgHeight - 50) / 50);
1335
- setLimit(rowCount);
1336
- }, [dataCount]);
1337
-
1338
- useEffect(() => {
1339
- const handleResize = () => {
1340
- setWindowHeight(window.innerHeight);
1341
- };
1342
-
1343
- window.addEventListener("resize", handleResize);
1344
-
1345
- // Clean up the event listener
1346
- return () => {
1347
- window.removeEventListener("resize", handleResize);
1348
- };
1349
- }, []);
1350
-
1351
- return (
1352
- <>
1353
- <div className="filterInput--alt">
1354
- <div className="icon-search">
1355
- <Search strokeWidth={2} size={18} />
1356
- </div>
1357
- <input
1358
- type="text"
1359
- placeholder="Search"
1360
- value={search}
1361
- onChange={handleChangeSearch}
1362
- />
1363
- </div>
1364
- <div className="filterAction--alt">
1365
- {form.sort && form.sort.title && (
1366
- <button className="btn" onClick={sortTrigger}>
1367
- <div className="icon-plus"></div> Sort Order
1368
- </button>
1369
- )}
1370
-
1371
- <button
1372
- className="btn"
1373
- onClick={() => {
1374
- let _url = form.url.replace("/ajax", "");
1375
-
1376
- navigate(_url + "/create", {
1377
- state: {
1378
- form: form,
1379
- },
1380
- });
1381
- }}
1382
- >
1383
- <div className="icon-plus"></div> Create
1384
- </button>
1385
- </div>
1386
- <ReactDataGrid
1387
- columns={gridColumns}
1388
- dataSource={data}
1389
- filterValue={filterValue}
1390
- defaultSortInfo={sortInfo}
1391
- enableColumnAutosize={false}
1392
- enableColumnFilterContextMenu={false}
1393
- enableSelection={false}
1394
- headerProps={headerProps}
1395
- idProperty={`visns-datagrid-${ajaxSetting.url.replace(
1396
- /\//g,
1397
- "-"
1398
- )}`}
1399
- limit={limit}
1400
- minRowHeight={40}
1401
- onFilterValueChange={setFilterValue}
1402
- onLimitChange={setLimit}
1403
- onRenderRow={onRenderRow}
1404
- pagination
1405
- renderColumnContextMenu={renderColumnContextMenu}
1406
- rowHeight={null}
1407
- showZebraRows={true}
1408
- style={gridStyle}
1409
- />
1410
- <Popup
1411
- open={modalShow}
1412
- onClose={modalClose}
1413
- closeOnDocumentClick={false}
1414
- >
1415
- <Form
1416
- closeModal={modalClose}
1417
- fetchTable={handleReload}
1418
- formSettings={formData}
1419
- formType={formType}
1420
- updateForm={setFormData}
1421
- columnId={formId}
1422
- childDropdownCallback={childDropdownCallback}
1423
- />
1424
- </Popup>
1425
- </>
1426
- );
105
+ const navigate = useNavigate();
106
+
107
+ /** Modal States */
108
+ const [formData, setFormData] = useState(form);
109
+ const [formType, setFormType] = useState('');
110
+ const [formId, setFormId] = useState(0);
111
+ const [modalShow, setModalShow] = useState(false);
112
+
113
+ /** Modal Functions */
114
+ const childDropdownCallback = (data) => {
115
+ let _form = { ...formData };
116
+
117
+ if (formData.fields.length > 0) {
118
+ formData.fields.forEach((a, b) => {
119
+ if (a.id === data.id) {
120
+ _form.fields[b].options = data.data;
121
+ }
122
+ });
123
+ }
124
+
125
+ setFormData(_form);
126
+ };
127
+
128
+ const modalOpen = (formType, formId) => {
129
+ setModalShow(true);
130
+ setFormType(formType);
131
+ setFormId(formId);
132
+ };
133
+
134
+ const modalClose = () => {
135
+ setModalShow(false);
136
+ };
137
+
138
+ /** Table States */
139
+ const [dataReload, setDataReload] = useState(0);
140
+ const [dSearch, setDSearch] = useState('');
141
+ const data = useCallback(
142
+ (params) => {
143
+ const sqlResult = loadData(params, dSearch, ajaxSetting);
144
+
145
+ sqlResult.then((res) => {
146
+ setDataCount(res.count);
147
+ });
148
+
149
+ return sqlResult;
150
+ },
151
+ [ajaxSetting, dataReload, dSearch]
152
+ );
153
+ const [filterDataSource, setFilterDataSource] = useState([]);
154
+ const [filterValue, setFilterValue] = useState([]);
155
+ const [gridColumns, setGridColumns] = useState([]);
156
+ const [limit, setLimit] = useState(ajaxSetting.take || 10);
157
+ const [search, setSearch] = useState('');
158
+ const sortInfo =
159
+ ajaxSetting.sortBy && ajaxSetting.sort
160
+ ? {
161
+ name: ajaxSetting.sortBy,
162
+ dir: ajaxSetting.sort === 'asc' ? 1 : -1,
163
+ }
164
+ : null;
165
+
166
+ /** Table Functions */
167
+ const handleChangeSearch = (e) => {
168
+ const { value } = e.target;
169
+ setSearch(value);
170
+ };
171
+
172
+ const handleSettingClick = (s, d) => {
173
+ switch (s.id) {
174
+ case 'update':
175
+ modalOpen('update', d.id);
176
+ break;
177
+ case 'delete':
178
+ confirmAlert({
179
+ title: 'Delete Item',
180
+ message: `Are you sure you want to delete ${
181
+ d.name ? d.name : d.label ? d.label : 'this item'
182
+ }?`,
183
+ buttons: [
184
+ {
185
+ label: 'Yes',
186
+ onClick: () =>
187
+ CustomFetch(
188
+ form.url + '/' + d[form.primaryKey],
189
+ 'DELETE',
190
+ {},
191
+ (result) => {
192
+ if (result.error === '') {
193
+ const min = 0;
194
+ const max = 999999999;
195
+ const randomNumber = Math.floor(
196
+ Math.random() *
197
+ (max - min + 1) +
198
+ min
199
+ );
200
+
201
+ setDataReload(randomNumber);
202
+
203
+ toast.success(
204
+ `The selected item has been deleted.`
205
+ );
206
+ } else {
207
+ toast.error(String(result.error));
208
+ }
209
+ }
210
+ ),
211
+ },
212
+ {
213
+ label: 'No',
214
+ onClick: () => close(),
215
+ },
216
+ ],
217
+ });
218
+ break;
219
+ default:
220
+ confirmAlert({
221
+ title: s.title,
222
+ message: '',
223
+ buttons: [
224
+ {
225
+ label: 'Yes',
226
+ onClick: () =>
227
+ CustomFetch(
228
+ s.url + '/' + d[form.primaryKey],
229
+ s.method,
230
+ {},
231
+ function (result) {
232
+ if (result.error === '') {
233
+ const min = 0;
234
+ const max = 999999999;
235
+ const randomNumber = Math.floor(
236
+ Math.random() *
237
+ (max - min + 1) +
238
+ min
239
+ );
240
+
241
+ setDataReload(randomNumber);
242
+
243
+ toast.success(String(s.title));
244
+ } else {
245
+ toast.error(String(result.error));
246
+ }
247
+ }
248
+ ),
249
+ },
250
+ {
251
+ label: 'No',
252
+ onClick: () => close(),
253
+ },
254
+ ],
255
+ });
256
+ break;
257
+ }
258
+ };
259
+
260
+ const handleReload = () => {
261
+ const min = 0;
262
+ const max = 999999999;
263
+ const randomNumber = Math.floor(Math.random() * (max - min + 1) + min);
264
+
265
+ setDataReload(randomNumber);
266
+ };
267
+
268
+ const onRowClick = useCallback((rowProps, event) => {
269
+ const cellElement = event.target.closest('.InovuaReactDataGrid__cell');
270
+ const columnIndex = Array.from(cellElement.parentNode.children).indexOf(
271
+ cellElement
272
+ );
273
+
274
+ let proceed = true;
275
+
276
+ columns.forEach((a, b) => {
277
+ if (
278
+ a.id === rowProps.columns[columnIndex].id &&
279
+ a.type === 'toggle'
280
+ ) {
281
+ proceed = false;
282
+ }
283
+ });
284
+
285
+ if (proceed) {
286
+ if (
287
+ rowProps.columns[columnIndex].link &&
288
+ rowProps.columns[columnIndex].link.url
289
+ ) {
290
+ if (rowProps.columns[columnIndex].link.folder) {
291
+ window.location.href =
292
+ rowProps.columns[columnIndex].link.url +
293
+ rowProps.data[rowProps.columns[columnIndex].link.key] +
294
+ '/' +
295
+ rowProps.columns[columnIndex].link.folder;
296
+ } else {
297
+ navigate(
298
+ `${rowProps.columns[columnIndex].link.url}${
299
+ rowProps.data[
300
+ rowProps.columns[columnIndex].link.key
301
+ ]
302
+ }`,
303
+ {
304
+ state: {
305
+ form: form,
306
+ },
307
+ }
308
+ );
309
+ }
310
+ } else {
311
+ modalOpen('update', rowProps.data[form.primaryKey]);
312
+ }
313
+ }
314
+ }, []);
315
+
316
+ const onRenderRow = useCallback((rowProps) => {
317
+ // save the original handlers to be called later
318
+ const { onClick } = rowProps;
319
+
320
+ rowProps.onClick = (event) => {
321
+ onRowClick(rowProps, event);
322
+ if (onClick) {
323
+ onClick(event);
324
+ }
325
+ };
326
+ }, []);
327
+
328
+ const sortTrigger = () => {
329
+ const url = form.url.replace('/ajax', '');
330
+ console.info(url);
331
+ const newState = {
332
+ form: form,
333
+ };
334
+
335
+ navigate(`${url}/sort`, {
336
+ state: newState,
337
+ });
338
+ };
339
+
340
+ /** Table Hooks */
341
+ useEffect(() => {
342
+ const delayedSetDSearch = debounce(() => {
343
+ setDSearch(search);
344
+ }, 300); // Adjust the delay (in milliseconds) according to your needs
345
+
346
+ delayedSetDSearch();
347
+
348
+ return delayedSetDSearch.cancel; // Cleanup the debounce timer on unmount
349
+ }, [search, setDSearch]);
350
+
351
+ const renderSetting = (s, d) => {
352
+ let iconStyle = {};
353
+
354
+ if (s.active) {
355
+ if (
356
+ d.hasOwnProperty(s.active.id) &&
357
+ !s.active.hasOwnProperty('type') &&
358
+ d[s.active.id] === s.active.value
359
+ ) {
360
+ iconStyle = {
361
+ color: s.active.colour,
362
+ };
363
+ } else if (s.active.hasOwnProperty('type')) {
364
+ switch (s.active.type) {
365
+ case 'greater':
366
+ if (d[s.active.id] > s.active.value) {
367
+ iconStyle = {
368
+ color: s.active.colour,
369
+ };
370
+ }
371
+ break;
372
+ case 'not null':
373
+ if (d[s.active.id] !== null) {
374
+ iconStyle = {
375
+ color: s.active.colour,
376
+ };
377
+ }
378
+ break;
379
+ default:
380
+ break;
381
+ }
382
+ }
383
+ }
384
+
385
+ const getIconComponent = (IconComponent) => (
386
+ <IconComponent
387
+ data-tooltip-id="system-tooltip"
388
+ data-tooltip-content={
389
+ iconStyle && iconStyle.color ? s.active.title : s.title
390
+ }
391
+ strokeWidth={2}
392
+ size={18}
393
+ className="tdaction"
394
+ style={iconStyle}
395
+ />
396
+ );
397
+
398
+ switch (s.id) {
399
+ case 'complete':
400
+ return getIconComponent(Check);
401
+ case 'delete':
402
+ return getIconComponent(Backspace);
403
+ case 'primary':
404
+ return getIconComponent(Ribbon);
405
+ case 'ssa':
406
+ return getIconComponent(Clock);
407
+ case 'update':
408
+ return getIconComponent(Edit);
409
+ default:
410
+ return null;
411
+ }
412
+ };
413
+
414
+ const renderColumnContextMenu = useCallback((menuProps, { cellProps }) => {
415
+ const filteredItems = menuProps.items
416
+ .map((item, key) => {
417
+ if (key >= 6 && key <= 9) {
418
+ return null; // Skip items with keys 6-9 [lock columns setting]
419
+ }
420
+ return item;
421
+ })
422
+ .filter(Boolean); // Filter out any null items
423
+
424
+ menuProps.items = filteredItems;
425
+ }, []);
426
+
427
+ useEffect(() => {
428
+ const renderColumn = (column) => {
429
+ let childValue;
430
+ let date;
431
+ let filterEditor = null;
432
+ let filterEditorProps = null;
433
+ let fileUrl = null;
434
+ let icons = [];
435
+ let relationName;
436
+ let selectedDataSource = null;
437
+ let stage;
438
+ let style;
439
+ let value;
440
+
441
+ const commonProps = {
442
+ header: column.label,
443
+ defaultFlex: 1,
444
+ link: column.link ? column.link : {},
445
+ minWidth:
446
+ column.minWidth && column.minWidth > 0
447
+ ? column.minWidth
448
+ : undefined,
449
+ maxWidth:
450
+ column.maxWidth && column.maxWidth > 0
451
+ ? column.maxWidth
452
+ : undefined,
453
+ };
454
+
455
+ switch (column.type) {
456
+ case 'address':
457
+ return {
458
+ ...commonProps,
459
+ name: `${column.type}.${column.id}`,
460
+ render: ({ data }) => {
461
+ if (data.address1) {
462
+ value += `${data.address1} `;
463
+ }
464
+
465
+ if (data.address2) {
466
+ value += `${data.address2} `;
467
+ }
468
+
469
+ if (data.suburb) {
470
+ value += `${data.suburb} `;
471
+ }
472
+
473
+ if (data.postcode) {
474
+ value += `${data.postcode} `;
475
+ }
476
+ },
477
+ };
478
+ case 'age':
479
+ return {
480
+ ...commonProps,
481
+ name: `${column.type}.${column.id}`,
482
+ render: ({ data }) => {
483
+ value = column.id.reduce((acc, id) => {
484
+ if (acc === '') {
485
+ return data[id];
486
+ } else {
487
+ return acc[id];
488
+ }
489
+ }, '');
490
+
491
+ if (value !== '' && value !== null) {
492
+ date = moment(value);
493
+
494
+ return (
495
+ <span>
496
+ {moment().diff(
497
+ date,
498
+ column.duration
499
+ ? column.duration
500
+ : 'years'
501
+ )}
502
+ </span>
503
+ );
504
+ } else {
505
+ return null;
506
+ }
507
+ },
508
+ };
509
+ case 'arrayCount':
510
+ return {
511
+ ...commonProps,
512
+ name: `${column.type}.${column.id}`,
513
+ sortable: false,
514
+ render: ({ data }) => {
515
+ if (data && data[column.id]) {
516
+ return data[column.id].length;
517
+ } else {
518
+ return null;
519
+ }
520
+ },
521
+ };
522
+ case 'coding':
523
+ return {
524
+ ...commonProps,
525
+ name: 'audits.name',
526
+ sortable: false,
527
+ render: ({ data }) => {
528
+ if (data) {
529
+ return handleCoding(column, data);
530
+ } else {
531
+ return null;
532
+ }
533
+ },
534
+ };
535
+ case 'created_by':
536
+ return {
537
+ ...commonProps,
538
+ name: 'audits.name',
539
+ sortable: false,
540
+ render: ({ data }) => {
541
+ if (
542
+ data.audits[0] &&
543
+ data.audits[0].user &&
544
+ data.audits[0].user.name
545
+ ) {
546
+ value = data.audits[0].user.name;
547
+
548
+ return <span>{value}</span>;
549
+ } else {
550
+ return null;
551
+ }
552
+ },
553
+ };
554
+ case 'currency':
555
+ return {
556
+ ...commonProps,
557
+ name: column.id,
558
+ render: ({ data }) => {
559
+ if (data) {
560
+ data = numeral(data[column.id]).format(
561
+ '$0,0.00'
562
+ );
563
+
564
+ return <span>{data}</span>;
565
+ } else {
566
+ return null;
567
+ }
568
+ },
569
+ };
570
+ case 'date':
571
+ if (column.filter && column.filter.type) {
572
+ filterEditor = DateFilter;
573
+ filterEditorProps = (props, { index }) => {
574
+ return {
575
+ dateFormat: 'DD-MM-YYYY',
576
+ placeholder: 'All Dates',
577
+ };
578
+ };
579
+ } else {
580
+ filterEditor = null;
581
+ filterEditorProps = null;
582
+ }
583
+
584
+ return {
585
+ ...commonProps,
586
+ name: column.id,
587
+ filterEditor: filterEditor,
588
+ filterEditorProps: filterEditorProps,
589
+ render: ({ data }) => {
590
+ if (
591
+ data &&
592
+ data[column.id] &&
593
+ moment(data[column.id]).isValid() &&
594
+ moment(data[column.id]).format('YYYY-MM-DD') !==
595
+ '1970-01-01'
596
+ ) {
597
+ const value = moment(data[column.id]).format(
598
+ column.format || 'DD-MM-YYYY'
599
+ );
600
+ style = {};
601
+
602
+ if (
603
+ column.active &&
604
+ column.active.id &&
605
+ column.active.value === 'expired'
606
+ ) {
607
+ if (
608
+ data[column.active.id] &&
609
+ moment(data[column.active.id]).isBefore(
610
+ moment()
611
+ )
612
+ ) {
613
+ style = {
614
+ color: column.active.colour,
615
+ };
616
+ }
617
+ }
618
+
619
+ return <span style={style}>{value}</span>;
620
+ } else {
621
+ return null;
622
+ }
623
+ },
624
+ };
625
+ case 'datetime':
626
+ if (column.filter && column.filter.type) {
627
+ filterEditor = DateFilter;
628
+ filterEditorProps = (props, { index }) => {
629
+ return {
630
+ dateFormat: 'DD-MM-YYYY',
631
+ placeholder: 'All Dates',
632
+ };
633
+ };
634
+ } else {
635
+ filterEditor = null;
636
+ filterEditorProps = null;
637
+ }
638
+
639
+ return {
640
+ ...commonProps,
641
+ name: column.id,
642
+ filterEditor: filterEditor,
643
+ filterEditorProps: filterEditorProps,
644
+ render: ({ data }) => {
645
+ if (
646
+ data &&
647
+ data[column.id] &&
648
+ moment(data[column.id]).isValid() &&
649
+ moment(data[column.id]).format('YYYY-MM-DD') !==
650
+ '1970-01-01'
651
+ ) {
652
+ data = moment(data[column.id]).format(
653
+ column.format
654
+ ? column.format
655
+ : 'DD-MM-YYYY hh:mm A'
656
+ );
657
+
658
+ return <span>{data}</span>;
659
+ } else {
660
+ return null;
661
+ }
662
+ },
663
+ };
664
+ case 'file':
665
+ return {
666
+ ...commonProps,
667
+ name: column.id,
668
+ sortable: false,
669
+ render: ({ data }) => {
670
+ if (data) {
671
+ return (
672
+ <span>
673
+ <CloudDownload
674
+ data-tooltip-id="system-tooltip"
675
+ data-tooltip-content="Download File"
676
+ strokeWidth={2}
677
+ size={18}
678
+ className="tdaction"
679
+ />
680
+ </span>
681
+ );
682
+ } else {
683
+ return null;
684
+ }
685
+ },
686
+ };
687
+ case 'icons':
688
+ return {
689
+ ...commonProps,
690
+ name: column.id,
691
+ sortable: false,
692
+ render: ({ data }) => {
693
+ icons = [];
694
+
695
+ if (column.icons && column.icons.length > 0) {
696
+ column.icons.forEach((icon) => {
697
+ icons.push(
698
+ <img
699
+ src={icon.url}
700
+ alt={icon.name}
701
+ data-tooltip-id="system-tooltip"
702
+ data-tooltip-content={icon.name}
703
+ />
704
+ );
705
+ });
706
+ }
707
+
708
+ if (data) {
709
+ return <span>{icons}</span>;
710
+ } else {
711
+ return null;
712
+ }
713
+ },
714
+ };
715
+ case 'image':
716
+ return {
717
+ ...commonProps,
718
+ name: column.id,
719
+ render: ({ data }) => {
720
+ if (data && data[column.id]) {
721
+ const fileUrl =
722
+ data[column.id][0]?.file_url ||
723
+ data[column.id]?.file_url;
724
+
725
+ if (fileUrl) {
726
+ return (
727
+ <span>
728
+ {parse(
729
+ `<img width="150" src="${fileUrl}" />`
730
+ )}
731
+ </span>
732
+ );
733
+ }
734
+ }
735
+
736
+ return null;
737
+ },
738
+ };
739
+ case 'json':
740
+ return {
741
+ ...commonProps,
742
+ name: column.id,
743
+ render: ({ data }) => {
744
+ if (
745
+ data &&
746
+ data[column.id] &&
747
+ data[column.id][column.jsonData]
748
+ ) {
749
+ data = data[column.id][column.jsonData];
750
+
751
+ return <span>{data}</span>;
752
+ } else {
753
+ return null;
754
+ }
755
+ },
756
+ };
757
+ case 'number':
758
+ return {
759
+ ...commonProps,
760
+ name: column.id,
761
+ type: 'number',
762
+ };
763
+ case 'option':
764
+ selectedDataSource = filterDataSource.reduce((acc, fds) => {
765
+ if (fds.id === column.id) {
766
+ return fds.dataset;
767
+ }
768
+ return acc;
769
+ }, null);
770
+
771
+ if (
772
+ column.filter &&
773
+ column.filter.type &&
774
+ column.filter.type === 'select'
775
+ ) {
776
+ filterEditor = SelectFilter;
777
+ filterEditorProps = {
778
+ placeholder: column.filter.placeholder
779
+ ? column.filter.placeholder
780
+ : 'All Options',
781
+ dataSource: selectedDataSource,
782
+ };
783
+ } else {
784
+ filterEditor = null;
785
+ filterEditorProps = null;
786
+ }
787
+
788
+ return {
789
+ ...commonProps,
790
+ name: column.id,
791
+ filterEditor: filterEditor,
792
+ filterEditorProps: filterEditorProps,
793
+ render: ({ data }) => {
794
+ if (
795
+ data &&
796
+ column.options &&
797
+ column.options[data[column.id]]
798
+ ) {
799
+ data = column.options[data[column.id]];
800
+
801
+ return <span>{data}</span>;
802
+ } else {
803
+ return null;
804
+ }
805
+ },
806
+ };
807
+ case 'placeholder':
808
+ return {
809
+ ...commonProps,
810
+ name: column.id,
811
+ sortable: false,
812
+ render: ({ data }) => {
813
+ if (data) {
814
+ return <span>{column.placeholder}</span>;
815
+ } else {
816
+ return null;
817
+ }
818
+ },
819
+ };
820
+ case 'relation':
821
+ relationName = column.id.reduce(
822
+ (acc, id) => acc + `${id}.`,
823
+ ''
824
+ );
825
+ relationName += column.nameFrom;
826
+
827
+ selectedDataSource = filterDataSource.reduce((acc, fds) => {
828
+ if (fds.id === relationName) {
829
+ return fds.dataset;
830
+ }
831
+ return acc;
832
+ }, null);
833
+
834
+ if (
835
+ column.filter &&
836
+ column.filter.type &&
837
+ column.filter.type === 'select'
838
+ ) {
839
+ filterEditor = SelectFilter;
840
+ filterEditorProps = {
841
+ placeholder: column.filter.placeholder
842
+ ? column.filter.placeholder
843
+ : 'All Options',
844
+ dataSource: selectedDataSource,
845
+ };
846
+ } else {
847
+ filterEditor = null;
848
+ filterEditorProps = null;
849
+ }
850
+
851
+ return {
852
+ ...commonProps,
853
+ name: relationName,
854
+ sortable: false,
855
+ filterEditor: filterEditor,
856
+ filterEditorProps: filterEditorProps,
857
+ render: ({ data }) => {
858
+ value = column.id.reduce((acc, id) => {
859
+ if (acc === '') {
860
+ return data[id];
861
+ } else {
862
+ if (acc && acc[id]) {
863
+ return acc[id];
864
+ } else {
865
+ return '';
866
+ }
867
+ }
868
+ }, '');
869
+
870
+ if (value) {
871
+ if (Array.isArray(column.nameFrom)) {
872
+ value = column.nameFrom
873
+ .map((nf) => value[nf])
874
+ .join(' ');
875
+ } else {
876
+ value = value[column.nameFrom];
877
+ }
878
+
879
+ if (
880
+ column.placeholder &&
881
+ column.placeholder !== ''
882
+ ) {
883
+ return <span>{column.placeholder}</span>;
884
+ } else {
885
+ return <span>{value}</span>;
886
+ }
887
+ } else {
888
+ return null;
889
+ }
890
+ },
891
+ };
892
+ case 'relationArray':
893
+ relationName =
894
+ column.id.reduce((acc, id) => acc + `${id}.`, '') +
895
+ column.nameFrom;
896
+
897
+ selectedDataSource = filterDataSource.reduce((acc, fds) => {
898
+ if (fds.id === relationName) {
899
+ return fds.dataset;
900
+ }
901
+ return acc;
902
+ }, null);
903
+
904
+ if (
905
+ column.filter &&
906
+ column.filter.type &&
907
+ column.filter.type === 'select'
908
+ ) {
909
+ filterEditor = SelectFilter;
910
+ filterEditorProps = {
911
+ placeholder: column.filter.placeholder
912
+ ? column.filter.placeholder
913
+ : 'All Options',
914
+ dataSource: selectedDataSource,
915
+ };
916
+ } else {
917
+ filterEditor = null;
918
+ filterEditorProps = null;
919
+ }
920
+
921
+ return {
922
+ ...commonProps,
923
+ name: relationName,
924
+ sortable: false,
925
+ filterEditor: filterEditor,
926
+ filterEditorProps: filterEditorProps,
927
+ render: ({ data }) => {
928
+ const relationValue = column.id.reduce(
929
+ (acc, id) =>
930
+ acc === ''
931
+ ? data[id]
932
+ : acc && acc[id]
933
+ ? acc[id]
934
+ : '',
935
+ ''
936
+ );
937
+
938
+ if (relationValue && Array.isArray(relationValue)) {
939
+ const nameProperties = Array.isArray(
940
+ column.nameFrom
941
+ )
942
+ ? column.nameFrom
943
+ : [column.nameFrom];
944
+
945
+ const values = relationValue
946
+ .map((rv) => {
947
+ if (
948
+ column.childId &&
949
+ Array.isArray(column.childId)
950
+ ) {
951
+ childValue = rv;
952
+
953
+ column.childId.forEach((a) => {
954
+ if (childValue[a]) {
955
+ childValue = childValue[a];
956
+ }
957
+ });
958
+
959
+ if (childValue) {
960
+ const propertyValues =
961
+ nameProperties
962
+ .map(
963
+ (prop) =>
964
+ childValue[prop]
965
+ )
966
+ .filter(
967
+ (value) =>
968
+ value !==
969
+ undefined &&
970
+ value !== null
971
+ );
972
+ return propertyValues.join(' ');
973
+ }
974
+ } else {
975
+ const propertyValues =
976
+ nameProperties
977
+ .map((prop) => rv[prop])
978
+ .filter(
979
+ (value) =>
980
+ value !==
981
+ undefined &&
982
+ value !== null
983
+ );
984
+ return propertyValues.join(' ');
985
+ }
986
+ })
987
+ .filter((value) => value !== '');
988
+
989
+ if (values.length > 0) {
990
+ let result = '';
991
+
992
+ if (
993
+ column.relation?.id &&
994
+ column.relation?.key
995
+ ) {
996
+ const relationValue =
997
+ column.relation.key.reduce(
998
+ (acc, id) =>
999
+ acc === ''
1000
+ ? data[id]
1001
+ : acc && acc[id]
1002
+ ? acc[id]
1003
+ : '',
1004
+ ''
1005
+ );
1006
+
1007
+ result = `${
1008
+ relationValue[column.relation.id]
1009
+ }<br />`;
1010
+ }
1011
+
1012
+ if (
1013
+ column.where &&
1014
+ column.where.id &&
1015
+ column.where.value
1016
+ ) {
1017
+ if (
1018
+ data[column.where.id] ===
1019
+ column.where.value
1020
+ ) {
1021
+ result += values.join('<br />');
1022
+ }
1023
+ } else {
1024
+ result += values.join('<br />');
1025
+ }
1026
+
1027
+ return <span>{parse(result)}</span>;
1028
+ }
1029
+ }
1030
+
1031
+ return null;
1032
+ },
1033
+ };
1034
+ case 'richtext':
1035
+ return {
1036
+ ...commonProps,
1037
+ name: column.id,
1038
+ render: ({ data }) => {
1039
+ if (data && data[column.id]) {
1040
+ return <span>{parse(data[column.id])}</span>;
1041
+ } else {
1042
+ return null;
1043
+ }
1044
+ },
1045
+ };
1046
+ case 'stage':
1047
+ return {
1048
+ ...commonProps,
1049
+ name: column.id,
1050
+ sortable: false,
1051
+ render: ({ data }) => {
1052
+ stage = '';
1053
+
1054
+ column.keyIds.forEach((a, b) => {
1055
+ if (data[a] === 1) {
1056
+ stage = column.valueIds[b];
1057
+ }
1058
+ });
1059
+
1060
+ return <span>{stage}</span>;
1061
+ },
1062
+ };
1063
+ case 'time':
1064
+ return {
1065
+ ...commonProps,
1066
+ name: column.id,
1067
+ render: ({ data }) => {
1068
+ if (
1069
+ data &&
1070
+ data[column.id] &&
1071
+ moment(data[column.id]).isValid() &&
1072
+ moment(data[column.id]).format('YYYY-MM-DD') !==
1073
+ '1970-01-01'
1074
+ ) {
1075
+ data = moment(data[column.id]).format(
1076
+ column.format ? column.format : 'hh:mm A'
1077
+ );
1078
+
1079
+ return <span>{data}</span>;
1080
+ } else {
1081
+ return null;
1082
+ }
1083
+ },
1084
+ };
1085
+ case 'toggle':
1086
+ return {
1087
+ ...commonProps,
1088
+ name: column.id,
1089
+ render: ({ data }) => {
1090
+ return (
1091
+ <Toggle
1092
+ name={column.id}
1093
+ checked={
1094
+ data[column.id] === 1 ? true : false
1095
+ }
1096
+ onChange={() => {
1097
+ CustomFetch(
1098
+ `${column.url}/${data.id}`,
1099
+ 'POST',
1100
+ {
1101
+ [column.id]:
1102
+ data[column.id] === 1
1103
+ ? 0
1104
+ : 1,
1105
+ },
1106
+ (res) => {
1107
+ if (res.error === '') {
1108
+ handleReload();
1109
+ } else {
1110
+ toast.error(res.error);
1111
+ }
1112
+ }
1113
+ );
1114
+ }}
1115
+ />
1116
+ );
1117
+ },
1118
+ };
1119
+ case 'url':
1120
+ return {
1121
+ ...commonProps,
1122
+ name: column.id,
1123
+ render: ({ data }) => {
1124
+ if (data && data[column.id]) {
1125
+ return (
1126
+ <span>
1127
+ <a
1128
+ href={data[column.id]}
1129
+ target="_blank"
1130
+ >
1131
+ Link
1132
+ </a>
1133
+ </span>
1134
+ );
1135
+ } else {
1136
+ return null;
1137
+ }
1138
+ },
1139
+ };
1140
+ default:
1141
+ selectedDataSource = filterDataSource.reduce((acc, fds) => {
1142
+ if (fds.id === column.id) {
1143
+ return fds.dataset;
1144
+ }
1145
+ return acc;
1146
+ }, null);
1147
+
1148
+ if (column.filter && column.filter.type) {
1149
+ switch (column.filter.type) {
1150
+ case 'select':
1151
+ filterEditor = SelectFilter;
1152
+ filterEditorProps = {
1153
+ placeholder: column.filter.placeholder
1154
+ ? column.filter.placeholder
1155
+ : 'All Options',
1156
+ dataSource: selectedDataSource,
1157
+ };
1158
+ break;
1159
+ default:
1160
+ filterEditor = null;
1161
+ filterEditorProps = null;
1162
+ break;
1163
+ }
1164
+ } else {
1165
+ filterEditor = null;
1166
+ filterEditorProps = null;
1167
+ }
1168
+
1169
+ return {
1170
+ ...commonProps,
1171
+ name: column.id,
1172
+ filterEditor: filterEditor,
1173
+ filterEditorProps: filterEditorProps,
1174
+ };
1175
+ }
1176
+ };
1177
+
1178
+ const newColumns = columns.map(renderColumn);
1179
+
1180
+ if (settings.length > 0) {
1181
+ newColumns.push({
1182
+ name: 'setting',
1183
+ header: 'Action',
1184
+ defaultWidth: 100,
1185
+ textAlign: 'center',
1186
+ render: ({ data }) => {
1187
+ return (
1188
+ <div className="tdactions">
1189
+ {settings.map((setting) => (
1190
+ <span
1191
+ key={`setting-${setting.id}`}
1192
+ onClick={(e) => {
1193
+ e.preventDefault();
1194
+ e.stopPropagation();
1195
+ handleSettingClick(setting, data);
1196
+ }}
1197
+ >
1198
+ {renderSetting(setting, data)}
1199
+ </span>
1200
+ ))}
1201
+ </div>
1202
+ );
1203
+ },
1204
+ });
1205
+ }
1206
+
1207
+ setGridColumns(newColumns);
1208
+
1209
+ const newFilterValue = columns
1210
+ .filter((column) => column.filter && column.filter.type) // Only consider columns with a filter type
1211
+ .map((column) => {
1212
+ // Map these filtered columns to a new object array
1213
+ const filterName = Array.isArray(column.id)
1214
+ ? column.id.reduce((acc, id) => acc + `${id}.`, '') +
1215
+ column.nameFrom
1216
+ : column.id;
1217
+
1218
+ return {
1219
+ key: column.filter.key ? column.filter.key : null,
1220
+ name: filterName,
1221
+ operator: column.filter.operator,
1222
+ type: column.filter.type,
1223
+ value: column.filter.value ? column.filter.value : '',
1224
+ };
1225
+ });
1226
+
1227
+ setFilterValue(newFilterValue);
1228
+ }, [columns, filterDataSource]);
1229
+
1230
+ useEffect(() => {
1231
+ if (setFilterData) {
1232
+ setFilterData(filterValue);
1233
+ }
1234
+ }, [filterValue]);
1235
+
1236
+ useEffect(() => {
1237
+ columns.forEach((column) => {
1238
+ if (column.filter && column.filter.url) {
1239
+ CustomFetch(
1240
+ column.filter.url,
1241
+ 'POST',
1242
+ column.filter.where ? { where: column.filter.where } : {},
1243
+ (res) => {
1244
+ const filterName = Array.isArray(column.id)
1245
+ ? column.id.reduce(
1246
+ (acc, id) => acc + `${id}.`,
1247
+ ''
1248
+ ) + column.nameFrom
1249
+ : column.id;
1250
+
1251
+ const filterIndex = filterDataSource.findIndex(
1252
+ (filter) => filter.id === filterName
1253
+ );
1254
+
1255
+ if (filterIndex >= 0) {
1256
+ const updatedFilter = {
1257
+ ...filterDataSource[filterIndex],
1258
+ dataset: res.data,
1259
+ };
1260
+ const updatedDataSource = [
1261
+ ...filterDataSource.slice(0, filterIndex),
1262
+ updatedFilter,
1263
+ ...filterDataSource.slice(filterIndex + 1),
1264
+ ];
1265
+ setFilterDataSource(updatedDataSource);
1266
+ } else {
1267
+ const newFilter = {
1268
+ id: filterName,
1269
+ dataset: res.data,
1270
+ };
1271
+ setFilterDataSource((prevState) => [
1272
+ ...prevState,
1273
+ newFilter,
1274
+ ]);
1275
+ }
1276
+ }
1277
+ );
1278
+ } else if (column.filter && column.filter.options) {
1279
+ const filterName = Array.isArray(column.id)
1280
+ ? column.id.reduce((acc, id) => acc + `${id}.`, '') +
1281
+ column.nameFrom
1282
+ : column.id;
1283
+
1284
+ const newFilter = {
1285
+ id: filterName,
1286
+ dataset: column.filter.options,
1287
+ };
1288
+
1289
+ setFilterDataSource((prevState) => [...prevState, newFilter]);
1290
+ }
1291
+ });
1292
+ }, []);
1293
+
1294
+ // Data Grid Styling
1295
+ const [windowHeight, setWindowHeight] = useState(window.innerHeight);
1296
+ const [dataCount, setDataCount] = useState(0);
1297
+ const [gridStyle, setGridStyle] = useState({
1298
+ minHeight:
1299
+ dataCount > 5
1300
+ ? dataCount > 8
1301
+ ? windowHeight * 0.7 > 550
1302
+ ? windowHeight * 0.7
1303
+ : 550
1304
+ : 450
1305
+ : 400,
1306
+ boxShadow: 'none',
1307
+ });
1308
+ const headerProps = {
1309
+ style: style ? style : {},
1310
+ };
1311
+
1312
+ useEffect(() => {
1313
+ setGridStyle((prevState) => ({
1314
+ ...prevState,
1315
+ minHeight:
1316
+ dataCount > 5
1317
+ ? dataCount > 8
1318
+ ? windowHeight * 0.7 > 550
1319
+ ? windowHeight * 0.7
1320
+ : 550
1321
+ : 450
1322
+ : 400,
1323
+ }));
1324
+
1325
+ let dgHeight =
1326
+ dataCount > 5
1327
+ ? dataCount > 8
1328
+ ? windowHeight * 0.7 > 550
1329
+ ? windowHeight * 0.7
1330
+ : 550
1331
+ : 450
1332
+ : 400;
1333
+
1334
+ let rowCount = Math.floor((dgHeight - 50) / 50);
1335
+ setLimit(rowCount);
1336
+ }, [dataCount]);
1337
+
1338
+ useEffect(() => {
1339
+ const handleResize = () => {
1340
+ setWindowHeight(window.innerHeight);
1341
+ };
1342
+
1343
+ window.addEventListener('resize', handleResize);
1344
+
1345
+ // Clean up the event listener
1346
+ return () => {
1347
+ window.removeEventListener('resize', handleResize);
1348
+ };
1349
+ }, []);
1350
+
1351
+ return (
1352
+ <>
1353
+ <div className="filterInput--alt">
1354
+ <div className="icon-search">
1355
+ <Search strokeWidth={2} size={18} />
1356
+ </div>
1357
+ <input
1358
+ type="text"
1359
+ placeholder="Search"
1360
+ value={search}
1361
+ onChange={handleChangeSearch}
1362
+ />
1363
+ </div>
1364
+ <div className="filterAction--alt">
1365
+ {form.sort && form.sort.title && (
1366
+ <button className="btn" onClick={sortTrigger}>
1367
+ <div className="icon-plus"></div> Sort Order
1368
+ </button>
1369
+ )}
1370
+
1371
+ {form.create && form.create.title && (
1372
+ <button
1373
+ className="btn"
1374
+ onClick={() => {
1375
+ let _url = form.url.replace('/ajax', '');
1376
+
1377
+ navigate(_url + '/create', {
1378
+ state: {
1379
+ form: form,
1380
+ },
1381
+ });
1382
+ }}
1383
+ >
1384
+ <div className="icon-plus"></div> Create
1385
+ </button>
1386
+ )}
1387
+ </div>
1388
+ <ReactDataGrid
1389
+ columns={gridColumns}
1390
+ dataSource={data}
1391
+ filterValue={filterValue}
1392
+ defaultSortInfo={sortInfo}
1393
+ enableColumnAutosize={false}
1394
+ enableColumnFilterContextMenu={false}
1395
+ enableSelection={false}
1396
+ headerProps={headerProps}
1397
+ idProperty={`visns-datagrid-${ajaxSetting.url.replace(
1398
+ /\//g,
1399
+ '-'
1400
+ )}`}
1401
+ limit={limit}
1402
+ minRowHeight={40}
1403
+ onFilterValueChange={setFilterValue}
1404
+ onLimitChange={setLimit}
1405
+ onRenderRow={onRenderRow}
1406
+ pagination
1407
+ renderColumnContextMenu={renderColumnContextMenu}
1408
+ rowHeight={null}
1409
+ showZebraRows={true}
1410
+ style={gridStyle}
1411
+ />
1412
+ <Popup
1413
+ open={modalShow}
1414
+ onClose={modalClose}
1415
+ closeOnDocumentClick={false}
1416
+ >
1417
+ <Form
1418
+ closeModal={modalClose}
1419
+ fetchTable={handleReload}
1420
+ formSettings={formData}
1421
+ formType={formType}
1422
+ updateForm={setFormData}
1423
+ columnId={formId}
1424
+ childDropdownCallback={childDropdownCallback}
1425
+ />
1426
+ </Popup>
1427
+ </>
1428
+ );
1427
1429
  };
1428
1430
 
1429
1431
  export default DataGrid;