@visns-studio/visns-components 5.15.29 → 5.15.31
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.
|
@@ -6,6 +6,7 @@ import StandardModal from './StandardModal';
|
|
|
6
6
|
import { arrayMove } from '@dnd-kit/sortable';
|
|
7
7
|
import {
|
|
8
8
|
DndContext,
|
|
9
|
+
DragOverlay,
|
|
9
10
|
closestCenter,
|
|
10
11
|
KeyboardSensor,
|
|
11
12
|
PointerSensor,
|
|
@@ -33,6 +34,10 @@ import {
|
|
|
33
34
|
Trash2 as TrashCan,
|
|
34
35
|
Edit as Pencil,
|
|
35
36
|
GripVertical as ChevronVertical,
|
|
37
|
+
ArrowUpDown,
|
|
38
|
+
Search,
|
|
39
|
+
ChevronDown,
|
|
40
|
+
ChevronRight,
|
|
36
41
|
} from 'lucide-react';
|
|
37
42
|
import { confirmDialog } from '../utils/ConfirmDialog';
|
|
38
43
|
|
|
@@ -107,6 +112,16 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
107
112
|
const [modalFormShow, setModalFormShow] = useState(false);
|
|
108
113
|
const [roles, setRoles] = useState([]);
|
|
109
114
|
const [hoveredField, setHoveredField] = useState(null);
|
|
115
|
+
const [activeId, setActiveId] = useState(null);
|
|
116
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
117
|
+
const [moveToDialog, setMoveToDialog] = useState({
|
|
118
|
+
show: false,
|
|
119
|
+
fieldId: null,
|
|
120
|
+
currentPos: 0,
|
|
121
|
+
});
|
|
122
|
+
const [moveToPosition, setMoveToPosition] = useState('');
|
|
123
|
+
const [collapsedSections, setCollapsedSections] = useState(new Set());
|
|
124
|
+
const sortTriggeredRef = useRef(false);
|
|
110
125
|
|
|
111
126
|
const canvasTypes = SketchConfig.canvasTypes;
|
|
112
127
|
|
|
@@ -203,6 +218,57 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
203
218
|
return tooltip.trim();
|
|
204
219
|
};
|
|
205
220
|
|
|
221
|
+
// Get field IDs that should be collapsed (under collapsed sections)
|
|
222
|
+
const getCollapsedFieldIds = () => {
|
|
223
|
+
if (!data.detail || collapsedSections.size === 0) return new Set();
|
|
224
|
+
const collapsed = new Set();
|
|
225
|
+
let currentlyCollapsed = false;
|
|
226
|
+
for (const field of data.detail) {
|
|
227
|
+
if (field.type === 'section') {
|
|
228
|
+
currentlyCollapsed = collapsedSections.has(field.id);
|
|
229
|
+
} else if (currentlyCollapsed) {
|
|
230
|
+
collapsed.add(field.id);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return collapsed;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const toggleSectionCollapse = (sectionId) => {
|
|
237
|
+
setCollapsedSections((prev) => {
|
|
238
|
+
const newSet = new Set(prev);
|
|
239
|
+
if (newSet.has(sectionId)) {
|
|
240
|
+
newSet.delete(sectionId);
|
|
241
|
+
} else {
|
|
242
|
+
newSet.add(sectionId);
|
|
243
|
+
}
|
|
244
|
+
return newSet;
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const handleMoveTo = (fieldId, targetPosition) => {
|
|
249
|
+
const currentIndex = data.detail.findIndex(
|
|
250
|
+
(item) => item.id === fieldId
|
|
251
|
+
);
|
|
252
|
+
const targetIndex = targetPosition - 1;
|
|
253
|
+
if (
|
|
254
|
+
currentIndex !== -1 &&
|
|
255
|
+
targetIndex >= 0 &&
|
|
256
|
+
targetIndex < data.detail.length &&
|
|
257
|
+
currentIndex !== targetIndex
|
|
258
|
+
) {
|
|
259
|
+
sortTriggeredRef.current = true;
|
|
260
|
+
const newData = arrayMove(data.detail, currentIndex, targetIndex);
|
|
261
|
+
setData((items) => ({
|
|
262
|
+
...items,
|
|
263
|
+
detail: newData,
|
|
264
|
+
}));
|
|
265
|
+
}
|
|
266
|
+
setMoveToDialog({ show: false, fieldId: null, currentPos: 0 });
|
|
267
|
+
setMoveToPosition('');
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const collapsedFieldIds = getCollapsedFieldIds();
|
|
271
|
+
|
|
206
272
|
// Create sortable field item using @dnd-kit
|
|
207
273
|
const SortableFieldItem = ({ field, index: counter }) => {
|
|
208
274
|
const {
|
|
@@ -224,38 +290,73 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
224
290
|
const style = {
|
|
225
291
|
transform: CSS.Transform.toString(transform),
|
|
226
292
|
transition: isDragging ? 'none' : transition,
|
|
227
|
-
opacity: isDragging ? 0.5 : 1,
|
|
228
293
|
minHeight: '64.2px',
|
|
229
294
|
position: 'relative',
|
|
230
295
|
zIndex: isDragging ? 1000 : 'auto',
|
|
231
|
-
// Prevent stretching during drag by setting responsive dimensions
|
|
232
|
-
...(isDragging && {
|
|
233
|
-
width:
|
|
234
|
-
field.size === 'full'
|
|
235
|
-
? 'min(600px, 90vw)'
|
|
236
|
-
: 'min(300px, 45vw)',
|
|
237
|
-
maxWidth: field.size === 'full' ? '800px' : '400px',
|
|
238
|
-
flexShrink: 0,
|
|
239
|
-
flexGrow: 0,
|
|
240
|
-
display: 'block',
|
|
241
|
-
}),
|
|
242
296
|
};
|
|
243
297
|
|
|
244
298
|
const fieldClassName = renderClassName(field);
|
|
245
299
|
|
|
300
|
+
// Search dimming
|
|
301
|
+
const isDimmed =
|
|
302
|
+
searchQuery &&
|
|
303
|
+
!(
|
|
304
|
+
field.label
|
|
305
|
+
?.toLowerCase()
|
|
306
|
+
.includes(searchQuery.toLowerCase()) ||
|
|
307
|
+
field.type
|
|
308
|
+
?.toLowerCase()
|
|
309
|
+
.includes(searchQuery.toLowerCase()) ||
|
|
310
|
+
field.id
|
|
311
|
+
?.toLowerCase()
|
|
312
|
+
.includes(searchQuery.toLowerCase())
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
// Collapse logic
|
|
316
|
+
const isCollapsed = collapsedFieldIds.has(field.id);
|
|
317
|
+
const isSection = field.type === 'section';
|
|
318
|
+
const isSectionCollapsed =
|
|
319
|
+
isSection && collapsedSections.has(field.id);
|
|
320
|
+
|
|
321
|
+
// When dragging, show a dashed placeholder
|
|
322
|
+
if (isDragging) {
|
|
323
|
+
return (
|
|
324
|
+
<div
|
|
325
|
+
ref={setNodeRef}
|
|
326
|
+
style={style}
|
|
327
|
+
className={`${fieldClassName} ${styles.dragPlaceholder}`}
|
|
328
|
+
data-field-size={field.size}
|
|
329
|
+
/>
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
246
333
|
return (
|
|
247
334
|
<div
|
|
248
335
|
ref={setNodeRef}
|
|
249
|
-
style={
|
|
336
|
+
style={{
|
|
337
|
+
...style,
|
|
338
|
+
opacity: isDimmed ? 0.25 : 1,
|
|
339
|
+
}}
|
|
250
340
|
className={`${fieldClassName} ${styles.interactiveField} ${
|
|
251
341
|
styles.previewField
|
|
252
|
-
} ${
|
|
253
|
-
data-tooltip-id={
|
|
254
|
-
|
|
342
|
+
} ${isCollapsed ? styles.collapsedField : ''}`}
|
|
343
|
+
data-tooltip-id={
|
|
344
|
+
hoveredField === field.id ? null : 'field-tooltip'
|
|
345
|
+
}
|
|
346
|
+
data-tooltip-content={
|
|
347
|
+
hoveredField === field.id
|
|
348
|
+
? null
|
|
349
|
+
: getFieldTooltip(field)
|
|
350
|
+
}
|
|
255
351
|
data-tooltip-place="top"
|
|
256
352
|
data-tooltip-delay-show={200}
|
|
257
353
|
data-field-size={field.size}
|
|
258
354
|
>
|
|
355
|
+
{/* Field index badge */}
|
|
356
|
+
<span className={styles.fieldIndex}>
|
|
357
|
+
#{counter + 1}
|
|
358
|
+
</span>
|
|
359
|
+
|
|
259
360
|
{/* Field info - always visible */}
|
|
260
361
|
<div className={styles.fieldInfo}>
|
|
261
362
|
<span className={styles.fieldInfoText}>
|
|
@@ -263,8 +364,12 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
263
364
|
</span>
|
|
264
365
|
</div>
|
|
265
366
|
|
|
266
|
-
{/* Field controls -
|
|
267
|
-
<div
|
|
367
|
+
{/* Field controls - drag handle always visible */}
|
|
368
|
+
<div
|
|
369
|
+
className={styles.fieldControls}
|
|
370
|
+
onMouseEnter={() => setHoveredField(field.id)}
|
|
371
|
+
onMouseLeave={() => setHoveredField(null)}
|
|
372
|
+
>
|
|
268
373
|
<div
|
|
269
374
|
{...attributes}
|
|
270
375
|
{...listeners}
|
|
@@ -272,12 +377,59 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
272
377
|
data-tooltip-id="action-tooltip"
|
|
273
378
|
data-tooltip-content="Drag to Reorder"
|
|
274
379
|
data-tooltip-place="top"
|
|
275
|
-
onMouseEnter={() => setHoveredField(field.id)}
|
|
276
|
-
onMouseLeave={() => setHoveredField(null)}
|
|
277
380
|
>
|
|
278
381
|
<ChevronVertical strokeWidth={3} size={24} />
|
|
279
382
|
</div>
|
|
280
383
|
<div className={styles.fieldActions}>
|
|
384
|
+
{isSection && (
|
|
385
|
+
<button
|
|
386
|
+
className={styles.collapseToggle}
|
|
387
|
+
onClick={(e) => {
|
|
388
|
+
e.preventDefault();
|
|
389
|
+
e.stopPropagation();
|
|
390
|
+
toggleSectionCollapse(field.id);
|
|
391
|
+
}}
|
|
392
|
+
data-tooltip-id="action-tooltip"
|
|
393
|
+
data-tooltip-content={
|
|
394
|
+
isSectionCollapsed
|
|
395
|
+
? 'Expand Section'
|
|
396
|
+
: 'Collapse Section'
|
|
397
|
+
}
|
|
398
|
+
data-tooltip-place="top"
|
|
399
|
+
>
|
|
400
|
+
{isSectionCollapsed ? (
|
|
401
|
+
<ChevronRight
|
|
402
|
+
strokeWidth={3}
|
|
403
|
+
size={20}
|
|
404
|
+
/>
|
|
405
|
+
) : (
|
|
406
|
+
<ChevronDown
|
|
407
|
+
strokeWidth={3}
|
|
408
|
+
size={20}
|
|
409
|
+
/>
|
|
410
|
+
)}
|
|
411
|
+
</button>
|
|
412
|
+
)}
|
|
413
|
+
<ArrowUpDown
|
|
414
|
+
className={styles.moveIcon}
|
|
415
|
+
strokeWidth={3}
|
|
416
|
+
size={20}
|
|
417
|
+
onClick={(e) => {
|
|
418
|
+
e.preventDefault();
|
|
419
|
+
e.stopPropagation();
|
|
420
|
+
setMoveToDialog({
|
|
421
|
+
show: true,
|
|
422
|
+
fieldId: field.id,
|
|
423
|
+
currentPos: counter + 1,
|
|
424
|
+
});
|
|
425
|
+
setMoveToPosition(
|
|
426
|
+
String(counter + 1)
|
|
427
|
+
);
|
|
428
|
+
}}
|
|
429
|
+
data-tooltip-id="action-tooltip"
|
|
430
|
+
data-tooltip-content="Move to Position"
|
|
431
|
+
data-tooltip-place="top"
|
|
432
|
+
/>
|
|
281
433
|
<Pencil
|
|
282
434
|
className={styles.editIcon}
|
|
283
435
|
strokeWidth={3}
|
|
@@ -290,8 +442,6 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
290
442
|
data-tooltip-id="action-tooltip"
|
|
291
443
|
data-tooltip-content="Edit Field"
|
|
292
444
|
data-tooltip-place="top"
|
|
293
|
-
onMouseEnter={() => setHoveredField(field.id)}
|
|
294
|
-
onMouseLeave={() => setHoveredField(null)}
|
|
295
445
|
/>
|
|
296
446
|
<TrashCan
|
|
297
447
|
className={styles.deleteIcon}
|
|
@@ -300,17 +450,20 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
300
450
|
onClick={(e) => {
|
|
301
451
|
e.preventDefault();
|
|
302
452
|
e.stopPropagation();
|
|
303
|
-
handleDeleteField(
|
|
453
|
+
handleDeleteField(
|
|
454
|
+
field.id,
|
|
455
|
+
field.label
|
|
456
|
+
);
|
|
304
457
|
}}
|
|
305
458
|
data-tooltip-id="action-tooltip"
|
|
306
459
|
data-tooltip-content="Delete Field"
|
|
307
460
|
data-tooltip-place="top"
|
|
308
|
-
onMouseEnter={() => setHoveredField(field.id)}
|
|
309
|
-
onMouseLeave={() => setHoveredField(null)}
|
|
310
461
|
/>
|
|
311
462
|
</div>
|
|
312
463
|
</div>
|
|
313
|
-
<div className={styles.fieldContent}>
|
|
464
|
+
<div className={styles.fieldContent}>
|
|
465
|
+
{renderField(field)}
|
|
466
|
+
</div>
|
|
314
467
|
</div>
|
|
315
468
|
);
|
|
316
469
|
};
|
|
@@ -462,7 +615,16 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
462
615
|
return closestCenter(args);
|
|
463
616
|
};
|
|
464
617
|
|
|
618
|
+
const handleDragStart = (event) => {
|
|
619
|
+
setActiveId(event.active.id);
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
const handleDragCancel = () => {
|
|
623
|
+
setActiveId(null);
|
|
624
|
+
};
|
|
625
|
+
|
|
465
626
|
const handleDragEnd = (event) => {
|
|
627
|
+
setActiveId(null);
|
|
466
628
|
const { active, over } = event;
|
|
467
629
|
|
|
468
630
|
if (active.id !== over?.id && over) {
|
|
@@ -474,6 +636,7 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
474
636
|
);
|
|
475
637
|
|
|
476
638
|
if (oldIndex !== -1 && newIndex !== -1) {
|
|
639
|
+
sortTriggeredRef.current = true;
|
|
477
640
|
const newData = arrayMove(data.detail, oldIndex, newIndex);
|
|
478
641
|
|
|
479
642
|
setData((items) => ({
|
|
@@ -1125,7 +1288,12 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
1125
1288
|
};
|
|
1126
1289
|
|
|
1127
1290
|
useEffect(() => {
|
|
1128
|
-
if (
|
|
1291
|
+
if (
|
|
1292
|
+
data.detail &&
|
|
1293
|
+
data.detail.length > 0 &&
|
|
1294
|
+
sortTriggeredRef.current
|
|
1295
|
+
) {
|
|
1296
|
+
sortTriggeredRef.current = false;
|
|
1129
1297
|
saveOnSort();
|
|
1130
1298
|
}
|
|
1131
1299
|
}, [data.detail]);
|
|
@@ -1162,6 +1330,56 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
1162
1330
|
: 'Form Template Preview'}
|
|
1163
1331
|
</span>
|
|
1164
1332
|
</div>
|
|
1333
|
+
{data.detail && data.detail.length > 5 && (
|
|
1334
|
+
<div className={styles.searchBar}>
|
|
1335
|
+
<Search
|
|
1336
|
+
size={16}
|
|
1337
|
+
className={styles.searchIcon}
|
|
1338
|
+
/>
|
|
1339
|
+
<input
|
|
1340
|
+
type="text"
|
|
1341
|
+
placeholder="Search fields by label, type, or ID..."
|
|
1342
|
+
value={searchQuery}
|
|
1343
|
+
onChange={(e) =>
|
|
1344
|
+
setSearchQuery(e.target.value)
|
|
1345
|
+
}
|
|
1346
|
+
className={styles.searchInput}
|
|
1347
|
+
/>
|
|
1348
|
+
{searchQuery && (
|
|
1349
|
+
<span className={styles.searchCount}>
|
|
1350
|
+
{
|
|
1351
|
+
data.detail.filter(
|
|
1352
|
+
(f) =>
|
|
1353
|
+
f.label
|
|
1354
|
+
?.toLowerCase()
|
|
1355
|
+
.includes(
|
|
1356
|
+
searchQuery.toLowerCase()
|
|
1357
|
+
) ||
|
|
1358
|
+
f.type
|
|
1359
|
+
?.toLowerCase()
|
|
1360
|
+
.includes(
|
|
1361
|
+
searchQuery.toLowerCase()
|
|
1362
|
+
) ||
|
|
1363
|
+
f.id
|
|
1364
|
+
?.toLowerCase()
|
|
1365
|
+
.includes(
|
|
1366
|
+
searchQuery.toLowerCase()
|
|
1367
|
+
)
|
|
1368
|
+
).length
|
|
1369
|
+
}{' '}
|
|
1370
|
+
of {data.detail.length}
|
|
1371
|
+
</span>
|
|
1372
|
+
)}
|
|
1373
|
+
{searchQuery && (
|
|
1374
|
+
<button
|
|
1375
|
+
className={styles.searchClear}
|
|
1376
|
+
onClick={() => setSearchQuery('')}
|
|
1377
|
+
>
|
|
1378
|
+
<CircleX size={16} />
|
|
1379
|
+
</button>
|
|
1380
|
+
)}
|
|
1381
|
+
</div>
|
|
1382
|
+
)}
|
|
1165
1383
|
{data.detail && data.detail.length > 0 ? (
|
|
1166
1384
|
<div className={styles.modal__content}>
|
|
1167
1385
|
<div className={styles.formcontainer}>
|
|
@@ -1170,7 +1388,15 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
1170
1388
|
collisionDetection={
|
|
1171
1389
|
customCollisionDetection
|
|
1172
1390
|
}
|
|
1391
|
+
onDragStart={handleDragStart}
|
|
1173
1392
|
onDragEnd={handleDragEnd}
|
|
1393
|
+
onDragCancel={handleDragCancel}
|
|
1394
|
+
autoScroll={{
|
|
1395
|
+
threshold: {
|
|
1396
|
+
x: 0.2,
|
|
1397
|
+
y: 0.15,
|
|
1398
|
+
},
|
|
1399
|
+
}}
|
|
1174
1400
|
>
|
|
1175
1401
|
<SortableContext
|
|
1176
1402
|
items={data.detail.map(
|
|
@@ -1192,6 +1418,39 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
1192
1418
|
)}
|
|
1193
1419
|
</div>
|
|
1194
1420
|
</SortableContext>
|
|
1421
|
+
<DragOverlay>
|
|
1422
|
+
{activeId
|
|
1423
|
+
? (() => {
|
|
1424
|
+
const activeField =
|
|
1425
|
+
data.detail.find(
|
|
1426
|
+
(f) =>
|
|
1427
|
+
f.id ===
|
|
1428
|
+
activeId
|
|
1429
|
+
);
|
|
1430
|
+
if (!activeField)
|
|
1431
|
+
return null;
|
|
1432
|
+
const overlayClassName =
|
|
1433
|
+
renderClassName(
|
|
1434
|
+
activeField
|
|
1435
|
+
);
|
|
1436
|
+
return (
|
|
1437
|
+
<div
|
|
1438
|
+
className={`${overlayClassName} ${styles.dragOverlayItem}`}
|
|
1439
|
+
>
|
|
1440
|
+
<div
|
|
1441
|
+
className={
|
|
1442
|
+
styles.fieldContent
|
|
1443
|
+
}
|
|
1444
|
+
>
|
|
1445
|
+
{renderField(
|
|
1446
|
+
activeField
|
|
1447
|
+
)}
|
|
1448
|
+
</div>
|
|
1449
|
+
</div>
|
|
1450
|
+
);
|
|
1451
|
+
})()
|
|
1452
|
+
: null}
|
|
1453
|
+
</DragOverlay>
|
|
1195
1454
|
</DndContext>
|
|
1196
1455
|
</div>
|
|
1197
1456
|
</div>
|
|
@@ -1545,146 +1804,169 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
1545
1804
|
dataField.type
|
|
1546
1805
|
) ? (
|
|
1547
1806
|
<div className={styles.formItemFull}>
|
|
1548
|
-
<
|
|
1549
|
-
className={
|
|
1807
|
+
<div
|
|
1808
|
+
className={
|
|
1809
|
+
styles.optionsHeader
|
|
1810
|
+
}
|
|
1550
1811
|
>
|
|
1551
|
-
<
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
option.label
|
|
1586
|
-
}
|
|
1587
|
-
onChange={(
|
|
1588
|
-
e
|
|
1589
|
-
) => {
|
|
1590
|
-
const newOptions =
|
|
1591
|
-
[
|
|
1592
|
-
...dataField.options,
|
|
1593
|
-
];
|
|
1594
|
-
newOptions[
|
|
1595
|
-
optionKey
|
|
1596
|
-
].label =
|
|
1597
|
-
e.target.value;
|
|
1598
|
-
newOptions[
|
|
1599
|
-
optionKey
|
|
1600
|
-
].id =
|
|
1601
|
-
`${slugify(e.target.value)}-`;
|
|
1602
|
-
setDataField(
|
|
1603
|
-
(
|
|
1604
|
-
items
|
|
1605
|
-
) => ({
|
|
1606
|
-
...items,
|
|
1607
|
-
options:
|
|
1608
|
-
newOptions,
|
|
1609
|
-
})
|
|
1610
|
-
);
|
|
1611
|
-
}}
|
|
1612
|
-
/>
|
|
1613
|
-
</td>
|
|
1614
|
-
<td>
|
|
1615
|
-
<button
|
|
1616
|
-
className={`${styles.tableActionBtn} ${styles.delete}`}
|
|
1617
|
-
onClick={
|
|
1618
|
-
handleDeleteOption
|
|
1619
|
-
}
|
|
1620
|
-
data-counter={
|
|
1621
|
-
optionKey
|
|
1622
|
-
}
|
|
1623
|
-
data-tooltip-id="system-tooltip"
|
|
1624
|
-
data-tooltip-content={
|
|
1625
|
-
'Delete Option'
|
|
1626
|
-
}
|
|
1627
|
-
>
|
|
1628
|
-
<TrashCan
|
|
1629
|
-
strokeWidth={
|
|
1630
|
-
2
|
|
1631
|
-
}
|
|
1632
|
-
size={
|
|
1633
|
-
14
|
|
1634
|
-
}
|
|
1635
|
-
/>
|
|
1636
|
-
</button>
|
|
1637
|
-
</td>
|
|
1638
|
-
</tr>
|
|
1639
|
-
)
|
|
1640
|
-
)
|
|
1641
|
-
) : (
|
|
1642
|
-
<tr>
|
|
1643
|
-
<td colSpan="2">
|
|
1644
|
-
No entry have
|
|
1645
|
-
been added.
|
|
1646
|
-
</td>
|
|
1647
|
-
</tr>
|
|
1648
|
-
)}
|
|
1649
|
-
</tbody>
|
|
1650
|
-
<tfoot>
|
|
1651
|
-
<tr>
|
|
1652
|
-
<td>
|
|
1653
|
-
<input
|
|
1654
|
-
type="text"
|
|
1655
|
-
name="label"
|
|
1656
|
-
onChange={
|
|
1657
|
-
handleDataOption
|
|
1658
|
-
}
|
|
1659
|
-
value={
|
|
1660
|
-
dataOption.label
|
|
1661
|
-
}
|
|
1662
|
-
placeholder="Enter label..."
|
|
1663
|
-
/>
|
|
1664
|
-
</td>
|
|
1665
|
-
<td>
|
|
1666
|
-
<button
|
|
1667
|
-
className={`${styles.tableActionBtn} ${styles.add}`}
|
|
1668
|
-
onClick={
|
|
1669
|
-
handleAddOption
|
|
1670
|
-
}
|
|
1671
|
-
data-tooltip-id="system-tooltip"
|
|
1672
|
-
data-tooltip-content={
|
|
1673
|
-
'Add Option'
|
|
1812
|
+
<span>
|
|
1813
|
+
Options
|
|
1814
|
+
</span>
|
|
1815
|
+
{dataField.options
|
|
1816
|
+
.length > 0 && (
|
|
1817
|
+
<span
|
|
1818
|
+
className={
|
|
1819
|
+
styles.optionsBadge
|
|
1820
|
+
}
|
|
1821
|
+
>
|
|
1822
|
+
{
|
|
1823
|
+
dataField
|
|
1824
|
+
.options
|
|
1825
|
+
.length
|
|
1826
|
+
}
|
|
1827
|
+
</span>
|
|
1828
|
+
)}
|
|
1829
|
+
</div>
|
|
1830
|
+
{dataField.options.length >
|
|
1831
|
+
0 ? (
|
|
1832
|
+
<div
|
|
1833
|
+
className={
|
|
1834
|
+
styles.optionsList
|
|
1835
|
+
}
|
|
1836
|
+
>
|
|
1837
|
+
{dataField.options.map(
|
|
1838
|
+
(
|
|
1839
|
+
option,
|
|
1840
|
+
optionKey
|
|
1841
|
+
) => (
|
|
1842
|
+
<div
|
|
1843
|
+
key={`option-${optionKey}`}
|
|
1844
|
+
className={
|
|
1845
|
+
styles.optionItem
|
|
1674
1846
|
}
|
|
1675
1847
|
>
|
|
1676
|
-
<
|
|
1677
|
-
|
|
1678
|
-
|
|
1848
|
+
<span
|
|
1849
|
+
className={
|
|
1850
|
+
styles.optionNumber
|
|
1851
|
+
}
|
|
1852
|
+
>
|
|
1853
|
+
{optionKey +
|
|
1854
|
+
1}
|
|
1855
|
+
</span>
|
|
1856
|
+
<input
|
|
1857
|
+
type="text"
|
|
1858
|
+
value={
|
|
1859
|
+
option.label
|
|
1860
|
+
}
|
|
1861
|
+
className={
|
|
1862
|
+
styles.optionInput
|
|
1679
1863
|
}
|
|
1680
|
-
|
|
1864
|
+
onChange={(
|
|
1865
|
+
e
|
|
1866
|
+
) => {
|
|
1867
|
+
const newOptions =
|
|
1868
|
+
[
|
|
1869
|
+
...dataField.options,
|
|
1870
|
+
];
|
|
1871
|
+
newOptions[
|
|
1872
|
+
optionKey
|
|
1873
|
+
].label =
|
|
1874
|
+
e.target.value;
|
|
1875
|
+
newOptions[
|
|
1876
|
+
optionKey
|
|
1877
|
+
].id =
|
|
1878
|
+
`${slugify(e.target.value)}-`;
|
|
1879
|
+
setDataField(
|
|
1880
|
+
(
|
|
1881
|
+
items
|
|
1882
|
+
) => ({
|
|
1883
|
+
...items,
|
|
1884
|
+
options:
|
|
1885
|
+
newOptions,
|
|
1886
|
+
})
|
|
1887
|
+
);
|
|
1888
|
+
}}
|
|
1681
1889
|
/>
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1890
|
+
<button
|
|
1891
|
+
className={
|
|
1892
|
+
styles.optionDelete
|
|
1893
|
+
}
|
|
1894
|
+
onClick={
|
|
1895
|
+
handleDeleteOption
|
|
1896
|
+
}
|
|
1897
|
+
data-counter={
|
|
1898
|
+
optionKey
|
|
1899
|
+
}
|
|
1900
|
+
data-tooltip-id="system-tooltip"
|
|
1901
|
+
data-tooltip-content="Delete Option"
|
|
1902
|
+
>
|
|
1903
|
+
<TrashCan
|
|
1904
|
+
strokeWidth={
|
|
1905
|
+
2
|
|
1906
|
+
}
|
|
1907
|
+
size={
|
|
1908
|
+
14
|
|
1909
|
+
}
|
|
1910
|
+
/>
|
|
1911
|
+
</button>
|
|
1912
|
+
</div>
|
|
1913
|
+
)
|
|
1914
|
+
)}
|
|
1915
|
+
</div>
|
|
1916
|
+
) : (
|
|
1917
|
+
<div
|
|
1918
|
+
className={
|
|
1919
|
+
styles.optionsEmpty
|
|
1920
|
+
}
|
|
1921
|
+
>
|
|
1922
|
+
No options added yet
|
|
1923
|
+
</div>
|
|
1924
|
+
)}
|
|
1925
|
+
<div
|
|
1926
|
+
className={
|
|
1927
|
+
styles.optionAddRow
|
|
1928
|
+
}
|
|
1929
|
+
>
|
|
1930
|
+
<input
|
|
1931
|
+
type="text"
|
|
1932
|
+
name="label"
|
|
1933
|
+
onChange={
|
|
1934
|
+
handleDataOption
|
|
1935
|
+
}
|
|
1936
|
+
value={
|
|
1937
|
+
dataOption.label
|
|
1938
|
+
}
|
|
1939
|
+
placeholder="Type new option and press Add..."
|
|
1940
|
+
className={
|
|
1941
|
+
styles.optionAddInput
|
|
1942
|
+
}
|
|
1943
|
+
onKeyDown={(e) => {
|
|
1944
|
+
if (
|
|
1945
|
+
e.key ===
|
|
1946
|
+
'Enter'
|
|
1947
|
+
) {
|
|
1948
|
+
e.preventDefault();
|
|
1949
|
+
handleAddOption(
|
|
1950
|
+
e
|
|
1951
|
+
);
|
|
1952
|
+
}
|
|
1953
|
+
}}
|
|
1954
|
+
/>
|
|
1955
|
+
<button
|
|
1956
|
+
className={`${styles.tableActionBtn} ${styles.add}`}
|
|
1957
|
+
onClick={
|
|
1958
|
+
handleAddOption
|
|
1959
|
+
}
|
|
1960
|
+
data-tooltip-id="system-tooltip"
|
|
1961
|
+
data-tooltip-content="Add Option"
|
|
1962
|
+
>
|
|
1963
|
+
<CirclePlus
|
|
1964
|
+
strokeWidth={2}
|
|
1965
|
+
size={14}
|
|
1966
|
+
/>
|
|
1967
|
+
Add
|
|
1968
|
+
</button>
|
|
1969
|
+
</div>
|
|
1688
1970
|
</div>
|
|
1689
1971
|
) : null}
|
|
1690
1972
|
|
|
@@ -1692,297 +1974,103 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
1692
1974
|
dataField.type
|
|
1693
1975
|
) ? (
|
|
1694
1976
|
<div className={styles.formItemFull}>
|
|
1695
|
-
<
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
>
|
|
1707
|
-
|
|
1708
|
-
</th>
|
|
1709
|
-
</tr>
|
|
1710
|
-
</thead>
|
|
1711
|
-
<tbody>
|
|
1712
|
-
{dataField.options.length >
|
|
1713
|
-
0 ? (
|
|
1714
|
-
dataField.options.map(
|
|
1715
|
-
(
|
|
1716
|
-
option,
|
|
1717
|
-
optionKey
|
|
1718
|
-
) => (
|
|
1719
|
-
<tr
|
|
1720
|
-
key={`option-${optionKey}`}
|
|
1721
|
-
>
|
|
1722
|
-
<td>
|
|
1723
|
-
<input
|
|
1724
|
-
type="text"
|
|
1725
|
-
value={
|
|
1726
|
-
option.label
|
|
1727
|
-
}
|
|
1728
|
-
onChange={(
|
|
1729
|
-
e
|
|
1730
|
-
) => {
|
|
1731
|
-
const newOptions =
|
|
1732
|
-
[
|
|
1733
|
-
...dataField.options,
|
|
1734
|
-
];
|
|
1735
|
-
newOptions[
|
|
1736
|
-
optionKey
|
|
1737
|
-
].label =
|
|
1738
|
-
e.target.value;
|
|
1739
|
-
newOptions[
|
|
1740
|
-
optionKey
|
|
1741
|
-
].id =
|
|
1742
|
-
`${slugify(e.target.value)}-`;
|
|
1743
|
-
setDataField(
|
|
1744
|
-
(
|
|
1745
|
-
items
|
|
1746
|
-
) => ({
|
|
1747
|
-
...items,
|
|
1748
|
-
options:
|
|
1749
|
-
newOptions,
|
|
1750
|
-
})
|
|
1751
|
-
);
|
|
1752
|
-
}}
|
|
1753
|
-
/>
|
|
1754
|
-
</td>
|
|
1755
|
-
<td>
|
|
1756
|
-
<select
|
|
1757
|
-
value={
|
|
1758
|
-
option.type
|
|
1759
|
-
}
|
|
1760
|
-
onChange={(
|
|
1761
|
-
e
|
|
1762
|
-
) => {
|
|
1763
|
-
const newOptions =
|
|
1764
|
-
[
|
|
1765
|
-
...dataField.options,
|
|
1766
|
-
];
|
|
1767
|
-
newOptions[
|
|
1768
|
-
optionKey
|
|
1769
|
-
].type =
|
|
1770
|
-
e.target.value;
|
|
1771
|
-
setDataField(
|
|
1772
|
-
(
|
|
1773
|
-
items
|
|
1774
|
-
) => ({
|
|
1775
|
-
...items,
|
|
1776
|
-
options:
|
|
1777
|
-
newOptions,
|
|
1778
|
-
})
|
|
1779
|
-
);
|
|
1780
|
-
}}
|
|
1781
|
-
>
|
|
1782
|
-
<option value="">
|
|
1783
|
-
No
|
|
1784
|
-
Type
|
|
1785
|
-
Selected
|
|
1786
|
-
</option>
|
|
1787
|
-
{fieldTypes
|
|
1788
|
-
.filter(
|
|
1789
|
-
(
|
|
1790
|
-
item
|
|
1791
|
-
) => {
|
|
1792
|
-
const excludedKeywords =
|
|
1793
|
-
[
|
|
1794
|
-
'dropdown',
|
|
1795
|
-
'dynamicdata',
|
|
1796
|
-
'file',
|
|
1797
|
-
'image',
|
|
1798
|
-
'plaintext',
|
|
1799
|
-
'plaintextheading',
|
|
1800
|
-
'section',
|
|
1801
|
-
'signature',
|
|
1802
|
-
'table',
|
|
1803
|
-
];
|
|
1804
|
-
// Exclude 'checkbox' only if dataField.type is 'table_text'
|
|
1805
|
-
if (
|
|
1806
|
-
dataField.type ===
|
|
1807
|
-
'table_text'
|
|
1808
|
-
) {
|
|
1809
|
-
// excludedKeywords.push(
|
|
1810
|
-
// 'checkbox'
|
|
1811
|
-
// );
|
|
1812
|
-
}
|
|
1813
|
-
return !excludedKeywords.some(
|
|
1814
|
-
(
|
|
1815
|
-
keyword
|
|
1816
|
-
) =>
|
|
1817
|
-
item.value.includes(
|
|
1818
|
-
keyword
|
|
1819
|
-
)
|
|
1820
|
-
);
|
|
1821
|
-
}
|
|
1822
|
-
)
|
|
1823
|
-
.map(
|
|
1824
|
-
(
|
|
1825
|
-
item,
|
|
1826
|
-
itemKey
|
|
1827
|
-
) => (
|
|
1828
|
-
<option
|
|
1829
|
-
value={
|
|
1830
|
-
item.value
|
|
1831
|
-
}
|
|
1832
|
-
key={`type-form-${item.value}-${itemKey}`}
|
|
1833
|
-
>
|
|
1834
|
-
{
|
|
1835
|
-
item.label
|
|
1836
|
-
}
|
|
1837
|
-
</option>
|
|
1838
|
-
)
|
|
1839
|
-
)}
|
|
1840
|
-
</select>
|
|
1841
|
-
</td>
|
|
1842
|
-
<td>
|
|
1843
|
-
<button
|
|
1844
|
-
className={`${styles.tableActionBtn} ${styles.delete}`}
|
|
1845
|
-
onClick={
|
|
1846
|
-
handleDeleteOption
|
|
1847
|
-
}
|
|
1848
|
-
data-counter={
|
|
1849
|
-
optionKey
|
|
1850
|
-
}
|
|
1851
|
-
data-tooltip-id="system-tooltip"
|
|
1852
|
-
data-tooltip-content={
|
|
1853
|
-
'Delete Option'
|
|
1854
|
-
}
|
|
1855
|
-
>
|
|
1856
|
-
<TrashCan
|
|
1857
|
-
strokeWidth={
|
|
1858
|
-
2
|
|
1859
|
-
}
|
|
1860
|
-
size={
|
|
1861
|
-
14
|
|
1862
|
-
}
|
|
1863
|
-
/>
|
|
1864
|
-
</button>
|
|
1865
|
-
</td>
|
|
1866
|
-
</tr>
|
|
1867
|
-
)
|
|
1868
|
-
)
|
|
1869
|
-
) : (
|
|
1870
|
-
<tr>
|
|
1871
|
-
<td colSpan="3">
|
|
1872
|
-
No entry has
|
|
1873
|
-
been added.
|
|
1874
|
-
</td>
|
|
1875
|
-
</tr>
|
|
1876
|
-
)}
|
|
1877
|
-
</tbody>
|
|
1878
|
-
<tfoot>
|
|
1879
|
-
<tr>
|
|
1880
|
-
<td>
|
|
1977
|
+
<div className={styles.optionsHeader}>
|
|
1978
|
+
<span>Columns</span>
|
|
1979
|
+
{dataField.options.length > 0 && (
|
|
1980
|
+
<span className={styles.optionsBadge}>
|
|
1981
|
+
{dataField.options.length}
|
|
1982
|
+
</span>
|
|
1983
|
+
)}
|
|
1984
|
+
</div>
|
|
1985
|
+
{dataField.options.length > 0 ? (
|
|
1986
|
+
<div className={styles.optionsList}>
|
|
1987
|
+
{dataField.options.map((option, optionKey) => (
|
|
1988
|
+
<div key={`option-${optionKey}`} className={styles.optionItem}>
|
|
1989
|
+
<span className={styles.optionNumber}>{optionKey + 1}</span>
|
|
1881
1990
|
<input
|
|
1882
1991
|
type="text"
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1992
|
+
value={option.label}
|
|
1993
|
+
className={styles.optionInput}
|
|
1994
|
+
placeholder="Column header..."
|
|
1995
|
+
onChange={(e) => {
|
|
1996
|
+
const newOptions = [...dataField.options];
|
|
1997
|
+
newOptions[optionKey].label = e.target.value;
|
|
1998
|
+
newOptions[optionKey].id = `${slugify(e.target.value)}-`;
|
|
1999
|
+
setDataField((items) => ({ ...items, options: newOptions }));
|
|
2000
|
+
}}
|
|
1891
2001
|
/>
|
|
1892
|
-
</td>
|
|
1893
|
-
<td>
|
|
1894
2002
|
<select
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
}
|
|
2003
|
+
value={option.type}
|
|
2004
|
+
className={styles.optionSelect}
|
|
2005
|
+
onChange={(e) => {
|
|
2006
|
+
const newOptions = [...dataField.options];
|
|
2007
|
+
newOptions[optionKey].type = e.target.value;
|
|
2008
|
+
setDataField((items) => ({ ...items, options: newOptions }));
|
|
2009
|
+
}}
|
|
1902
2010
|
>
|
|
1903
|
-
<option value="">
|
|
1904
|
-
Please
|
|
1905
|
-
Select an
|
|
1906
|
-
Option
|
|
1907
|
-
</option>
|
|
2011
|
+
<option value="">No Type</option>
|
|
1908
2012
|
{fieldTypes
|
|
1909
|
-
.filter(
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
'dynamicdata',
|
|
1917
|
-
'file',
|
|
1918
|
-
'image',
|
|
1919
|
-
'plaintext',
|
|
1920
|
-
'plaintextheading',
|
|
1921
|
-
'section',
|
|
1922
|
-
'signature',
|
|
1923
|
-
'table',
|
|
1924
|
-
];
|
|
1925
|
-
// Exclude 'checkbox' only if dataField.type is 'table_text'
|
|
1926
|
-
if (
|
|
1927
|
-
dataField.type ===
|
|
1928
|
-
'table_text'
|
|
1929
|
-
) {
|
|
1930
|
-
// excludedKeywords.push(
|
|
1931
|
-
// 'checkbox'
|
|
1932
|
-
// );
|
|
1933
|
-
}
|
|
1934
|
-
return !excludedKeywords.some(
|
|
1935
|
-
(
|
|
1936
|
-
keyword
|
|
1937
|
-
) =>
|
|
1938
|
-
item.value.includes(
|
|
1939
|
-
keyword
|
|
1940
|
-
)
|
|
1941
|
-
);
|
|
1942
|
-
}
|
|
1943
|
-
)
|
|
1944
|
-
.map(
|
|
1945
|
-
(
|
|
1946
|
-
item,
|
|
1947
|
-
itemKey
|
|
1948
|
-
) => (
|
|
1949
|
-
<option
|
|
1950
|
-
value={
|
|
1951
|
-
item.value
|
|
1952
|
-
}
|
|
1953
|
-
key={`type-${item.value}-${itemKey}`}
|
|
1954
|
-
>
|
|
1955
|
-
{
|
|
1956
|
-
item.label
|
|
1957
|
-
}
|
|
1958
|
-
</option>
|
|
1959
|
-
)
|
|
1960
|
-
)}
|
|
2013
|
+
.filter((item) => {
|
|
2014
|
+
const excludedKeywords = ['dropdown','dynamicdata','file','image','plaintext','plaintextheading','section','signature','table'];
|
|
2015
|
+
return !excludedKeywords.some((keyword) => item.value.includes(keyword));
|
|
2016
|
+
})
|
|
2017
|
+
.map((item, itemKey) => (
|
|
2018
|
+
<option value={item.value} key={`type-form-${item.value}-${itemKey}`}>{item.label}</option>
|
|
2019
|
+
))}
|
|
1961
2020
|
</select>
|
|
1962
|
-
</td>
|
|
1963
|
-
<td>
|
|
1964
2021
|
<button
|
|
1965
|
-
className={
|
|
1966
|
-
onClick={
|
|
1967
|
-
|
|
1968
|
-
}
|
|
2022
|
+
className={styles.optionDelete}
|
|
2023
|
+
onClick={handleDeleteOption}
|
|
2024
|
+
data-counter={optionKey}
|
|
1969
2025
|
data-tooltip-id="system-tooltip"
|
|
1970
|
-
data-tooltip-content=
|
|
1971
|
-
'Add Option'
|
|
1972
|
-
}
|
|
2026
|
+
data-tooltip-content="Delete Column"
|
|
1973
2027
|
>
|
|
1974
|
-
<
|
|
1975
|
-
strokeWidth={
|
|
1976
|
-
2
|
|
1977
|
-
}
|
|
1978
|
-
size={14}
|
|
1979
|
-
/>
|
|
1980
|
-
Add
|
|
2028
|
+
<TrashCan strokeWidth={2} size={14} />
|
|
1981
2029
|
</button>
|
|
1982
|
-
</
|
|
1983
|
-
|
|
1984
|
-
</
|
|
1985
|
-
|
|
2030
|
+
</div>
|
|
2031
|
+
))}
|
|
2032
|
+
</div>
|
|
2033
|
+
) : (
|
|
2034
|
+
<div className={styles.optionsEmpty}>No columns added yet</div>
|
|
2035
|
+
)}
|
|
2036
|
+
<div className={styles.optionAddRow}>
|
|
2037
|
+
<input
|
|
2038
|
+
type="text"
|
|
2039
|
+
name="label"
|
|
2040
|
+
onChange={handleDataOption}
|
|
2041
|
+
value={dataOption.label}
|
|
2042
|
+
placeholder="Type column header..."
|
|
2043
|
+
className={styles.optionAddInput}
|
|
2044
|
+
onKeyDown={(e) => {
|
|
2045
|
+
if (e.key === 'Enter') { e.preventDefault(); handleAddOption(e); }
|
|
2046
|
+
}}
|
|
2047
|
+
/>
|
|
2048
|
+
<select
|
|
2049
|
+
name="type"
|
|
2050
|
+
value={dataOption.type}
|
|
2051
|
+
onChange={handleDataOption}
|
|
2052
|
+
className={styles.optionSelect}
|
|
2053
|
+
>
|
|
2054
|
+
<option value="">Select Type</option>
|
|
2055
|
+
{fieldTypes
|
|
2056
|
+
.filter((item) => {
|
|
2057
|
+
const excludedKeywords = ['dropdown','dynamicdata','file','image','plaintext','plaintextheading','section','signature','table'];
|
|
2058
|
+
return !excludedKeywords.some((keyword) => item.value.includes(keyword));
|
|
2059
|
+
})
|
|
2060
|
+
.map((item, itemKey) => (
|
|
2061
|
+
<option value={item.value} key={`type-${item.value}-${itemKey}`}>{item.label}</option>
|
|
2062
|
+
))}
|
|
2063
|
+
</select>
|
|
2064
|
+
<button
|
|
2065
|
+
className={`${styles.tableActionBtn} ${styles.add}`}
|
|
2066
|
+
onClick={handleAddOption}
|
|
2067
|
+
data-tooltip-id="system-tooltip"
|
|
2068
|
+
data-tooltip-content="Add Column"
|
|
2069
|
+
>
|
|
2070
|
+
<CirclePlus strokeWidth={2} size={14} />
|
|
2071
|
+
Add
|
|
2072
|
+
</button>
|
|
2073
|
+
</div>
|
|
1986
2074
|
</div>
|
|
1987
2075
|
) : null}
|
|
1988
2076
|
|
|
@@ -2061,135 +2149,68 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
2061
2149
|
dataField.type
|
|
2062
2150
|
) ? (
|
|
2063
2151
|
<div className={styles.formItemFull}>
|
|
2064
|
-
<
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
</tr>
|
|
2078
|
-
</thead>
|
|
2079
|
-
<tbody>
|
|
2080
|
-
{dataField.rows?.length >
|
|
2081
|
-
0 ? (
|
|
2082
|
-
dataField.rows.map(
|
|
2083
|
-
(row, rowKey) => (
|
|
2084
|
-
<tr
|
|
2085
|
-
key={`row-${rowKey}`}
|
|
2086
|
-
>
|
|
2087
|
-
<td>
|
|
2088
|
-
<input
|
|
2089
|
-
type="text"
|
|
2090
|
-
value={
|
|
2091
|
-
row.label
|
|
2092
|
-
}
|
|
2093
|
-
onChange={(
|
|
2094
|
-
e
|
|
2095
|
-
) => {
|
|
2096
|
-
const newRows =
|
|
2097
|
-
[
|
|
2098
|
-
...dataField.rows,
|
|
2099
|
-
];
|
|
2100
|
-
newRows[
|
|
2101
|
-
rowKey
|
|
2102
|
-
].label =
|
|
2103
|
-
e.target.value;
|
|
2104
|
-
newRows[
|
|
2105
|
-
rowKey
|
|
2106
|
-
].id =
|
|
2107
|
-
`${slugify(e.target.value)}-`;
|
|
2108
|
-
setDataField(
|
|
2109
|
-
(
|
|
2110
|
-
items
|
|
2111
|
-
) => ({
|
|
2112
|
-
...items,
|
|
2113
|
-
rows: newRows,
|
|
2114
|
-
})
|
|
2115
|
-
);
|
|
2116
|
-
}}
|
|
2117
|
-
/>
|
|
2118
|
-
</td>
|
|
2119
|
-
<td>
|
|
2120
|
-
<button
|
|
2121
|
-
className={`${styles.tableActionBtn} ${styles.delete}`}
|
|
2122
|
-
onClick={
|
|
2123
|
-
handleDeleteRowOption
|
|
2124
|
-
}
|
|
2125
|
-
data-counter={
|
|
2126
|
-
rowKey
|
|
2127
|
-
}
|
|
2128
|
-
data-tooltip-id="system-tooltip"
|
|
2129
|
-
data-tooltip-content={
|
|
2130
|
-
'Delete Row'
|
|
2131
|
-
}
|
|
2132
|
-
>
|
|
2133
|
-
<TrashCan
|
|
2134
|
-
strokeWidth={
|
|
2135
|
-
2
|
|
2136
|
-
}
|
|
2137
|
-
size={
|
|
2138
|
-
14
|
|
2139
|
-
}
|
|
2140
|
-
/>
|
|
2141
|
-
</button>
|
|
2142
|
-
</td>
|
|
2143
|
-
</tr>
|
|
2144
|
-
)
|
|
2145
|
-
)
|
|
2146
|
-
) : (
|
|
2147
|
-
<tr>
|
|
2148
|
-
<td colSpan="2">
|
|
2149
|
-
No entry has
|
|
2150
|
-
been added.
|
|
2151
|
-
</td>
|
|
2152
|
-
</tr>
|
|
2153
|
-
)}
|
|
2154
|
-
</tbody>
|
|
2155
|
-
<tfoot>
|
|
2156
|
-
<tr>
|
|
2157
|
-
<td>
|
|
2152
|
+
<div className={styles.optionsHeader}>
|
|
2153
|
+
<span>Rows</span>
|
|
2154
|
+
{dataField.rows?.length > 0 && (
|
|
2155
|
+
<span className={styles.optionsBadge}>
|
|
2156
|
+
{dataField.rows.length}
|
|
2157
|
+
</span>
|
|
2158
|
+
)}
|
|
2159
|
+
</div>
|
|
2160
|
+
{dataField.rows?.length > 0 ? (
|
|
2161
|
+
<div className={styles.optionsList}>
|
|
2162
|
+
{dataField.rows.map((row, rowKey) => (
|
|
2163
|
+
<div key={`row-${rowKey}`} className={styles.optionItem}>
|
|
2164
|
+
<span className={styles.optionNumber}>{rowKey + 1}</span>
|
|
2158
2165
|
<input
|
|
2159
2166
|
type="text"
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2167
|
+
value={row.label}
|
|
2168
|
+
className={styles.optionInput}
|
|
2169
|
+
placeholder="Row label..."
|
|
2170
|
+
onChange={(e) => {
|
|
2171
|
+
const newRows = [...dataField.rows];
|
|
2172
|
+
newRows[rowKey].label = e.target.value;
|
|
2173
|
+
newRows[rowKey].id = `${slugify(e.target.value)}-`;
|
|
2174
|
+
setDataField((items) => ({ ...items, rows: newRows }));
|
|
2175
|
+
}}
|
|
2168
2176
|
/>
|
|
2169
|
-
</td>
|
|
2170
|
-
<td>
|
|
2171
2177
|
<button
|
|
2172
|
-
className={
|
|
2173
|
-
onClick={
|
|
2174
|
-
|
|
2175
|
-
}
|
|
2178
|
+
className={styles.optionDelete}
|
|
2179
|
+
onClick={handleDeleteRowOption}
|
|
2180
|
+
data-counter={rowKey}
|
|
2176
2181
|
data-tooltip-id="system-tooltip"
|
|
2177
|
-
data-tooltip-content=
|
|
2178
|
-
'Add Row'
|
|
2179
|
-
}
|
|
2182
|
+
data-tooltip-content="Delete Row"
|
|
2180
2183
|
>
|
|
2181
|
-
<
|
|
2182
|
-
strokeWidth={
|
|
2183
|
-
2
|
|
2184
|
-
}
|
|
2185
|
-
size={14}
|
|
2186
|
-
/>
|
|
2187
|
-
Add
|
|
2184
|
+
<TrashCan strokeWidth={2} size={14} />
|
|
2188
2185
|
</button>
|
|
2189
|
-
</
|
|
2190
|
-
|
|
2191
|
-
</
|
|
2192
|
-
|
|
2186
|
+
</div>
|
|
2187
|
+
))}
|
|
2188
|
+
</div>
|
|
2189
|
+
) : (
|
|
2190
|
+
<div className={styles.optionsEmpty}>No rows added yet</div>
|
|
2191
|
+
)}
|
|
2192
|
+
<div className={styles.optionAddRow}>
|
|
2193
|
+
<input
|
|
2194
|
+
type="text"
|
|
2195
|
+
name="label"
|
|
2196
|
+
onChange={handleRowOption}
|
|
2197
|
+
value={rowOption.label}
|
|
2198
|
+
placeholder="Type new row label and press Add..."
|
|
2199
|
+
className={styles.optionAddInput}
|
|
2200
|
+
onKeyDown={(e) => {
|
|
2201
|
+
if (e.key === 'Enter') { e.preventDefault(); handleAddRowOption(e); }
|
|
2202
|
+
}}
|
|
2203
|
+
/>
|
|
2204
|
+
<button
|
|
2205
|
+
className={`${styles.tableActionBtn} ${styles.add}`}
|
|
2206
|
+
onClick={handleAddRowOption}
|
|
2207
|
+
data-tooltip-id="system-tooltip"
|
|
2208
|
+
data-tooltip-content="Add Row"
|
|
2209
|
+
>
|
|
2210
|
+
<CirclePlus strokeWidth={2} size={14} />
|
|
2211
|
+
Add
|
|
2212
|
+
</button>
|
|
2213
|
+
</div>
|
|
2193
2214
|
</div>
|
|
2194
2215
|
) : null}
|
|
2195
2216
|
|
|
@@ -2322,6 +2343,83 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
2322
2343
|
</div>
|
|
2323
2344
|
</StandardModal>
|
|
2324
2345
|
|
|
2346
|
+
{/* Move-to-position dialog */}
|
|
2347
|
+
{moveToDialog.show && (
|
|
2348
|
+
<div
|
|
2349
|
+
className={styles.moveToOverlay}
|
|
2350
|
+
onClick={() =>
|
|
2351
|
+
setMoveToDialog({
|
|
2352
|
+
show: false,
|
|
2353
|
+
fieldId: null,
|
|
2354
|
+
currentPos: 0,
|
|
2355
|
+
})
|
|
2356
|
+
}
|
|
2357
|
+
>
|
|
2358
|
+
<div
|
|
2359
|
+
className={styles.moveToDialog}
|
|
2360
|
+
onClick={(e) => e.stopPropagation()}
|
|
2361
|
+
>
|
|
2362
|
+
<h3>Move Field to Position</h3>
|
|
2363
|
+
<p>
|
|
2364
|
+
Current position: {moveToDialog.currentPos} of{' '}
|
|
2365
|
+
{data.detail.length}
|
|
2366
|
+
</p>
|
|
2367
|
+
<div className={styles.moveToInputGroup}>
|
|
2368
|
+
<input
|
|
2369
|
+
type="number"
|
|
2370
|
+
min="1"
|
|
2371
|
+
max={data.detail.length}
|
|
2372
|
+
value={moveToPosition}
|
|
2373
|
+
onChange={(e) =>
|
|
2374
|
+
setMoveToPosition(e.target.value)
|
|
2375
|
+
}
|
|
2376
|
+
autoFocus
|
|
2377
|
+
onKeyDown={(e) => {
|
|
2378
|
+
if (e.key === 'Enter') {
|
|
2379
|
+
handleMoveTo(
|
|
2380
|
+
moveToDialog.fieldId,
|
|
2381
|
+
parseInt(moveToPosition)
|
|
2382
|
+
);
|
|
2383
|
+
} else if (e.key === 'Escape') {
|
|
2384
|
+
setMoveToDialog({
|
|
2385
|
+
show: false,
|
|
2386
|
+
fieldId: null,
|
|
2387
|
+
currentPos: 0,
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
}}
|
|
2391
|
+
/>
|
|
2392
|
+
<span>of {data.detail.length}</span>
|
|
2393
|
+
</div>
|
|
2394
|
+
<div className={styles.moveToActions}>
|
|
2395
|
+
<button
|
|
2396
|
+
className={styles.btn}
|
|
2397
|
+
onClick={() =>
|
|
2398
|
+
handleMoveTo(
|
|
2399
|
+
moveToDialog.fieldId,
|
|
2400
|
+
parseInt(moveToPosition)
|
|
2401
|
+
)
|
|
2402
|
+
}
|
|
2403
|
+
>
|
|
2404
|
+
Move
|
|
2405
|
+
</button>
|
|
2406
|
+
<button
|
|
2407
|
+
className={`${styles.btn} ${styles.btnCancel}`}
|
|
2408
|
+
onClick={() =>
|
|
2409
|
+
setMoveToDialog({
|
|
2410
|
+
show: false,
|
|
2411
|
+
fieldId: null,
|
|
2412
|
+
currentPos: 0,
|
|
2413
|
+
})
|
|
2414
|
+
}
|
|
2415
|
+
>
|
|
2416
|
+
Cancel
|
|
2417
|
+
</button>
|
|
2418
|
+
</div>
|
|
2419
|
+
</div>
|
|
2420
|
+
</div>
|
|
2421
|
+
)}
|
|
2422
|
+
|
|
2325
2423
|
{/* React Tooltips */}
|
|
2326
2424
|
<Tooltip
|
|
2327
2425
|
id="field-tooltip"
|