@visns-studio/visns-components 5.1.5 → 5.1.7
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 +1 -1
- package/src/components/crm/Field.jsx +6 -0
- package/src/components/crm/generic/GenericDynamic.jsx +125 -121
- package/src/components/crm/generic/GenericEditableTable.jsx +108 -16
- package/src/components/crm/generic/styles/GenericEditableTable.module.scss +57 -0
- package/src/components/crm/styles/Field.module.scss +4 -0
package/package.json
CHANGED
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
78
78
|
},
|
|
79
79
|
"name": "@visns-studio/visns-components",
|
|
80
|
-
"version": "5.1.
|
|
80
|
+
"version": "5.1.7",
|
|
81
81
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
82
82
|
"main": "src/index.js",
|
|
83
83
|
"files": [
|
|
@@ -144,6 +144,8 @@ function Field({
|
|
|
144
144
|
break;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
console.info(settings);
|
|
148
|
+
|
|
147
149
|
switch (settings.size) {
|
|
148
150
|
case 'full':
|
|
149
151
|
setFormItemClass(`${styles.formItem} ${styles.fwItem}`);
|
|
@@ -157,6 +159,10 @@ function Field({
|
|
|
157
159
|
}
|
|
158
160
|
}, [settings, counter]);
|
|
159
161
|
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
console.info(formItemClass);
|
|
164
|
+
}, [formItemClass]);
|
|
165
|
+
|
|
160
166
|
const fetchChildDropdownData = (s, v) => {
|
|
161
167
|
let filter = {};
|
|
162
168
|
|
|
@@ -682,125 +682,6 @@ const GenericDynamic = ({
|
|
|
682
682
|
return (
|
|
683
683
|
<>
|
|
684
684
|
<div className={styles.formSplit}>
|
|
685
|
-
{multiple && shouldDisplayFormList(data, type) && (
|
|
686
|
-
<>
|
|
687
|
-
<div className={styles.gridtxt__header}>
|
|
688
|
-
<span>Form List</span>
|
|
689
|
-
</div>
|
|
690
|
-
<table className={styles.contentTable}>
|
|
691
|
-
<thead>
|
|
692
|
-
<tr>
|
|
693
|
-
<th>ID</th>
|
|
694
|
-
<th>Form</th>
|
|
695
|
-
<th>Created By</th>
|
|
696
|
-
<th>Created At</th>
|
|
697
|
-
<th>Updated By</th>
|
|
698
|
-
<th>Updated At</th>
|
|
699
|
-
<th></th>
|
|
700
|
-
</tr>
|
|
701
|
-
</thead>
|
|
702
|
-
<tbody>
|
|
703
|
-
{typeof data[type]?.map === 'function' &&
|
|
704
|
-
data[type].map((item, index) => {
|
|
705
|
-
const idAsNumber = parseFloat(item.id);
|
|
706
|
-
if (
|
|
707
|
-
!isNaN(idAsNumber) &&
|
|
708
|
-
Number.isInteger(idAsNumber)
|
|
709
|
-
) {
|
|
710
|
-
return (
|
|
711
|
-
<tr
|
|
712
|
-
key={`form-list-${index}`}
|
|
713
|
-
onClick={(e) => {
|
|
714
|
-
e.preventDefault();
|
|
715
|
-
handleSelectForm(
|
|
716
|
-
item,
|
|
717
|
-
index
|
|
718
|
-
);
|
|
719
|
-
}}
|
|
720
|
-
>
|
|
721
|
-
<td>{item.id}</td>
|
|
722
|
-
<td>{item.form_label}</td>
|
|
723
|
-
<td>{item.created_by}</td>
|
|
724
|
-
<td>
|
|
725
|
-
{item.created_at
|
|
726
|
-
? moment(
|
|
727
|
-
item.created_at
|
|
728
|
-
).format(
|
|
729
|
-
'DD-MM-YYYY hh:mm A'
|
|
730
|
-
)
|
|
731
|
-
: null}
|
|
732
|
-
</td>
|
|
733
|
-
<td>{item.updated_by}</td>
|
|
734
|
-
<td>
|
|
735
|
-
{item.updated_at
|
|
736
|
-
? moment(
|
|
737
|
-
item.updated_at
|
|
738
|
-
).format(
|
|
739
|
-
'DD-MM-YYYY hh:mm A'
|
|
740
|
-
)
|
|
741
|
-
: null}
|
|
742
|
-
</td>
|
|
743
|
-
<td>
|
|
744
|
-
<div
|
|
745
|
-
className={
|
|
746
|
-
styles.tdActions
|
|
747
|
-
}
|
|
748
|
-
>
|
|
749
|
-
<span
|
|
750
|
-
data-tooltip-id="system-tooltip"
|
|
751
|
-
data-tooltip-content="Download Form"
|
|
752
|
-
className="tooltip"
|
|
753
|
-
onClick={() =>
|
|
754
|
-
handleDownloadForm(
|
|
755
|
-
item,
|
|
756
|
-
label,
|
|
757
|
-
originalData
|
|
758
|
-
)
|
|
759
|
-
}
|
|
760
|
-
>
|
|
761
|
-
<CloudDownload
|
|
762
|
-
strokeWidth={
|
|
763
|
-
2
|
|
764
|
-
}
|
|
765
|
-
size={18}
|
|
766
|
-
className={
|
|
767
|
-
styles.tdAction
|
|
768
|
-
}
|
|
769
|
-
/>
|
|
770
|
-
</span>
|
|
771
|
-
<span
|
|
772
|
-
data-tooltip-id="system-tooltip"
|
|
773
|
-
data-tooltip-content="Delete Form"
|
|
774
|
-
className="tooltip"
|
|
775
|
-
onClick={() =>
|
|
776
|
-
handleDeleteForm(
|
|
777
|
-
item.id,
|
|
778
|
-
index
|
|
779
|
-
)
|
|
780
|
-
}
|
|
781
|
-
>
|
|
782
|
-
<Backspace
|
|
783
|
-
strokeWidth={
|
|
784
|
-
2
|
|
785
|
-
}
|
|
786
|
-
size={18}
|
|
787
|
-
className={
|
|
788
|
-
styles.tdAction
|
|
789
|
-
}
|
|
790
|
-
/>
|
|
791
|
-
</span>
|
|
792
|
-
</div>
|
|
793
|
-
</td>
|
|
794
|
-
</tr>
|
|
795
|
-
);
|
|
796
|
-
}
|
|
797
|
-
return null;
|
|
798
|
-
})}
|
|
799
|
-
</tbody>
|
|
800
|
-
</table>
|
|
801
|
-
</>
|
|
802
|
-
)}
|
|
803
|
-
|
|
804
685
|
{activeForm && (
|
|
805
686
|
<>
|
|
806
687
|
<div className={styles.gridtxt__header}>
|
|
@@ -810,7 +691,7 @@ const GenericDynamic = ({
|
|
|
810
691
|
</span>
|
|
811
692
|
</div>
|
|
812
693
|
<div className={styles.formcontainer}>
|
|
813
|
-
<
|
|
694
|
+
<form className={styles.modalForm}>
|
|
814
695
|
{typeof activeForm === 'object' &&
|
|
815
696
|
!Array.isArray(activeForm)
|
|
816
697
|
? Object.entries(activeForm)
|
|
@@ -916,10 +797,133 @@ const GenericDynamic = ({
|
|
|
916
797
|
/>
|
|
917
798
|
)
|
|
918
799
|
)}
|
|
919
|
-
</
|
|
800
|
+
</form>
|
|
920
801
|
</div>
|
|
921
802
|
</>
|
|
922
803
|
)}
|
|
804
|
+
|
|
805
|
+
{multiple && shouldDisplayFormList(data, type) && (
|
|
806
|
+
<>
|
|
807
|
+
<div
|
|
808
|
+
className={styles.gridtxt__header}
|
|
809
|
+
style={{ paddingTop: '20px' }}
|
|
810
|
+
>
|
|
811
|
+
<span>Form List</span>
|
|
812
|
+
</div>
|
|
813
|
+
<table className={styles.contentTable}>
|
|
814
|
+
<thead>
|
|
815
|
+
<tr>
|
|
816
|
+
<th>ID</th>
|
|
817
|
+
<th>Form</th>
|
|
818
|
+
<th>Created By</th>
|
|
819
|
+
<th>Created At</th>
|
|
820
|
+
<th>Updated By</th>
|
|
821
|
+
<th>Updated At</th>
|
|
822
|
+
<th></th>
|
|
823
|
+
</tr>
|
|
824
|
+
</thead>
|
|
825
|
+
<tbody>
|
|
826
|
+
{typeof data[type]?.map === 'function' &&
|
|
827
|
+
data[type].map((item, index) => {
|
|
828
|
+
const idAsNumber = parseFloat(item.id);
|
|
829
|
+
if (
|
|
830
|
+
!isNaN(idAsNumber) &&
|
|
831
|
+
Number.isInteger(idAsNumber)
|
|
832
|
+
) {
|
|
833
|
+
return (
|
|
834
|
+
<tr
|
|
835
|
+
key={`form-list-${index}`}
|
|
836
|
+
onClick={(e) => {
|
|
837
|
+
e.preventDefault();
|
|
838
|
+
handleSelectForm(
|
|
839
|
+
item,
|
|
840
|
+
index
|
|
841
|
+
);
|
|
842
|
+
}}
|
|
843
|
+
>
|
|
844
|
+
<td>{item.id}</td>
|
|
845
|
+
<td>{item.form_label}</td>
|
|
846
|
+
<td>{item.created_by}</td>
|
|
847
|
+
<td>
|
|
848
|
+
{item.created_at
|
|
849
|
+
? moment(
|
|
850
|
+
item.created_at
|
|
851
|
+
).format(
|
|
852
|
+
'DD-MM-YYYY hh:mm A'
|
|
853
|
+
)
|
|
854
|
+
: null}
|
|
855
|
+
</td>
|
|
856
|
+
<td>{item.updated_by}</td>
|
|
857
|
+
<td>
|
|
858
|
+
{item.updated_at
|
|
859
|
+
? moment(
|
|
860
|
+
item.updated_at
|
|
861
|
+
).format(
|
|
862
|
+
'DD-MM-YYYY hh:mm A'
|
|
863
|
+
)
|
|
864
|
+
: null}
|
|
865
|
+
</td>
|
|
866
|
+
<td>
|
|
867
|
+
<div
|
|
868
|
+
className={
|
|
869
|
+
styles.tdActions
|
|
870
|
+
}
|
|
871
|
+
>
|
|
872
|
+
<span
|
|
873
|
+
data-tooltip-id="system-tooltip"
|
|
874
|
+
data-tooltip-content="Download Form"
|
|
875
|
+
className="tooltip"
|
|
876
|
+
onClick={() =>
|
|
877
|
+
handleDownloadForm(
|
|
878
|
+
item,
|
|
879
|
+
label,
|
|
880
|
+
originalData
|
|
881
|
+
)
|
|
882
|
+
}
|
|
883
|
+
>
|
|
884
|
+
<CloudDownload
|
|
885
|
+
strokeWidth={
|
|
886
|
+
2
|
|
887
|
+
}
|
|
888
|
+
size={18}
|
|
889
|
+
className={
|
|
890
|
+
styles.tdAction
|
|
891
|
+
}
|
|
892
|
+
/>
|
|
893
|
+
</span>
|
|
894
|
+
<span
|
|
895
|
+
data-tooltip-id="system-tooltip"
|
|
896
|
+
data-tooltip-content="Delete Form"
|
|
897
|
+
className="tooltip"
|
|
898
|
+
onClick={() =>
|
|
899
|
+
handleDeleteForm(
|
|
900
|
+
item.id,
|
|
901
|
+
index
|
|
902
|
+
)
|
|
903
|
+
}
|
|
904
|
+
>
|
|
905
|
+
<Backspace
|
|
906
|
+
strokeWidth={
|
|
907
|
+
2
|
|
908
|
+
}
|
|
909
|
+
size={18}
|
|
910
|
+
className={
|
|
911
|
+
styles.tdAction
|
|
912
|
+
}
|
|
913
|
+
/>
|
|
914
|
+
</span>
|
|
915
|
+
</div>
|
|
916
|
+
</td>
|
|
917
|
+
</tr>
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
return null;
|
|
921
|
+
})}
|
|
922
|
+
</tbody>
|
|
923
|
+
</table>
|
|
924
|
+
<div style={{ paddingBottom: '56px' }}></div>
|
|
925
|
+
</>
|
|
926
|
+
)}
|
|
923
927
|
</div>
|
|
924
928
|
<div className={styles.polActions}>
|
|
925
929
|
{buttons &&
|
|
@@ -1,16 +1,93 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useState } from 'react';
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
2
3
|
import debounce from 'lodash.debounce';
|
|
3
4
|
import { toast } from 'react-toastify';
|
|
4
|
-
import Popup from 'reactjs-popup';
|
|
5
5
|
import { confirmAlert } from 'react-confirm-alert';
|
|
6
6
|
import { TrashCan, ArrowUp, ArrowDown } from 'akar-icons';
|
|
7
|
+
import { CompactPicker } from 'react-color';
|
|
7
8
|
|
|
8
9
|
import CustomFetch from '../Fetch';
|
|
9
|
-
import Form from '../Form';
|
|
10
10
|
import MultiSelect from '../MultiSelect';
|
|
11
11
|
|
|
12
12
|
import 'react-confirm-alert/src/react-confirm-alert.css';
|
|
13
13
|
import styles from './styles/GenericEditableTable.module.scss';
|
|
14
|
+
import { set } from 'lodash';
|
|
15
|
+
|
|
16
|
+
const ColourPicker = ({ value, columnId, keyCounter, onChange }) => {
|
|
17
|
+
const [colorPickerShow, setColorPickerShow] = useState(false);
|
|
18
|
+
const colorPickerRef = useRef(null);
|
|
19
|
+
const buttonRef = useRef(null); // Reference to the button for positioning
|
|
20
|
+
const popoverRef = useRef(null); // Reference to the popover
|
|
21
|
+
|
|
22
|
+
// Handle clicks outside of the color picker to close it
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const handleClickOutside = (event) => {
|
|
25
|
+
// Check if click is outside both the button and the popover
|
|
26
|
+
if (
|
|
27
|
+
popoverRef.current &&
|
|
28
|
+
!popoverRef.current.contains(event.target) &&
|
|
29
|
+
buttonRef.current &&
|
|
30
|
+
!buttonRef.current.contains(event.target)
|
|
31
|
+
) {
|
|
32
|
+
setColorPickerShow(false); // Close the color picker
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
37
|
+
return () =>
|
|
38
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
39
|
+
}, []);
|
|
40
|
+
|
|
41
|
+
const buttonRect = buttonRef.current
|
|
42
|
+
? buttonRef.current.getBoundingClientRect()
|
|
43
|
+
: {}; // Get button position
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div className={styles.cpicker}>
|
|
47
|
+
<div className={styles.cpicker__btn} ref={colorPickerRef}>
|
|
48
|
+
<button
|
|
49
|
+
ref={buttonRef} // Attach ref to the button
|
|
50
|
+
style={
|
|
51
|
+
value && value !== 'null' ? { background: value } : {}
|
|
52
|
+
}
|
|
53
|
+
onClick={(e) => {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
setColorPickerShow(!colorPickerShow); // Toggle visibility
|
|
56
|
+
}}
|
|
57
|
+
>
|
|
58
|
+
☐
|
|
59
|
+
</button>
|
|
60
|
+
|
|
61
|
+
{colorPickerShow &&
|
|
62
|
+
ReactDOM.createPortal(
|
|
63
|
+
<div
|
|
64
|
+
ref={popoverRef} // Attach ref to the popover
|
|
65
|
+
className={styles.colour_popover}
|
|
66
|
+
style={{
|
|
67
|
+
position: 'absolute',
|
|
68
|
+
left: buttonRect.left, // Position it based on button's position
|
|
69
|
+
top: buttonRect.bottom + 5, // Position below the button with a small offset
|
|
70
|
+
zIndex: 9999,
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
<div
|
|
74
|
+
className={styles.colour_cover}
|
|
75
|
+
onClick={() => setColorPickerShow(false)}
|
|
76
|
+
/>
|
|
77
|
+
<CompactPicker
|
|
78
|
+
color={value || ''}
|
|
79
|
+
onChangeComplete={(color) => {
|
|
80
|
+
onChange(color.hex, columnId, keyCounter);
|
|
81
|
+
setColorPickerShow(false);
|
|
82
|
+
}}
|
|
83
|
+
/>
|
|
84
|
+
</div>,
|
|
85
|
+
document.body // Render the popover inside the body
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
14
91
|
|
|
15
92
|
const GenericEditableTable = ({
|
|
16
93
|
schedulingConfig,
|
|
@@ -93,6 +170,7 @@ const GenericEditableTable = ({
|
|
|
93
170
|
};
|
|
94
171
|
|
|
95
172
|
const handleFieldChange = (value, fieldId, keyCounter) => {
|
|
173
|
+
console.info('handleFieldChange', value, fieldId, keyCounter);
|
|
96
174
|
setLocalData((prev) => {
|
|
97
175
|
const updatedDetail = [...prev];
|
|
98
176
|
updatedDetail[keyCounter] = {
|
|
@@ -178,6 +256,15 @@ const GenericEditableTable = ({
|
|
|
178
256
|
if (!entry || !column) return null;
|
|
179
257
|
|
|
180
258
|
switch (column.type) {
|
|
259
|
+
case 'colour':
|
|
260
|
+
return (
|
|
261
|
+
<ColourPicker
|
|
262
|
+
value={entry[column.id] || ''}
|
|
263
|
+
columnId={column.id}
|
|
264
|
+
keyCounter={keyCounter}
|
|
265
|
+
onChange={handleFieldChange}
|
|
266
|
+
/>
|
|
267
|
+
);
|
|
181
268
|
case 'currency':
|
|
182
269
|
case 'number':
|
|
183
270
|
return (
|
|
@@ -405,19 +492,24 @@ const GenericEditableTable = ({
|
|
|
405
492
|
.reduce((sum, entry) => {
|
|
406
493
|
// For each row, sum the values based on column.keys
|
|
407
494
|
const subtotal =
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
495
|
+
Array.isArray(
|
|
496
|
+
column.keys
|
|
497
|
+
) // Ensure column.keys is an array
|
|
498
|
+
? column.keys.reduce(
|
|
499
|
+
(
|
|
500
|
+
rowSum,
|
|
501
|
+
key
|
|
502
|
+
) =>
|
|
503
|
+
rowSum +
|
|
504
|
+
(parseFloat(
|
|
505
|
+
entry[
|
|
506
|
+
key
|
|
507
|
+
]
|
|
508
|
+
) ||
|
|
509
|
+
0),
|
|
510
|
+
0
|
|
511
|
+
)
|
|
512
|
+
: 0; // Default to 0 if column.keys is not an array
|
|
421
513
|
return sum + subtotal;
|
|
422
514
|
}, 0)
|
|
423
515
|
.toLocaleString('en-AU', {
|
|
@@ -197,3 +197,60 @@
|
|
|
197
197
|
color: var(--primary-color); /* Set text color to primary color */
|
|
198
198
|
border-top: 2px solid var(--primary-color); /* Add border top to separate subtotal row */
|
|
199
199
|
}
|
|
200
|
+
|
|
201
|
+
.colour {
|
|
202
|
+
&__cover {
|
|
203
|
+
position: fixed;
|
|
204
|
+
top: 0;
|
|
205
|
+
right: 0;
|
|
206
|
+
bottom: 0;
|
|
207
|
+
left: 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
&__popover {
|
|
211
|
+
position: absolute;
|
|
212
|
+
z-index: 9999;
|
|
213
|
+
left: 50%; /* Position to the center or adjust accordingly */
|
|
214
|
+
top: 50%; /* Adjust top based on your layout */
|
|
215
|
+
transform: translate(-50%, -50%); /* Center it */
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.cpicker {
|
|
220
|
+
width: 100%;
|
|
221
|
+
display: flex;
|
|
222
|
+
flex-wrap: nowrap;
|
|
223
|
+
align-items: center;
|
|
224
|
+
|
|
225
|
+
&__btn {
|
|
226
|
+
flex: 1;
|
|
227
|
+
|
|
228
|
+
button {
|
|
229
|
+
width: 40px; /* Keep it compact */
|
|
230
|
+
height: 40px; /* Square button */
|
|
231
|
+
font-size: 1.5rem; /* Adjusted for a better icon size */
|
|
232
|
+
font-weight: 600;
|
|
233
|
+
color: #fff; /* White icon color */
|
|
234
|
+
background-color: #b0b0b0; /* Neutral grey base */
|
|
235
|
+
border: 2px solid #999; /* Light border for definition */
|
|
236
|
+
border-radius: 8px; /* Rounded corners */
|
|
237
|
+
cursor: pointer;
|
|
238
|
+
transition: all 0.3s ease; /* Smooth transition for hover effect */
|
|
239
|
+
|
|
240
|
+
&:hover {
|
|
241
|
+
background-color: #999; /* Darken the background on hover */
|
|
242
|
+
border-color: #666; /* Darken the border on hover */
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
&:focus {
|
|
246
|
+
outline: none; /* Remove default focus outline */
|
|
247
|
+
box-shadow: 0 0 0 2px rgba(72, 168, 58, 0.5); /* Custom focus outline */
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
&:active {
|
|
251
|
+
background-color: #888; /* Lighter grey on click */
|
|
252
|
+
transform: scale(0.98); /* Shrink on click */
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|