@visns-studio/visns-components 5.8.11 → 5.8.13
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 +12 -12
- package/src/components/crm/Autocomplete.jsx +211 -49
- package/src/components/crm/Field.jsx +28 -1
- package/src/components/crm/Form.jsx +20 -7
- package/src/components/crm/SectionHeader.jsx +29 -0
- package/src/components/crm/examples/FormStylingGuide.md +71 -0
- package/src/components/crm/examples/FormWithSectionHeaders.jsx +266 -0
- package/src/components/crm/generic/ConfirmationDialog.jsx +97 -0
- package/src/components/crm/generic/GenericIndex.jsx +2 -3
- package/src/components/crm/generic/GenericQuote.jsx +413 -120
- package/src/components/crm/generic/SortableQuoteItems.jsx +114 -70
- package/src/components/crm/styles/Autocomplete.module.scss +97 -13
- package/src/components/crm/styles/Field.module.scss +88 -5
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
SortableContainer,
|
|
4
|
+
SortableElement,
|
|
5
|
+
sortableHandle,
|
|
6
|
+
} from 'react-sortable-hoc';
|
|
3
7
|
import { ChevronVertical, Pencil, TrashCan } from 'akar-icons';
|
|
4
8
|
import get from 'lodash/get';
|
|
5
9
|
import { formatCurrency } from './utils/formatters';
|
|
@@ -12,76 +16,116 @@ const DragHandle = sortableHandle(() => (
|
|
|
12
16
|
));
|
|
13
17
|
|
|
14
18
|
// Sortable table row component
|
|
15
|
-
const SortableRow = SortableElement(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
e
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
19
|
+
const SortableRow = SortableElement(
|
|
20
|
+
({ row, index, rowIndex, columns, onEdit, onDelete }) => {
|
|
21
|
+
return (
|
|
22
|
+
<tr className={styles.sortableRow}>
|
|
23
|
+
<td className={styles.dragHandleCell}>
|
|
24
|
+
<DragHandle />
|
|
25
|
+
</td>
|
|
26
|
+
{columns.map((column) => {
|
|
27
|
+
const cellValue = get(row, column.id, '');
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<td
|
|
31
|
+
key={`row-${rowIndex || index}-column-${column.id}`}
|
|
32
|
+
style={column.style || {}}
|
|
33
|
+
className={styles.tableCell}
|
|
34
|
+
>
|
|
35
|
+
{column.id === 'subtotal' ||
|
|
36
|
+
column.label === 'Subtotal'
|
|
37
|
+
? formatCurrency(
|
|
38
|
+
parseFloat(get(row, 'rate', 0)) *
|
|
39
|
+
parseFloat(get(row, 'qty', 1))
|
|
40
|
+
)
|
|
41
|
+
: column.type === 'currency'
|
|
42
|
+
? formatCurrency(cellValue)
|
|
43
|
+
: cellValue}
|
|
44
|
+
</td>
|
|
45
|
+
);
|
|
46
|
+
})}
|
|
47
|
+
<td className={styles.actionCell}>
|
|
48
|
+
<div className={styles.actionButtons}>
|
|
49
|
+
<Pencil
|
|
50
|
+
className={styles.editButton}
|
|
51
|
+
strokeWidth={2}
|
|
52
|
+
size={20}
|
|
53
|
+
onClick={(e) => {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
e.stopPropagation();
|
|
56
|
+
// Use onEdit directly - it already has the index captured in the closure
|
|
57
|
+
console.log(
|
|
58
|
+
'Edit clicked with rowIndex:',
|
|
59
|
+
rowIndex || index
|
|
60
|
+
);
|
|
61
|
+
onEdit(row);
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
<TrashCan
|
|
65
|
+
className={styles.deleteButton}
|
|
66
|
+
strokeWidth={2}
|
|
67
|
+
size={20}
|
|
68
|
+
onClick={(e) => {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
e.stopPropagation();
|
|
71
|
+
console.log(
|
|
72
|
+
'Delete button clicked for row:',
|
|
73
|
+
row
|
|
74
|
+
);
|
|
75
|
+
// Make sure we're passing the row to the handleDelete function
|
|
76
|
+
// which will then pass it along with the index to the parent component
|
|
77
|
+
onDelete(row);
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
</td>
|
|
82
|
+
</tr>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
);
|
|
68
86
|
|
|
69
87
|
// Sortable table body component
|
|
70
|
-
const SortableTableBody = SortableContainer(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
const SortableTableBody = SortableContainer(
|
|
89
|
+
({ items, columns, onEdit, onDelete }) => {
|
|
90
|
+
return (
|
|
91
|
+
<tbody>
|
|
92
|
+
{items.map((row, index) => {
|
|
93
|
+
// Create a wrapped onEdit function that explicitly includes the index
|
|
94
|
+
const handleEdit = (rowData) => {
|
|
95
|
+
console.log(
|
|
96
|
+
'SortableTableBody handleEdit with explicit index:',
|
|
97
|
+
index
|
|
98
|
+
);
|
|
99
|
+
onEdit(rowData, index);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Create a wrapped onDelete function that explicitly includes the index
|
|
103
|
+
const handleDelete = (rowData) => {
|
|
104
|
+
console.log(
|
|
105
|
+
'SortableTableBody handleDelete with explicit index:',
|
|
106
|
+
index,
|
|
107
|
+
'row data:',
|
|
108
|
+
rowData
|
|
109
|
+
);
|
|
110
|
+
// Make sure we're passing all required parameters
|
|
111
|
+
onDelete(rowData, index);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<SortableRow
|
|
116
|
+
key={`row-${index}`}
|
|
117
|
+
index={index}
|
|
118
|
+
row={row}
|
|
119
|
+
rowIndex={index} // Pass an additional prop for the row index
|
|
120
|
+
columns={columns}
|
|
121
|
+
onEdit={handleEdit}
|
|
122
|
+
onDelete={handleDelete}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
})}
|
|
126
|
+
</tbody>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
);
|
|
86
130
|
|
|
87
131
|
export default SortableTableBody;
|
|
@@ -1,36 +1,120 @@
|
|
|
1
|
-
.AutocompletePlace
|
|
2
|
-
|
|
1
|
+
.AutocompletePlace {
|
|
2
|
+
position: relative;
|
|
3
|
+
width: 100%;
|
|
4
|
+
|
|
5
|
+
.toggleActive {
|
|
6
|
+
color: var(--secondary-color);
|
|
7
|
+
}
|
|
3
8
|
}
|
|
4
9
|
|
|
5
|
-
.AutocompletePlace {
|
|
10
|
+
.AutocompletePlace-inputWrapper {
|
|
6
11
|
position: relative;
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
7
14
|
width: 100%;
|
|
8
15
|
|
|
9
|
-
> svg {
|
|
16
|
+
> svg:not(.AutocompletePlace-searchIcon) {
|
|
10
17
|
position: absolute;
|
|
11
|
-
right: 0.
|
|
12
|
-
top:
|
|
13
|
-
|
|
18
|
+
right: 0.5rem;
|
|
19
|
+
top: 50%;
|
|
20
|
+
transform: translateY(-50%);
|
|
14
21
|
cursor: pointer;
|
|
15
22
|
}
|
|
23
|
+
}
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
.AutocompletePlace-searchIcon {
|
|
26
|
+
position: absolute;
|
|
27
|
+
left: 0.75rem;
|
|
28
|
+
color: var(--paragraph-color);
|
|
29
|
+
pointer-events: none;
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
.AutocompletePlace-input {
|
|
23
|
-
padding: 0.65rem 3rem 0.65rem
|
|
33
|
+
padding: 0.65rem 3rem 0.65rem 2.25rem !important;
|
|
24
34
|
height: 38px;
|
|
35
|
+
width: 100%;
|
|
36
|
+
border: 1px solid rgba(var(--primary-rgb), 0.2);
|
|
37
|
+
border-radius: 4px;
|
|
38
|
+
outline: none;
|
|
39
|
+
font-size: 0.9rem;
|
|
40
|
+
|
|
41
|
+
&:focus {
|
|
42
|
+
border-color: rgba(var(--primary-rgb), 0.5);
|
|
43
|
+
box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.AutocompletePlace-results {
|
|
48
|
+
position: absolute;
|
|
49
|
+
top: 100%;
|
|
50
|
+
left: 0;
|
|
51
|
+
right: 0;
|
|
52
|
+
z-index: 999;
|
|
53
|
+
margin: 0;
|
|
54
|
+
padding: 0;
|
|
55
|
+
background-color: #fff;
|
|
56
|
+
border: 1px solid rgba(var(--primary-rgb), 0.2);
|
|
57
|
+
border-radius: 4px;
|
|
58
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
59
|
+
max-height: 250px;
|
|
60
|
+
overflow-y: auto;
|
|
61
|
+
margin-top: 4px;
|
|
62
|
+
list-style-type: none;
|
|
63
|
+
width: 100%;
|
|
25
64
|
}
|
|
26
65
|
|
|
27
66
|
.AutocompletePlace-items {
|
|
28
67
|
list-style: none;
|
|
29
68
|
border-bottom: 1px solid rgba(var(--primary-rgb), 0.1);
|
|
30
69
|
cursor: pointer;
|
|
31
|
-
padding:
|
|
70
|
+
padding: 8px 12px;
|
|
71
|
+
font-size: 0.9rem;
|
|
72
|
+
|
|
73
|
+
&:last-child {
|
|
74
|
+
border-bottom: none;
|
|
75
|
+
}
|
|
32
76
|
|
|
33
77
|
&:hover {
|
|
34
|
-
background-color: rgba(var(--
|
|
78
|
+
background-color: rgba(var(--primary-rgb), 0.05);
|
|
35
79
|
}
|
|
36
80
|
}
|
|
81
|
+
|
|
82
|
+
.AutocompletePlace-itemMain {
|
|
83
|
+
display: flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
gap: 4px;
|
|
86
|
+
margin-bottom: 2px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.AutocompletePlace-itemAddress {
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
color: var(--primary-color);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.AutocompletePlace-itemText {
|
|
95
|
+
color: var(--paragraph-color);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.AutocompletePlace-itemSecondary {
|
|
99
|
+
font-size: 0.8rem;
|
|
100
|
+
color: rgba(var(--paragraph-rgb), 0.7);
|
|
101
|
+
white-space: nowrap;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
text-overflow: ellipsis;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.AutocompletePlace-itemSeparator {
|
|
107
|
+
opacity: 0.6;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.AutocompletePlace-loading {
|
|
111
|
+
font-style: italic;
|
|
112
|
+
color: var(--paragraph-color);
|
|
113
|
+
text-align: center;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.AutocompletePlace-noResults {
|
|
117
|
+
font-style: italic;
|
|
118
|
+
color: var(--paragraph-color);
|
|
119
|
+
text-align: center;
|
|
120
|
+
}
|
|
@@ -494,18 +494,101 @@ input[type='file']:hover {
|
|
|
494
494
|
margin-right: 5px;
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
+
/* Section header styling for form sections */
|
|
498
|
+
.sectionHeader {
|
|
499
|
+
display: flex;
|
|
500
|
+
align-items: center;
|
|
501
|
+
width: 100%;
|
|
502
|
+
padding: 0.85em 1.2em;
|
|
503
|
+
background: var(--primary-color, #2684ff);
|
|
504
|
+
border-radius: var(--br, 3px);
|
|
505
|
+
box-sizing: border-box;
|
|
506
|
+
margin: 0.5em 0 1em 0;
|
|
507
|
+
position: relative;
|
|
508
|
+
overflow: hidden;
|
|
509
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
|
510
|
+
|
|
511
|
+
/* Add a subtle gradient overlay for depth */
|
|
512
|
+
&::before {
|
|
513
|
+
content: '';
|
|
514
|
+
position: absolute;
|
|
515
|
+
top: 0;
|
|
516
|
+
left: 0;
|
|
517
|
+
width: 100%;
|
|
518
|
+
height: 100%;
|
|
519
|
+
background: linear-gradient(
|
|
520
|
+
to right,
|
|
521
|
+
rgba(255, 255, 255, 0.15),
|
|
522
|
+
rgba(255, 255, 255, 0.05)
|
|
523
|
+
);
|
|
524
|
+
pointer-events: none;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
svg {
|
|
528
|
+
margin-right: 8px;
|
|
529
|
+
color: var(--secondary-color, #fff);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
span {
|
|
533
|
+
font-size: 1em;
|
|
534
|
+
color: var(--secondary-color, #fff);
|
|
535
|
+
font-weight: 600;
|
|
536
|
+
letter-spacing: 0.02em;
|
|
537
|
+
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/* Line break styling for form sections */
|
|
497
542
|
.formbreak {
|
|
498
543
|
display: block;
|
|
499
544
|
width: 100%;
|
|
500
|
-
padding:
|
|
501
|
-
background
|
|
502
|
-
|
|
545
|
+
padding: 0.85em 1.2em;
|
|
546
|
+
/* Use a more reliable background that works with any color scheme */
|
|
547
|
+
background: var(--primary-color, #2684ff);
|
|
548
|
+
border-radius: var(--br, 3px);
|
|
503
549
|
box-sizing: border-box;
|
|
504
|
-
border:
|
|
550
|
+
border-left: 4px solid var(--secondary-color, #fff);
|
|
551
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
552
|
+
margin: 0.5em 0;
|
|
553
|
+
position: relative;
|
|
554
|
+
overflow: hidden;
|
|
555
|
+
|
|
556
|
+
/* Add a subtle gradient overlay for depth */
|
|
557
|
+
&::before {
|
|
558
|
+
content: '';
|
|
559
|
+
position: absolute;
|
|
560
|
+
top: 0;
|
|
561
|
+
left: 0;
|
|
562
|
+
width: 100%;
|
|
563
|
+
height: 100%;
|
|
564
|
+
background: linear-gradient(
|
|
565
|
+
to right,
|
|
566
|
+
rgba(255, 255, 255, 0.1),
|
|
567
|
+
rgba(255, 255, 255, 0)
|
|
568
|
+
);
|
|
569
|
+
pointer-events: none;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
&::after {
|
|
573
|
+
content: '';
|
|
574
|
+
position: absolute;
|
|
575
|
+
bottom: 0;
|
|
576
|
+
left: 0;
|
|
577
|
+
width: 100%;
|
|
578
|
+
height: 2px;
|
|
579
|
+
background: var(--tertiary-color, #fff);
|
|
580
|
+
opacity: 0.3;
|
|
581
|
+
}
|
|
505
582
|
|
|
506
583
|
span {
|
|
507
584
|
font-size: 0.95em;
|
|
508
|
-
color: var(--
|
|
585
|
+
color: var(--tertiary-color, #fff);
|
|
586
|
+
font-weight: 500;
|
|
587
|
+
letter-spacing: 0.01em;
|
|
588
|
+
display: flex;
|
|
589
|
+
align-items: center;
|
|
590
|
+
position: relative;
|
|
591
|
+
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
|
|
509
592
|
}
|
|
510
593
|
}
|
|
511
594
|
|