@visns-studio/visns-components 5.4.3 → 5.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
3
|
"@emotion/is-prop-valid": "^1.3.1",
|
|
4
|
-
"@fontsource/barlow": "^5.
|
|
4
|
+
"@fontsource/barlow": "^5.2.5",
|
|
5
5
|
"@inovua/reactdatagrid-community": "^5.10.2",
|
|
6
6
|
"@inovua/reactdatagrid-enterprise": "^5.10.2",
|
|
7
7
|
"@nivo/bar": "^0.88.0",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
79
79
|
},
|
|
80
80
|
"name": "@visns-studio/visns-components",
|
|
81
|
-
"version": "5.4.
|
|
81
|
+
"version": "5.4.5",
|
|
82
82
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
83
83
|
"main": "src/index.js",
|
|
84
84
|
"files": [
|
|
@@ -23,8 +23,9 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
23
23
|
const swapy = useRef(null);
|
|
24
24
|
const container = useRef(null);
|
|
25
25
|
const navigate = useNavigate();
|
|
26
|
+
const initialLoadRef = useRef(true); // Ref to track initial load
|
|
26
27
|
const [dashboardSetting, setDashboardSetting] = useState(
|
|
27
|
-
userProfile.dashboard_setting || setting
|
|
28
|
+
dynamicDashboard ? userProfile.dashboard_setting || setting : setting
|
|
28
29
|
);
|
|
29
30
|
const [data, setData] = useState({});
|
|
30
31
|
const [dropdowns, setDropdowns] = useState({});
|
|
@@ -84,6 +85,7 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
84
85
|
try {
|
|
85
86
|
const promises = dashboardSetting.widgets.map(async (widget) => {
|
|
86
87
|
const widgetFilters = appliedFilters[widget.id] || {};
|
|
88
|
+
|
|
87
89
|
if (widget.filters) {
|
|
88
90
|
for (const filter of widget.filters) {
|
|
89
91
|
if (filter.url) {
|
|
@@ -110,12 +112,12 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
|
-
|
|
114
115
|
if (widget.api?.url && widget.api?.method) {
|
|
115
116
|
const requestParams = {
|
|
116
|
-
...widgetFilters,
|
|
117
117
|
...(widget.api.params || {}),
|
|
118
|
+
...widgetFilters,
|
|
118
119
|
};
|
|
120
|
+
|
|
119
121
|
return CustomFetch(
|
|
120
122
|
widget.api.url,
|
|
121
123
|
widget.api.method,
|
|
@@ -124,11 +126,21 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
124
126
|
}
|
|
125
127
|
return null;
|
|
126
128
|
});
|
|
129
|
+
|
|
127
130
|
const results = await Promise.all(promises);
|
|
131
|
+
|
|
128
132
|
const fetchedData = dashboardSetting.widgets.reduce(
|
|
129
133
|
(acc, widget, index) => {
|
|
130
134
|
if (results[index]) {
|
|
131
|
-
|
|
135
|
+
// Check if the response indicates an error
|
|
136
|
+
if (results[index]?.data?.value) {
|
|
137
|
+
console.error(
|
|
138
|
+
`API error for widget ${widget.id}:`,
|
|
139
|
+
results[index].data.value
|
|
140
|
+
);
|
|
141
|
+
} else {
|
|
142
|
+
acc[widget.id] = results[index]?.data;
|
|
143
|
+
}
|
|
132
144
|
}
|
|
133
145
|
return acc;
|
|
134
146
|
},
|
|
@@ -140,19 +152,41 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
140
152
|
}
|
|
141
153
|
};
|
|
142
154
|
|
|
155
|
+
// Single useEffect for initial data fetch
|
|
143
156
|
useEffect(() => {
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
157
|
+
// This will run once after filters are initialized
|
|
158
|
+
if (Object.keys(filters).length > 0 && initialLoadRef.current) {
|
|
159
|
+
// Fetch data once with initial filters
|
|
160
|
+
fetchData(filters);
|
|
161
|
+
// Mark initial load as complete
|
|
162
|
+
initialLoadRef.current = false;
|
|
163
|
+
}
|
|
164
|
+
}, [filters]);
|
|
165
|
+
|
|
166
|
+
// Handle filter changes after initial load
|
|
167
|
+
const isInitialFilterChangeRef = useRef(true);
|
|
148
168
|
|
|
149
|
-
|
|
150
|
-
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
// Skip the first filter change (which happens during initialization)
|
|
171
|
+
if (isInitialFilterChangeRef.current) {
|
|
172
|
+
isInitialFilterChangeRef.current = false;
|
|
151
173
|
return;
|
|
152
174
|
}
|
|
153
175
|
|
|
154
|
-
|
|
155
|
-
|
|
176
|
+
// Only fetch data if filters have been initialized
|
|
177
|
+
if (!initialLoadRef.current && Object.keys(filters).length > 0) {
|
|
178
|
+
fetchData(filters);
|
|
179
|
+
}
|
|
180
|
+
}, [filters]);
|
|
181
|
+
|
|
182
|
+
// Handle dashboardSetting changes
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
// Skip the initial render
|
|
185
|
+
if (!initialLoadRef.current) {
|
|
186
|
+
// Only fetch data if it's not the initial load
|
|
187
|
+
fetchData(filters);
|
|
188
|
+
}
|
|
189
|
+
}, [dashboardSetting]);
|
|
156
190
|
|
|
157
191
|
const openModal = (widgetId) => {
|
|
158
192
|
setModalContent(widgetId);
|
|
@@ -453,10 +487,12 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
453
487
|
<button
|
|
454
488
|
className={`${styles.btn} ${styles['btn-secondary']}`}
|
|
455
489
|
onClick={() => {
|
|
490
|
+
// Clear filters
|
|
456
491
|
setFilters((prevFilters) => ({
|
|
457
492
|
...prevFilters,
|
|
458
493
|
[widget.id]: {},
|
|
459
494
|
}));
|
|
495
|
+
|
|
460
496
|
fetchData();
|
|
461
497
|
}}
|
|
462
498
|
>
|
|
@@ -470,11 +506,22 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
470
506
|
|
|
471
507
|
const renderWidget = (widget) => {
|
|
472
508
|
const widgetData = data[widget.id] || [];
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
509
|
+
|
|
510
|
+
// More detailed check for valid data
|
|
511
|
+
const hasData =
|
|
512
|
+
// Array with items
|
|
513
|
+
(Array.isArray(widgetData) && widgetData.length > 0) ||
|
|
514
|
+
// Object with data array
|
|
515
|
+
(widgetData?.data &&
|
|
516
|
+
Array.isArray(widgetData.data) &&
|
|
517
|
+
widgetData.data.length > 0) ||
|
|
518
|
+
// Simple value for counter widgets
|
|
519
|
+
(widget.type === 'counter' &&
|
|
520
|
+
widgetData !== null &&
|
|
521
|
+
widgetData !== undefined);
|
|
522
|
+
|
|
523
|
+
if (hasData || widget.type === 'bar') {
|
|
524
|
+
// Always try to render bar charts for debugging
|
|
478
525
|
switch (widget.type) {
|
|
479
526
|
case 'counter':
|
|
480
527
|
return (
|
|
@@ -524,8 +571,33 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
524
571
|
let colors = {};
|
|
525
572
|
let keys = [];
|
|
526
573
|
|
|
527
|
-
// Handle
|
|
574
|
+
// Handle specific structure with bar.data property
|
|
528
575
|
if (
|
|
576
|
+
widgetData.bar &&
|
|
577
|
+
widgetData.bar.data &&
|
|
578
|
+
Array.isArray(widgetData.bar.data)
|
|
579
|
+
) {
|
|
580
|
+
barData = widgetData.bar.data;
|
|
581
|
+
|
|
582
|
+
// Use the keys from the data
|
|
583
|
+
if (widgetData.keys && Array.isArray(widgetData.keys)) {
|
|
584
|
+
keys = widgetData.keys;
|
|
585
|
+
} else if (barData[0]) {
|
|
586
|
+
// Extract keys from the first item, excluding indexBy field (usually 'supervisor')
|
|
587
|
+
const indexField =
|
|
588
|
+
widget.props.indexBy || 'supervisor';
|
|
589
|
+
keys = Object.keys(barData[0] || {}).filter(
|
|
590
|
+
(key) => key !== indexField
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Set the indexBy field based on the data structure
|
|
595
|
+
if (barData[0] && barData[0].supervisor) {
|
|
596
|
+
widget.props.indexBy = 'supervisor';
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
// Handle new data structure (from your first example)
|
|
600
|
+
else if (
|
|
529
601
|
widgetData.data &&
|
|
530
602
|
Array.isArray(widgetData.data) &&
|
|
531
603
|
widgetData.colors
|
|
@@ -533,9 +605,13 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
533
605
|
barData = widgetData.data;
|
|
534
606
|
colors = widgetData.colors;
|
|
535
607
|
// Extract keys from the first data item, excluding 'month' or any other index field
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
608
|
+
if (barData[0]) {
|
|
609
|
+
keys = Object.keys(barData[0] || {}).filter(
|
|
610
|
+
(key) => key !== 'month'
|
|
611
|
+
);
|
|
612
|
+
} else {
|
|
613
|
+
console.log(`No data items found in barData`);
|
|
614
|
+
}
|
|
539
615
|
}
|
|
540
616
|
// Handle newer data structure (from your second example)
|
|
541
617
|
else if (
|
|
@@ -545,6 +621,7 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
545
621
|
) {
|
|
546
622
|
barData = widgetData.data;
|
|
547
623
|
keys = widgetData.keys;
|
|
624
|
+
|
|
548
625
|
// Extract colors from the first data item
|
|
549
626
|
if (barData[0]) {
|
|
550
627
|
keys.forEach((key) => {
|
|
@@ -555,25 +632,103 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
555
632
|
});
|
|
556
633
|
}
|
|
557
634
|
}
|
|
635
|
+
// Handle array of arrays structure
|
|
636
|
+
else if (
|
|
637
|
+
Array.isArray(widgetData) &&
|
|
638
|
+
widgetData.length > 0 &&
|
|
639
|
+
Array.isArray(widgetData[0])
|
|
640
|
+
) {
|
|
641
|
+
barData = widgetData[0];
|
|
642
|
+
// Try to extract keys from the first item
|
|
643
|
+
if (barData[0]) {
|
|
644
|
+
keys = Object.keys(barData[0] || {}).filter(
|
|
645
|
+
(key) => key !== 'month'
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
558
649
|
// Handle legacy data structure
|
|
559
650
|
else {
|
|
560
651
|
barData =
|
|
561
652
|
widgetData.bar?.data ||
|
|
562
653
|
widgetData.data ||
|
|
563
654
|
widgetData;
|
|
655
|
+
|
|
656
|
+
// Check if barData is an array of arrays and use the first one
|
|
657
|
+
if (
|
|
658
|
+
Array.isArray(barData) &&
|
|
659
|
+
barData.length > 0 &&
|
|
660
|
+
Array.isArray(barData[0])
|
|
661
|
+
) {
|
|
662
|
+
barData = barData[0];
|
|
663
|
+
}
|
|
664
|
+
|
|
564
665
|
if (widgetData.keys) {
|
|
565
|
-
keys = widgetData.keys
|
|
666
|
+
keys = Array.isArray(widgetData.keys)
|
|
667
|
+
? widgetData.keys
|
|
668
|
+
: [];
|
|
669
|
+
} else if (barData && barData[0]) {
|
|
670
|
+
// Try to extract keys from the first item
|
|
671
|
+
keys = Object.keys(barData[0] || {}).filter(
|
|
672
|
+
(key) => key !== 'month'
|
|
673
|
+
);
|
|
566
674
|
}
|
|
567
675
|
}
|
|
568
676
|
|
|
569
|
-
//
|
|
570
|
-
if
|
|
677
|
+
// Always use static colors from props if available
|
|
678
|
+
// First check if we have stored original colors
|
|
679
|
+
if (
|
|
680
|
+
widget.props._originalColors &&
|
|
681
|
+
Array.isArray(widget.props._originalColors)
|
|
682
|
+
) {
|
|
683
|
+
// Use the stored original colors
|
|
684
|
+
const originalColors = widget.props._originalColors;
|
|
685
|
+
|
|
686
|
+
// Create a direct mapping of keys to colors
|
|
687
|
+
const colorMap = {};
|
|
688
|
+
if (Array.isArray(keys)) {
|
|
689
|
+
keys.forEach((key, index) => {
|
|
690
|
+
colorMap[key] =
|
|
691
|
+
originalColors[
|
|
692
|
+
index % originalColors.length
|
|
693
|
+
];
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
// Otherwise use the colors from the props
|
|
698
|
+
else if (
|
|
699
|
+
widget.props.colors &&
|
|
700
|
+
Array.isArray(widget.props.colors) &&
|
|
701
|
+
widget.props.colors.length > 0
|
|
702
|
+
) {
|
|
703
|
+
// Store the original colors array
|
|
704
|
+
const originalColors = [...widget.props.colors];
|
|
705
|
+
|
|
706
|
+
// Create a direct mapping of keys to colors
|
|
707
|
+
const colorMap = {};
|
|
708
|
+
if (Array.isArray(keys)) {
|
|
709
|
+
keys.forEach((key, index) => {
|
|
710
|
+
colorMap[key] =
|
|
711
|
+
originalColors[
|
|
712
|
+
index % originalColors.length
|
|
713
|
+
];
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// Store the original colors array in a separate property
|
|
718
|
+
// This ensures it's preserved for future renders
|
|
719
|
+
widget.props._originalColors = originalColors;
|
|
720
|
+
}
|
|
721
|
+
// Fallback to API colors if no static colors in props
|
|
722
|
+
else if (Object.keys(colors).length > 0) {
|
|
571
723
|
widget.props.colors = ({ id }) => colors[id];
|
|
572
724
|
}
|
|
573
725
|
|
|
574
726
|
// Set keys in props if they exist
|
|
575
|
-
if (keys.length > 0) {
|
|
727
|
+
if (Array.isArray(keys) && keys.length > 0) {
|
|
576
728
|
widget.props.keys = keys;
|
|
729
|
+
} else {
|
|
730
|
+
// Set default keys if none are found
|
|
731
|
+
widget.props.keys = ['value'];
|
|
577
732
|
}
|
|
578
733
|
|
|
579
734
|
// Handle legend setup
|
|
@@ -604,19 +759,60 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
|
|
|
604
759
|
widget.props.tooltip = CustomTooltip;
|
|
605
760
|
}
|
|
606
761
|
|
|
607
|
-
|
|
762
|
+
// Ensure barData is an array and has items
|
|
763
|
+
if (Array.isArray(barData) && barData.length > 0) {
|
|
764
|
+
// Make sure we have an indexBy field in each data item
|
|
765
|
+
const indexField = widget.props.indexBy || 'month';
|
|
766
|
+
const hasIndexField = barData.every(
|
|
767
|
+
(item) =>
|
|
768
|
+
item &&
|
|
769
|
+
typeof item === 'object' &&
|
|
770
|
+
indexField in item
|
|
771
|
+
);
|
|
772
|
+
|
|
773
|
+
if (!hasIndexField) {
|
|
774
|
+
console.warn(
|
|
775
|
+
`Bar data items missing required index field '${indexField}'`
|
|
776
|
+
);
|
|
777
|
+
// Add a default index if missing
|
|
778
|
+
barData = barData.map((item, i) => ({
|
|
779
|
+
...item,
|
|
780
|
+
[indexField]:
|
|
781
|
+
item[indexField] || `Item ${i + 1}`,
|
|
782
|
+
}));
|
|
783
|
+
}
|
|
784
|
+
|
|
608
785
|
return (
|
|
609
786
|
<div style={{ height: widget.height || '600px' }}>
|
|
610
787
|
<ResponsiveBar
|
|
611
788
|
key={`${widget.id}-${widget.size}`}
|
|
612
789
|
data={barData}
|
|
790
|
+
indexBy={indexField}
|
|
791
|
+
{...widget.props}
|
|
792
|
+
/>
|
|
793
|
+
</div>
|
|
794
|
+
);
|
|
795
|
+
} else {
|
|
796
|
+
// Create dummy data if no data is available
|
|
797
|
+
const dummyData = [
|
|
798
|
+
{
|
|
799
|
+
month: 'No Data',
|
|
800
|
+
value: 0,
|
|
801
|
+
},
|
|
802
|
+
];
|
|
803
|
+
|
|
804
|
+
return (
|
|
805
|
+
<div style={{ height: widget.height || '600px' }}>
|
|
806
|
+
<ResponsiveBar
|
|
807
|
+
key={`${widget.id}-${widget.size}`}
|
|
808
|
+
data={dummyData}
|
|
613
809
|
indexBy="month"
|
|
810
|
+
keys={['value']}
|
|
614
811
|
{...widget.props}
|
|
615
812
|
/>
|
|
616
813
|
</div>
|
|
617
814
|
);
|
|
618
815
|
}
|
|
619
|
-
break;
|
|
620
816
|
}
|
|
621
817
|
case 'line':
|
|
622
818
|
if (widgetData.length > 0) {
|
|
@@ -1070,10 +1070,14 @@ function GenericDetail({
|
|
|
1070
1070
|
case 'dropzone':
|
|
1071
1071
|
const downloadFile = (file) => {
|
|
1072
1072
|
const { id, file_url, file_name } = file;
|
|
1073
|
+
const toastId = toast.loading(
|
|
1074
|
+
'Downloading file...'
|
|
1075
|
+
);
|
|
1073
1076
|
|
|
1074
1077
|
// If file_url exists, use it for the download, else use the id to download
|
|
1075
1078
|
const urlToDownload =
|
|
1076
|
-
file_url ||
|
|
1079
|
+
file_url ||
|
|
1080
|
+
`/ajax/files/downloadContent/${id}`;
|
|
1077
1081
|
|
|
1078
1082
|
// Use fetch to retrieve the file as a blob
|
|
1079
1083
|
fetch(urlToDownload, {
|
|
@@ -1083,19 +1087,129 @@ function GenericDetail({
|
|
|
1083
1087
|
'application/octet-stream', // Specify content type as binary
|
|
1084
1088
|
},
|
|
1085
1089
|
})
|
|
1086
|
-
.then((response) =>
|
|
1090
|
+
.then(async (response) => {
|
|
1091
|
+
if (!response.ok) {
|
|
1092
|
+
// Try to extract error message from response if possible
|
|
1093
|
+
// Clone the response to read it as JSON first
|
|
1094
|
+
const clonedResponse =
|
|
1095
|
+
response.clone();
|
|
1096
|
+
|
|
1097
|
+
try {
|
|
1098
|
+
// First try to parse as JSON
|
|
1099
|
+
const errorData =
|
|
1100
|
+
await clonedResponse.json();
|
|
1101
|
+
|
|
1102
|
+
if (
|
|
1103
|
+
errorData &&
|
|
1104
|
+
errorData.error
|
|
1105
|
+
) {
|
|
1106
|
+
throw new Error(
|
|
1107
|
+
errorData.error
|
|
1108
|
+
);
|
|
1109
|
+
} else if (
|
|
1110
|
+
errorData &&
|
|
1111
|
+
errorData.message
|
|
1112
|
+
) {
|
|
1113
|
+
throw new Error(
|
|
1114
|
+
errorData.message
|
|
1115
|
+
);
|
|
1116
|
+
} else if (
|
|
1117
|
+
errorData &&
|
|
1118
|
+
errorData.value
|
|
1119
|
+
) {
|
|
1120
|
+
throw new Error(
|
|
1121
|
+
errorData.value
|
|
1122
|
+
);
|
|
1123
|
+
} else {
|
|
1124
|
+
// JSON parsed but no known error fields
|
|
1125
|
+
throw new Error(
|
|
1126
|
+
`HTTP error! Status: ${response.status}`
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
} catch (jsonError) {
|
|
1130
|
+
// If we can't parse as JSON, try to get text
|
|
1131
|
+
try {
|
|
1132
|
+
const textResponse =
|
|
1133
|
+
response.clone();
|
|
1134
|
+
const errorText =
|
|
1135
|
+
await textResponse.text();
|
|
1136
|
+
|
|
1137
|
+
// Check if the text looks like JSON but wasn't parsed correctly
|
|
1138
|
+
if (
|
|
1139
|
+
errorText.includes(
|
|
1140
|
+
'"error":'
|
|
1141
|
+
)
|
|
1142
|
+
) {
|
|
1143
|
+
// Try to extract the error message with regex
|
|
1144
|
+
const errorMatch =
|
|
1145
|
+
errorText.match(
|
|
1146
|
+
/"error":"([^"]+)"/i
|
|
1147
|
+
);
|
|
1148
|
+
if (
|
|
1149
|
+
errorMatch &&
|
|
1150
|
+
errorMatch[1]
|
|
1151
|
+
) {
|
|
1152
|
+
throw new Error(
|
|
1153
|
+
errorMatch[1]
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// If we got text but couldn't extract a specific error
|
|
1159
|
+
if (
|
|
1160
|
+
errorText &&
|
|
1161
|
+
errorText.length < 100
|
|
1162
|
+
) {
|
|
1163
|
+
throw new Error(
|
|
1164
|
+
errorText
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
} catch (textError) {
|
|
1168
|
+
// If all else fails, fall back to status
|
|
1169
|
+
throw new Error(
|
|
1170
|
+
`HTTP error! Status: ${response.status}`
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
return response.blob(); // Convert response to Blob
|
|
1176
|
+
})
|
|
1087
1177
|
.then((blob) => {
|
|
1178
|
+
// Validate that we have a valid blob with content
|
|
1179
|
+
if (!blob || blob.size === 0) {
|
|
1180
|
+
throw new Error(
|
|
1181
|
+
'Downloaded file is empty or invalid'
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1088
1185
|
// Use FileSaver to download the file with the specified name
|
|
1089
1186
|
saveAs(blob, file_name);
|
|
1187
|
+
|
|
1188
|
+
toast.update(toastId, {
|
|
1189
|
+
render: 'Download successful!',
|
|
1190
|
+
type: 'success',
|
|
1191
|
+
isLoading: false,
|
|
1192
|
+
autoClose: 5000,
|
|
1193
|
+
closeButton: true,
|
|
1194
|
+
});
|
|
1090
1195
|
})
|
|
1091
1196
|
.catch((error) => {
|
|
1092
1197
|
console.error(
|
|
1093
1198
|
'Error downloading the file:',
|
|
1094
1199
|
error
|
|
1095
1200
|
);
|
|
1201
|
+
|
|
1202
|
+
toast.update(toastId, {
|
|
1203
|
+
render: `Error downloading file: ${
|
|
1204
|
+
error.message || 'Unknown error'
|
|
1205
|
+
}`,
|
|
1206
|
+
type: 'error',
|
|
1207
|
+
isLoading: false,
|
|
1208
|
+
autoClose: 5000,
|
|
1209
|
+
closeButton: true,
|
|
1210
|
+
});
|
|
1096
1211
|
});
|
|
1097
1212
|
};
|
|
1098
|
-
|
|
1099
1213
|
const deleteFile = (e, id, name) => {
|
|
1100
1214
|
if (e) {
|
|
1101
1215
|
e.stopPropagation();
|
|
@@ -434,42 +434,109 @@ const GenericDynamic = ({
|
|
|
434
434
|
|
|
435
435
|
const handleCustomButton = async (s) => {
|
|
436
436
|
let payload = {};
|
|
437
|
-
|
|
438
|
-
case 'save':
|
|
439
|
-
if (s.payload?.length > 0) {
|
|
440
|
-
s.payload.forEach((p) => {
|
|
441
|
-
if (data[p]) {
|
|
442
|
-
payload[p] = data[p];
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
}
|
|
437
|
+
let toastId;
|
|
446
438
|
|
|
447
|
-
|
|
439
|
+
try {
|
|
440
|
+
switch (s.type) {
|
|
441
|
+
case 'save':
|
|
442
|
+
toastId = toast.loading('Downloading file...');
|
|
443
|
+
|
|
444
|
+
if (s.payload?.length > 0) {
|
|
445
|
+
s.payload.forEach((p) => {
|
|
446
|
+
if (data[p]) {
|
|
447
|
+
payload[p] = data[p];
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
}
|
|
448
451
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
452
|
+
const resSave = await Download(s.url, s.method, payload);
|
|
453
|
+
|
|
454
|
+
if (resSave.data) {
|
|
455
|
+
// Check if response has a value property which indicates an error
|
|
456
|
+
if (resSave.data.value) {
|
|
457
|
+
toast.update(toastId, {
|
|
458
|
+
render: `Error: ${resSave.data.value}`,
|
|
459
|
+
type: 'error',
|
|
460
|
+
isLoading: false,
|
|
461
|
+
autoClose: 5000,
|
|
462
|
+
closeButton: true,
|
|
463
|
+
});
|
|
464
|
+
} else {
|
|
465
|
+
saveAs(resSave.data);
|
|
466
|
+
toast.update(toastId, {
|
|
467
|
+
render: 'Download successful!',
|
|
468
|
+
type: 'success',
|
|
469
|
+
isLoading: false,
|
|
470
|
+
autoClose: 5000,
|
|
471
|
+
closeButton: true,
|
|
472
|
+
});
|
|
458
473
|
}
|
|
459
|
-
}
|
|
460
|
-
|
|
474
|
+
} else {
|
|
475
|
+
toast.update(toastId, {
|
|
476
|
+
render: 'Error: No data received',
|
|
477
|
+
type: 'error',
|
|
478
|
+
isLoading: false,
|
|
479
|
+
autoClose: 5000,
|
|
480
|
+
closeButton: true,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
break;
|
|
484
|
+
|
|
485
|
+
case 'fetch':
|
|
486
|
+
toastId = toast.loading('Fetching data...');
|
|
461
487
|
|
|
462
|
-
|
|
488
|
+
if (s.payload?.length > 0) {
|
|
489
|
+
s.payload.forEach((p) => {
|
|
490
|
+
if (data[p]) {
|
|
491
|
+
payload[p] = data[p];
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
}
|
|
463
495
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
s.
|
|
496
|
+
const resFetch = await CustomFetch(
|
|
497
|
+
s.url,
|
|
498
|
+
s.method,
|
|
499
|
+
payload
|
|
467
500
|
);
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
501
|
+
|
|
502
|
+
if (resFetch.data.error === '') {
|
|
503
|
+
toast.update(toastId, {
|
|
504
|
+
render: s.message
|
|
505
|
+
? s.message
|
|
506
|
+
: 'Form fetched successfully',
|
|
507
|
+
type: 'success',
|
|
508
|
+
isLoading: false,
|
|
509
|
+
autoClose: 5000,
|
|
510
|
+
closeButton: true,
|
|
511
|
+
});
|
|
512
|
+
} else {
|
|
513
|
+
toast.update(toastId, {
|
|
514
|
+
render: `Error: ${resFetch.data.error}`,
|
|
515
|
+
type: 'error',
|
|
516
|
+
isLoading: false,
|
|
517
|
+
autoClose: 5000,
|
|
518
|
+
closeButton: true,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
break;
|
|
522
|
+
|
|
523
|
+
default:
|
|
524
|
+
console.info(s, 'default');
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
} catch (error) {
|
|
528
|
+
console.error('Error in handleCustomButton:', error);
|
|
529
|
+
if (toastId) {
|
|
530
|
+
toast.update(toastId, {
|
|
531
|
+
render: `Error: ${error.message || 'Unknown error'}`,
|
|
532
|
+
type: 'error',
|
|
533
|
+
isLoading: false,
|
|
534
|
+
autoClose: 5000,
|
|
535
|
+
closeButton: true,
|
|
536
|
+
});
|
|
537
|
+
} else {
|
|
538
|
+
toast.error(`Error: ${error.message || 'Unknown error'}`);
|
|
539
|
+
}
|
|
473
540
|
}
|
|
474
541
|
};
|
|
475
542
|
|