@visns-studio/visns-components 4.7.2 → 4.7.4

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.
Files changed (99) hide show
  1. package/package.json +15 -14
  2. package/src/components/cms/DataGrid.jsx +1461 -0
  3. package/src/components/cms/DropZone.jsx +349 -0
  4. package/src/components/cms/Field.jsx +802 -0
  5. package/src/components/cms/Form.jsx +476 -0
  6. package/src/components/cms/generic/CmsDetail.jsx +36 -0
  7. package/src/components/cms/generic/CmsIndex.jsx +73 -0
  8. package/src/components/cms/generic/CmsSort.jsx +125 -0
  9. package/src/components/cms/sorting/Item.jsx +115 -0
  10. package/src/components/cms/sorting/List.jsx +30 -0
  11. package/src/components/crm/AsyncSelect.jsx +125 -0
  12. package/src/components/crm/Autocomplete.jsx +174 -0
  13. package/src/components/crm/Breadcrumb.jsx +52 -0
  14. package/src/components/crm/Call.jsx +220 -0
  15. package/src/components/crm/DataGrid.jsx +2701 -0
  16. package/src/components/crm/Download.jsx +101 -0
  17. package/src/components/crm/Fetch.jsx +119 -0
  18. package/src/components/crm/Field.jsx +1637 -0
  19. package/src/components/crm/Form.jsx +1409 -0
  20. package/src/components/crm/Loader.jsx +29 -0
  21. package/src/components/crm/MultiSelect.jsx +78 -0
  22. package/src/components/crm/Navigation.jsx +619 -0
  23. package/src/components/crm/Notification.jsx +197 -0
  24. package/src/components/crm/QrCode.jsx +83 -0
  25. package/src/components/crm/Select.jsx +58 -0
  26. package/src/components/crm/SelectList.jsx +21 -0
  27. package/src/components/crm/TableFilter.jsx +198 -0
  28. package/src/components/crm/auth/Login.jsx +223 -0
  29. package/src/components/crm/auth/Profile.jsx +280 -0
  30. package/src/components/crm/auth/Reset.jsx +111 -0
  31. package/src/components/crm/auth/Verify.jsx +174 -0
  32. package/src/components/crm/auth/styles/Login.module.scss +243 -0
  33. package/src/components/crm/auth/styles/Profile.module.scss +222 -0
  34. package/src/components/crm/auth/styles/Reset.module.scss +216 -0
  35. package/src/components/crm/auth/styles/Verify.module.scss +216 -0
  36. package/src/components/crm/generic/AuditLog.jsx +108 -0
  37. package/src/components/crm/generic/AuditLogs.jsx +115 -0
  38. package/src/components/crm/generic/GenericAuth.jsx +166 -0
  39. package/src/components/crm/generic/GenericDashboard.jsx +42 -0
  40. package/src/components/crm/generic/GenericDetail.jsx +1499 -0
  41. package/src/components/crm/generic/GenericDynamic.jsx +916 -0
  42. package/src/components/crm/generic/GenericFormBuilder.jsx +1909 -0
  43. package/src/components/crm/generic/GenericIndex.jsx +376 -0
  44. package/src/components/crm/generic/GenericMain.jsx +129 -0
  45. package/src/components/crm/generic/GenericSort.jsx +188 -0
  46. package/src/components/crm/generic/NotificationList.jsx +64 -0
  47. package/src/components/crm/generic/styles/AuditLog.module.scss +147 -0
  48. package/src/components/crm/generic/styles/AuditLogs.module.scss +92 -0
  49. package/src/components/crm/generic/styles/GenericDetail.module.scss +634 -0
  50. package/src/components/crm/generic/styles/GenericDynamic.module.scss +932 -0
  51. package/src/components/crm/generic/styles/GenericFormBuilder.module.scss +944 -0
  52. package/src/components/crm/generic/styles/GenericIndex.module.scss +247 -0
  53. package/src/components/crm/generic/styles/GenericMain.module.scss +91 -0
  54. package/src/components/crm/generic/styles/GenericSort.module.scss +123 -0
  55. package/src/components/crm/generic/styles/NotificationList.module.scss +67 -0
  56. package/src/components/crm/sorting/Item.jsx +117 -0
  57. package/src/components/crm/sorting/List.jsx +32 -0
  58. package/src/components/crm/sorting/styles/Item.module.scss +68 -0
  59. package/src/components/crm/sorting/styles/List.module.scss +68 -0
  60. package/src/components/crm/styles/AsyncSelect.module.scss +8 -0
  61. package/src/components/crm/styles/Autocomplete.module.scss +44 -0
  62. package/src/components/crm/styles/DataGrid.module.scss +210 -0
  63. package/src/components/crm/styles/Field.module.scss +311 -0
  64. package/src/components/crm/styles/Form.module.scss +499 -0
  65. package/src/components/crm/styles/Loader.module.scss +94 -0
  66. package/src/components/crm/styles/MultiSelect.module.scss +8 -0
  67. package/src/components/crm/styles/Navigation.module.scss +978 -0
  68. package/src/components/crm/styles/Notification.module.scss +147 -0
  69. package/src/components/crm/styles/QrCode.module.scss +87 -0
  70. package/src/components/crm/styles/TableFilter.module.scss +52 -0
  71. package/src/components/styles/global.css +73 -0
  72. package/src/index.js +86 -0
  73. package/dist/104e5636d8ddb791614c.woff2 +0 -0
  74. package/dist/11fe6a83d647de5daf95.woff +0 -0
  75. package/dist/141e2a8c7836495afe2a.woff +0 -0
  76. package/dist/2ba5877f7079830b5383.woff +0 -0
  77. package/dist/2d6836f45b2037be41f3.woff +0 -0
  78. package/dist/399.0a0f3e0d21be1057d599.css +0 -8
  79. package/dist/399.b8f57fa3f8c0c10119e4.js +0 -1
  80. package/dist/47d566c3b1293dfd9d77.woff +0 -0
  81. package/dist/6282a13cbba671a71913.woff2 +0 -0
  82. package/dist/78266f551031aa9db127.woff +0 -0
  83. package/dist/7b7da89f1e3fdcbfe36c.woff2 +0 -0
  84. package/dist/7e78e8338af7efeda712.woff2 +0 -0
  85. package/dist/7fa387951673abf164b1.woff2 +0 -0
  86. package/dist/819d59862c2d0640aad8.woff +0 -0
  87. package/dist/b615e1a6c838ea059a56.woff +0 -0
  88. package/dist/b9b1aa739c660c4ce67c.woff2 +0 -0
  89. package/dist/c5f3640b11df9414facb.woff +0 -0
  90. package/dist/da26d162ff5af71d6590.woff2 +0 -0
  91. package/dist/dd5b2912dbf896310865.woff2 +0 -0
  92. package/dist/f282b331272463c1aa6c.woff2 +0 -0
  93. package/dist/index.css +0 -2902
  94. package/dist/index.js +0 -2
  95. package/dist/index.js.LICENSE.txt +0 -150
  96. package/dist/main.83b033670d64419bb497.css +0 -1
  97. package/dist/main.b1723d17cd2d3513ab62.js +0 -1
  98. package/dist/report.html +0 -39
  99. package/dist/runtime.33c276593b23f8035b8d.js +0 -1
@@ -0,0 +1,1909 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { useParams } from 'react-router-dom';
3
+ import Popup from 'reactjs-popup';
4
+ import { arrayMoveImmutable } from 'array-move';
5
+ import { confirmAlert } from 'react-confirm-alert';
6
+ import parse from 'html-react-parser';
7
+ import Toggle from 'react-toggle';
8
+ import { toast } from 'react-toastify';
9
+ import { v4 as uuidv4 } from 'uuid';
10
+ import { Editor } from '@tinymce/tinymce-react';
11
+ import { CircleChevronRight, CirclePlus, CircleX, TrashCan } from 'akar-icons';
12
+
13
+ import 'react-toggle/style.css';
14
+ import 'react-datepicker/dist/react-datepicker.css';
15
+ import 'react-confirm-alert/src/react-confirm-alert.css';
16
+
17
+ import Breadcrumb from '../Breadcrumb';
18
+ import CustomFetch from '../Fetch';
19
+ import SortableList from '../../../components/cms/sorting/List';
20
+
21
+ import styles from './styles/GenericFormBuilder.module.scss'; // Import the CSS module
22
+
23
+ function GenericFormBuilder({ setting, urlParam, userProfile }) {
24
+ const editorRef = useRef(null);
25
+ const routeParams = useParams();
26
+
27
+ const { dynamicDropdowns, fetchUrl, fields, parentUrl, formTitle } =
28
+ setting;
29
+
30
+ const { dataId } = useParams();
31
+ const [data, setData] = useState({});
32
+ const [dataField, setDataField] = useState({
33
+ id: '',
34
+ label: '',
35
+ description: '',
36
+ type: '',
37
+ options: [],
38
+ rows: [],
39
+ size: 'half',
40
+ required: 'no',
41
+ });
42
+ const [dataOption, setDataOption] = useState({
43
+ id: '',
44
+ label: '',
45
+ type: '',
46
+ });
47
+ const [fieldTypes, setFieldTypes] = useState([
48
+ { value: 'checkbox', label: 'Checkbox' },
49
+ { value: 'html5_date', label: 'Date' },
50
+ { value: 'html5_datetime', label: 'Date & Time' },
51
+ { value: 'dropdown', label: 'Dropdown' },
52
+ ...(dynamicDropdowns && dynamicDropdowns.length > 0
53
+ ? [{ value: 'dynamicDropdown', label: 'Dynamic Dropdown' }]
54
+ : []),
55
+ { value: 'dynamicdata', label: 'Dynamic Data' },
56
+ { value: 'file', label: 'File' },
57
+ { value: 'plaintextheading', label: 'Heading' },
58
+ { value: 'image', label: 'Image' },
59
+ { value: 'number', label: 'Number' },
60
+ { value: 'plaintext', label: 'Plain Text' },
61
+ { value: 'section', label: 'Section' },
62
+ { value: 'signature', label: 'Signature' },
63
+ { value: 'table_radio', label: 'Table (Radio)' },
64
+ { value: 'table_text', label: 'Table (Custom)' },
65
+ { value: 'text', label: 'Text' },
66
+ { value: 'textarea', label: 'Textarea' },
67
+ { value: 'html5_time', label: 'Time' },
68
+ { value: 'toggle', label: 'Toggle' },
69
+ ]);
70
+ const [rowOption, setRowOption] = useState({
71
+ id: '',
72
+ label: '',
73
+ });
74
+ const [modalShow, setModalShow] = useState(false);
75
+ const [modalType, setModalType] = useState({
76
+ type: 'create',
77
+ key: '',
78
+ });
79
+ const [modalFormShow, setModalFormShow] = useState(false);
80
+ const [roles, setRoles] = useState([]);
81
+
82
+ /** Data Option Functionalities */
83
+ const handleDataOption = (e) => {
84
+ const { name, value } = e.target;
85
+
86
+ setDataOption((items) => ({
87
+ ...items,
88
+ [name]: value,
89
+ id: `${slugify(value)}-`,
90
+ }));
91
+ };
92
+
93
+ const handleAddOption = (e) => {
94
+ e.preventDefault();
95
+
96
+ if (dataOption.label !== '') {
97
+ const isLabelUnique = !dataField.options.some(
98
+ (option) => option.label === dataOption.label
99
+ );
100
+
101
+ if (isLabelUnique) {
102
+ setDataField((items) => ({
103
+ ...items,
104
+ options: [...items.options, dataOption],
105
+ }));
106
+
107
+ setDataOption(() => ({
108
+ id: '',
109
+ label: '',
110
+ type: '',
111
+ }));
112
+ } else {
113
+ toast.warn('Option label must be unique.');
114
+ }
115
+ } else {
116
+ toast.warn('Please enter a label for the option.');
117
+ }
118
+ };
119
+
120
+ const handleDeleteOption = (e) => {
121
+ e.preventDefault();
122
+
123
+ const { counter } = e.target.dataset;
124
+
125
+ setDataField((prevState) => {
126
+ const options = prevState.options.slice();
127
+ options.splice(counter, 1);
128
+
129
+ return {
130
+ ...prevState,
131
+ options: options,
132
+ };
133
+ });
134
+ };
135
+
136
+ /** Row Option Functionalities */
137
+ const handleRowOption = (e) => {
138
+ const { name, value } = e.target;
139
+
140
+ setRowOption((items) => ({
141
+ ...items,
142
+ [name]: value,
143
+ id: `${slugify(value)}-`,
144
+ }));
145
+ };
146
+
147
+ const handleAddRowOption = (e) => {
148
+ e.preventDefault();
149
+
150
+ // Initialize rows if it doesn't exist
151
+ if (!dataField.rows) {
152
+ setDataField((items) => ({
153
+ ...items,
154
+ rows: [],
155
+ }));
156
+ }
157
+
158
+ if (rowOption.label !== '') {
159
+ const isLabelUnique = dataField.rows
160
+ ? !dataField.rows.some(
161
+ (option) => option.label === rowOption.label
162
+ )
163
+ : true;
164
+
165
+ if (isLabelUnique) {
166
+ setDataField((items) => ({
167
+ ...items,
168
+ rows: [...(items.rows || []), rowOption],
169
+ }));
170
+
171
+ setRowOption(() => ({
172
+ id: '',
173
+ label: '',
174
+ }));
175
+ } else {
176
+ toast.warn('Option label must be unique.');
177
+ }
178
+ } else {
179
+ toast.warn('Please enter a label for the option.');
180
+ }
181
+ };
182
+
183
+ const handleDeleteRowOption = (e) => {
184
+ e.preventDefault();
185
+
186
+ const { counter } = e.target.dataset;
187
+
188
+ setDataField((prevState) => {
189
+ const rows = prevState.rows.slice();
190
+ rows.splice(counter, 1);
191
+
192
+ return {
193
+ ...prevState,
194
+ rows: rows,
195
+ };
196
+ });
197
+ };
198
+
199
+ /** Field Functionalities */
200
+ const onSortEnd = ({ oldIndex, newIndex }) => {
201
+ const newData = arrayMoveImmutable(data.detail, oldIndex, newIndex);
202
+
203
+ setData((items) => ({
204
+ ...items,
205
+ detail: newData,
206
+ }));
207
+ };
208
+
209
+ const handleCloseModal = () => {
210
+ setModalShow(false);
211
+ setDataField(() => ({
212
+ label: '',
213
+ type: '',
214
+ options: [],
215
+ rows: [],
216
+ size: 'half',
217
+ required: 'no',
218
+ }));
219
+ setModalType(() => ({
220
+ type: 'create',
221
+ key: '',
222
+ }));
223
+ };
224
+
225
+ const handleOpenModal = () => {
226
+ setModalShow(true);
227
+ };
228
+
229
+ const slugify = (text) => {
230
+ return text.replace(/\s+/g, '-').toLowerCase();
231
+ };
232
+
233
+ const handleChangeForm = (e) => {
234
+ if (e) {
235
+ const { name, value } = e.target;
236
+ const updatedValue = name === 'id' ? slugify(value) : value;
237
+
238
+ setDataField((items) => ({
239
+ ...items,
240
+ [name]: updatedValue,
241
+ }));
242
+
243
+ if (name === 'label') {
244
+ setDataField((items) => ({
245
+ ...items,
246
+ id: slugify(value),
247
+ }));
248
+ }
249
+ }
250
+ };
251
+
252
+ const handleChangeFormRichEditor = (e, value, name) => {
253
+ setDataField((items) => ({
254
+ ...items,
255
+ [name]: value,
256
+ }));
257
+ };
258
+
259
+ const handleEdit = (key) => {
260
+ const { detail } = data;
261
+
262
+ setDataField(() => ({
263
+ ...detail[key],
264
+ }));
265
+
266
+ setModalType(() => ({
267
+ type: 'update',
268
+ key: key,
269
+ }));
270
+
271
+ handleOpenModal();
272
+ };
273
+
274
+ const handleDeleteField = (id, label) => {
275
+ confirmAlert({
276
+ title: `Delete "${label}" Field`,
277
+ message: 'Are you sure you want to delete this field?',
278
+ buttons: [
279
+ {
280
+ label: 'Yes',
281
+ onClick: () => {
282
+ const index = data.detail.findIndex(
283
+ (item) => item.id === id
284
+ );
285
+
286
+ if (index > -1) {
287
+ let newDetail = [...data.detail];
288
+ newDetail.splice(index, 1);
289
+
290
+ setData((items) => ({
291
+ ...items,
292
+ detail: newDetail,
293
+ }));
294
+
295
+ handleCloseModal();
296
+ }
297
+ },
298
+ },
299
+ {
300
+ label: 'No',
301
+ onClick: () => close(),
302
+ },
303
+ ],
304
+ });
305
+ };
306
+
307
+ const handleSaveField = (e) => {
308
+ if (e) {
309
+ e.preventDefault();
310
+ }
311
+
312
+ let field = dataField;
313
+
314
+ field.id = formatFieldId(field.id);
315
+
316
+ let errorMessage = validateField(field);
317
+
318
+ if (errorMessage === '') {
319
+ saveFieldData(field);
320
+ handleCloseModal();
321
+ } else {
322
+ displayErrorMessage(errorMessage);
323
+ }
324
+ };
325
+
326
+ const formatFieldId = (id) => {
327
+ return id.includes('::') ? id : `${id}::${uuidv4()}`;
328
+ };
329
+
330
+ const validateField = (field) => {
331
+ let errors = [];
332
+
333
+ if (!isIdValid(field.id)) {
334
+ errors.push('Please enter a unique id for the field.');
335
+ }
336
+
337
+ if (field.type === 'plaintext') {
338
+ if (!field.label || field.label === '') {
339
+ errors.push('Please enter a label for the field.');
340
+ }
341
+
342
+ if (!field.description || field.description === '') {
343
+ errors.push('Please enter a description for the field.');
344
+ }
345
+ } else {
346
+ if (!field.label || field.label === '') {
347
+ errors.push('Please enter a label for the field.');
348
+ }
349
+ }
350
+
351
+ if (field.type === '') {
352
+ errors.push('Please select a type for the field.');
353
+ } else if (
354
+ field.type === 'dropdown' &&
355
+ (!field.options || field.options.length === 0)
356
+ ) {
357
+ errors.push('Please add options for the dropdown.');
358
+ } else if (
359
+ field.type === 'table_text' &&
360
+ (!field.options || field.options.length === 0)
361
+ ) {
362
+ errors.push('Please add options for the table.');
363
+ } else if (field.type === 'table_radio') {
364
+ if (!field.options || field.options.length === 0) {
365
+ errors.push('Please add options for the table.');
366
+ }
367
+ if (!field.rows || field.rows.length === 0) {
368
+ errors.push('Please add rows for the table.');
369
+ }
370
+ }
371
+
372
+ if (!field.size || field.size === '') {
373
+ errors.push('Please select a size for the field.');
374
+ }
375
+
376
+ if (field.required === '') {
377
+ errors.push('Is the field a required field?');
378
+ }
379
+
380
+ return errors.join('<br />');
381
+ };
382
+
383
+ const isIdValid = (id) => {
384
+ if (id === '') {
385
+ return false;
386
+ }
387
+ if (
388
+ modalType.type === 'create' ||
389
+ id !== data.detail[modalType.key]?.id
390
+ ) {
391
+ return data.detail
392
+ ? data.detail.every((field) => field.id !== id)
393
+ : true;
394
+ }
395
+ return true;
396
+ };
397
+
398
+ const saveFieldData = (field) => {
399
+ let newDetail =
400
+ modalType.type === 'create'
401
+ ? [...(data.detail || []), field]
402
+ : data.detail.map((f, index) =>
403
+ index === modalType.key ? field : f
404
+ );
405
+
406
+ setData((items) => ({
407
+ ...items,
408
+ detail: newDetail,
409
+ }));
410
+ };
411
+
412
+ const displayErrorMessage = (errorMessage) => {
413
+ toast.error(<div>{parse(errorMessage)}</div>);
414
+ };
415
+
416
+ /** Form Functionalities */
417
+ const renderClassName = (d) => {
418
+ const sizeClassMap = {
419
+ full: styles.fwBuilderItem,
420
+ half: styles.halfBuilderItem,
421
+ quarter: styles.qtrBuilderItem,
422
+ };
423
+
424
+ return `${styles.formBuilderItem} ${
425
+ sizeClassMap[d.size] || styles.halfBuilderItem
426
+ }`;
427
+ };
428
+
429
+ const renderField = (field) => {
430
+ switch (field.type) {
431
+ case 'checkbox':
432
+ return (
433
+ <label className={styles.fi__label}>
434
+ <span className={styles.fi__spancheckbox}>
435
+ {field.label}{' '}
436
+ {field.required === 'yes' ? '*' : null}
437
+ </span>
438
+ {field.options.length > 0 ? (
439
+ <div className={styles.fi__optionscontainer}>
440
+ {field.options.map((option, index) => (
441
+ <div
442
+ key={`${field.id}-checkbox-option-${index}`}
443
+ className={styles.fi__checkboxcontainer}
444
+ >
445
+ <input
446
+ type="checkbox"
447
+ className={
448
+ styles.fi__customcheckbox
449
+ }
450
+ />
451
+ <label
452
+ className={styles.fi__checkboxlabel}
453
+ >
454
+ {option.label}
455
+ </label>{' '}
456
+ </div>
457
+ ))}
458
+ </div>
459
+ ) : null}
460
+ </label>
461
+ );
462
+ case 'date':
463
+ return (
464
+ <label className={styles.fi__label}>
465
+ <input type="date" />
466
+ <span className={styles.fi__span}>
467
+ {field.label}{' '}
468
+ {field.required === 'yes' ? '*' : null}
469
+ </span>
470
+ </label>
471
+ );
472
+ case 'datetime':
473
+ return (
474
+ <label className={styles.fi__label}>
475
+ <input type="datetime-local" />
476
+ <span className={styles.fi__span}>
477
+ {field.label}{' '}
478
+ {field.required === 'yes' ? '*' : null}
479
+ </span>
480
+ </label>
481
+ );
482
+ case 'dropdown':
483
+ case 'dynamicDropdown':
484
+ return (
485
+ <label className={styles.fi__label}>
486
+ <select>
487
+ <option>Please Select an Option</option>
488
+ </select>
489
+ <span className={styles.fi__span}>
490
+ {field.label}{' '}
491
+ {field.required === 'yes' ? '*' : null}
492
+ </span>
493
+ </label>
494
+ );
495
+ case 'dynamicdata':
496
+ return (
497
+ <label className={styles.fi__label}>
498
+ <strong>{field.label}</strong> [Dynamic Data]
499
+ </label>
500
+ );
501
+ case 'file':
502
+ return (
503
+ <label className={styles.fi__label}>
504
+ <input type="file" />
505
+ <span className={styles.fi__span}>
506
+ {field.label}{' '}
507
+ {field.required === 'yes' ? '*' : null}
508
+ </span>
509
+ </label>
510
+ );
511
+ case 'image':
512
+ return (
513
+ <label className={styles.fi__label}>
514
+ <input type="file" />
515
+ <span className={styles.fi__span}>
516
+ {field.label}{' '}
517
+ {field.required === 'yes' ? '*' : null}
518
+ </span>
519
+ </label>
520
+ );
521
+ case 'plaintextheading':
522
+ return (
523
+ <label className={styles.fi__label}>
524
+ <h2>{field.label}</h2>
525
+ </label>
526
+ );
527
+ case 'plaintext':
528
+ return (
529
+ <label className={styles.fi__label}>
530
+ {field.description ? parse(field.description) : null}
531
+ </label>
532
+ );
533
+ case 'number':
534
+ return (
535
+ <label className={styles.fi__label}>
536
+ <input type="number" />
537
+ <span className={styles.fi__span}>
538
+ {field.label}{' '}
539
+ {field.required === 'yes' ? '*' : null}
540
+ </span>
541
+ </label>
542
+ );
543
+ case 'section':
544
+ return (
545
+ <div className={styles.gridtxt__header}>
546
+ <span>{field.label}</span>
547
+ </div>
548
+ );
549
+ case 'signature':
550
+ return (
551
+ <label className={styles.fi__label}>
552
+ <span
553
+ className={`${styles.fi__span} ${styles.prefocus}`}
554
+ >
555
+ {field.label}{' '}
556
+ {field.required === 'yes' ? '*' : null}
557
+ </span>
558
+ <button
559
+ type="button"
560
+ className={styles.signButton}
561
+ onClick={() => {
562
+ // Handle signature logic here
563
+ }}
564
+ >
565
+ Click to Sign
566
+ </button>
567
+ <div className={styles.signaturePlaceholder}>
568
+ <p>
569
+ <strong>Name:</strong> [Placeholder]
570
+ </p>
571
+ <p>
572
+ <strong>Date:</strong> [Placeholder]
573
+ </p>
574
+ </div>
575
+ </label>
576
+ );
577
+ case 'table_radio':
578
+ return (
579
+ <label className={styles.fi__label}>
580
+ <table className={styles.contentTable}>
581
+ <thead>
582
+ <tr>
583
+ <th></th>
584
+ {field.options.map((option, index) => (
585
+ <th
586
+ key={`${field.id}-table-text-option-${index}`}
587
+ >
588
+ {option.label}
589
+ </th>
590
+ ))}
591
+ </tr>
592
+ </thead>
593
+ <tbody>
594
+ {field.rows.map((row, rowKey) => (
595
+ <tr
596
+ key={`${field.id}-table-text-row-data-${rowKey}`}
597
+ >
598
+ <td>{row.label}</td>
599
+ {field.options.map(
600
+ (option, optionKey) => (
601
+ <td
602
+ key={`${field.id}-table-text-data-${optionKey}-${rowKey}`}
603
+ ></td>
604
+ )
605
+ )}
606
+ </tr>
607
+ ))}
608
+ </tbody>
609
+ </table>
610
+ <span
611
+ className={`${styles.fi__span} ${styles.prefocus}`}
612
+ >
613
+ {field.label}{' '}
614
+ {field.required === 'yes' ? '*' : null}
615
+ </span>
616
+ </label>
617
+ );
618
+ case 'table_text':
619
+ return (
620
+ <label className={styles.fi__label}>
621
+ <table className={styles.contentTable}>
622
+ <thead>
623
+ <tr>
624
+ {field.options.map((option, index) => (
625
+ <th
626
+ key={`${field.id}-table-text-option-${index}`}
627
+ >
628
+ {option.label}
629
+ </th>
630
+ ))}
631
+ </tr>
632
+ </thead>
633
+ <tbody>
634
+ <tr>
635
+ {field.options.map((option, index) => (
636
+ <td
637
+ key={`${field.id}-table-text-data-${index}`}
638
+ >
639
+ [Placeholder Data]
640
+ </td>
641
+ ))}
642
+ </tr>
643
+ </tbody>
644
+ </table>
645
+ <span
646
+ className={`${styles.fi__span} ${styles.prefocus}`}
647
+ >
648
+ {field.label}{' '}
649
+ {field.required === 'yes' ? '*' : null}
650
+ </span>
651
+ </label>
652
+ );
653
+ case 'textarea':
654
+ return (
655
+ <label className={styles.fi__label}>
656
+ <textarea rows="5"></textarea>
657
+ <span className={styles.fi__span}>
658
+ {field.label}{' '}
659
+ {field.required === 'yes' ? '*' : null}
660
+ </span>
661
+ </label>
662
+ );
663
+ case 'time':
664
+ return (
665
+ <label className={styles.fi__label}>
666
+ <input type="time" />
667
+ <span className={styles.fi__span}>
668
+ {field.label}{' '}
669
+ {field.required === 'yes' ? '*' : null}
670
+ </span>
671
+ </label>
672
+ );
673
+ case 'toggle':
674
+ return (
675
+ <div>
676
+ <Toggle />
677
+ <span className={styles.fi__toggletxt}>
678
+ {field.label}{' '}
679
+ {field.required === 'yes' ? '*' : null}
680
+ </span>
681
+ </div>
682
+ );
683
+ default:
684
+ return (
685
+ <label className={styles.fi__label}>
686
+ <input type="text" />
687
+ <span className={styles.fi__span}>
688
+ {field.label}{' '}
689
+ {field.required === 'yes' ? '*' : null}
690
+ </span>
691
+ </label>
692
+ );
693
+ }
694
+ };
695
+
696
+ const handleCloseModalForm = () => {
697
+ setModalFormShow(false);
698
+ };
699
+
700
+ const handleOpenModalForm = () => {
701
+ setModalFormShow(true);
702
+ };
703
+
704
+ const handleChange = (e) => {
705
+ if (e) {
706
+ const { name, value } = e.target;
707
+
708
+ setData((prevState) => ({
709
+ ...prevState,
710
+ [name]: value,
711
+ }));
712
+ }
713
+ };
714
+
715
+ const handleSubmit = async (e) => {
716
+ try {
717
+ if (e) {
718
+ e.preventDefault();
719
+
720
+ let _error = '';
721
+
722
+ if (data.label === '') {
723
+ _error += 'Please a label for the form.<br />';
724
+ }
725
+
726
+ if (_error === '') {
727
+ const res = await CustomFetch(
728
+ `${fetchUrl}/${dataId}`,
729
+ 'PUT',
730
+ {
731
+ ...data,
732
+ }
733
+ );
734
+
735
+ if (res.data.error === '') {
736
+ toast.success(
737
+ "You have successfully updated the form's detail."
738
+ );
739
+
740
+ handleCloseModalForm();
741
+ } else {
742
+ toast.error(String(res.data.error));
743
+ }
744
+ } else {
745
+ toast.error(<div>{parse(_error)}</div>);
746
+ }
747
+ }
748
+ } catch (err) {
749
+ toast.error(`Error: ${err}`);
750
+ }
751
+ };
752
+
753
+ const fetchData = async () => {
754
+ try {
755
+ const res = await CustomFetch(
756
+ `${fetchUrl}/${routeParams[urlParam]}`,
757
+ 'GET',
758
+ {}
759
+ );
760
+
761
+ setData(res.data);
762
+ } catch (err) {
763
+ toast.error(`Error: ${err}`);
764
+ }
765
+ };
766
+
767
+ const saveOnSort = async () => {
768
+ try {
769
+ const res = await CustomFetch(
770
+ `${fetchUrl}/sort/${dataId}`,
771
+ 'POST',
772
+ {
773
+ detail: data.detail,
774
+ }
775
+ );
776
+
777
+ if (res.data.error !== '') {
778
+ toast.error(String(res.data.error));
779
+ }
780
+ } catch (err) {
781
+ toast.error(`Error: ${err}`);
782
+ }
783
+ };
784
+
785
+ const fetchRoles = async () => {
786
+ try {
787
+ const res = await CustomFetch('/ajax/roles/dropdown', 'POST', {});
788
+
789
+ setRoles(res.data.data);
790
+ } catch (err) {
791
+ console.info(err);
792
+ }
793
+ };
794
+
795
+ useEffect(() => {
796
+ if (data.detail && data.detail.length > 0) {
797
+ saveOnSort();
798
+ }
799
+ }, [data.detail]);
800
+
801
+ useEffect(() => {
802
+ fetchData();
803
+ fetchRoles();
804
+ }, []);
805
+
806
+ return (
807
+ <div>
808
+ <div className={styles.grid__row}>
809
+ <div className={`${styles.grid__full} ${styles.crmtitle}`}>
810
+ <Breadcrumb
811
+ data={data}
812
+ page={{
813
+ previousUrl: parentUrl,
814
+ title: 'Forms',
815
+ titleKey: 'label',
816
+ }}
817
+ />
818
+ </div>
819
+ </div>
820
+ <div className={styles.grid}>
821
+ <div className={styles.grid__subrow}>
822
+ <div className={styles.grid__subnav}>
823
+ {data.detail && data.detail.length > 0 ? (
824
+ <SortableList
825
+ handleClick={handleEdit}
826
+ handleDelete={handleDeleteField}
827
+ items={data.detail}
828
+ onSortEnd={onSortEnd}
829
+ axis="xy"
830
+ helperClass={styles.dragitem}
831
+ transitionDuration={250}
832
+ showImage={false}
833
+ useDragHandle
834
+ />
835
+ ) : null}
836
+ </div>
837
+ <div className={styles.grid__subcontent}>
838
+ <div className={styles.formSplit}>
839
+ <div className={styles.gridtxt__header}>
840
+ <span>{formTitle ? formTitle : null}</span>
841
+ </div>
842
+ {data.detail && data.detail.length > 0 ? (
843
+ <div className={styles.modal__content}>
844
+ <div className={styles.formcontainer}>
845
+ <form className={styles.modalForm}>
846
+ {data.detail.map((a, b) => (
847
+ <div
848
+ key={`form-preview-field-${b}`}
849
+ className={renderClassName(
850
+ a
851
+ )}
852
+ style={{
853
+ minHeight: '64.2px',
854
+ }}
855
+ >
856
+ {renderField(a)}
857
+ </div>
858
+ ))}
859
+ </form>
860
+ </div>
861
+ </div>
862
+ ) : null}
863
+ </div>
864
+ <div className={styles.polActions}>
865
+ <button
866
+ className={styles.btn}
867
+ onClick={handleOpenModal}
868
+ >
869
+ Add Field
870
+ </button>
871
+ <button
872
+ className={styles.btn}
873
+ onClick={handleOpenModalForm}
874
+ >
875
+ Edit Form
876
+ </button>
877
+ </div>
878
+ </div>
879
+ </div>
880
+ </div>
881
+
882
+ <Popup
883
+ open={modalShow}
884
+ onClose={handleCloseModal}
885
+ closeOnDocumentClick={false}
886
+ >
887
+ <div className={styles.modalwrap}>
888
+ <div className={styles.modal}>
889
+ <div className={styles.modal__header}>
890
+ <h1>
891
+ {modalType.type === 'create'
892
+ ? 'Add new Field'
893
+ : 'Update existing Field'}
894
+ </h1>
895
+ <button
896
+ className={styles.modal__close}
897
+ onClick={handleCloseModal}
898
+ >
899
+ <CircleX strokeWidth={1} size={24} />
900
+ </button>
901
+ </div>
902
+ <div className={styles.modal__content}>
903
+ <div className={styles.formcontainer}>
904
+ <form className={styles.modalForm}>
905
+ <div className={styles.formItem}>
906
+ <label className={styles.fi__label}>
907
+ <select
908
+ name="type"
909
+ value={dataField.type}
910
+ onChange={handleChangeForm}
911
+ >
912
+ <option>
913
+ Please Select an Option
914
+ </option>
915
+ {fieldTypes.map(
916
+ (item, itemKey) => (
917
+ <option
918
+ value={item.value}
919
+ key={`${item.value}-${itemKey}`}
920
+ >
921
+ {item.label}
922
+ </option>
923
+ )
924
+ )}
925
+ </select>
926
+ <span className={styles.fi__span}>
927
+ Type *
928
+ </span>
929
+ </label>
930
+ </div>
931
+ <div className={styles.formItem}>
932
+ <label className={styles.fi__label}>
933
+ <input
934
+ type="text"
935
+ name="label"
936
+ value={
937
+ dataField.label
938
+ ? dataField.label
939
+ : ''
940
+ }
941
+ onChange={handleChangeForm}
942
+ placeholder=" "
943
+ />
944
+ <span className={styles.fi__span}>
945
+ Label *
946
+ </span>
947
+ </label>
948
+ </div>
949
+ {dataField.type === 'dynamicdata' && (
950
+ <div className={styles.formItem}>
951
+ <label className={styles.fi__label}>
952
+ <select
953
+ name="dynamicfield"
954
+ value={
955
+ dataField.dynamicfield
956
+ }
957
+ onChange={handleChangeForm}
958
+ >
959
+ <option value="">
960
+ Please select an option
961
+ </option>
962
+ {fields.map((category) => (
963
+ <optgroup
964
+ label={
965
+ category.label
966
+ }
967
+ key={`dynamic-field-category-${category.id}`}
968
+ >
969
+ {category.data.map(
970
+ (field) => (
971
+ <option
972
+ value={`${category.id}::${field.value}`}
973
+ key={`dynamic-field-category-${category.id}-${field.value}`}
974
+ >
975
+ {
976
+ field.label
977
+ }
978
+ </option>
979
+ )
980
+ )}
981
+ </optgroup>
982
+ ))}
983
+ </select>
984
+ <span
985
+ className={styles.fi__span}
986
+ >
987
+ Dynamic Field *
988
+ </span>
989
+ </label>
990
+ </div>
991
+ )}
992
+ {dataField.type === 'dynamicDropdown' && (
993
+ <div className={styles.formItem}>
994
+ <label className={styles.fi__label}>
995
+ <select
996
+ name="dynamicDropdown"
997
+ value={
998
+ dataField.dynamicDropdown
999
+ }
1000
+ onChange={handleChangeForm}
1001
+ >
1002
+ <option value="">
1003
+ Please select an option
1004
+ </option>
1005
+ {dynamicDropdowns.map(
1006
+ (
1007
+ dropdown,
1008
+ dropdownKey
1009
+ ) => (
1010
+ <option
1011
+ value={`${dropdown.url}`}
1012
+ key={`dynamic-dropdown-${dropdownKey}`}
1013
+ >
1014
+ {dropdown.label}
1015
+ </option>
1016
+ )
1017
+ )}
1018
+ </select>
1019
+ <span
1020
+ className={styles.fi__span}
1021
+ >
1022
+ Dropdown *
1023
+ </span>
1024
+ </label>
1025
+ </div>
1026
+ )}
1027
+
1028
+ <div className={styles.formItem}>
1029
+ <label className={styles.fi__label}>
1030
+ <select
1031
+ name="size"
1032
+ value={dataField.size}
1033
+ onChange={handleChangeForm}
1034
+ >
1035
+ <option>
1036
+ Please Select an Option
1037
+ </option>
1038
+ <option value="quarter">
1039
+ Quarter
1040
+ </option>
1041
+ <option value="half">
1042
+ Half
1043
+ </option>
1044
+ <option value="full">
1045
+ Full
1046
+ </option>
1047
+ </select>
1048
+ <span className={styles.fi__span}>
1049
+ Size *
1050
+ </span>
1051
+ </label>
1052
+ </div>
1053
+ <div className={styles.formItem}>
1054
+ <label className={styles.fi__label}>
1055
+ <select
1056
+ name="required"
1057
+ value={dataField.required}
1058
+ onChange={handleChangeForm}
1059
+ >
1060
+ {dataField.type ===
1061
+ 'section' ? (
1062
+ <option value="no">
1063
+ No
1064
+ </option>
1065
+ ) : (
1066
+ <>
1067
+ <option>
1068
+ Please Select an
1069
+ Option
1070
+ </option>
1071
+ <option value="no">
1072
+ No
1073
+ </option>
1074
+ <option value="yes">
1075
+ Yes
1076
+ </option>
1077
+ </>
1078
+ )}
1079
+ </select>
1080
+ <span className={styles.fi__span}>
1081
+ Required? *
1082
+ </span>
1083
+ </label>
1084
+ </div>
1085
+
1086
+ {dataField.type === 'image' && (
1087
+ <div className={styles.formItem}>
1088
+ <label className={styles.fi__label}>
1089
+ <select
1090
+ name="image_qty"
1091
+ value={dataField.image_qty}
1092
+ onChange={handleChangeForm}
1093
+ >
1094
+ <option>
1095
+ Please Select an Option
1096
+ </option>
1097
+ <option value="single">
1098
+ Single
1099
+ </option>
1100
+ <option value="bulk">
1101
+ Bulk
1102
+ </option>
1103
+ </select>
1104
+ <span
1105
+ className={styles.fi__span}
1106
+ >
1107
+ Single or Bulk Image?
1108
+ </span>
1109
+ </label>
1110
+ </div>
1111
+ )}
1112
+
1113
+ {dataField.type === 'plaintext' && (
1114
+ <div
1115
+ className={`${styles.formItem} ${styles.fwItem}`}
1116
+ >
1117
+ <label className={styles.fi__label}>
1118
+ <Editor
1119
+ tinymceScriptSrc="https://d16lktya8ojp5z.cloudfront.net/generic/packages/tinymce_v701/tinymce.min.js"
1120
+ licenseKey="gpl"
1121
+ onEditorChange={(
1122
+ value,
1123
+ e
1124
+ ) => {
1125
+ handleChangeFormRichEditor(
1126
+ e,
1127
+ value,
1128
+ 'description'
1129
+ );
1130
+ }}
1131
+ onInit={(evt, editor) =>
1132
+ (editorRef.current =
1133
+ editor)
1134
+ }
1135
+ value={
1136
+ dataField.description ||
1137
+ ''
1138
+ }
1139
+ init={{
1140
+ branding: false,
1141
+ height: 500,
1142
+ menubar: false,
1143
+ plugins: [
1144
+ 'advlist',
1145
+ 'autolink',
1146
+ 'lists',
1147
+ 'link',
1148
+ 'image',
1149
+ 'charmap',
1150
+ 'preview',
1151
+ 'anchor',
1152
+ 'searchreplace',
1153
+ 'visualblocks',
1154
+ 'code',
1155
+ 'fullscreen',
1156
+ 'insertdatetime',
1157
+ 'media',
1158
+ 'table',
1159
+ 'code',
1160
+ ],
1161
+ toolbar:
1162
+ 'undo redo | blocks | ' +
1163
+ 'bold italic forecolor | alignleft aligncenter ' +
1164
+ 'alignright alignjustify | bullist numlist outdent indent | ' +
1165
+ 'removeformat | table',
1166
+ content_style:
1167
+ 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }',
1168
+ }}
1169
+ />
1170
+ <span
1171
+ className={styles.fi__span}
1172
+ >
1173
+ Description *
1174
+ </span>
1175
+ </label>
1176
+ </div>
1177
+ )}
1178
+
1179
+ {[
1180
+ 'checkbox',
1181
+ 'dropdown',
1182
+ 'table_radio',
1183
+ ].includes(dataField.type) ? (
1184
+ <div
1185
+ className={`${styles.formItem} ${styles.fwItem}`}
1186
+ >
1187
+ <table
1188
+ className={styles.contentTable}
1189
+ >
1190
+ <thead
1191
+ className={
1192
+ styles.gridHeaders
1193
+ }
1194
+ >
1195
+ <tr>
1196
+ <th
1197
+ style={{
1198
+ width: '450px',
1199
+ }}
1200
+ >
1201
+ {dataField.type ===
1202
+ 'table_text' ||
1203
+ dataField.type ===
1204
+ 'table_radio'
1205
+ ? 'Column Header'
1206
+ : 'Label'}
1207
+ </th>
1208
+ <th></th>
1209
+ </tr>
1210
+ </thead>
1211
+ <tbody>
1212
+ {dataField.options.length >
1213
+ 0 ? (
1214
+ dataField.options.map(
1215
+ (
1216
+ option,
1217
+ optionKey
1218
+ ) => (
1219
+ <tr
1220
+ key={`option-${optionKey}`}
1221
+ >
1222
+ <td>
1223
+ <input
1224
+ type="text"
1225
+ value={
1226
+ option.label
1227
+ }
1228
+ onChange={(
1229
+ e
1230
+ ) => {
1231
+ const newOptions =
1232
+ [
1233
+ ...dataField.options,
1234
+ ];
1235
+ newOptions[
1236
+ optionKey
1237
+ ].label =
1238
+ e.target.value;
1239
+ setDataField(
1240
+ (
1241
+ items
1242
+ ) => ({
1243
+ ...items,
1244
+ options:
1245
+ newOptions,
1246
+ })
1247
+ );
1248
+ }}
1249
+ />
1250
+ </td>
1251
+ <td
1252
+ style={{
1253
+ textAlign:
1254
+ 'center',
1255
+ }}
1256
+ >
1257
+ <button
1258
+ className={
1259
+ styles.btn
1260
+ }
1261
+ style={{
1262
+ padding:
1263
+ '5px 20px',
1264
+ }}
1265
+ onClick={
1266
+ handleDeleteOption
1267
+ }
1268
+ data-counter={
1269
+ optionKey
1270
+ }
1271
+ data-tooltip-id="system-tooltip"
1272
+ data-tooltip-content={
1273
+ 'Delete Option'
1274
+ }
1275
+ >
1276
+ <TrashCan
1277
+ strokeWidth={
1278
+ 2
1279
+ }
1280
+ size={
1281
+ 12
1282
+ }
1283
+ />
1284
+ </button>
1285
+ </td>
1286
+ </tr>
1287
+ )
1288
+ )
1289
+ ) : (
1290
+ <tr>
1291
+ <td colSpan="2">
1292
+ No entry have
1293
+ been added.
1294
+ </td>
1295
+ </tr>
1296
+ )}
1297
+ </tbody>
1298
+ <tfoot>
1299
+ <tr>
1300
+ <td>
1301
+ <input
1302
+ type="text"
1303
+ style={{
1304
+ padding:
1305
+ '5px',
1306
+ height: '52px',
1307
+ padding:
1308
+ '1rem',
1309
+ }}
1310
+ name="label"
1311
+ onChange={
1312
+ handleDataOption
1313
+ }
1314
+ value={
1315
+ dataOption.label
1316
+ }
1317
+ placeholder="Column Header"
1318
+ />
1319
+ </td>
1320
+ <td
1321
+ style={{
1322
+ textAlign:
1323
+ 'center',
1324
+ }}
1325
+ >
1326
+ <button
1327
+ className={
1328
+ styles.btn
1329
+ }
1330
+ style={{
1331
+ padding:
1332
+ '5px 20px',
1333
+ }}
1334
+ onClick={
1335
+ handleAddOption
1336
+ }
1337
+ data-tooltip-id="system-tooltip"
1338
+ data-tooltip-content={
1339
+ 'Add Option'
1340
+ }
1341
+ >
1342
+ <CirclePlus
1343
+ strokeWidth={
1344
+ 2
1345
+ }
1346
+ size={12}
1347
+ />
1348
+ </button>
1349
+ </td>
1350
+ </tr>
1351
+ </tfoot>
1352
+ </table>
1353
+ </div>
1354
+ ) : null}
1355
+
1356
+ {['table_text'].includes(dataField.type) ? (
1357
+ <div
1358
+ className={`${styles.formItem} ${styles.fwItem}`}
1359
+ >
1360
+ <table
1361
+ className={styles.contentTable}
1362
+ >
1363
+ <thead
1364
+ className={
1365
+ styles.gridHeaders
1366
+ }
1367
+ >
1368
+ <tr>
1369
+ <th
1370
+ style={{
1371
+ width: '450px',
1372
+ }}
1373
+ >
1374
+ Column Header
1375
+ </th>
1376
+ <th>Column Type</th>
1377
+ <th></th>
1378
+ </tr>
1379
+ </thead>
1380
+ <tbody>
1381
+ {dataField.options.length >
1382
+ 0 ? (
1383
+ dataField.options.map(
1384
+ (
1385
+ option,
1386
+ optionKey
1387
+ ) => (
1388
+ <tr
1389
+ key={`option-${optionKey}`}
1390
+ >
1391
+ <td>
1392
+ <input
1393
+ type="text"
1394
+ value={
1395
+ option.label
1396
+ }
1397
+ onChange={(
1398
+ e
1399
+ ) => {
1400
+ const newOptions =
1401
+ [
1402
+ ...dataField.options,
1403
+ ];
1404
+ newOptions[
1405
+ optionKey
1406
+ ].label =
1407
+ e.target.value;
1408
+ setDataField(
1409
+ (
1410
+ items
1411
+ ) => ({
1412
+ ...items,
1413
+ options:
1414
+ newOptions,
1415
+ })
1416
+ );
1417
+ }}
1418
+ />
1419
+ </td>
1420
+ <td>
1421
+ <select
1422
+ value={
1423
+ option.type
1424
+ }
1425
+ onChange={(
1426
+ e
1427
+ ) => {
1428
+ const newOptions =
1429
+ [
1430
+ ...dataField.options,
1431
+ ];
1432
+ newOptions[
1433
+ optionKey
1434
+ ].type =
1435
+ e.target.value;
1436
+ setDataField(
1437
+ (
1438
+ items
1439
+ ) => ({
1440
+ ...items,
1441
+ options:
1442
+ newOptions,
1443
+ })
1444
+ );
1445
+ }}
1446
+ >
1447
+ {fieldTypes
1448
+ .filter(
1449
+ (
1450
+ item
1451
+ ) =>
1452
+ ![
1453
+ 'checkbox',
1454
+ 'dropdown',
1455
+ 'dynamicdata',
1456
+ 'signature',
1457
+ 'table',
1458
+ ].some(
1459
+ (
1460
+ keyword
1461
+ ) =>
1462
+ item.value.includes(
1463
+ keyword
1464
+ )
1465
+ )
1466
+ )
1467
+ .map(
1468
+ (
1469
+ item,
1470
+ itemKey
1471
+ ) => (
1472
+ <option
1473
+ value={
1474
+ item.value
1475
+ }
1476
+ key={`type-form-${item.value}-${itemKey}`}
1477
+ >
1478
+ {
1479
+ item.label
1480
+ }
1481
+ </option>
1482
+ )
1483
+ )}
1484
+ </select>
1485
+ </td>
1486
+ <td
1487
+ style={{
1488
+ textAlign:
1489
+ 'center',
1490
+ }}
1491
+ >
1492
+ <button
1493
+ className={
1494
+ styles.btn
1495
+ }
1496
+ style={{
1497
+ padding:
1498
+ '5px 20px',
1499
+ }}
1500
+ onClick={
1501
+ handleDeleteOption
1502
+ }
1503
+ data-counter={
1504
+ optionKey
1505
+ }
1506
+ data-tooltip-id="system-tooltip"
1507
+ data-tooltip-content={
1508
+ 'Delete Option'
1509
+ }
1510
+ >
1511
+ <TrashCan
1512
+ strokeWidth={
1513
+ 2
1514
+ }
1515
+ size={
1516
+ 12
1517
+ }
1518
+ />
1519
+ </button>
1520
+ </td>
1521
+ </tr>
1522
+ )
1523
+ )
1524
+ ) : (
1525
+ <tr>
1526
+ <td colSpan="3">
1527
+ No entry has
1528
+ been added.
1529
+ </td>
1530
+ </tr>
1531
+ )}
1532
+ </tbody>
1533
+ <tfoot>
1534
+ <tr>
1535
+ <td>
1536
+ <input
1537
+ type="text"
1538
+ style={{
1539
+ padding:
1540
+ '5px',
1541
+ height: '52px',
1542
+ padding:
1543
+ '1rem',
1544
+ }}
1545
+ name="label"
1546
+ onChange={
1547
+ handleDataOption
1548
+ }
1549
+ value={
1550
+ dataOption.label
1551
+ }
1552
+ placeholder="Column Header"
1553
+ />
1554
+ </td>
1555
+ <td>
1556
+ <select
1557
+ name="type"
1558
+ value={
1559
+ dataOption.type
1560
+ }
1561
+ onChange={
1562
+ handleDataOption
1563
+ }
1564
+ >
1565
+ <option>
1566
+ Please
1567
+ Select an
1568
+ Option
1569
+ </option>
1570
+ {fieldTypes
1571
+ .filter(
1572
+ (
1573
+ item
1574
+ ) =>
1575
+ ![
1576
+ 'checkbox',
1577
+ 'dropdown',
1578
+ 'dynamicdata',
1579
+ 'signature',
1580
+ 'table',
1581
+ ].some(
1582
+ (
1583
+ keyword
1584
+ ) =>
1585
+ item.value.includes(
1586
+ keyword
1587
+ )
1588
+ )
1589
+ )
1590
+ .map(
1591
+ (
1592
+ item,
1593
+ itemKey
1594
+ ) => (
1595
+ <option
1596
+ value={
1597
+ item.value
1598
+ }
1599
+ key={`type-${item.value}-${itemKey}`}
1600
+ >
1601
+ {
1602
+ item.label
1603
+ }
1604
+ </option>
1605
+ )
1606
+ )}
1607
+ </select>
1608
+ </td>
1609
+ <td
1610
+ style={{
1611
+ textAlign:
1612
+ 'center',
1613
+ }}
1614
+ >
1615
+ <button
1616
+ className={
1617
+ styles.btn
1618
+ }
1619
+ style={{
1620
+ padding:
1621
+ '5px 20px',
1622
+ }}
1623
+ onClick={
1624
+ handleAddOption
1625
+ }
1626
+ data-tooltip-id="system-tooltip"
1627
+ data-tooltip-content={
1628
+ 'Add Option'
1629
+ }
1630
+ >
1631
+ <CirclePlus
1632
+ strokeWidth={
1633
+ 2
1634
+ }
1635
+ size={12}
1636
+ />
1637
+ </button>
1638
+ </td>
1639
+ </tr>
1640
+ </tfoot>
1641
+ </table>
1642
+ </div>
1643
+ ) : null}
1644
+
1645
+ {['signature'].includes(dataField.type) ? (
1646
+ <div className={styles.formItem}>
1647
+ <label className={styles.fi__label}>
1648
+ <select
1649
+ name="role"
1650
+ value={dataField.role}
1651
+ onChange={handleChangeForm}
1652
+ >
1653
+ <option>
1654
+ No Role Associated
1655
+ </option>
1656
+ {roles.map(
1657
+ (role, roleKey) => (
1658
+ <option
1659
+ value={role.id}
1660
+ key={roleKey}
1661
+ >
1662
+ {role.label}
1663
+ </option>
1664
+ )
1665
+ )}
1666
+ </select>
1667
+ <span
1668
+ className={styles.fi__span}
1669
+ >
1670
+ Single or Bulk Image?
1671
+ </span>
1672
+ </label>
1673
+ </div>
1674
+ ) : null}
1675
+
1676
+ {['table_radio'].includes(
1677
+ dataField.type
1678
+ ) ? (
1679
+ <div
1680
+ className={`${styles.formItem} ${styles.fwItem}`}
1681
+ >
1682
+ <table
1683
+ className={styles.contentTable}
1684
+ >
1685
+ <thead
1686
+ className={
1687
+ styles.gridHeaders
1688
+ }
1689
+ >
1690
+ <tr>
1691
+ <th
1692
+ style={{
1693
+ width: '450px',
1694
+ }}
1695
+ >
1696
+ Row Label
1697
+ </th>
1698
+ <th></th>
1699
+ </tr>
1700
+ </thead>
1701
+ <tbody>
1702
+ {dataField.rows?.length >
1703
+ 0 ? (
1704
+ dataField.rows.map(
1705
+ (row, rowKey) => (
1706
+ <tr
1707
+ key={`row-${rowKey}`}
1708
+ >
1709
+ <td>
1710
+ <input
1711
+ type="text"
1712
+ value={
1713
+ row.label
1714
+ }
1715
+ onChange={(
1716
+ e
1717
+ ) => {
1718
+ const newRows =
1719
+ [
1720
+ ...dataField.rows,
1721
+ ];
1722
+ newRows[
1723
+ rowKey
1724
+ ].label =
1725
+ e.target.value;
1726
+ setDataField(
1727
+ (
1728
+ items
1729
+ ) => ({
1730
+ ...items,
1731
+ rows: newRows,
1732
+ })
1733
+ );
1734
+ }}
1735
+ />
1736
+ </td>
1737
+ <td
1738
+ style={{
1739
+ textAlign:
1740
+ 'center',
1741
+ }}
1742
+ >
1743
+ <button
1744
+ className={
1745
+ styles.btn
1746
+ }
1747
+ style={{
1748
+ padding:
1749
+ '5px 20px',
1750
+ }}
1751
+ onClick={
1752
+ handleDeleteRowOption
1753
+ }
1754
+ data-counter={
1755
+ rowKey
1756
+ }
1757
+ data-tooltip-id="system-tooltip"
1758
+ data-tooltip-content={
1759
+ 'Delete Option'
1760
+ }
1761
+ >
1762
+ <TrashCan
1763
+ strokeWidth={
1764
+ 2
1765
+ }
1766
+ size={
1767
+ 12
1768
+ }
1769
+ />
1770
+ </button>
1771
+ </td>
1772
+ </tr>
1773
+ )
1774
+ )
1775
+ ) : (
1776
+ <tr>
1777
+ <td colSpan="2">
1778
+ No entry has
1779
+ been added.
1780
+ </td>
1781
+ </tr>
1782
+ )}
1783
+ </tbody>
1784
+ <tfoot>
1785
+ <tr>
1786
+ <td>
1787
+ <input
1788
+ type="text"
1789
+ style={{
1790
+ padding:
1791
+ '5px',
1792
+ }}
1793
+ name="label"
1794
+ onChange={
1795
+ handleRowOption
1796
+ }
1797
+ value={
1798
+ rowOption.label
1799
+ }
1800
+ />
1801
+ </td>
1802
+ <td
1803
+ style={{
1804
+ textAlign:
1805
+ 'center',
1806
+ }}
1807
+ >
1808
+ <button
1809
+ className={
1810
+ styles.btn
1811
+ }
1812
+ style={{
1813
+ padding:
1814
+ '5px 20px',
1815
+ }}
1816
+ onClick={
1817
+ handleAddRowOption
1818
+ }
1819
+ data-tooltip-id="system-tooltip"
1820
+ data-tooltip-content={
1821
+ 'Add Option'
1822
+ }
1823
+ >
1824
+ <CirclePlus
1825
+ strokeWidth={
1826
+ 2
1827
+ }
1828
+ size={12}
1829
+ />
1830
+ </button>
1831
+ </td>
1832
+ </tr>
1833
+ </tfoot>
1834
+ </table>
1835
+ </div>
1836
+ ) : null}
1837
+
1838
+ <div
1839
+ className={`${styles.formItem} ${styles.fwItem} ${styles.lastItem}`}
1840
+ >
1841
+ <button
1842
+ className={`${styles.btn}`}
1843
+ onClick={handleSaveField}
1844
+ >
1845
+ Save
1846
+ </button>
1847
+ </div>
1848
+ </form>
1849
+ </div>
1850
+ </div>
1851
+ </div>
1852
+ </div>
1853
+ </Popup>
1854
+
1855
+ <Popup
1856
+ open={modalFormShow}
1857
+ onClose={handleCloseModalForm}
1858
+ closeOnDocumentClick={false}
1859
+ >
1860
+ <div className={styles.modalwrap}>
1861
+ <div className={styles.modal}>
1862
+ <div className={styles.modal__header}>
1863
+ <h1>Update Form Detail</h1>
1864
+ <button
1865
+ className={styles.modal__close}
1866
+ onClick={handleCloseModalForm}
1867
+ >
1868
+ <CircleX strokeWidth={1} size={24} />
1869
+ </button>
1870
+ </div>
1871
+ <div className={styles.modal__content}>
1872
+ <div className={styles.formcontainer}>
1873
+ <form className={styles.modalForm}>
1874
+ <div className={styles.formItem}>
1875
+ <label className={styles.fi__label}>
1876
+ <input
1877
+ type="text"
1878
+ name="label"
1879
+ value={
1880
+ data.label ? data.label : ''
1881
+ }
1882
+ onChange={handleChange}
1883
+ />
1884
+ <span className={styles.fi__span}>
1885
+ Label *
1886
+ </span>
1887
+ </label>
1888
+ </div>
1889
+ <div
1890
+ className={`${styles.formItem} ${styles.fwItem} ${styles.lastItem}`}
1891
+ >
1892
+ <button
1893
+ className={`${styles.btn}`}
1894
+ onClick={handleSubmit}
1895
+ >
1896
+ Save
1897
+ </button>
1898
+ </div>
1899
+ </form>
1900
+ </div>
1901
+ </div>
1902
+ </div>
1903
+ </div>
1904
+ </Popup>
1905
+ </div>
1906
+ );
1907
+ }
1908
+
1909
+ export default GenericFormBuilder;