@visns-studio/visns-components 3.3.7 → 3.3.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.
@@ -1388,24 +1388,62 @@ const DataGrid = forwardRef(
1388
1388
  sortable: false,
1389
1389
  render: ({ data }) => {
1390
1390
  if (data && data[column.id]) {
1391
- return (
1392
- <span
1393
- onClick={(e) => {
1394
- e.stopPropagation();
1395
- e.preventDefault();
1396
-
1397
- handleDownload(data[column.id]);
1398
- }}
1399
- >
1400
- <CloudDownload
1401
- data-tooltip-id="system-tooltip"
1402
- data-tooltip-content="Download File"
1403
- strokeWidth={2}
1404
- size={18}
1405
- className="tdaction"
1406
- />
1407
- </span>
1408
- );
1391
+ // Check if the data is an array of files
1392
+ if (Array.isArray(data[column.id])) {
1393
+ // Return a span for each file in the array with added margin
1394
+ return data[column.id].map(
1395
+ (file, index) => (
1396
+ <span
1397
+ key={index} // Use index as a key; consider using unique ids if available
1398
+ onClick={(e) => {
1399
+ e.stopPropagation();
1400
+ e.preventDefault();
1401
+ handleDownload(file);
1402
+ }}
1403
+ style={{
1404
+ marginRight: '10px',
1405
+ display: 'inline-block',
1406
+ }} // Added margin right and display style
1407
+ >
1408
+ <CloudDownload
1409
+ data-tooltip-id={`system-tooltip`}
1410
+ data-tooltip-content={`Download File ${file.file_name}`}
1411
+ strokeWidth={2}
1412
+ size={18}
1413
+ className="tdaction"
1414
+ />
1415
+ </span>
1416
+ )
1417
+ );
1418
+ } else {
1419
+ // Return a single span for a single file with added margin
1420
+ return (
1421
+ <span
1422
+ onClick={(e) => {
1423
+ e.stopPropagation();
1424
+ e.preventDefault();
1425
+ handleDownload(
1426
+ data[column.id]
1427
+ );
1428
+ }}
1429
+ style={{
1430
+ marginRight: '10px',
1431
+ display: 'inline-block',
1432
+ }} // Added margin right and display style for consistency
1433
+ >
1434
+ <CloudDownload
1435
+ data-tooltip-id="system-tooltip"
1436
+ data-tooltip-content={`Download File ${
1437
+ data[column.id]
1438
+ .file_name
1439
+ }`}
1440
+ strokeWidth={2}
1441
+ size={18}
1442
+ className="tdaction"
1443
+ />
1444
+ </span>
1445
+ );
1446
+ }
1409
1447
  } else {
1410
1448
  return null;
1411
1449
  }
@@ -8,7 +8,7 @@ import { BlockPicker } from 'react-color';
8
8
  import { CopyToClipboard } from 'react-copy-to-clipboard';
9
9
  import { NumericFormat, PatternFormat } from 'react-number-format';
10
10
  import { Editor } from '@tinymce/tinymce-react';
11
- import { Copy } from 'akar-icons';
11
+ import { Copy, TrashCan } from 'akar-icons';
12
12
 
13
13
  import CustomFetch from './Fetch';
14
14
  import MultiSelect from './MultiSelect';
@@ -232,6 +232,7 @@ function Field({
232
232
  'copytoclipboard',
233
233
  'date',
234
234
  'datetime',
235
+ 'file',
235
236
  'gallery',
236
237
  'multi-dropdown',
237
238
  'multi-dropdown-ajax',
@@ -735,14 +736,73 @@ function Field({
735
736
  />
736
737
  );
737
738
  case 'file':
738
- return (
739
- <input
740
- type="file"
741
- data-name={settings.id}
742
- className={inputClass[settings.id]}
743
- onChange={onChange}
744
- />
745
- );
739
+ if (
740
+ settings.hasOwnProperty('multiple') &&
741
+ settings.multiple === true
742
+ ) {
743
+ return (
744
+ <>
745
+ <input
746
+ type="file"
747
+ multiple
748
+ data-name={settings.id}
749
+ className={inputClass[settings.id]}
750
+ onChange={onChange}
751
+ />
752
+ {inputValue && inputValue.length > 0 && (
753
+ <ul className="file-list">
754
+ {inputValue.map((file, index) => (
755
+ <li
756
+ key={`file-${settings.id}-${index}`}
757
+ >
758
+ {file.name}
759
+ <button
760
+ className="trash-button"
761
+ onClick={(e) => {
762
+ e.preventDefault();
763
+ e.stopPropagation();
764
+
765
+ // Create a new array excluding the file at `index`
766
+ const updatedFiles =
767
+ inputValue.filter(
768
+ (_, fileIndex) =>
769
+ fileIndex !==
770
+ index
771
+ );
772
+
773
+ // Update formData[settings.id] using setFormData
774
+ setFormData(
775
+ (prevFormData) => ({
776
+ ...prevFormData,
777
+ [settings.id]:
778
+ updatedFiles,
779
+ })
780
+ );
781
+ }}
782
+ >
783
+ <TrashCan
784
+ data-tooltip-id="system-tooltip"
785
+ data-tooltip-content="Remove File"
786
+ strokeWidth={2}
787
+ size={24}
788
+ />
789
+ </button>
790
+ </li>
791
+ ))}
792
+ </ul>
793
+ )}
794
+ </>
795
+ );
796
+ } else {
797
+ return (
798
+ <input
799
+ type="file"
800
+ data-name={settings.id}
801
+ className={inputClass[settings.id]}
802
+ onChange={onChange}
803
+ />
804
+ );
805
+ }
746
806
  case 'gallery':
747
807
  let htmlContainer = '';
748
808
 
@@ -831,6 +891,7 @@ function Field({
831
891
  'copytoclipboard',
832
892
  'date',
833
893
  'datetime',
894
+ 'file',
834
895
  'gallery',
835
896
  'line-break',
836
897
  'multi-dropdown',
@@ -64,7 +64,10 @@ function Form({
64
64
  if (e.target.files) {
65
65
  setFormData((prevState) => ({
66
66
  ...prevState,
67
- [id]: e.target.files[0],
67
+ [id]:
68
+ e.target.files.length > 1
69
+ ? Array.from(e.target.files)
70
+ : e.target.files[0],
68
71
  }));
69
72
  } else {
70
73
  setFormData((prevState) => ({
@@ -414,27 +417,41 @@ function Form({
414
417
  }
415
418
  };
416
419
 
417
- const handleSubmit = (e) => {
418
- if (e) {
419
- e.preventDefault();
420
- }
420
+ const handleSubmit = async (e) => {
421
+ try {
422
+ if (e) {
423
+ e.preventDefault();
424
+ }
421
425
 
422
- let fields = formSettings.fields;
423
- let _inputClass = inputClass;
424
- let validation = '';
426
+ let fields = formSettings.fields;
427
+ let _inputClass = inputClass;
428
+ let validation = '';
425
429
 
426
- if (['create', 'update'].includes(formType)) {
427
- fields.forEach((item) => {
428
- if (item.required === true) {
429
- if (
430
- formData[item.id] === '' ||
431
- formData[item.id] === undefined
432
- ) {
430
+ if (['create', 'update'].includes(formType)) {
431
+ fields.forEach((item) => {
432
+ if (item.required === true) {
433
433
  if (
434
- item.hasOwnProperty('required_check') &&
435
- item.required_check !== ''
434
+ formData[item.id] === '' ||
435
+ formData[item.id] === undefined
436
436
  ) {
437
- if (formData[item.required_check] === '') {
437
+ if (
438
+ item.hasOwnProperty('required_check') &&
439
+ item.required_check !== ''
440
+ ) {
441
+ if (formData[item.required_check] === '') {
442
+ if (
443
+ !validation.includes(
444
+ item.label +
445
+ ' is a required field.<br/>'
446
+ )
447
+ ) {
448
+ validation +=
449
+ item.label +
450
+ ' is a required field.<br/>';
451
+ }
452
+ _inputClass[item.id] = 'inputError';
453
+ }
454
+ } else {
438
455
  if (
439
456
  !validation.includes(
440
457
  item.label +
@@ -449,264 +466,223 @@ function Form({
449
466
  }
450
467
  } else {
451
468
  if (
452
- !validation.includes(
453
- item.label + ' is a required field.<br/>'
454
- )
469
+ item.hasOwnProperty('required_check') &&
470
+ item.required_check !== ''
455
471
  ) {
456
- validation +=
457
- item.label + ' is a required field.<br/>';
472
+ _inputClass[item.required_check] = '';
458
473
  }
459
- _inputClass[item.id] = 'inputError';
474
+ _inputClass[item.id] = '';
460
475
  }
461
476
  } else {
462
477
  if (
463
- item.hasOwnProperty('required_check') &&
464
- item.required_check !== ''
478
+ item.hasOwnProperty('required_rely') &&
479
+ item.required_rely !== ''
465
480
  ) {
466
- _inputClass[item.required_check] = '';
481
+ if (formData[item.required_rely] === '') {
482
+ _inputClass[item.id] = '';
483
+ } else {
484
+ if (formData[item.id] === '') {
485
+ if (
486
+ !validation.includes(
487
+ item.label +
488
+ ' is a required field.<br/>'
489
+ )
490
+ ) {
491
+ validation +=
492
+ item.label +
493
+ ' is a required field.<br/>';
494
+ }
495
+ _inputClass[item.id] = 'inputError';
496
+ } else {
497
+ _inputClass[item.id] = '';
498
+ }
499
+ }
500
+ } else {
501
+ _inputClass[item.id] = '';
467
502
  }
468
- _inputClass[item.id] = '';
469
503
  }
504
+ });
505
+
506
+ setInputClass(_inputClass);
507
+ }
508
+
509
+ if (validation !== '') {
510
+ toast.error(<div>{parse(validation)}</div>);
511
+ } else {
512
+ let url = formSettings.url;
513
+ let method = 'POST';
514
+ let fileUpload = false;
515
+ let fileKey = '';
516
+
517
+ if (formSettings.customUrl && formSettings.customMethod) {
518
+ url = formSettings.customUrl;
519
+ if (formSettings.customDataId) {
520
+ url += `/${formData[formSettings.primaryKey]}`;
521
+ }
522
+ method = formSettings.customMethod;
470
523
  } else {
471
- if (
472
- item.hasOwnProperty('required_rely') &&
473
- item.required_rely !== ''
474
- ) {
475
- if (formData[item.required_rely] === '') {
476
- _inputClass[item.id] = '';
477
- } else {
478
- if (formData[item.id] === '') {
479
- if (
480
- !validation.includes(
481
- item.label +
482
- ' is a required field.<br/>'
483
- )
484
- ) {
485
- validation +=
486
- item.label +
487
- ' is a required field.<br/>';
524
+ switch (formType) {
525
+ case 'create':
526
+ if (
527
+ formSettings.hasOwnProperty('json') &&
528
+ formSettings.json === true
529
+ ) {
530
+ url += '/jsonStore';
531
+ }
532
+ break;
533
+ case 'update':
534
+ case 'delete':
535
+ if (
536
+ formSettings.hasOwnProperty('json') &&
537
+ formSettings.json === true
538
+ ) {
539
+ if (formType === 'update') {
540
+ url += `/jsonUpdate`;
541
+ } else {
542
+ url += `/jsonDelete/${
543
+ formData[formSettings.primaryKey]
544
+ }`;
488
545
  }
489
- _inputClass[item.id] = 'inputError';
490
546
  } else {
491
- _inputClass[item.id] = '';
547
+ url += `/${formData[formSettings.primaryKey]}`;
492
548
  }
493
- }
494
- } else {
495
- _inputClass[item.id] = '';
549
+
550
+ method = formType === 'update' ? 'PUT' : 'DELETE';
551
+ break;
496
552
  }
497
553
  }
498
- });
499
-
500
- setInputClass(_inputClass);
501
- }
502
554
 
503
- if (validation !== '') {
504
- toast.error(<div>{parse(validation)}</div>);
505
- } else {
506
- let url = formSettings.url;
507
- let method = 'POST';
508
- let fileUpload = false;
509
- let fileKey = '';
510
-
511
- if (formSettings.customUrl && formSettings.customMethod) {
512
- url = formSettings.customUrl;
513
- if (formSettings.customDataId) {
514
- url += `/${formData[formSettings.primaryKey]}`;
515
- }
516
- method = formSettings.customMethod;
517
- } else {
518
- switch (formType) {
519
- case 'create':
520
- if (
521
- formSettings.hasOwnProperty('json') &&
522
- formSettings.json === true
523
- ) {
524
- url += '/jsonStore';
525
- }
526
- break;
527
- case 'update':
528
- case 'delete':
555
+ if (!_.isEmpty(formData)) {
556
+ Object.keys(formData).forEach((item) => {
529
557
  if (
530
- formSettings.hasOwnProperty('json') &&
531
- formSettings.json === true
558
+ formData[item] !== undefined &&
559
+ (item === 'file' ||
560
+ (formData[item] instanceof File &&
561
+ formData[item] !== null))
532
562
  ) {
533
- if (formType === 'update') {
534
- url += `/jsonUpdate`;
535
- } else {
536
- url += `/jsonDelete/${
537
- formData[formSettings.primaryKey]
538
- }`;
539
- }
540
- } else {
541
- url += `/${formData[formSettings.primaryKey]}`;
563
+ fileUpload = true;
564
+ fileKey = item;
542
565
  }
566
+ });
567
+ }
568
+
569
+ if (fileUpload === true && formData[fileKey] !== null) {
570
+ // Check if formData[fileKey] is an array of file objects
571
+ if (Array.isArray(formData[fileKey])) {
572
+ // Already an array, so no need to convert
573
+ const files = formData[fileKey];
574
+
575
+ // Use Promise.all to wait for all file uploads to complete
576
+ const uploadPromises = files.map(async (file) => {
577
+ const fileRes = await Vapor.store(file, {
578
+ progress: (progress) => {
579
+ setUploadProgress(progress * 100);
580
+ },
581
+ });
543
582
 
544
- method = formType === 'update' ? 'PUT' : 'DELETE';
545
- break;
583
+ // Return an object for each file with its upload details
584
+ return {
585
+ uuid: fileRes.uuid,
586
+ key: fileRes.key,
587
+ bucket: fileRes.bucket,
588
+ filename: file.name,
589
+ filesize: file.size,
590
+ extension: fileRes.extension,
591
+ };
592
+ });
593
+
594
+ // Wait for all file uploads to complete
595
+ const uploadedFiles = await Promise.all(uploadPromises);
596
+
597
+ // Store the details of uploaded files in formData, under a specific key
598
+ formData['uploadedFiles'] = uploadedFiles;
599
+ } else if (formData[fileKey] instanceof File) {
600
+ // Handle single file upload (original logic remains the same)
601
+ const fileRes = await Vapor.store(formData[fileKey], {
602
+ progress: (progress) => {
603
+ setUploadProgress(progress * 100);
604
+ },
605
+ });
606
+
607
+ formData['uuid'] = fileRes.uuid;
608
+ formData['key'] = fileRes.key;
609
+ formData['bucket'] = fileRes.bucket;
610
+ formData['filename'] = formData[fileKey].name;
611
+ formData['filesize'] = formData[fileKey].size;
612
+ formData['extension'] = fileRes.extension;
613
+ }
546
614
  }
547
- }
548
615
 
549
- if (!_.isEmpty(formData)) {
550
- Object.keys(formData).forEach((item) => {
551
- if (
552
- formData[item] !== undefined &&
553
- (item === 'file' ||
554
- (formData[item] instanceof File &&
555
- formData[item] !== null))
556
- ) {
557
- fileUpload = true;
558
- fileKey = item;
616
+ const res = await CustomFetch(url, method, formData);
617
+
618
+ if (res.data.error === '') {
619
+ if (fetchTable) {
620
+ fetchTable();
559
621
  }
560
- });
561
- }
562
622
 
563
- if (
564
- fileUpload === true &&
565
- formData[fileKey] !== null &&
566
- formData[fileKey] instanceof File
567
- ) {
568
- Vapor.store(formData[fileKey], {
569
- progress: (progress) => {
570
- setUploadProgress(progress * 100);
571
- },
572
- }).then((response) => {
573
- formData['uuid'] = response.uuid;
574
- formData['key'] = response.key;
575
- formData['bucket'] = response.bucket;
576
- formData['filename'] = formData[fileKey].name;
577
- formData['filesize'] = formData[fileKey].size;
578
- formData['extension'] = response.extension;
579
-
580
- CustomFetch(url, method, formData, function (result) {
581
- if (result.error === '') {
582
- if (fetchTable) {
583
- fetchTable();
584
- }
623
+ if (closeModal) {
624
+ closeModal();
625
+ }
585
626
 
586
- if (closeModal) {
587
- closeModal();
588
- }
627
+ toast.success(
628
+ formSettings?.save?.toast?.success
629
+ ? formSettings.save.toast.success
630
+ : 'Entry successfully saved into the system.'
631
+ );
589
632
 
590
- toast.success(
591
- formSettings?.save?.toast?.success
592
- ? formSettings.save.toast.success
593
- : 'Entry successfully saved into the system.'
594
- );
633
+ if (
634
+ formSettings.hasOwnProperty('redirect') &&
635
+ formSettings.redirect &&
636
+ res.data.data &&
637
+ res.data.data.id
638
+ ) {
639
+ navigate(formSettings.redirect + res.data.data.id);
640
+ }
595
641
 
596
- if (result.redirect) {
597
- navigate(result.redirect);
598
- }
642
+ if (res.data.redirect) {
643
+ navigate(res.data.redirect);
644
+ }
599
645
 
646
+ if (
647
+ formSettings?.save?.return?.type &&
648
+ formSettings?.save?.return?.param
649
+ ) {
650
+ if (formSettings.save.return.type === 'table') {
600
651
  if (
601
- formSettings?.save?.return?.type &&
602
- formSettings?.save?.return?.param
652
+ result[formSettings.save.return.param].length >
653
+ 0
603
654
  ) {
604
- if (formSettings.save.return.type === 'table') {
605
- if (
606
- result[formSettings.save.return.param]
607
- .length > 0
608
- ) {
609
- const td = parseTableData(
610
- result[
611
- formSettings.save.return.param
612
- ]
613
- );
614
-
615
- setTableData((prevState) => ({
616
- ...prevState,
617
- ...td,
618
- }));
619
- } else {
620
- setTableData((prevState) => ({
621
- ...prevState,
622
- columns: [],
623
- dataSource: [],
624
- }));
625
- }
626
- }
627
- }
628
- } else {
629
- toast.error(
630
- <div>
631
- {parse(
632
- result.error !== undefined
633
- ? result.error
634
- : ''
635
- )}
636
- </div>
637
- );
638
- }
639
- });
640
- });
641
- } else {
642
- CustomFetch(url, method, formData, function (result) {
643
- if (result.error === '') {
644
- if (fetchTable) {
645
- fetchTable();
646
- }
647
-
648
- if (closeModal) {
649
- closeModal();
650
- }
651
-
652
- toast.success(
653
- formSettings?.save?.toast?.success
654
- ? formSettings.save.toast.success
655
- : 'Entry successfully saved into the system.'
656
- );
657
-
658
- if (
659
- formSettings.hasOwnProperty('redirect') &&
660
- formSettings.redirect &&
661
- result.data &&
662
- result.data.id
663
- ) {
664
- navigate(formSettings.redirect + result.data.id);
665
- }
666
-
667
- if (result.redirect) {
668
- navigate(result.redirect);
669
- }
670
-
671
- if (
672
- formSettings?.save?.return?.type &&
673
- formSettings?.save?.return?.param
674
- ) {
675
- if (formSettings.save.return.type === 'table') {
676
- if (
655
+ const td = parseTableData(
677
656
  result[formSettings.save.return.param]
678
- .length > 0
679
- ) {
680
- const td = parseTableData(
681
- result[formSettings.save.return.param]
682
- );
657
+ );
683
658
 
684
- setTableData((prevState) => ({
685
- ...prevState,
686
- ...td,
687
- }));
688
- } else {
689
- setTableData((prevState) => ({
690
- ...prevState,
691
- columns: [],
692
- dataSource: [],
693
- }));
694
- }
659
+ setTableData((prevState) => ({
660
+ ...prevState,
661
+ ...td,
662
+ }));
663
+ } else {
664
+ setTableData((prevState) => ({
665
+ ...prevState,
666
+ columns: [],
667
+ dataSource: [],
668
+ }));
695
669
  }
696
670
  }
697
- } else {
698
- toast.error(
699
- <div>
700
- {parse(
701
- result.error !== undefined
702
- ? result.error
703
- : ''
704
- )}
705
- </div>
706
- );
707
671
  }
708
- });
672
+ } else {
673
+ toast.error(
674
+ <div>
675
+ {parse(
676
+ res.data.error !== undefined
677
+ ? res.data.error
678
+ : ''
679
+ )}
680
+ </div>
681
+ );
682
+ }
709
683
  }
684
+ } catch (err) {
685
+ console.error(err);
710
686
  }
711
687
  };
712
688
 
@@ -1189,6 +1165,7 @@ function Form({
1189
1165
  childDropdownCallback
1190
1166
  }
1191
1167
  fetchData={fetchData}
1168
+ formData={formData}
1192
1169
  inputClass={inputClass}
1193
1170
  inputValue={
1194
1171
  item.hasOwnProperty('key')
package/package.json CHANGED
@@ -49,7 +49,7 @@
49
49
  "react-dom": "^17.0.1"
50
50
  },
51
51
  "name": "@visns-studio/visns-components",
52
- "version": "3.3.7",
52
+ "version": "3.3.8",
53
53
  "description": "Various packages to assist in the development of our Custom Applications.",
54
54
  "main": "index.js",
55
55
  "scripts": {