@visns-studio/visns-components 1.7.1 → 1.7.3

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