@visns-studio/visns-components 3.6.2 → 3.6.4

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.
@@ -428,6 +428,22 @@ function Field({
428
428
  autoComplete="off"
429
429
  />
430
430
  );
431
+ case 'html5_datetime':
432
+ return (
433
+ <input
434
+ type="datetime-local"
435
+ data-name={settings.id}
436
+ className={inputClass[settings.id]}
437
+ placeholder=" "
438
+ onChange={onChange}
439
+ value={
440
+ inputValue && inputValue !== 'null'
441
+ ? inputValue
442
+ : ''
443
+ }
444
+ autoComplete="off"
445
+ />
446
+ );
431
447
  case 'html5_time':
432
448
  return (
433
449
  <input
@@ -975,7 +991,7 @@ function Field({
975
991
  case 'richeditor':
976
992
  return (
977
993
  <Editor
978
- apiKey="51mqcxkrrco6unmr6h8exc5mkhtjwi6fpyedy3r493px8cbq"
994
+ apiKey={userProfile?.settings?.api?.tinymce}
979
995
  onEditorChange={(value, e) => {
980
996
  onChangeRicheditor(e, value, settings.id);
981
997
  }}
@@ -15,6 +15,7 @@ import 'react-confirm-alert/src/react-confirm-alert.css';
15
15
  import Breadcrumb from '../Breadcrumb';
16
16
  import CustomFetch from '../Fetch';
17
17
  import Form from '../Form';
18
+ import GenericDynamic from './GenericDynamic';
18
19
  import QrCode from '../QrCode';
19
20
  import Table from '../DataGrid';
20
21
  import TableFilter from '../TableFilter';
@@ -430,6 +431,19 @@ function GenericDetail({ extraUrlParam, setting, urlParam, userProfile }) {
430
431
  </Dropzone>
431
432
  </div>
432
433
  );
434
+ case 'dynamicform':
435
+ return (
436
+ <GenericDynamic
437
+ data={data}
438
+ fetchData={handleReload}
439
+ label={activeTabConfig.setting.label}
440
+ multiple={false}
441
+ primaryKey={activeTabConfig.setting.key}
442
+ setData={setData}
443
+ setting={activeTabConfig.setting.url}
444
+ type={activeTabConfig.setting.type}
445
+ />
446
+ );
433
447
  case 'form':
434
448
  const updateValueFromParam = (item, value) => {
435
449
  if (item && item.urlParam) {
@@ -1030,7 +1044,7 @@ function GenericDetail({ extraUrlParam, setting, urlParam, userProfile }) {
1030
1044
  }
1031
1045
  );
1032
1046
  }
1033
- }, [routeParams, dataReload]);
1047
+ }, [routeParams['*'], dataReload]);
1034
1048
 
1035
1049
  useEffect(() => {
1036
1050
  setSubnav(() => {
@@ -12,17 +12,23 @@ import Download from '../Download';
12
12
  import Field from '../Field';
13
13
 
14
14
  const updateField = (fields, name, value) => {
15
- return Object.entries(fields).reduce((updatedFields, [key, field]) => {
16
- // Check if the current field is the one to be updated
17
- if (field.id === name) {
18
- // Update the value of the field
19
- updatedFields[key] = { ...field, value };
20
- } else {
21
- // Keep the field as is
22
- updatedFields[key] = field;
23
- }
24
- return updatedFields;
25
- }, {});
15
+ // Check if fields is an array of objects
16
+ if (Array.isArray(fields)) {
17
+ return fields.map((field) => ({
18
+ ...field,
19
+ // Update only the field that matches name
20
+ value: field.id === name ? value : field.value,
21
+ }));
22
+ }
23
+
24
+ // If fields is a single object, handle accordingly
25
+ return Object.entries(fields).reduce(
26
+ (acc, [key, field]) => ({
27
+ ...acc,
28
+ [key]: field.id === name ? { ...field, value } : field,
29
+ }),
30
+ {}
31
+ );
26
32
  };
27
33
 
28
34
  const renderValue = (field, data) => {
@@ -60,7 +66,16 @@ const renderValue = (field, data) => {
60
66
  }
61
67
  };
62
68
 
63
- const GenericDynamic = ({ data, fetchData, label, setData, setting, type }) => {
69
+ const GenericDynamic = ({
70
+ data,
71
+ fetchData,
72
+ label,
73
+ multiple = true,
74
+ primaryKey,
75
+ setData,
76
+ setting,
77
+ type,
78
+ }) => {
64
79
  const toastId = useRef(null);
65
80
  const [activeForm, setActiveForm] = useState([]);
66
81
  const [activeFormKey, setActiveFormKey] = useState(0);
@@ -351,8 +366,9 @@ const GenericDynamic = ({ data, fetchData, label, setData, setting, type }) => {
351
366
  });
352
367
 
353
368
  if (error === '') {
369
+ console.info(setting);
354
370
  const res = await CustomFetch(setting.save, 'POST', {
355
- client_id: data.id,
371
+ [primaryKey]: data.id,
356
372
  form_data: {
357
373
  ...activeForm,
358
374
  },
@@ -374,24 +390,32 @@ const GenericDynamic = ({ data, fetchData, label, setData, setting, type }) => {
374
390
 
375
391
  useEffect(() => {
376
392
  if (data[type] && data[type].length > 0) {
377
- // Retrieve the last form of the specified type
378
- let lastForm = data[type][data[type].length - 1];
379
-
380
- if (lastForm && typeof lastForm === 'object') {
381
- Object.entries(lastForm).forEach(([key, field]) => {
382
- if (field && field.required) {
383
- if (
384
- field.required === 'yes' ||
385
- field.required === 'no'
386
- ) {
387
- lastForm[key].required = field.required === 'yes';
393
+ if (multiple) {
394
+ // Retrieve the last form of the specified type
395
+ let lastForm = data[type][data[type].length - 1];
396
+
397
+ if (lastForm && typeof lastForm === 'object') {
398
+ Object.entries(lastForm).forEach(([key, field]) => {
399
+ if (field && field.required) {
400
+ if (
401
+ field.required === 'yes' ||
402
+ field.required === 'no'
403
+ ) {
404
+ lastForm[key].required =
405
+ field.required === 'yes';
406
+ }
388
407
  }
389
- }
390
- });
408
+ });
391
409
 
392
- // Update the active form with the modified lastForm
393
- setActiveForm(lastForm);
394
- setActiveFormKey(data[type].length - 1);
410
+ // Update the active form with the modified lastForm
411
+ setActiveForm(lastForm);
412
+ setActiveFormKey(data[type].length - 1);
413
+ }
414
+ } else {
415
+ if (activeForm.length === 0) {
416
+ setActiveForm(data[type]);
417
+ setActiveFormKey(0);
418
+ }
395
419
  }
396
420
  } else {
397
421
  setActiveForm([]);
@@ -399,10 +423,14 @@ const GenericDynamic = ({ data, fetchData, label, setData, setting, type }) => {
399
423
  }
400
424
  }, [data, type]);
401
425
 
426
+ useEffect(() => {
427
+ console.info(activeForm);
428
+ }, [activeForm]);
429
+
402
430
  return (
403
431
  <>
404
432
  <div className="formSplit">
405
- {data[type] && data[type].length > 1 && (
433
+ {multiple && data[type] && data[type].length > 1 && (
406
434
  <>
407
435
  <div className="gridtxt__header">
408
436
  <span>Form List</span>
@@ -422,92 +450,92 @@ const GenericDynamic = ({ data, fetchData, label, setData, setting, type }) => {
422
450
  </tr>
423
451
  </thead>
424
452
  <tbody>
425
- {data[type].map((item, index) => {
426
- const idAsNumber = parseFloat(item.id);
427
- if (
428
- !isNaN(idAsNumber) &&
429
- Number.isInteger(idAsNumber)
430
- ) {
431
- return (
432
- <tr
433
- key={`form-list-${index}`}
434
- onClick={(e) => {
435
- e.preventDefault();
436
-
437
- handleSelectForm(
438
- item,
439
- index
440
- );
441
- }}
442
- >
443
- <td>Form #{item.id}</td>
444
- <td>{item.created_by}</td>
445
- <td>
446
- {item.created_at
447
- ? moment(
448
- item.created_at
449
- ).format(
450
- 'DD-MM-YYYY hh:mm A'
451
- )
452
- : null}
453
- </td>
454
- <td>{item.updated_by}</td>
455
- <td>
456
- {item.updated_at
457
- ? moment(
458
- item.updated_at
459
- ).format(
460
- 'DD-MM-YYYY hh:mm A'
461
- )
462
- : null}
463
- </td>
464
- <td>
465
- <div className="tdactions">
466
- <span
467
- data-tooltip-id="system-tooltip"
468
- data-tooltip-content={
469
- 'Download Form'
470
- }
471
- className="tooltip"
472
- onClick={() =>
473
- handleDownloadForm(
474
- item,
475
- index
476
- )
477
- }
478
- >
479
- <CloudDownload
480
- strokeWidth={2}
481
- size={18}
482
- className="tdaction"
483
- />
484
- </span>
485
- <span
486
- data-tooltip-id="system-tooltip"
487
- data-tooltip-content={
488
- 'Delete Form'
489
- }
490
- className="tooltip"
491
- onClick={() =>
492
- handleDeleteForm(
493
- item.id,
494
- index
495
- )
496
- }
497
- >
498
- <Backspace
499
- strokeWidth={2}
500
- size={18}
501
- className="tdaction"
502
- />
503
- </span>
504
- </div>
505
- </td>
506
- </tr>
507
- );
508
- }
509
- return null;
510
- })}
453
+ {typeof data[type]?.map === 'function' &&
454
+ data[type].map((item, index) => {
455
+ const idAsNumber = parseFloat(item.id);
456
+ if (
457
+ !isNaN(idAsNumber) &&
458
+ Number.isInteger(idAsNumber)
459
+ ) {
460
+ return (
461
+ <tr
462
+ key={`form-list-${index}`}
463
+ onClick={(e) => {
464
+ e.preventDefault();
465
+ handleSelectForm(
466
+ item,
467
+ index
468
+ );
469
+ }}
470
+ >
471
+ <td>Form #{item.id}</td>
472
+ <td>{item.created_by}</td>
473
+ <td>
474
+ {item.created_at
475
+ ? moment(
476
+ item.created_at
477
+ ).format(
478
+ 'DD-MM-YYYY hh:mm A'
479
+ )
480
+ : null}
481
+ </td>
482
+ <td>{item.updated_by}</td>
483
+ <td>
484
+ {item.updated_at
485
+ ? moment(
486
+ item.updated_at
487
+ ).format(
488
+ 'DD-MM-YYYY hh:mm A'
489
+ )
490
+ : null}
491
+ </td>
492
+ <td>
493
+ <div className="tdactions">
494
+ <span
495
+ data-tooltip-id="system-tooltip"
496
+ data-tooltip-content="Download Form"
497
+ className="tooltip"
498
+ onClick={() =>
499
+ handleDownloadForm(
500
+ item,
501
+ index
502
+ )
503
+ }
504
+ >
505
+ <CloudDownload
506
+ strokeWidth={
507
+ 2
508
+ }
509
+ size={18}
510
+ className="tdaction"
511
+ />
512
+ </span>
513
+ <span
514
+ data-tooltip-id="system-tooltip"
515
+ data-tooltip-content="Delete Form"
516
+ className="tooltip"
517
+ onClick={() =>
518
+ handleDeleteForm(
519
+ item.id,
520
+ index
521
+ )
522
+ }
523
+ >
524
+ <Backspace
525
+ strokeWidth={
526
+ 2
527
+ }
528
+ size={18}
529
+ className="tdaction"
530
+ />
531
+ </span>
532
+ </div>
533
+ </td>
534
+ </tr>
535
+ );
536
+ }
537
+ return null;
538
+ })}
511
539
  </tbody>
512
540
  </table>
513
541
  </>
@@ -517,7 +545,8 @@ const GenericDynamic = ({ data, fetchData, label, setData, setting, type }) => {
517
545
  <>
518
546
  <div className="gridtxt__header">
519
547
  <span>
520
- {label} - Form #{activeForm.id}
548
+ {label}{' '}
549
+ {multiple && ` - Form #${activeForm?.id ?? ''}`}
521
550
  </span>
522
551
  </div>
523
552
  <div
@@ -525,78 +554,117 @@ const GenericDynamic = ({ data, fetchData, label, setData, setting, type }) => {
525
554
  style={{ paddingBottom: '50px' }}
526
555
  >
527
556
  <div className="modalForm">
528
- {activeForm &&
529
- Object.entries(activeForm)
530
- .filter(([key, value]) => {
531
- // Check if the value is an object and has the required keys
532
- return (
533
- value &&
534
- typeof value === 'object' &&
535
- [
536
- 'id',
537
- 'label',
538
- 'type',
539
- 'size',
540
- 'value',
541
- ].every((k) =>
542
- value.hasOwnProperty(k)
543
- )
544
- );
545
- })
546
- .map(([key, field]) => {
547
- // Check if the field is not hidden
548
- if (field.hide === 0) {
549
- return (
550
- <Field
551
- settings={field}
552
- key={`field-${key}-${field.id}`}
553
- formData={activeForm}
554
- inputClass={''}
555
- inputValue={renderValue(
556
- field,
557
- data
558
- )}
559
- onChange={handleChange}
560
- onChangeCheckbox={
561
- handleChangeCheckbox
562
- }
563
- onChangeColour={() => {}}
564
- onChangeDate={
565
- handleChangeDate
566
- }
567
- onChangeSelect={() => {}}
568
- onChangeRicheditor={() => {}}
569
- onChangeToggle={
570
- handleChange
571
- }
572
- onChangeNumberFormat={() => {}}
573
- onFileDownload={
574
- handleFileDownload
575
- }
576
- autocompleteCallback={() => {}}
577
- childDropdownCallback={() => {}}
578
- setFormData={setData}
579
- style={{}}
580
- />
581
- );
582
- }
583
- return null;
584
- })}
557
+ {
558
+ // Check if activeForm is an object and not an array when multiple is true
559
+ multiple &&
560
+ typeof activeForm === 'object' &&
561
+ !Array.isArray(activeForm)
562
+ ? Object.entries(activeForm)
563
+ .filter(
564
+ ([key, value]) =>
565
+ typeof value ===
566
+ 'object' &&
567
+ [
568
+ 'id',
569
+ 'label',
570
+ 'type',
571
+ 'size',
572
+ 'value',
573
+ ].every((k) =>
574
+ value.hasOwnProperty(
575
+ k
576
+ )
577
+ )
578
+ )
579
+ .map(
580
+ ([key, field]) =>
581
+ field.hide === 0 && (
582
+ <Field
583
+ settings={field}
584
+ key={`field-${key}-${field.id}`}
585
+ formData={
586
+ activeForm
587
+ }
588
+ inputClass={''}
589
+ inputValue={renderValue(
590
+ field,
591
+ data
592
+ )}
593
+ onChange={
594
+ handleChange
595
+ }
596
+ onChangeCheckbox={
597
+ handleChangeCheckbox
598
+ }
599
+ onChangeDate={
600
+ handleChangeDate
601
+ }
602
+ onFileDownload={
603
+ handleFileDownload
604
+ }
605
+ // Omitted other props for brevity
606
+ style={{}}
607
+ />
608
+ )
609
+ )
610
+ : // Handle case where activeForm is an array and multiple is false
611
+ typeof activeForm?.map ===
612
+ 'function' &&
613
+ activeForm.map(
614
+ (field, index) =>
615
+ field.hide === 0 && (
616
+ <Field
617
+ settings={field}
618
+ key={`field-array-${index}-${field.id}`}
619
+ formData={activeForm}
620
+ inputClass={''}
621
+ inputValue={renderValue(
622
+ field,
623
+ data
624
+ )}
625
+ onChange={
626
+ handleChange
627
+ }
628
+ onChangeCheckbox={
629
+ handleChangeCheckbox
630
+ }
631
+ onChangeDate={
632
+ handleChangeDate
633
+ }
634
+ onFileDownload={
635
+ handleFileDownload
636
+ }
637
+ // Omitted other props for brevity
638
+ style={{}}
639
+ />
640
+ )
641
+ )
642
+ }
585
643
  </div>
586
644
  </div>
587
645
  </>
588
646
  )}
589
647
  </div>
590
648
  <div className="polActions">
591
- <button className="btn" onClick={handleAddNewForm}>
592
- Add New Form
593
- </button>
594
-
595
- {activeForm && activeForm.form_status === 0 && (
596
- <button className="btn" onClick={handleSaveForm}>
597
- Save
649
+ {multiple && (
650
+ <button className="btn" onClick={handleAddNewForm}>
651
+ Add New Form
598
652
  </button>
599
653
  )}
654
+
655
+ {activeForm && (
656
+ <>
657
+ {multiple && activeForm.form_status === 0 ? (
658
+ <button className="btn" onClick={handleSaveForm}>
659
+ Save
660
+ </button>
661
+ ) : (
662
+ <button className="btn" onClick={handleSaveForm}>
663
+ Save
664
+ </button>
665
+ )}
666
+ </>
667
+ )}
600
668
  </div>
601
669
  </>
602
670
  );
@@ -176,7 +176,7 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
176
176
  handleOpenModal();
177
177
  };
178
178
 
179
- const handleDeleteField = (key, label) => {
179
+ const handleDeleteField = (id, label) => {
180
180
  confirmAlert({
181
181
  title: `Delete "${label}" Field`,
182
182
  message: 'Are you sure you want to delete this field?',
@@ -184,15 +184,24 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
184
184
  {
185
185
  label: 'Yes',
186
186
  onClick: () => {
187
- let newDetail = data.detail;
188
- newDetail.splice(key, 1);
187
+ // Find the index of the object with the matching id
188
+ const index = data.detail.findIndex(
189
+ (item) => item.id === id
190
+ );
191
+
192
+ // Proceed only if the item was found
193
+ if (index > -1) {
194
+ let newDetail = [...data.detail]; // Create a copy of the detail array
195
+ newDetail.splice(index, 1); // Remove the item at the found index
189
196
 
190
- setData((items) => ({
191
- ...items,
192
- detail: [...newDetail],
193
- }));
197
+ // Update the state with the new detail array
198
+ setData((items) => ({
199
+ ...items,
200
+ detail: newDetail,
201
+ }));
194
202
 
195
- handleCloseModal();
203
+ handleCloseModal();
204
+ }
196
205
  },
197
206
  },
198
207
  {
@@ -689,10 +698,10 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
689
698
  <option value="checkbox">
690
699
  Checkbox
691
700
  </option>
692
- <option value="date">
701
+ <option value="html5_date">
693
702
  Date
694
703
  </option>
695
- <option value="datetime">
704
+ <option value="html5_datetime">
696
705
  Date & Time
697
706
  </option>
698
707
  <option value="dropdown">
@@ -722,7 +731,7 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
722
731
  <option value="textarea">
723
732
  Textarea
724
733
  </option>
725
- <option value="time">
734
+ <option value="html5_time">
726
735
  Time
727
736
  </option>
728
737
  <option value="toggle">
@@ -840,8 +849,8 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
840
849
  <label className="fi__label">
841
850
  <Editor
842
851
  apiKey={
843
- userProfile.settings.api
844
- .tinymce
852
+ userProfile?.settings
853
+ ?.api?.tinymce
845
854
  }
846
855
  onEditorChange={(
847
856
  value,
package/package.json CHANGED
@@ -50,7 +50,7 @@
50
50
  "react-dom": "^17.0.1"
51
51
  },
52
52
  "name": "@visns-studio/visns-components",
53
- "version": "3.6.2",
53
+ "version": "3.6.4",
54
54
  "description": "Various packages to assist in the development of our Custom Applications.",
55
55
  "main": "index.js",
56
56
  "scripts": {