@visns-studio/visns-components 3.6.3 → 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.
package/components/crm/Field.jsx
CHANGED
|
@@ -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
|
|
@@ -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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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 = ({
|
|
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
|
-
|
|
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
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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]
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
e
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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}
|
|
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
|
-
{
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
592
|
-
|
|
593
|
-
|
|
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 = (
|
|
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
|
-
|
|
188
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
197
|
+
// Update the state with the new detail array
|
|
198
|
+
setData((items) => ({
|
|
199
|
+
...items,
|
|
200
|
+
detail: newDetail,
|
|
201
|
+
}));
|
|
194
202
|
|
|
195
|
-
|
|
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="
|
|
701
|
+
<option value="html5_date">
|
|
693
702
|
Date
|
|
694
703
|
</option>
|
|
695
|
-
<option value="
|
|
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="
|
|
734
|
+
<option value="html5_time">
|
|
726
735
|
Time
|
|
727
736
|
</option>
|
|
728
737
|
<option value="toggle">
|
package/package.json
CHANGED