@visns-studio/visns-components 4.10.48 → 5.0.1-8.1

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.
Files changed (61) hide show
  1. package/package.json +29 -29
  2. package/src/components/cms/Field.jsx +39 -63
  3. package/src/components/crm/AsyncSelect.jsx +121 -15
  4. package/src/components/crm/Breadcrumb.jsx +2 -18
  5. package/src/components/crm/DataGrid.jsx +51 -424
  6. package/src/components/crm/Field.jsx +185 -358
  7. package/src/components/crm/Form.jsx +104 -92
  8. package/src/components/crm/MultiSelect.jsx +66 -45
  9. package/src/components/crm/Navigation.jsx +9 -92
  10. package/src/components/crm/QuickAction.jsx +1 -0
  11. package/src/components/crm/auth/Login.jsx +9 -1
  12. package/src/components/crm/auth/Profile.jsx +4 -2
  13. package/src/components/crm/auth/styles/Login.module.scss +52 -82
  14. package/src/components/crm/auth/styles/Profile.module.scss +150 -44
  15. package/src/components/crm/auth/styles/Reset.module.scss +55 -37
  16. package/src/components/crm/auth/styles/Verify.module.scss +55 -76
  17. package/src/components/crm/generic/GenericAuth.jsx +12 -5
  18. package/src/components/crm/generic/GenericDashboard.jsx +30 -340
  19. package/src/components/crm/generic/GenericDetail.jsx +534 -86
  20. package/src/components/crm/generic/GenericDynamic.jsx +76 -94
  21. package/src/components/crm/generic/GenericEditableTable.jsx +407 -0
  22. package/src/components/crm/generic/GenericFormBuilder.jsx +19 -79
  23. package/src/components/crm/generic/GenericIndex.jsx +1 -2
  24. package/src/components/crm/generic/styles/AuditLog.module.scss +4 -37
  25. package/src/components/crm/generic/styles/AuditLogs.module.scss +0 -51
  26. package/src/components/crm/generic/styles/GenericDetail.module.scss +263 -244
  27. package/src/components/crm/generic/styles/GenericDynamic.module.scss +100 -198
  28. package/src/components/crm/generic/styles/GenericEditableTable.module.scss +178 -0
  29. package/src/components/crm/generic/styles/GenericFormBuilder.module.scss +63 -101
  30. package/src/components/crm/generic/styles/GenericIndex.module.scss +46 -66
  31. package/src/components/crm/generic/styles/GenericMain.module.scss +7 -7
  32. package/src/components/crm/generic/styles/GenericSort.module.scss +0 -36
  33. package/src/components/crm/generic/styles/NotificationList.module.scss +1 -32
  34. package/src/components/crm/styles/Autocomplete.module.scss +12 -20
  35. package/src/components/crm/styles/DataGrid.module.scss +28 -86
  36. package/src/components/crm/styles/Field.module.scss +72 -252
  37. package/src/components/crm/styles/Form.module.scss +141 -450
  38. package/src/components/crm/styles/Navigation.module.scss +356 -507
  39. package/src/components/crm/styles/Notification.module.scss +1 -0
  40. package/src/components/crm/styles/QrCode.module.scss +4 -18
  41. package/src/components/crm/styles/SwitchAccount.module.scss +0 -1
  42. package/src/components/crm/styles/TableFilter.module.scss +2 -1
  43. package/src/components/styles/global.css +164 -34
  44. package/src/index.js +0 -8
  45. package/src/components/crm/generic/styles/GenericDashboard.module.scss +0 -325
  46. package/src/components/crm/sketch/SketchField.jsx +0 -395
  47. package/src/components/crm/sketch/arrow.jsx +0 -108
  48. package/src/components/crm/sketch/circle.jsx +0 -75
  49. package/src/components/crm/sketch/default-tool.jsx +0 -16
  50. package/src/components/crm/sketch/fabrictool.jsx +0 -22
  51. package/src/components/crm/sketch/history.jsx +0 -144
  52. package/src/components/crm/sketch/json/config.json +0 -14
  53. package/src/components/crm/sketch/line.jsx +0 -64
  54. package/src/components/crm/sketch/pan.jsx +0 -48
  55. package/src/components/crm/sketch/pencil.jsx +0 -36
  56. package/src/components/crm/sketch/rectangle-label-object.jsx +0 -69
  57. package/src/components/crm/sketch/rectangle-label.jsx +0 -93
  58. package/src/components/crm/sketch/rectangle.jsx +0 -76
  59. package/src/components/crm/sketch/select.jsx +0 -16
  60. package/src/components/crm/sketch/tools.jsx +0 -11
  61. package/src/components/crm/sketch/utils.jsx +0 -67
@@ -14,6 +14,7 @@ import debounce from 'lodash.debounce';
14
14
  import moment from 'moment';
15
15
  import numeral from 'numeral';
16
16
  import Popup from 'reactjs-popup';
17
+ import 'reactjs-popup/dist/index.css';
17
18
  import parse from 'html-react-parser';
18
19
  import { saveAs } from 'file-saver';
19
20
  import NumberFilter from '@inovua/reactdatagrid-community/NumberFilter';
@@ -59,7 +60,7 @@ import 'react-confirm-alert/src/react-confirm-alert.css';
59
60
  import CustomFetch from './Fetch';
60
61
  import Download from './Download';
61
62
  import Form from './Form';
62
- import _, { set } from 'lodash';
63
+ import _ from 'lodash';
63
64
 
64
65
  const loadData = async (
65
66
  { skip, limit, sortInfo, filterValue },
@@ -94,7 +95,6 @@ const loadData = async (
94
95
  id: identifier,
95
96
  value: fv.value,
96
97
  operator: fv.operator,
97
- whereHas: fv.whereHas || [],
98
98
  });
99
99
  }
100
100
  } else {
@@ -150,19 +150,6 @@ const DataGrid = forwardRef(
150
150
  }
151
151
  }, [audioSource]);
152
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
-
166
153
  /** Gallery Modal States */
167
154
  const [modalGalleryShow, setModalGalleryShow] = useState(false);
168
155
  const [galleryData, setGalleryData] = useState([]);
@@ -182,32 +169,17 @@ const DataGrid = forwardRef(
182
169
  const [formId, setFormId] = useState(0);
183
170
  const [modalShow, setModalShow] = useState(false);
184
171
 
185
- const [formSettingData, setFormSettingData] = useState({});
186
- const [formSettingType, setFormSettingType] = useState('');
187
- const [formSettingId, setFormSettingId] = useState(0);
188
- const [modalSettingShow, setModalSettingShow] = useState(false);
189
-
190
172
  /** Modal Functions */
191
- const modalOpen = (type, id) => {
173
+ const modalOpen = (formType, formId) => {
192
174
  setModalShow(true);
193
- setFormType(type);
194
- setFormId(id);
175
+ setFormType(formType);
176
+ setFormId(formId);
195
177
  };
196
178
 
197
179
  const modalClose = () => {
198
180
  setModalShow(false);
199
181
  };
200
182
 
201
- const modalSettingOpen = (type, id) => {
202
- setModalSettingShow(true);
203
- setFormSettingType(type);
204
- setFormSettingId(id);
205
- };
206
-
207
- const modalSettingClose = () => {
208
- setModalSettingShow(false);
209
- };
210
-
211
183
  useEffect(() => {
212
184
  setFormData(form);
213
185
  }, [form]);
@@ -257,65 +229,23 @@ const DataGrid = forwardRef(
257
229
  const toastId = toast.loading('Starting download please wait...');
258
230
 
259
231
  try {
260
- if (d.id && d.id > 0) {
261
- const res = await Download(
262
- `/ajax/files/download/${d.id}/null`,
263
- 'GET',
264
- {}
265
- );
232
+ const res = await Download(
233
+ `/ajax/files/download/${d.id}/null`,
234
+ 'GET',
235
+ {}
236
+ );
266
237
 
267
- if (res.data.error) {
268
- toast.error(res.data.error);
269
- } else {
270
- // Assuming the response contains a Blob or similar data
271
- if (res.data && res.data instanceof Blob) {
272
- const fileName = `${d.file_name}`;
273
- saveAs(res.data, fileName);
274
- } else {
275
- // Handle the case where the response is not a Blob
276
- toast.error('Invalid file format received.');
277
- }
278
- }
238
+ if (res.data.error) {
239
+ toast.error(res.data.error);
279
240
  } else {
280
- toast.error(
281
- 'An issue with downloading the file has occurred.'
282
- );
283
- }
284
- } catch (error) {
285
- console.info(error);
286
- } finally {
287
- // Dismiss the loading toast in the finally block to ensure it's always dismissed
288
- toast.dismiss(toastId);
289
- }
290
- };
291
-
292
- const handleDownloadPath = async (file) => {
293
- const toastId = toast.loading('Starting download please wait...');
294
-
295
- try {
296
- if (file.file_path && file.file_name && file.file_extension) {
297
- const res = await Download(
298
- `/ajax/files/downloadByPath`,
299
- 'POST',
300
- { ...file }
301
- );
302
-
303
- if (res.data.error) {
304
- toast.error(res.data.error);
241
+ // Assuming the response contains a Blob or similar data
242
+ if (res.data && res.data instanceof Blob) {
243
+ const fileName = `${d.file_name}`;
244
+ saveAs(res.data, fileName);
305
245
  } else {
306
- // Assuming the response contains a Blob or similar data
307
- if (res.data && res.data instanceof Blob) {
308
- const fileName = `${file.file_name}`;
309
- saveAs(res.data, fileName);
310
- } else {
311
- // Handle the case where the response is not a Blob
312
- toast.error('Invalid file format received.');
313
- }
246
+ // Handle the case where the response is not a Blob
247
+ toast.error('Invalid file format received.');
314
248
  }
315
- } else {
316
- toast.error(
317
- 'An issue with downloading the file has occurred.'
318
- );
319
249
  }
320
250
  } catch (error) {
321
251
  console.info(error);
@@ -570,25 +500,6 @@ const DataGrid = forwardRef(
570
500
  ],
571
501
  });
572
502
  break;
573
- case 'form':
574
- if (s.key) {
575
- let fsd = s.form;
576
-
577
- if (fsd.fields && fsd.fields.length > 0) {
578
- fsd.fields.forEach((fItem, fKey) => {
579
- if (fItem.id === s.key) {
580
- fsd.fields[fKey].value = d.id;
581
- }
582
- });
583
-
584
- setFormSettingData((prevState) => ({
585
- ...prevState,
586
- ...fsd,
587
- }));
588
- }
589
- }
590
- modalSettingOpen('create', 0);
591
- break;
592
503
  case 'envelope':
593
504
  CustomFetch(s.url, 'POST', { id: d[s.key] }, (result) => {
594
505
  toast.success(result.message);
@@ -660,14 +571,6 @@ const DataGrid = forwardRef(
660
571
  );
661
572
  }
662
573
  break;
663
- case 'view':
664
- modalJsonOpen();
665
- setJsonData((prevState) => ({
666
- ...prevState,
667
- data: d[s.key],
668
- headers: s.headers,
669
- }));
670
- break;
671
574
  case 'update':
672
575
  modalOpen('update', d.id);
673
576
  break;
@@ -757,9 +660,7 @@ const DataGrid = forwardRef(
757
660
  } else {
758
661
  const column = rowProps.columns[columnIndex];
759
662
 
760
- const excludedColumnTypes = ['dropdown', 'text_input'];
761
-
762
- if (!excludedColumnTypes.includes(column.type)) {
663
+ if (column.type !== 'dropdown') {
763
664
  if (column.id !== '__checkbox-column') {
764
665
  if (column.link && column.link.hasOwnProperty('url')) {
765
666
  if (column.link.url) {
@@ -767,17 +668,7 @@ const DataGrid = forwardRef(
767
668
  const linkUrl = column.link.url;
768
669
  const linkKey =
769
670
  rowProps.columns[columnIndex].link.key;
770
- const rowData = linkKey.includes('.')
771
- ? linkKey
772
- .split('.')
773
- .reduce(
774
- (obj, key) =>
775
- obj && obj[key]
776
- ? obj[key]
777
- : null,
778
- rowProps.data
779
- )
780
- : rowProps.data[linkKey];
671
+ const rowData = rowProps.data[linkKey];
781
672
 
782
673
  if (column.link.hasOwnProperty('folder')) {
783
674
  const linkFolder =
@@ -794,13 +685,7 @@ const DataGrid = forwardRef(
794
685
  }
795
686
  }
796
687
  } else {
797
- if (rowData) {
798
- navigate(`${linkUrl}${rowData}`);
799
- } else {
800
- toast.warn(
801
- 'No data available for this link.'
802
- );
803
- }
688
+ navigate(`${linkUrl}${rowData}`);
804
689
  }
805
690
  } else {
806
691
  if (rowProps.data[column.id]) {
@@ -1231,7 +1116,6 @@ const DataGrid = forwardRef(
1231
1116
  return getIconComponent(Network);
1232
1117
  case 'gallery':
1233
1118
  return getIconComponent(Image);
1234
- case 'form':
1235
1119
  case 'link':
1236
1120
  return getIconComponent(LinkOut);
1237
1121
  case 'primary':
@@ -1244,8 +1128,6 @@ const DataGrid = forwardRef(
1244
1128
  return getIconComponent(Clock);
1245
1129
  case 'update':
1246
1130
  return getIconComponent(Edit);
1247
- case 'view':
1248
- return getIconComponent(Search);
1249
1131
  default:
1250
1132
  return null;
1251
1133
  }
@@ -1828,19 +1710,9 @@ const DataGrid = forwardRef(
1828
1710
  onClick={(e) => {
1829
1711
  e.stopPropagation();
1830
1712
  e.preventDefault();
1831
-
1832
- if (
1833
- file.id &&
1834
- file.id > 0
1835
- ) {
1836
- handleDownload(
1837
- file
1838
- );
1839
- } else {
1840
- handleDownloadPath(
1841
- file
1842
- );
1843
- }
1713
+ handleDownload(
1714
+ file
1715
+ );
1844
1716
  }}
1845
1717
  style={{
1846
1718
  marginRight:
@@ -2064,38 +1936,6 @@ const DataGrid = forwardRef(
2064
1936
  }, '');
2065
1937
 
2066
1938
  if (value) {
2067
- let columnStyle = {};
2068
- let columnValueChecker = '';
2069
-
2070
- if (
2071
- column?.active?.id &&
2072
- column?.active?.value
2073
- ) {
2074
- if (
2075
- data[column.active.id]
2076
- ?.value
2077
- ) {
2078
- columnValueChecker =
2079
- data[column.active.id]
2080
- ?.value;
2081
- } else if (
2082
- data[column.active.id]
2083
- ) {
2084
- columnValueChecker =
2085
- data[column.active.id];
2086
- }
2087
-
2088
- if (
2089
- columnValueChecker ===
2090
- column.active.value
2091
- ) {
2092
- columnStyle = {
2093
- color: column.active
2094
- .colour,
2095
- };
2096
- }
2097
- }
2098
-
2099
1939
  if (Array.isArray(value)) {
2100
1940
  if (value[0]) {
2101
1941
  value = value[0];
@@ -2128,7 +1968,7 @@ const DataGrid = forwardRef(
2128
1968
  column.placeholder !== ''
2129
1969
  ) {
2130
1970
  return (
2131
- <span style={columnStyle}>
1971
+ <span>
2132
1972
  {column.placeholder}
2133
1973
  </span>
2134
1974
  );
@@ -2149,13 +1989,7 @@ const DataGrid = forwardRef(
2149
1989
  }
2150
1990
 
2151
1991
  if (typeof value === 'string') {
2152
- return (
2153
- <span
2154
- style={columnStyle}
2155
- >
2156
- {value}
2157
- </span>
2158
- );
1992
+ return <span>{value}</span>;
2159
1993
  } else {
2160
1994
  return null;
2161
1995
  }
@@ -2376,51 +2210,6 @@ const DataGrid = forwardRef(
2376
2210
  return <span>{stage}</span>;
2377
2211
  },
2378
2212
  };
2379
- case 'text_input':
2380
- columnId = Array.isArray(column.id)
2381
- ? column.id.join('-')
2382
- : column.id;
2383
-
2384
- return {
2385
- ...commonProps,
2386
- name: columnId,
2387
- render: ({ data }) => {
2388
- const debouncedOnChange = debounce(
2389
- (name, value) => {
2390
- if (
2391
- column.update?.key &&
2392
- column.update?.url &&
2393
- column.update?.method
2394
- ) {
2395
- handleDropdownUpdate(
2396
- column.update.key,
2397
- `${column.update.url}/${data.id}`,
2398
- column.update.method,
2399
- value
2400
- );
2401
- }
2402
- },
2403
- 1000
2404
- );
2405
-
2406
- const handleChange = (e) => {
2407
- const { name, value } = e.target;
2408
- debouncedOnChange(name, value);
2409
- };
2410
-
2411
- return (
2412
- <input
2413
- name={column.id}
2414
- defaultValue={
2415
- data[column.id] || ''
2416
- }
2417
- style={{ padding: '7px' }}
2418
- onChange={handleChange}
2419
- type="text"
2420
- />
2421
- );
2422
- },
2423
- };
2424
2213
  case 'time':
2425
2214
  return {
2426
2215
  ...commonProps,
@@ -2593,12 +2382,32 @@ const DataGrid = forwardRef(
2593
2382
  data[column.id] &&
2594
2383
  data[column.id] !== ''
2595
2384
  ) {
2385
+ let content = String(
2386
+ data[column.id]
2387
+ );
2388
+
2389
+ // If removeFormat is true, strip HTML tags
2390
+ if (column.removeFormat) {
2391
+ content = content.replace(
2392
+ /<\/?[^>]+(>|$)/g,
2393
+ ''
2394
+ ); // Simple regex to strip HTML tags
2395
+ }
2396
+
2397
+ // If truncate has a value, limit content to specified number of characters
2398
+ if (column.truncate) {
2399
+ content =
2400
+ content.length >
2401
+ column.truncate
2402
+ ? content.substring(
2403
+ 0,
2404
+ column.truncate
2405
+ ) + '...'
2406
+ : content;
2407
+ }
2408
+
2596
2409
  return (
2597
- <span>
2598
- {parse(
2599
- String(data[column.id])
2600
- )}
2601
- </span>
2410
+ <span>{parse(content)}</span>
2602
2411
  );
2603
2412
  } else {
2604
2413
  return null;
@@ -2677,7 +2486,6 @@ const DataGrid = forwardRef(
2677
2486
  name: filterName,
2678
2487
  operator: column.filter.operator,
2679
2488
  type: column.filter.type,
2680
- whereHas: column.filter.whereHas || [],
2681
2489
  value: filterValue,
2682
2490
  reset: column.filter.reset
2683
2491
  ? column.filter.reset
@@ -2739,69 +2547,6 @@ const DataGrid = forwardRef(
2739
2547
  }
2740
2548
  };
2741
2549
 
2742
- const snakeCaseToTitle = (text) => {
2743
- return text
2744
- .replace(/_/g, ' ')
2745
- .replace(/\b\w/g, (char) => char.toUpperCase()); // Capitalize first letter of each word
2746
- };
2747
-
2748
- // Recursive function to handle nested objects
2749
- const renderField = (key, value) => {
2750
- // If the value is an object, recursively render its fields
2751
- if (typeof value === 'object' && value !== null) {
2752
- return (
2753
- <div key={key} style={{ marginBottom: '1rem' }}>
2754
- <h4
2755
- style={{
2756
- fontSize: '1.2rem',
2757
- marginBottom: '0.5rem',
2758
- color: '#333',
2759
- borderBottom: '1px solid #ccc',
2760
- }}
2761
- >
2762
- {snakeCaseToTitle(key)}
2763
- </h4>
2764
- <div style={{ paddingLeft: '1.5rem' }}>
2765
- {Object.keys(value).map((childKey) =>
2766
- renderField(childKey, value[childKey])
2767
- )}
2768
- </div>
2769
- </div>
2770
- );
2771
- }
2772
- // Otherwise, render the key and value as a label and paragraph
2773
- return (
2774
- <div key={key} style={{ marginBottom: '1rem' }}>
2775
- <span
2776
- style={{
2777
- fontWeight: 'bold',
2778
- marginBottom: '0.2rem',
2779
- display: 'block',
2780
- color: '#444',
2781
- }}
2782
- >
2783
- {snakeCaseToTitle(key)}
2784
- </span>
2785
- <p
2786
- style={{
2787
- margin: 0,
2788
- color: '#666',
2789
- backgroundColor: '#f9f9f9',
2790
- padding: '0.5rem',
2791
- borderRadius: '5px',
2792
- }}
2793
- >
2794
- {value !== null ? value : 'N/A'}
2795
- </p>
2796
- </div>
2797
- );
2798
- };
2799
-
2800
- const getHeaderLabel = (headers, parentKey) => {
2801
- const headerObj = headers.find((header) => header.id === parentKey);
2802
- return headerObj ? headerObj.label : snakeCaseToTitle(parentKey);
2803
- };
2804
-
2805
2550
  useEffect(() => {
2806
2551
  columns.forEach((column) => {
2807
2552
  if (column.filter && column.filter.url) {
@@ -2854,7 +2599,6 @@ const DataGrid = forwardRef(
2854
2599
  : 400,
2855
2600
  boxShadow: 'none',
2856
2601
  });
2857
-
2858
2602
  const headerProps = {
2859
2603
  style: style ? style : {},
2860
2604
  };
@@ -2970,29 +2714,6 @@ const DataGrid = forwardRef(
2970
2714
  userProfile={userProfile}
2971
2715
  />
2972
2716
  </Popup>
2973
- <Popup
2974
- open={modalSettingShow}
2975
- onClose={modalSettingClose}
2976
- closeOnDocumentClick={false}
2977
- nested
2978
- >
2979
- <Form
2980
- ajaxSetting={ajaxSetting}
2981
- api={api}
2982
- closeModal={modalSettingClose}
2983
- columnId={formSettingId}
2984
- fetchTable={handleReload}
2985
- formSettings={formSettingData}
2986
- formType={formSettingType}
2987
- gridRef={gridRef}
2988
- mapbox={mapbox}
2989
- modalOpen={modalSettingOpen}
2990
- paramValue={paramValue}
2991
- style={style}
2992
- updateForm={setFormSettingData}
2993
- userProfile={userProfile}
2994
- />
2995
- </Popup>
2996
2717
  <Popup
2997
2718
  open={modalGalleryShow}
2998
2719
  onClose={modalGalleryClose}
@@ -3022,100 +2743,6 @@ const DataGrid = forwardRef(
3022
2743
  </div>
3023
2744
  </div>
3024
2745
  </Popup>
3025
- <Popup
3026
- open={modalJsonShow}
3027
- onClose={modalJsonClose}
3028
- closeOnDocumentClick={false}
3029
- >
3030
- <div
3031
- className={`${styles.modalwrap} ${styles['top--modal']}`}
3032
- >
3033
- <div className={styles.modal}>
3034
- <div className={styles.modal__header}>
3035
- <h1>View Data</h1>
3036
- <button
3037
- className={styles.modal__close}
3038
- onClick={modalJsonClose}
3039
- >
3040
- <CircleX strokeWidth={1} size={24} />
3041
- </button>
3042
- </div>
3043
- <div className={styles.modal__content}>
3044
- <div className={styles.formcontainer}>
3045
- <div
3046
- style={{
3047
- lineHeight: '1.5',
3048
- }}
3049
- >
3050
- {jsonData.headers &&
3051
- jsonData.headers.map((header) => {
3052
- const parentKey = header.id;
3053
-
3054
- // Skip rendering if the parentKey is "id" or doesn't exist in jsonData
3055
- if (
3056
- parentKey === 'id' ||
3057
- !(
3058
- parentKey in
3059
- jsonData.data
3060
- )
3061
- )
3062
- return null;
3063
-
3064
- return (
3065
- <div
3066
- key={parentKey}
3067
- style={{
3068
- marginBottom:
3069
- '2rem',
3070
- }}
3071
- >
3072
- {/* Section Header */}
3073
- <h3
3074
- style={{
3075
- fontSize:
3076
- '1.4rem',
3077
- marginBottom:
3078
- '1rem',
3079
- color: '#222',
3080
- borderBottom:
3081
- '2px solid #ddd',
3082
- }}
3083
- >
3084
- {getHeaderLabel(
3085
- jsonData.headers,
3086
- parentKey
3087
- )}
3088
- </h3>
3089
- <div
3090
- style={{
3091
- paddingLeft:
3092
- '1rem',
3093
- }}
3094
- >
3095
- {/* Render fields for each section */}
3096
- {Object.keys(
3097
- jsonData.data[
3098
- parentKey
3099
- ]
3100
- ).map((childKey) =>
3101
- renderField(
3102
- childKey,
3103
- jsonData
3104
- .data[
3105
- parentKey
3106
- ][childKey]
3107
- )
3108
- )}
3109
- </div>
3110
- </div>
3111
- );
3112
- })}
3113
- </div>
3114
- </div>
3115
- </div>
3116
- </div>
3117
- </div>
3118
- </Popup>
3119
2746
  </>
3120
2747
  );
3121
2748
  }