@visns-studio/visns-components 5.3.11 → 5.3.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 +1 -1
- package/src/components/crm/DataGrid.jsx +19 -5
- package/src/components/crm/Field.jsx +38 -0
- package/src/components/crm/Form.jsx +77 -24
- package/src/components/crm/generic/GenericAuth.jsx +1 -1
- package/src/components/crm/generic/GenericIndex.jsx +34 -5
- package/src/components/crm/styles/DataGrid.module.scss +79 -1
- package/src/components/crm/styles/Form.module.scss +36 -1
package/package.json
CHANGED
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
79
79
|
},
|
|
80
80
|
"name": "@visns-studio/visns-components",
|
|
81
|
-
"version": "5.3.
|
|
81
|
+
"version": "5.3.13",
|
|
82
82
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
83
83
|
"main": "src/index.js",
|
|
84
84
|
"files": [
|
|
@@ -140,6 +140,7 @@ const DataGrid = forwardRef(
|
|
|
140
140
|
settings,
|
|
141
141
|
setConfig,
|
|
142
142
|
setFilterData,
|
|
143
|
+
setTableData,
|
|
143
144
|
setTotal,
|
|
144
145
|
setRowsSelected,
|
|
145
146
|
style,
|
|
@@ -209,7 +210,9 @@ const DataGrid = forwardRef(
|
|
|
209
210
|
setTotal(res.count);
|
|
210
211
|
}
|
|
211
212
|
setDataCount(res.count);
|
|
212
|
-
|
|
213
|
+
if (setTableData) {
|
|
214
|
+
setTableData(res.data);
|
|
215
|
+
}
|
|
213
216
|
dataRef.current = res.data;
|
|
214
217
|
});
|
|
215
218
|
|
|
@@ -2625,6 +2628,11 @@ const DataGrid = forwardRef(
|
|
|
2625
2628
|
/<\/?[^>]+(>|$)/g,
|
|
2626
2629
|
''
|
|
2627
2630
|
); // Simple regex to strip HTML tags
|
|
2631
|
+
} else {
|
|
2632
|
+
// Replace p tags with br tags
|
|
2633
|
+
content = content
|
|
2634
|
+
.replace(/<p>/g, '')
|
|
2635
|
+
.replace(/<\/p>/g, '<br>');
|
|
2628
2636
|
}
|
|
2629
2637
|
|
|
2630
2638
|
// If truncate has a value, limit content to specified number of characters
|
|
@@ -2985,10 +2993,16 @@ const DataGrid = forwardRef(
|
|
|
2985
2993
|
</div>
|
|
2986
2994
|
<div className={styles.modal__content}>
|
|
2987
2995
|
<div className={styles.formcontainer}>
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2996
|
+
{galleryData.length > 0 ? (
|
|
2997
|
+
<Gallery
|
|
2998
|
+
images={galleryData}
|
|
2999
|
+
enableImageSelection={false}
|
|
3000
|
+
/>
|
|
3001
|
+
) : (
|
|
3002
|
+
<div className={styles.noDataMessage}>
|
|
3003
|
+
No images available in the gallery
|
|
3004
|
+
</div>
|
|
3005
|
+
)}
|
|
2992
3006
|
</div>
|
|
2993
3007
|
</div>
|
|
2994
3008
|
</div>
|
|
@@ -72,6 +72,7 @@ function Field({
|
|
|
72
72
|
}) {
|
|
73
73
|
const editorRef = useRef(null);
|
|
74
74
|
const fileImageInputRef = useRef(null);
|
|
75
|
+
const [autoValue, setAutoValue] = useState('');
|
|
75
76
|
const [colorPickerShow, setColorPickerShow] = useState(false);
|
|
76
77
|
const [counter, setCounter] = useState(0);
|
|
77
78
|
const [dataOptions, setDataOptions] = useState([]);
|
|
@@ -117,6 +118,31 @@ function Field({
|
|
|
117
118
|
marginTop: '6px',
|
|
118
119
|
};
|
|
119
120
|
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
const fetchAutoValue = async () => {
|
|
123
|
+
if (settings.type === 'text' && settings.url) {
|
|
124
|
+
try {
|
|
125
|
+
const res = await CustomFetch(settings.url, 'POST', {});
|
|
126
|
+
if (res.data) {
|
|
127
|
+
setAutoValue(res.data);
|
|
128
|
+
// Simulate an onChange event to update the form data
|
|
129
|
+
const simulatedEvent = {
|
|
130
|
+
target: {
|
|
131
|
+
dataset: { name: settings.id },
|
|
132
|
+
value: res.data,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
onChange(simulatedEvent);
|
|
136
|
+
}
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error('Error fetching auto value:', error);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
fetchAutoValue();
|
|
144
|
+
}, [settings.url, settings.type, settings.id]);
|
|
145
|
+
|
|
120
146
|
useEffect(() => {
|
|
121
147
|
const fetchOptions = () => {
|
|
122
148
|
let filter = {};
|
|
@@ -1669,6 +1695,18 @@ function Field({
|
|
|
1669
1695
|
></textarea>
|
|
1670
1696
|
);
|
|
1671
1697
|
case 'text':
|
|
1698
|
+
return (
|
|
1699
|
+
<input
|
|
1700
|
+
type={settings.type}
|
|
1701
|
+
data-name={settings.id}
|
|
1702
|
+
className={inputClass[settings.id]}
|
|
1703
|
+
placeholder=" "
|
|
1704
|
+
onChange={onChange}
|
|
1705
|
+
value={inputValue || autoValue || ''}
|
|
1706
|
+
readOnly={settings.readOnly ? settings.readOnly : false}
|
|
1707
|
+
autoComplete="off"
|
|
1708
|
+
/>
|
|
1709
|
+
);
|
|
1672
1710
|
case 'password':
|
|
1673
1711
|
return (
|
|
1674
1712
|
<input
|
|
@@ -799,8 +799,43 @@ function Form({
|
|
|
799
799
|
if (closeModal) {
|
|
800
800
|
closeModal();
|
|
801
801
|
if (type === 'saveAnother') {
|
|
802
|
-
|
|
803
|
-
|
|
802
|
+
const { saveAnother } =
|
|
803
|
+
formSettings?.update || {};
|
|
804
|
+
|
|
805
|
+
if (
|
|
806
|
+
saveAnother?.url &&
|
|
807
|
+
saveAnother?.method &&
|
|
808
|
+
saveAnother?.data
|
|
809
|
+
) {
|
|
810
|
+
// Process data object to handle now() timestamps
|
|
811
|
+
const processedData = Object.entries(
|
|
812
|
+
saveAnother.data
|
|
813
|
+
).reduce((acc, [key, value]) => {
|
|
814
|
+
acc[key] =
|
|
815
|
+
value === 'now()'
|
|
816
|
+
? moment().format(
|
|
817
|
+
'YYYY-MM-DD HH:mm:ss'
|
|
818
|
+
) // Format that strtotime() can parse
|
|
819
|
+
: value;
|
|
820
|
+
return acc;
|
|
821
|
+
}, {});
|
|
822
|
+
|
|
823
|
+
const saveAnotherUrl = `${
|
|
824
|
+
saveAnother.url
|
|
825
|
+
}/${formData[saveAnother.dataKey]}`;
|
|
826
|
+
const resSaveAnother = await CustomFetch(
|
|
827
|
+
saveAnotherUrl,
|
|
828
|
+
saveAnother.method,
|
|
829
|
+
processedData
|
|
830
|
+
);
|
|
831
|
+
|
|
832
|
+
if (resSaveAnother.data.error === '') {
|
|
833
|
+
toast.success(saveAnother.message);
|
|
834
|
+
}
|
|
835
|
+
} else {
|
|
836
|
+
fetchData();
|
|
837
|
+
modalOpen('create', 0);
|
|
838
|
+
}
|
|
804
839
|
}
|
|
805
840
|
}
|
|
806
841
|
toast.success(
|
|
@@ -1493,30 +1528,48 @@ function Form({
|
|
|
1493
1528
|
formSettings.create?.hasOwnProperty(
|
|
1494
1529
|
'saveAnother'
|
|
1495
1530
|
) ? (
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1531
|
+
<div
|
|
1532
|
+
className={`${styles.formItem} ${styles.fwItem} ${styles.buttonContainer}`}
|
|
1533
|
+
>
|
|
1534
|
+
<button
|
|
1535
|
+
className={styles.btn}
|
|
1536
|
+
onClick={handleSubmit}
|
|
1537
|
+
data-type="save"
|
|
1538
|
+
>
|
|
1539
|
+
Save & Close
|
|
1540
|
+
</button>
|
|
1541
|
+
<button
|
|
1542
|
+
className={styles.btn}
|
|
1543
|
+
onClick={handleSubmit}
|
|
1544
|
+
data-type="saveAnother"
|
|
1499
1545
|
>
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1546
|
+
Save & Create Another
|
|
1547
|
+
</button>
|
|
1548
|
+
</div>
|
|
1549
|
+
) : formType === 'update' &&
|
|
1550
|
+
formSettings.update?.hasOwnProperty(
|
|
1551
|
+
'saveAnother'
|
|
1552
|
+
) ? (
|
|
1553
|
+
<div
|
|
1554
|
+
className={`${styles.formItem} ${styles.fwItem} ${styles.buttonContainer}`}
|
|
1555
|
+
>
|
|
1556
|
+
<button
|
|
1557
|
+
className={styles.btn}
|
|
1558
|
+
onClick={handleSubmit}
|
|
1559
|
+
data-type="save"
|
|
1560
|
+
>
|
|
1561
|
+
Save & Close
|
|
1562
|
+
</button>
|
|
1563
|
+
<button
|
|
1564
|
+
className={styles.btn}
|
|
1565
|
+
onClick={handleSubmit}
|
|
1566
|
+
data-type="saveAnother"
|
|
1510
1567
|
>
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
Save & Create Another
|
|
1517
|
-
</button>
|
|
1518
|
-
</div>
|
|
1519
|
-
</>
|
|
1568
|
+
{formSettings.update.saveAnother
|
|
1569
|
+
.label ||
|
|
1570
|
+
'Save & Create Another'}
|
|
1571
|
+
</button>
|
|
1572
|
+
</div>
|
|
1520
1573
|
) : (
|
|
1521
1574
|
<div
|
|
1522
1575
|
className={`${styles.formItem} ${styles.fwItem} ${styles.lastItem}`}
|
|
@@ -185,6 +185,7 @@ function GenericIndex({
|
|
|
185
185
|
const gridRef = useRef(null);
|
|
186
186
|
const params = useParams();
|
|
187
187
|
const [rowsSelected, setRowsSelected] = useState({});
|
|
188
|
+
const [tableData, setTableData] = useState([]);
|
|
188
189
|
const [tableInfo, setTableInfo] = useState({});
|
|
189
190
|
const [total, setTotal] = useState(0);
|
|
190
191
|
const windowHeight = useWindowHeight();
|
|
@@ -196,30 +197,57 @@ function GenericIndex({
|
|
|
196
197
|
setting.tableSetting
|
|
197
198
|
);
|
|
198
199
|
|
|
200
|
+
// Add a ref to store the latest rowsSelected value
|
|
201
|
+
const rowsSelectedRef = useRef({});
|
|
202
|
+
|
|
203
|
+
// Update the ref whenever rowsSelected changes
|
|
204
|
+
useEffect(() => {
|
|
205
|
+
rowsSelectedRef.current = rowsSelected;
|
|
206
|
+
}, [rowsSelected]);
|
|
207
|
+
|
|
199
208
|
const handleCheckboxUpdate = useCallback(async () => {
|
|
200
209
|
try {
|
|
201
210
|
const { data, method, message, url } = setting?.functions
|
|
202
211
|
?.checkboxUpdate
|
|
203
212
|
? setting.functions.checkboxUpdate
|
|
204
213
|
: config.form.functions.checkboxUpdate;
|
|
205
|
-
|
|
214
|
+
|
|
215
|
+
if (!Object.keys(rowsSelectedRef.current).length) {
|
|
206
216
|
toast.warning(message.warning);
|
|
207
217
|
return;
|
|
208
218
|
}
|
|
219
|
+
|
|
220
|
+
// Create a map of selected rows with full data from tableData
|
|
221
|
+
const selectedRowsData = {};
|
|
222
|
+
Object.entries(rowsSelectedRef.current).forEach(([id, value]) => {
|
|
223
|
+
if (value) {
|
|
224
|
+
// Only include if selected (value is true)
|
|
225
|
+
const fullRowData = tableData.find(
|
|
226
|
+
(row) => row.id === parseInt(id)
|
|
227
|
+
);
|
|
228
|
+
if (fullRowData) {
|
|
229
|
+
selectedRowsData[id] = fullRowData;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
209
234
|
const res = await CustomFetch(url, method, {
|
|
210
235
|
...data,
|
|
211
|
-
rows:
|
|
236
|
+
rows: selectedRowsData,
|
|
212
237
|
});
|
|
238
|
+
|
|
213
239
|
if (res.data.error === '') {
|
|
214
240
|
toast.success(message.success);
|
|
215
241
|
gridRef.current.reload();
|
|
216
|
-
} else {
|
|
217
|
-
toast.error(message.error);
|
|
218
242
|
}
|
|
219
243
|
} catch (error) {
|
|
220
244
|
console.error(error);
|
|
221
245
|
}
|
|
222
|
-
}, [
|
|
246
|
+
}, [
|
|
247
|
+
setting?.functions?.checkboxUpdate,
|
|
248
|
+
config.form?.functions?.checkboxUpdate,
|
|
249
|
+
tableData,
|
|
250
|
+
]);
|
|
223
251
|
|
|
224
252
|
const handleExport = async (e) => {
|
|
225
253
|
try {
|
|
@@ -268,6 +296,7 @@ function GenericIndex({
|
|
|
268
296
|
ref={gridRef}
|
|
269
297
|
gridHeight={windowHeight * 0.65}
|
|
270
298
|
setConfig={setConfig}
|
|
299
|
+
setTableData={setTableData}
|
|
271
300
|
setTotal={setTotal}
|
|
272
301
|
style={userProfile?.settings?.style || {}}
|
|
273
302
|
userProfile={userProfile}
|
|
@@ -124,4 +124,82 @@
|
|
|
124
124
|
height: 18px;
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
|
-
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.modalwrap {
|
|
130
|
+
background: var(--tertiary-color);
|
|
131
|
+
border-radius: 3px;
|
|
132
|
+
overflow: visible;
|
|
133
|
+
border-top-left-radius: var(--br);
|
|
134
|
+
border-top-right-radius: var(--br);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.top--modal {
|
|
138
|
+
position: relative;
|
|
139
|
+
z-index: 1000;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.modal {
|
|
143
|
+
width: 100%;
|
|
144
|
+
position: relative;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.modal__header {
|
|
148
|
+
width: 100%;
|
|
149
|
+
border-bottom: 1px solid rgba(var(--primary-rgb), 0.15);
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
justify-content: space-between;
|
|
153
|
+
padding: 0.75rem;
|
|
154
|
+
|
|
155
|
+
h1 {
|
|
156
|
+
color: var(--secondary-color);
|
|
157
|
+
margin: 0;
|
|
158
|
+
padding: 0;
|
|
159
|
+
font-size: 1.15em;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.modal__close {
|
|
164
|
+
width: max-content;
|
|
165
|
+
background: rgba(var(--paragraph-rgb), 0.05);
|
|
166
|
+
cursor: pointer;
|
|
167
|
+
padding: 0.25rem;
|
|
168
|
+
margin: 0;
|
|
169
|
+
outline: none;
|
|
170
|
+
border: none;
|
|
171
|
+
border-radius: var(--br);
|
|
172
|
+
display: block;
|
|
173
|
+
line-height: 1;
|
|
174
|
+
|
|
175
|
+
svg {
|
|
176
|
+
color: var(--primary-color);
|
|
177
|
+
display: block;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.modal__content {
|
|
182
|
+
width: 100%;
|
|
183
|
+
position: relative;
|
|
184
|
+
padding: 0.75rem;
|
|
185
|
+
max-height: 80vh;
|
|
186
|
+
overflow-y: auto;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.formcontainer {
|
|
190
|
+
width: 100%;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.noDataMessage {
|
|
194
|
+
text-align: center;
|
|
195
|
+
color: var(--secondary-color);
|
|
196
|
+
font-size: 1.125em;
|
|
197
|
+
padding: 2rem;
|
|
198
|
+
margin: 2rem auto;
|
|
199
|
+
background: var(--tertiary-color);
|
|
200
|
+
border: 1px solid rgba(var(--primary-rgb), 0.15);
|
|
201
|
+
border-radius: var(--br);
|
|
202
|
+
max-width: 80%;
|
|
203
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
204
|
+
font-style: italic;
|
|
205
|
+
}
|
|
@@ -240,7 +240,7 @@ input[type='file'] {
|
|
|
240
240
|
position: relative;
|
|
241
241
|
padding: 0.75rem;
|
|
242
242
|
max-height: 80vh;
|
|
243
|
-
|
|
243
|
+
overflow-y: auto;
|
|
244
244
|
|
|
245
245
|
.btn {
|
|
246
246
|
background: var(--primary-color);
|
|
@@ -265,6 +265,30 @@ input[type='file'] {
|
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
.btn {
|
|
269
|
+
width: max-content;
|
|
270
|
+
display: inline-block;
|
|
271
|
+
position: relative;
|
|
272
|
+
padding: 0.65rem 1rem;
|
|
273
|
+
cursor: pointer;
|
|
274
|
+
font-size: 1rem;
|
|
275
|
+
color: var(--tertiary-color);
|
|
276
|
+
text-decoration: none;
|
|
277
|
+
overflow: hidden;
|
|
278
|
+
background: var(--primary-color);
|
|
279
|
+
border: 1px solid rgba(var(--primary-color--rgb), 1.1);
|
|
280
|
+
border-radius: var(--br);
|
|
281
|
+
outline: none;
|
|
282
|
+
transition: all 0.2s cubic-bezier(0.85, 0, 0.15, 1) 0s;
|
|
283
|
+
font-size: 1.25em;
|
|
284
|
+
|
|
285
|
+
&:hover {
|
|
286
|
+
color: var(--primary-color);
|
|
287
|
+
background: var(--highlight-color);
|
|
288
|
+
border: 1px solid rgba(var(--highlight-rgb), 1.05);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
268
292
|
.saveBtn {
|
|
269
293
|
width: max-content;
|
|
270
294
|
display: inline-block;
|
|
@@ -302,3 +326,14 @@ input[type='file'] {
|
|
|
302
326
|
padding: 0.35em 1em;
|
|
303
327
|
margin: 0 0.15em;
|
|
304
328
|
}
|
|
329
|
+
|
|
330
|
+
.buttonContainer {
|
|
331
|
+
display: flex;
|
|
332
|
+
justify-content: center;
|
|
333
|
+
gap: 1rem;
|
|
334
|
+
|
|
335
|
+
button {
|
|
336
|
+
flex: 0 1 auto;
|
|
337
|
+
min-width: 200px;
|
|
338
|
+
}
|
|
339
|
+
}
|