@visns-studio/visns-components 5.10.11 → 5.11.2
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/README.md +85 -0
- package/package.json +7 -7
- package/src/components/cms/DataGrid.jsx +8 -8
- package/src/components/cms/DropZone.jsx +1 -1
- package/src/components/cms/Form.jsx +1 -1
- package/src/components/cms/Gallery.jsx +1 -1
- package/src/components/cms/sorting/Item.jsx +1 -1
- package/src/components/crm/Autocomplete.jsx +3 -3
- package/src/components/crm/Breadcrumb.jsx +4 -4
- package/src/components/crm/BusinessCardOcr.jsx +681 -95
- package/src/components/crm/DataGrid.jsx +34 -32
- package/src/components/crm/Field.jsx +12 -12
- package/src/components/crm/Form.jsx +2 -2
- package/src/components/crm/Navigation.jsx +11 -11
- package/src/components/crm/Notification.jsx +2 -2
- package/src/components/crm/QuickAction.jsx +3 -3
- package/src/components/crm/SectionHeader.jsx +1 -1
- package/src/components/crm/SwitchAccount.jsx +4 -4
- package/src/components/crm/auth/ClientLogin.jsx +2 -2
- package/src/components/crm/auth/ClientOTPVerify.jsx +2 -2
- package/src/components/crm/auth/Login.jsx +3 -3
- package/src/components/crm/auth/Reset.jsx +2 -2
- package/src/components/crm/auth/TwoFactorAuth.jsx +2 -2
- package/src/components/crm/columns/ColumnRenderers.jsx +320 -259
- package/src/components/crm/controls/DataGridSearch.jsx +5 -5
- package/src/components/crm/generic/AlternativeActionModal.jsx +100 -0
- package/src/components/crm/generic/ContactSelectorModal.jsx +423 -0
- package/src/components/crm/generic/DatePickerDialog.jsx +302 -0
- package/src/components/crm/generic/DateRangeSelectorModal.jsx +181 -0
- package/src/components/crm/generic/GenericClientPortal.jsx +1 -1
- package/src/components/crm/generic/GenericDashboard.jsx +4 -4
- package/src/components/crm/generic/GenericDetail.jsx +6 -6
- package/src/components/crm/generic/GenericDynamic.jsx +3 -3
- package/src/components/crm/generic/GenericEditableTable.jsx +4 -4
- package/src/components/crm/generic/GenericFormBuilder.jsx +6 -6
- package/src/components/crm/generic/GenericGrid.jsx +2888 -0
- package/src/components/crm/generic/GenericIndex.jsx +5 -1255
- package/src/components/crm/generic/GenericReport.jsx +966 -646
- package/src/components/crm/generic/GenericReportForm.jsx +194 -0
- package/src/components/crm/generic/NotificationList.jsx +1 -1
- package/src/components/crm/generic/ReasonCollectorModal.jsx +194 -0
- package/src/components/crm/generic/SortableQuoteItems.jsx +3 -3
- package/src/components/crm/generic/shared/formatters.js +231 -0
- package/src/components/crm/generic/shared/gridUtils.js +194 -0
- package/src/components/crm/generic/styles/AlternativeActionModal.css +127 -0
- package/src/components/crm/generic/styles/ContactSelectorModal.css +367 -0
- package/src/components/crm/generic/styles/DatePickerDialog.css +84 -0
- package/src/components/crm/generic/styles/DateRangeSelectorModal.css +115 -0
- package/src/components/crm/generic/styles/GenericIndex.module.scss +382 -0
- package/src/components/crm/generic/styles/GenericReport.module.scss +96 -0
- package/src/components/crm/generic/styles/ReasonCollectorModal.css +217 -0
- package/src/components/crm/modals/GalleryModal.jsx +2 -2
- package/src/components/crm/sorting/Item.jsx +3 -3
- package/src/components/crm/styles/BusinessCardOcr.module.scss +197 -4
- package/src/index.js +4 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sort data based on column configuration
|
|
3
|
+
* @param {Array} data - Data array to sort
|
|
4
|
+
* @param {string} key - Column key to sort by
|
|
5
|
+
* @param {string} direction - Sort direction ('asc' or 'desc')
|
|
6
|
+
* @param {Array} gridHeaders - Grid headers configuration
|
|
7
|
+
* @returns {Array} Sorted data array
|
|
8
|
+
*/
|
|
9
|
+
export const sortData = (data, key, direction, gridHeaders) => {
|
|
10
|
+
if (!key) return [...data];
|
|
11
|
+
|
|
12
|
+
return [...data].sort((a, b) => {
|
|
13
|
+
// Find the header config for this key to determine type
|
|
14
|
+
const headerConfig = gridHeaders.find((h) => h.key === key);
|
|
15
|
+
const type = headerConfig?.type || 'text';
|
|
16
|
+
|
|
17
|
+
// Get values, handling null/undefined
|
|
18
|
+
let aValue = a[key] === null || a[key] === undefined ? '' : a[key];
|
|
19
|
+
let bValue = b[key] === null || b[key] === undefined ? '' : b[key];
|
|
20
|
+
|
|
21
|
+
// Sort based on type
|
|
22
|
+
switch (type) {
|
|
23
|
+
case 'number':
|
|
24
|
+
case 'year':
|
|
25
|
+
aValue = parseFloat(aValue) || 0;
|
|
26
|
+
bValue = parseFloat(bValue) || 0;
|
|
27
|
+
break;
|
|
28
|
+
case 'date':
|
|
29
|
+
// Convert to timestamp for comparison
|
|
30
|
+
aValue = aValue ? new Date(aValue).getTime() : 0;
|
|
31
|
+
bValue = bValue ? new Date(bValue).getTime() : 0;
|
|
32
|
+
break;
|
|
33
|
+
default:
|
|
34
|
+
// For text, convert to lowercase strings
|
|
35
|
+
aValue = String(aValue).toLowerCase();
|
|
36
|
+
bValue = String(bValue).toLowerCase();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Compare values
|
|
40
|
+
if (aValue < bValue) {
|
|
41
|
+
return direction === 'asc' ? -1 : 1;
|
|
42
|
+
}
|
|
43
|
+
if (aValue > bValue) {
|
|
44
|
+
return direction === 'asc' ? 1 : -1;
|
|
45
|
+
}
|
|
46
|
+
return 0;
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Filter data based on filter values and configuration
|
|
52
|
+
* @param {Array} data - Data array to filter
|
|
53
|
+
* @param {Object} filterValues - Filter values object
|
|
54
|
+
* @param {Array} gridHeaders - Grid headers configuration
|
|
55
|
+
* @returns {Array} Filtered data array
|
|
56
|
+
*/
|
|
57
|
+
export const filterData = (data, filterValues, gridHeaders) => {
|
|
58
|
+
// If no filter values are set, return the original data
|
|
59
|
+
if (Object.keys(filterValues).length === 0) {
|
|
60
|
+
return data;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Filter the data based on the filter values
|
|
64
|
+
return data.filter((row) => {
|
|
65
|
+
// Check each filter
|
|
66
|
+
return Object.entries(filterValues).every(([key, value]) => {
|
|
67
|
+
// Skip empty filter values
|
|
68
|
+
if (!value) return true;
|
|
69
|
+
|
|
70
|
+
// Get the row value
|
|
71
|
+
const rowValue = row[key];
|
|
72
|
+
if (rowValue === null || rowValue === undefined) return false;
|
|
73
|
+
|
|
74
|
+
// Find the header config for this key
|
|
75
|
+
const headerConfig = gridHeaders.find((h) => h.key === key);
|
|
76
|
+
if (!headerConfig || !headerConfig.filter) return true;
|
|
77
|
+
|
|
78
|
+
const { type, operator } = headerConfig.filter;
|
|
79
|
+
|
|
80
|
+
// Apply filter based on type and operator
|
|
81
|
+
switch (type) {
|
|
82
|
+
case 'string':
|
|
83
|
+
const rowStr = String(rowValue).toLowerCase();
|
|
84
|
+
const filterStr = String(value).toLowerCase();
|
|
85
|
+
|
|
86
|
+
switch (operator) {
|
|
87
|
+
case 'equals':
|
|
88
|
+
return rowStr === filterStr;
|
|
89
|
+
case 'contains':
|
|
90
|
+
return rowStr.includes(filterStr);
|
|
91
|
+
case 'startsWith':
|
|
92
|
+
return rowStr.startsWith(filterStr);
|
|
93
|
+
case 'endsWith':
|
|
94
|
+
return rowStr.endsWith(filterStr);
|
|
95
|
+
default:
|
|
96
|
+
return rowStr.includes(filterStr);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
case 'number':
|
|
100
|
+
const rowNum = parseFloat(rowValue);
|
|
101
|
+
const filterNum = parseFloat(value);
|
|
102
|
+
|
|
103
|
+
if (isNaN(rowNum) || isNaN(filterNum)) return false;
|
|
104
|
+
|
|
105
|
+
switch (operator) {
|
|
106
|
+
case 'equals':
|
|
107
|
+
return rowNum === filterNum;
|
|
108
|
+
case 'greaterThan':
|
|
109
|
+
return rowNum > filterNum;
|
|
110
|
+
case 'lessThan':
|
|
111
|
+
return rowNum < filterNum;
|
|
112
|
+
case 'greaterThanOrEqual':
|
|
113
|
+
return rowNum >= filterNum;
|
|
114
|
+
case 'lessThanOrEqual':
|
|
115
|
+
return rowNum <= filterNum;
|
|
116
|
+
default:
|
|
117
|
+
return rowNum === filterNum;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
case 'date':
|
|
121
|
+
const rowDate = new Date(rowValue);
|
|
122
|
+
const filterDate = new Date(value);
|
|
123
|
+
|
|
124
|
+
if (isNaN(rowDate.getTime()) || isNaN(filterDate.getTime()))
|
|
125
|
+
return false;
|
|
126
|
+
|
|
127
|
+
switch (operator) {
|
|
128
|
+
case 'equals':
|
|
129
|
+
return (
|
|
130
|
+
rowDate.toDateString() ===
|
|
131
|
+
filterDate.toDateString()
|
|
132
|
+
);
|
|
133
|
+
case 'after':
|
|
134
|
+
return rowDate > filterDate;
|
|
135
|
+
case 'before':
|
|
136
|
+
return rowDate < filterDate;
|
|
137
|
+
default:
|
|
138
|
+
return (
|
|
139
|
+
rowDate.toDateString() ===
|
|
140
|
+
filterDate.toDateString()
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
default:
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Transform headers from API response to grid headers format
|
|
153
|
+
* @param {Object} headerData - Header data from API response
|
|
154
|
+
* @returns {Array} Formatted grid headers array
|
|
155
|
+
*/
|
|
156
|
+
export const transformApiHeaders = (headerData) => {
|
|
157
|
+
const headerEntries = Object.entries(headerData);
|
|
158
|
+
return headerEntries.map(([key, config]) => ({
|
|
159
|
+
key,
|
|
160
|
+
label: config.label || key,
|
|
161
|
+
sort: config.sort || key,
|
|
162
|
+
type: config.type || 'text',
|
|
163
|
+
filter: config.filter || null,
|
|
164
|
+
onClick: config.onClick || null,
|
|
165
|
+
}));
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Initialize filter values from grid headers
|
|
170
|
+
* @param {Array} gridHeaders - Grid headers array
|
|
171
|
+
* @returns {Object} Initial filter values object
|
|
172
|
+
*/
|
|
173
|
+
export const initializeFilterValues = (gridHeaders) => {
|
|
174
|
+
const initialFilterValues = {};
|
|
175
|
+
gridHeaders.forEach((header) => {
|
|
176
|
+
if (header.filter) {
|
|
177
|
+
initialFilterValues[header.key] = '';
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
return initialFilterValues;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get sort indicator style based on current sort configuration
|
|
185
|
+
* @param {string} key - Column key
|
|
186
|
+
* @param {Object} sortConfig - Current sort configuration
|
|
187
|
+
* @returns {Object} Style object for sort indicator
|
|
188
|
+
*/
|
|
189
|
+
export const getSortIndicatorStyle = (key, sortConfig) => {
|
|
190
|
+
if (sortConfig.key !== key) {
|
|
191
|
+
return { opacity: 0.3 }; // Dim the icon when not sorting by this column
|
|
192
|
+
}
|
|
193
|
+
return {}; // Full opacity when sorting by this column
|
|
194
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/* Alternative Action Modal Styles */
|
|
2
|
+
.alternative-action-modal {
|
|
3
|
+
text-align: center;
|
|
4
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.alternative-message {
|
|
8
|
+
margin-bottom: 24px;
|
|
9
|
+
color: #4a5568;
|
|
10
|
+
font-size: 16px;
|
|
11
|
+
line-height: 1.5;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.alternative-options {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
gap: 12px;
|
|
18
|
+
margin: 20px 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.alternative-action-option {
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
padding: 16px 20px;
|
|
25
|
+
border: 2px solid #e2e8f0;
|
|
26
|
+
border-radius: 12px;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
transition: all 0.2s ease;
|
|
29
|
+
background-color: #ffffff;
|
|
30
|
+
text-align: left;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.alternative-action-option:hover {
|
|
34
|
+
border-color: #4299e1;
|
|
35
|
+
background-color: #f7fafc;
|
|
36
|
+
transform: translateY(-1px);
|
|
37
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.alternative-action-option:active {
|
|
41
|
+
transform: translateY(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.alternative-icon {
|
|
45
|
+
font-size: 24px;
|
|
46
|
+
margin-right: 16px;
|
|
47
|
+
min-width: 32px;
|
|
48
|
+
text-align: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.alternative-content {
|
|
52
|
+
flex: 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.alternative-label {
|
|
56
|
+
font-weight: 600;
|
|
57
|
+
color: #2d3748;
|
|
58
|
+
font-size: 16px;
|
|
59
|
+
margin-bottom: 4px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.alternative-description {
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
color: #718096;
|
|
65
|
+
line-height: 1.4;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* SweetAlert2 custom classes */
|
|
69
|
+
.alternative-swal-container {
|
|
70
|
+
z-index: 10000;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.alternative-swal-popup {
|
|
74
|
+
border-radius: 16px;
|
|
75
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
76
|
+
max-width: 480px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.alternative-swal-content {
|
|
80
|
+
padding: 24px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.alternative-swal-cancel {
|
|
84
|
+
background-color: #e2e8f0 !important;
|
|
85
|
+
color: #4a5568 !important;
|
|
86
|
+
border: none !important;
|
|
87
|
+
border-radius: 8px !important;
|
|
88
|
+
font-weight: 600 !important;
|
|
89
|
+
padding: 12px 24px !important;
|
|
90
|
+
font-size: 14px !important;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.alternative-swal-cancel:hover {
|
|
94
|
+
background-color: #cbd5e0 !important;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Responsive design */
|
|
98
|
+
@media (max-width: 640px) {
|
|
99
|
+
.alternative-action-option {
|
|
100
|
+
padding: 14px 16px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.alternative-icon {
|
|
104
|
+
font-size: 20px;
|
|
105
|
+
margin-right: 12px;
|
|
106
|
+
min-width: 28px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.alternative-label {
|
|
110
|
+
font-size: 15px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.alternative-description {
|
|
114
|
+
font-size: 13px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.alternative-options {
|
|
118
|
+
gap: 10px;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Focus styles for accessibility */
|
|
123
|
+
.alternative-action-option:focus {
|
|
124
|
+
outline: none;
|
|
125
|
+
border-color: #4299e1;
|
|
126
|
+
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);
|
|
127
|
+
}
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/* Contact Selector Modal Styles */
|
|
2
|
+
|
|
3
|
+
.contact-selector-dialog {
|
|
4
|
+
max-width: 90vw !important;
|
|
5
|
+
width: 600px !important;
|
|
6
|
+
min-width: 400px !important;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.contact-selector-content {
|
|
10
|
+
max-width: 100% !important;
|
|
11
|
+
overflow: hidden !important;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.contact-selector-modal {
|
|
15
|
+
text-align: left;
|
|
16
|
+
font-family: inherit;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.contact-modal-header {
|
|
20
|
+
margin-bottom: 15px;
|
|
21
|
+
padding-bottom: 10px;
|
|
22
|
+
border-bottom: 1px solid #e5e7eb;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.contact-modal-message {
|
|
26
|
+
margin: 0 0 8px 0;
|
|
27
|
+
color: #374151;
|
|
28
|
+
font-size: 14px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.field-info {
|
|
32
|
+
color: #6b7280;
|
|
33
|
+
font-size: 12px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Existing contacts section */
|
|
37
|
+
.existing-contacts {
|
|
38
|
+
margin-bottom: 18px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.existing-contacts h4 {
|
|
42
|
+
margin: 0 0 8px 0;
|
|
43
|
+
font-size: 13px;
|
|
44
|
+
font-weight: 600;
|
|
45
|
+
color: #374151;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.contacts-list {
|
|
49
|
+
max-height: 180px;
|
|
50
|
+
overflow-y: auto;
|
|
51
|
+
border: 1px solid #e5e7eb;
|
|
52
|
+
border-radius: 4px;
|
|
53
|
+
padding: 6px;
|
|
54
|
+
background-color: #f9fafb;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.contact-item {
|
|
58
|
+
display: flex;
|
|
59
|
+
justify-content: space-between;
|
|
60
|
+
align-items: flex-start;
|
|
61
|
+
padding: 8px;
|
|
62
|
+
margin-bottom: 6px;
|
|
63
|
+
background-color: #ffffff;
|
|
64
|
+
border: 1px solid #e5e7eb;
|
|
65
|
+
border-radius: 4px;
|
|
66
|
+
position: relative;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.contact-item:last-child {
|
|
70
|
+
margin-bottom: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.contact-info {
|
|
74
|
+
flex: 1;
|
|
75
|
+
min-width: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.contact-info strong {
|
|
79
|
+
color: #111827;
|
|
80
|
+
font-weight: 500;
|
|
81
|
+
display: block;
|
|
82
|
+
margin-bottom: 2px;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.contact-info small {
|
|
86
|
+
color: #6b7280;
|
|
87
|
+
font-size: 12px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.contact-type {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
background-color: #dbeafe;
|
|
93
|
+
color: #1e40af;
|
|
94
|
+
padding: 2px 6px;
|
|
95
|
+
border-radius: 10px;
|
|
96
|
+
font-size: 10px;
|
|
97
|
+
font-weight: 500;
|
|
98
|
+
margin-top: 4px;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.contact-item .contact-type {
|
|
102
|
+
position: absolute;
|
|
103
|
+
top: 8px;
|
|
104
|
+
right: 35px;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.remove-contact-btn {
|
|
108
|
+
background-color: #dc2626;
|
|
109
|
+
color: white;
|
|
110
|
+
border: none;
|
|
111
|
+
border-radius: 50%;
|
|
112
|
+
width: 24px;
|
|
113
|
+
height: 24px;
|
|
114
|
+
font-size: 14px;
|
|
115
|
+
font-weight: bold;
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
display: flex;
|
|
118
|
+
align-items: center;
|
|
119
|
+
justify-content: center;
|
|
120
|
+
flex-shrink: 0;
|
|
121
|
+
transition: background-color 0.2s ease;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.remove-contact-btn:hover {
|
|
125
|
+
background-color: #b91c1c;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.no-contacts {
|
|
129
|
+
text-align: center;
|
|
130
|
+
color: #6b7280;
|
|
131
|
+
font-style: italic;
|
|
132
|
+
margin: 0;
|
|
133
|
+
padding: 20px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Add contact section */
|
|
137
|
+
.add-contact-section {
|
|
138
|
+
border-top: 1px solid #e5e7eb;
|
|
139
|
+
padding-top: 15px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.add-contact-section h4 {
|
|
143
|
+
margin: 0 0 10px 0;
|
|
144
|
+
font-size: 13px;
|
|
145
|
+
font-weight: 600;
|
|
146
|
+
color: #374151;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.existing-contact-selector {
|
|
150
|
+
margin-bottom: 15px;
|
|
151
|
+
padding: 12px;
|
|
152
|
+
background-color: #f9fafb;
|
|
153
|
+
border-radius: 6px;
|
|
154
|
+
border: 1px solid #e5e7eb;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.existing-contact-selector label {
|
|
158
|
+
display: block;
|
|
159
|
+
margin-bottom: 6px;
|
|
160
|
+
font-weight: 500;
|
|
161
|
+
color: #374151;
|
|
162
|
+
font-size: 12px;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.contact-select-row {
|
|
166
|
+
display: flex;
|
|
167
|
+
gap: 8px;
|
|
168
|
+
align-items: flex-end;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.existing-contact-selector select {
|
|
172
|
+
flex: 1;
|
|
173
|
+
margin: 0 !important;
|
|
174
|
+
padding: 6px 10px !important;
|
|
175
|
+
border: 1px solid #d1d5db !important;
|
|
176
|
+
border-radius: 4px !important;
|
|
177
|
+
font-size: 13px !important;
|
|
178
|
+
background-color: white !important;
|
|
179
|
+
height: 32px !important;
|
|
180
|
+
min-width: 0;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.add-contact-btn {
|
|
184
|
+
background-color: #4f46e5;
|
|
185
|
+
color: white;
|
|
186
|
+
border: none;
|
|
187
|
+
padding: 6px 12px;
|
|
188
|
+
border-radius: 4px;
|
|
189
|
+
font-size: 12px;
|
|
190
|
+
font-weight: 500;
|
|
191
|
+
cursor: pointer;
|
|
192
|
+
transition: background-color 0.2s ease;
|
|
193
|
+
height: 32px;
|
|
194
|
+
white-space: nowrap;
|
|
195
|
+
flex-shrink: 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.add-contact-btn:hover {
|
|
199
|
+
background-color: #4338ca;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.add-contact-btn:disabled {
|
|
203
|
+
background-color: #9ca3af;
|
|
204
|
+
cursor: not-allowed;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* Manual contact section */
|
|
208
|
+
.manual-contact-section {
|
|
209
|
+
border-top: 1px solid #e5e7eb;
|
|
210
|
+
padding-top: 12px;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.manual-contact-toggle {
|
|
214
|
+
margin-bottom: 10px;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.toggle-manual-btn {
|
|
218
|
+
background-color: #6b7280;
|
|
219
|
+
color: white;
|
|
220
|
+
border: none;
|
|
221
|
+
padding: 8px 16px;
|
|
222
|
+
border-radius: 4px;
|
|
223
|
+
font-size: 12px;
|
|
224
|
+
cursor: pointer;
|
|
225
|
+
transition: background-color 0.2s ease;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.toggle-manual-btn:hover {
|
|
229
|
+
background-color: #4b5563;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.manual-contact-form {
|
|
233
|
+
padding: 12px;
|
|
234
|
+
background-color: #f9fafb;
|
|
235
|
+
border-radius: 6px;
|
|
236
|
+
border: 1px solid #e5e7eb;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.form-group {
|
|
240
|
+
margin-bottom: 10px;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.form-group:last-child {
|
|
244
|
+
margin-bottom: 0;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.form-field-row {
|
|
248
|
+
display: flex;
|
|
249
|
+
gap: 8px;
|
|
250
|
+
align-items: center;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.form-group label {
|
|
254
|
+
font-weight: 500;
|
|
255
|
+
color: #374151;
|
|
256
|
+
font-size: 12px;
|
|
257
|
+
white-space: nowrap;
|
|
258
|
+
min-width: 60px;
|
|
259
|
+
flex-shrink: 0;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.form-group input {
|
|
263
|
+
flex: 1;
|
|
264
|
+
margin: 0 !important;
|
|
265
|
+
padding: 6px 10px !important;
|
|
266
|
+
border: 1px solid #d1d5db !important;
|
|
267
|
+
border-radius: 4px !important;
|
|
268
|
+
font-size: 13px !important;
|
|
269
|
+
box-sizing: border-box !important;
|
|
270
|
+
height: 32px !important;
|
|
271
|
+
min-width: 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.form-group input:focus {
|
|
275
|
+
border-color: #4f46e5 !important;
|
|
276
|
+
outline: none !important;
|
|
277
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1) !important;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.form-group input[style*="border-color: rgb(220, 38, 38)"] {
|
|
281
|
+
border-color: #dc2626 !important;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* Contact limits */
|
|
285
|
+
.contact-limits {
|
|
286
|
+
margin-top: 15px;
|
|
287
|
+
text-align: center;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.contact-limits small {
|
|
291
|
+
color: #6b7280;
|
|
292
|
+
font-size: 11px;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* Responsive design */
|
|
296
|
+
@media (max-width: 640px) {
|
|
297
|
+
.contact-selector-dialog {
|
|
298
|
+
width: 95vw !important;
|
|
299
|
+
max-width: 95vw !important;
|
|
300
|
+
min-width: 300px !important;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.contact-select-row {
|
|
304
|
+
flex-direction: column;
|
|
305
|
+
gap: 6px;
|
|
306
|
+
align-items: stretch;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.existing-contact-selector select {
|
|
310
|
+
margin-bottom: 6px !important;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.add-contact-btn {
|
|
314
|
+
width: 100%;
|
|
315
|
+
height: 36px;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.form-field-row {
|
|
319
|
+
flex-direction: column;
|
|
320
|
+
gap: 4px;
|
|
321
|
+
align-items: stretch;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.form-group label {
|
|
325
|
+
min-width: auto;
|
|
326
|
+
margin-bottom: 4px;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.form-group input {
|
|
330
|
+
height: 36px !important;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.contact-item {
|
|
334
|
+
flex-direction: column;
|
|
335
|
+
align-items: flex-start;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.contact-type {
|
|
339
|
+
position: static !important;
|
|
340
|
+
margin-top: 8px;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.remove-contact-btn {
|
|
344
|
+
position: absolute;
|
|
345
|
+
top: 8px;
|
|
346
|
+
right: 8px;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* Integration with SweetAlert2 */
|
|
351
|
+
.contact-selector-dialog .swal2-html-container {
|
|
352
|
+
margin: 0 !important;
|
|
353
|
+
padding: 0 !important;
|
|
354
|
+
overflow: visible !important;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.contact-selector-dialog .swal2-actions {
|
|
358
|
+
margin-top: 20px !important;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.contact-selector-dialog .swal2-confirm {
|
|
362
|
+
background-color: var(--primary-color, #4f46e5) !important;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.contact-selector-dialog .swal2-cancel {
|
|
366
|
+
background-color: #6b7280 !important;
|
|
367
|
+
}
|