@visns-studio/visns-components 4.10.6 → 4.10.8

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
@@ -75,7 +75,7 @@
75
75
  "react-dom": "^17.0.0 || ^18.0.0"
76
76
  },
77
77
  "name": "@visns-studio/visns-components",
78
- "version": "4.10.6",
78
+ "version": "4.10.8",
79
79
  "description": "Various packages to assist in the development of our Custom Applications.",
80
80
  "main": "src/index.js",
81
81
  "files": [
@@ -60,6 +60,7 @@ import CustomFetch from './Fetch';
60
60
  import Download from './Download';
61
61
  import Form from './Form';
62
62
  import _ from 'lodash';
63
+ import { distance2D } from 'framer-motion';
63
64
 
64
65
  const loadData = async (
65
66
  { skip, limit, sortInfo, filterValue },
@@ -149,6 +150,19 @@ const DataGrid = forwardRef(
149
150
  }
150
151
  }, [audioSource]);
151
152
 
153
+ /** JSON Modal States */
154
+ const [modalJsonShow, setModalJsonShow] = useState(false);
155
+ const [jsonData, setJsonData] = useState({});
156
+
157
+ /** JSON Modal Functions */
158
+ const modalJsonOpen = () => {
159
+ setModalJsonShow(true);
160
+ };
161
+
162
+ const modalJsonClose = () => {
163
+ setModalJsonShow(false);
164
+ };
165
+
152
166
  /** Gallery Modal States */
153
167
  const [modalGalleryShow, setModalGalleryShow] = useState(false);
154
168
  const [galleryData, setGalleryData] = useState([]);
@@ -228,23 +242,65 @@ const DataGrid = forwardRef(
228
242
  const toastId = toast.loading('Starting download please wait...');
229
243
 
230
244
  try {
231
- const res = await Download(
232
- `/ajax/files/download/${d.id}/null`,
233
- 'GET',
234
- {}
235
- );
245
+ if (d.id && d.id > 0) {
246
+ const res = await Download(
247
+ `/ajax/files/download/${d.id}/null`,
248
+ 'GET',
249
+ {}
250
+ );
236
251
 
237
- if (res.data.error) {
238
- toast.error(res.data.error);
252
+ if (res.data.error) {
253
+ toast.error(res.data.error);
254
+ } else {
255
+ // Assuming the response contains a Blob or similar data
256
+ if (res.data && res.data instanceof Blob) {
257
+ const fileName = `${d.file_name}`;
258
+ saveAs(res.data, fileName);
259
+ } else {
260
+ // Handle the case where the response is not a Blob
261
+ toast.error('Invalid file format received.');
262
+ }
263
+ }
239
264
  } else {
240
- // Assuming the response contains a Blob or similar data
241
- if (res.data && res.data instanceof Blob) {
242
- const fileName = `${d.file_name}`;
243
- saveAs(res.data, fileName);
265
+ toast.error(
266
+ 'An issue with downloading the file has occurred.'
267
+ );
268
+ }
269
+ } catch (error) {
270
+ console.info(error);
271
+ } finally {
272
+ // Dismiss the loading toast in the finally block to ensure it's always dismissed
273
+ toast.dismiss(toastId);
274
+ }
275
+ };
276
+
277
+ const handleDownloadPath = async (file) => {
278
+ const toastId = toast.loading('Starting download please wait...');
279
+
280
+ try {
281
+ if (file.file_path && file.file_name && file.file_extension) {
282
+ const res = await Download(
283
+ `/ajax/files/downloadByPath`,
284
+ 'POST',
285
+ { ...file }
286
+ );
287
+
288
+ if (res.data.error) {
289
+ toast.error(res.data.error);
244
290
  } else {
245
- // Handle the case where the response is not a Blob
246
- toast.error('Invalid file format received.');
291
+ // Assuming the response contains a Blob or similar data
292
+ if (res.data && res.data instanceof Blob) {
293
+ const fileName = `${file.file_name}`;
294
+ saveAs(res.data, fileName);
295
+ } else {
296
+ // Handle the case where the response is not a Blob
297
+ toast.error('Invalid file format received.');
298
+ }
247
299
  }
300
+ } else {
301
+ toast.error(
302
+ 'An issue with downloading the file has occurred.'
303
+ );
248
304
  }
249
305
  } catch (error) {
250
306
  console.info(error);
@@ -570,6 +626,15 @@ const DataGrid = forwardRef(
570
626
  );
571
627
  }
572
628
  break;
629
+ case 'view':
630
+ modalJsonOpen();
631
+ console.info(d[s.key], s.headers);
632
+ setJsonData((prevState) => ({
633
+ ...prevState,
634
+ data: d[s.key],
635
+ headers: s.headers,
636
+ }));
637
+ break;
573
638
  case 'update':
574
639
  modalOpen('update', d.id);
575
640
  break;
@@ -1127,6 +1192,8 @@ const DataGrid = forwardRef(
1127
1192
  return getIconComponent(Clock);
1128
1193
  case 'update':
1129
1194
  return getIconComponent(Edit);
1195
+ case 'view':
1196
+ return getIconComponent(Search);
1130
1197
  default:
1131
1198
  return null;
1132
1199
  }
@@ -1709,9 +1776,19 @@ const DataGrid = forwardRef(
1709
1776
  onClick={(e) => {
1710
1777
  e.stopPropagation();
1711
1778
  e.preventDefault();
1712
- handleDownload(
1713
- file
1714
- );
1779
+
1780
+ if (
1781
+ file.id &&
1782
+ file.id > 0
1783
+ ) {
1784
+ handleDownload(
1785
+ file
1786
+ );
1787
+ } else {
1788
+ handleDownloadPath(
1789
+ file
1790
+ );
1791
+ }
1715
1792
  }}
1716
1793
  style={{
1717
1794
  marginRight:
@@ -2526,6 +2603,69 @@ const DataGrid = forwardRef(
2526
2603
  }
2527
2604
  };
2528
2605
 
2606
+ const snakeCaseToTitle = (text) => {
2607
+ return text
2608
+ .replace(/_/g, ' ')
2609
+ .replace(/\b\w/g, (char) => char.toUpperCase()); // Capitalize first letter of each word
2610
+ };
2611
+
2612
+ // Recursive function to handle nested objects
2613
+ const renderField = (key, value) => {
2614
+ // If the value is an object, recursively render its fields
2615
+ if (typeof value === 'object' && value !== null) {
2616
+ return (
2617
+ <div key={key} style={{ marginBottom: '1rem' }}>
2618
+ <h4
2619
+ style={{
2620
+ fontSize: '1.2rem',
2621
+ marginBottom: '0.5rem',
2622
+ color: '#333',
2623
+ borderBottom: '1px solid #ccc',
2624
+ }}
2625
+ >
2626
+ {snakeCaseToTitle(key)}
2627
+ </h4>
2628
+ <div style={{ paddingLeft: '1.5rem' }}>
2629
+ {Object.keys(value).map((childKey) =>
2630
+ renderField(childKey, value[childKey])
2631
+ )}
2632
+ </div>
2633
+ </div>
2634
+ );
2635
+ }
2636
+ // Otherwise, render the key and value as a label and paragraph
2637
+ return (
2638
+ <div key={key} style={{ marginBottom: '1rem' }}>
2639
+ <span
2640
+ style={{
2641
+ fontWeight: 'bold',
2642
+ marginBottom: '0.2rem',
2643
+ display: 'block',
2644
+ color: '#444',
2645
+ }}
2646
+ >
2647
+ {snakeCaseToTitle(key)}
2648
+ </span>
2649
+ <p
2650
+ style={{
2651
+ margin: 0,
2652
+ color: '#666',
2653
+ backgroundColor: '#f9f9f9',
2654
+ padding: '0.5rem',
2655
+ borderRadius: '5px',
2656
+ }}
2657
+ >
2658
+ {value !== null ? value : 'N/A'}
2659
+ </p>
2660
+ </div>
2661
+ );
2662
+ };
2663
+
2664
+ const getHeaderLabel = (headers, parentKey) => {
2665
+ const headerObj = headers.find((header) => header.id === parentKey);
2666
+ return headerObj ? headerObj.label : snakeCaseToTitle(parentKey);
2667
+ };
2668
+
2529
2669
  useEffect(() => {
2530
2670
  columns.forEach((column) => {
2531
2671
  if (column.filter && column.filter.url) {
@@ -2578,10 +2718,15 @@ const DataGrid = forwardRef(
2578
2718
  : 400,
2579
2719
  boxShadow: 'none',
2580
2720
  });
2721
+
2581
2722
  const headerProps = {
2582
2723
  style: style ? style : {},
2583
2724
  };
2584
2725
 
2726
+ useEffect(() => {
2727
+ console.info(jsonData);
2728
+ }, [jsonData]);
2729
+
2585
2730
  useEffect(() => {
2586
2731
  const getMinimumHeight = () => {
2587
2732
  if (gridHeight > 0) return gridHeight;
@@ -2722,6 +2867,100 @@ const DataGrid = forwardRef(
2722
2867
  </div>
2723
2868
  </div>
2724
2869
  </Popup>
2870
+ <Popup
2871
+ open={modalJsonShow}
2872
+ onClose={modalJsonClose}
2873
+ closeOnDocumentClick={false}
2874
+ >
2875
+ <div
2876
+ className={`${styles.modalwrap} ${styles['top--modal']}`}
2877
+ >
2878
+ <div className={styles.modal}>
2879
+ <div className={styles.modal__header}>
2880
+ <h1>View Data</h1>
2881
+ <button
2882
+ className={styles.modal__close}
2883
+ onClick={modalJsonClose}
2884
+ >
2885
+ <CircleX strokeWidth={1} size={24} />
2886
+ </button>
2887
+ </div>
2888
+ <div className={styles.modal__content}>
2889
+ <div className={styles.formcontainer}>
2890
+ <div
2891
+ style={{
2892
+ lineHeight: '1.5',
2893
+ }}
2894
+ >
2895
+ {jsonData.headers &&
2896
+ jsonData.headers.map((header) => {
2897
+ const parentKey = header.id;
2898
+
2899
+ // Skip rendering if the parentKey is "id" or doesn't exist in jsonData
2900
+ if (
2901
+ parentKey === 'id' ||
2902
+ !(
2903
+ parentKey in
2904
+ jsonData.data
2905
+ )
2906
+ )
2907
+ return null;
2908
+
2909
+ return (
2910
+ <div
2911
+ key={parentKey}
2912
+ style={{
2913
+ marginBottom:
2914
+ '2rem',
2915
+ }}
2916
+ >
2917
+ {/* Section Header */}
2918
+ <h3
2919
+ style={{
2920
+ fontSize:
2921
+ '1.4rem',
2922
+ marginBottom:
2923
+ '1rem',
2924
+ color: '#222',
2925
+ borderBottom:
2926
+ '2px solid #ddd',
2927
+ }}
2928
+ >
2929
+ {getHeaderLabel(
2930
+ jsonData.headers,
2931
+ parentKey
2932
+ )}
2933
+ </h3>
2934
+ <div
2935
+ style={{
2936
+ paddingLeft:
2937
+ '1rem',
2938
+ }}
2939
+ >
2940
+ {/* Render fields for each section */}
2941
+ {Object.keys(
2942
+ jsonData.data[
2943
+ parentKey
2944
+ ]
2945
+ ).map((childKey) =>
2946
+ renderField(
2947
+ childKey,
2948
+ jsonData
2949
+ .data[
2950
+ parentKey
2951
+ ][childKey]
2952
+ )
2953
+ )}
2954
+ </div>
2955
+ </div>
2956
+ );
2957
+ })}
2958
+ </div>
2959
+ </div>
2960
+ </div>
2961
+ </div>
2962
+ </div>
2963
+ </Popup>
2725
2964
  </>
2726
2965
  );
2727
2966
  }