@visns-studio/visns-components 3.4.12 → 3.5.0

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.
@@ -0,0 +1,1013 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { useParams, Link } 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 CustomFetch from '../Fetch';
18
+ import SortableList from '../../../components/cms/sorting/List';
19
+
20
+ function GenericFormBuilder({ setting, urlParam, userProfile }) {
21
+ const editorRef = useRef(null);
22
+ const routeParams = useParams();
23
+
24
+ const { fetchUrl, fields } = setting;
25
+
26
+ const { dataId } = useParams();
27
+ const [data, setData] = useState({});
28
+ const [dataField, setDataField] = useState({
29
+ id: '',
30
+ label: '',
31
+ description: '',
32
+ type: '',
33
+ options: [],
34
+ size: 'half',
35
+ required: 'no',
36
+ });
37
+ const [dataOption, setDataOption] = useState({
38
+ id: '',
39
+ label: '',
40
+ });
41
+ const [modalShow, setModalShow] = useState(false);
42
+ const [modalType, setModalType] = useState({
43
+ type: 'create',
44
+ key: '',
45
+ });
46
+ const [modalFormShow, setModalFormShow] = useState(false);
47
+
48
+ /** Data Option Functionalities */
49
+ const handleDataOption = (e) => {
50
+ const { name, value } = e.target;
51
+
52
+ setDataOption((items) => ({
53
+ ...items,
54
+ [name]: value,
55
+ id: `${slugify(value)}-`,
56
+ }));
57
+ };
58
+
59
+ const handleAddOption = (e) => {
60
+ e.preventDefault();
61
+
62
+ if (dataOption.label !== '') {
63
+ // Check if the label is already present in the options array
64
+ const isLabelUnique = !dataField.options.some(
65
+ (option) => option.label === dataOption.label
66
+ );
67
+
68
+ if (isLabelUnique) {
69
+ setDataField((items) => ({
70
+ ...items,
71
+ options: [...items.options, dataOption],
72
+ }));
73
+
74
+ setDataOption(() => ({
75
+ id: '',
76
+ label: '',
77
+ }));
78
+ } else {
79
+ toast.warn('Option label must be unique.');
80
+ }
81
+ } else {
82
+ toast.warn('Please enter a label for the option.');
83
+ }
84
+ };
85
+
86
+ const handleDeleteOption = (e) => {
87
+ e.preventDefault();
88
+
89
+ const { counter } = e.target.dataset;
90
+
91
+ setDataField((prevState) => {
92
+ const options = prevState.options.slice(); // Create a copy of the options array
93
+ options.splice(counter, 1); // Remove the option at the specified index
94
+
95
+ return {
96
+ ...prevState,
97
+ options: options, // Update the options array in the state
98
+ };
99
+ });
100
+ };
101
+
102
+ /** Field Functionalities */
103
+ const onSortEnd = ({ oldIndex, newIndex }) => {
104
+ const newData = arrayMoveImmutable(data.detail, oldIndex, newIndex);
105
+
106
+ setData((items) => ({
107
+ ...items,
108
+ detail: newData,
109
+ }));
110
+ };
111
+
112
+ const handleCloseModal = () => {
113
+ setModalShow(false);
114
+ setDataField(() => ({
115
+ label: '',
116
+ type: '',
117
+ options: [],
118
+ size: 'quarter',
119
+ required: 'no',
120
+ }));
121
+ setModalType(() => ({
122
+ type: 'create',
123
+ key: '',
124
+ }));
125
+ };
126
+
127
+ const handleOpenModal = () => {
128
+ setModalShow(true);
129
+ };
130
+
131
+ const slugify = (text) => {
132
+ // Implement your slugification logic here
133
+ // Example: Convert spaces to hyphens and lowercase the text
134
+ return text.replace(/\s+/g, '-').toLowerCase();
135
+ };
136
+
137
+ const handleChangeForm = (e) => {
138
+ if (e) {
139
+ const { name, value } = e.target;
140
+ const updatedValue = name === 'id' ? slugify(value) : value;
141
+
142
+ setDataField((items) => ({
143
+ ...items,
144
+ [name]: updatedValue,
145
+ }));
146
+
147
+ if (name === 'label') {
148
+ setDataField((items) => ({
149
+ ...items,
150
+ id: slugify(value),
151
+ }));
152
+ }
153
+ }
154
+ };
155
+
156
+ const handleChangeFormRichEditor = (e, value, name) => {
157
+ setDataField((items) => ({
158
+ ...items,
159
+ [name]: value,
160
+ }));
161
+ };
162
+
163
+ const handleEdit = (key) => {
164
+ const { detail } = data;
165
+
166
+ setDataField(() => ({
167
+ ...detail[key],
168
+ }));
169
+
170
+ setModalType(() => ({
171
+ type: 'update',
172
+ key: key,
173
+ }));
174
+
175
+ handleOpenModal();
176
+ };
177
+
178
+ const handleDeleteField = (key, label) => {
179
+ confirmAlert({
180
+ title: `Delete "${label}" Field`,
181
+ message: 'Are you sure you want to delete this field?',
182
+ buttons: [
183
+ {
184
+ label: 'Yes',
185
+ onClick: () => {
186
+ let newDetail = data.detail;
187
+ newDetail.splice(key, 1);
188
+
189
+ setData((items) => ({
190
+ ...items,
191
+ detail: [...newDetail],
192
+ }));
193
+
194
+ handleCloseModal();
195
+ },
196
+ },
197
+ {
198
+ label: 'No',
199
+ onClick: () => close(),
200
+ },
201
+ ],
202
+ });
203
+ };
204
+
205
+ const handleSaveField = (e) => {
206
+ if (e) {
207
+ e.preventDefault();
208
+ }
209
+
210
+ let field = dataField;
211
+
212
+ // Ensure the field ID is unique and formatted
213
+ field.id = formatFieldId(field.id);
214
+
215
+ let errorMessage = validateField(field);
216
+
217
+ if (errorMessage === '') {
218
+ saveFieldData(field);
219
+ handleCloseModal();
220
+ } else {
221
+ displayErrorMessage(errorMessage);
222
+ }
223
+ };
224
+
225
+ const formatFieldId = (id) => {
226
+ return id.includes('::') ? id : `${id}::${uuidv4()}`;
227
+ };
228
+
229
+ const validateField = (field) => {
230
+ let errors = [];
231
+
232
+ // Validate ID
233
+ if (!isIdValid(field.id)) {
234
+ errors.push('Please enter a unique id for the field.');
235
+ }
236
+
237
+ // Modify Validation for Label and Description based on Type
238
+ if (field.type === 'plaintext' || field.type === 'plaintextheading') {
239
+ // For plaintext or plaintextheading, description is required
240
+ if (!field.description || field.description === '') {
241
+ errors.push('Please enter a description for the field.');
242
+ }
243
+ } else {
244
+ // For other types, label is required
245
+ if (!field.label || field.label === '') {
246
+ errors.push('Please enter a label for the field.');
247
+ }
248
+ }
249
+
250
+ // Validate Type and Options for Dropdown
251
+ if (field.type === '') {
252
+ errors.push('Please select a type for the field.');
253
+ } else if (
254
+ field.type === 'dropdown' &&
255
+ (!field.options || field.options.length === 0)
256
+ ) {
257
+ errors.push('Please add options for the dropdown.');
258
+ }
259
+
260
+ // Validate Size
261
+ if (!field.size || field.size === '') {
262
+ errors.push('Please select a size for the field.');
263
+ }
264
+
265
+ // Validate Required
266
+ if (field.required === '') {
267
+ errors.push('Is the field a required field?');
268
+ }
269
+
270
+ return errors.join('<br />');
271
+ };
272
+
273
+ const isIdValid = (id) => {
274
+ if (id === '') {
275
+ return false;
276
+ }
277
+ if (
278
+ modalType.type === 'create' ||
279
+ id !== data.detail[modalType.key]?.id
280
+ ) {
281
+ return data.detail
282
+ ? data.detail.every((field) => field.id !== id)
283
+ : true;
284
+ }
285
+ return true;
286
+ };
287
+
288
+ const saveFieldData = (field) => {
289
+ let newDetail =
290
+ modalType.type === 'create'
291
+ ? [...(data.detail || []), field]
292
+ : data.detail.map((f, index) =>
293
+ index === modalType.key ? field : f
294
+ );
295
+
296
+ setData((items) => ({
297
+ ...items,
298
+ detail: newDetail,
299
+ }));
300
+ };
301
+
302
+ const displayErrorMessage = (errorMessage) => {
303
+ toast.error(<div>{parse(errorMessage)}</div>);
304
+ };
305
+
306
+ /** Form Functionalities */
307
+ const renderClassName = (d) => {
308
+ const sizeClassMap = {
309
+ full: 'formBuilderItem fwBuilderItem',
310
+ half: 'formBuilderItem halfBuilderItem',
311
+ quarter: 'formBuilderItem qtrBuilderItem',
312
+ };
313
+
314
+ return sizeClassMap[d.size] || 'formBuilderItem halfBuilderItem';
315
+ };
316
+
317
+ const renderLabel = (field, children) => (
318
+ <label className="fi__label">
319
+ {children}
320
+ <span
321
+ className={
322
+ field.type === 'checkbox' ? 'fi__spancheckbox' : 'fi__span'
323
+ }
324
+ >
325
+ {field.label} {field.required === 'yes' ? '*' : null}
326
+ </span>
327
+ </label>
328
+ );
329
+
330
+ const renderField = (field) => {
331
+ switch (field.type) {
332
+ case 'checkbox':
333
+ return renderLabel(
334
+ field,
335
+ field.options.length > 0 && (
336
+ <div className="fi__optionscontainer">
337
+ {field.options.map((option, index) => (
338
+ <div
339
+ key={`${field.id}-checkbox-option-${index}`}
340
+ className="fi__checkboxcontainer"
341
+ >
342
+ <input
343
+ type="checkbox"
344
+ className="fi__customcheckbox"
345
+ />
346
+ <label className="fi__checkboxlabel">
347
+ {option.label}
348
+ </label>{' '}
349
+ </div>
350
+ ))}
351
+ </div>
352
+ )
353
+ );
354
+ case 'dynamicdata':
355
+ return (
356
+ <label className="fi__label">
357
+ <strong>{field.label}</strong> [Dynamic Data]
358
+ </label>
359
+ );
360
+ case 'plaintextheading':
361
+ return (
362
+ <label className="fi__label">
363
+ <h2>{field.label}</h2>
364
+ </label>
365
+ );
366
+ case 'plaintext':
367
+ return (
368
+ <label className="fi__label">
369
+ {field.description ? parse(field.description) : null}
370
+ </label>
371
+ );
372
+ case 'toggle':
373
+ return (
374
+ <div>
375
+ <Toggle />
376
+ <span className="fi__toggletxt">
377
+ {field.label}{' '}
378
+ {field.required === 'yes' ? '*' : null}
379
+ </span>
380
+ </div>
381
+ );
382
+ default:
383
+ const inputType =
384
+ field.type === 'dropdown' ? (
385
+ <select>
386
+ <option>Please Select an Option</option>
387
+ </select>
388
+ ) : (
389
+ <input
390
+ type={
391
+ field.type === 'datetime'
392
+ ? 'datetime-local'
393
+ : field.type
394
+ }
395
+ />
396
+ );
397
+
398
+ return renderLabel(field, inputType);
399
+ }
400
+ };
401
+
402
+ const handleCloseModalForm = () => {
403
+ setModalFormShow(false);
404
+ };
405
+
406
+ const handleOpenModalForm = () => {
407
+ setModalFormShow(true);
408
+ };
409
+
410
+ const handleChange = (e) => {
411
+ if (e) {
412
+ const { name, value } = e.target;
413
+
414
+ setData((prevState) => ({
415
+ ...prevState,
416
+ [name]: value,
417
+ }));
418
+ }
419
+ };
420
+
421
+ const handleSubmit = async (e) => {
422
+ try {
423
+ if (e) {
424
+ e.preventDefault();
425
+
426
+ let _error = '';
427
+
428
+ if (data.label === '') {
429
+ _error += 'Please a label for the form.<br />';
430
+ }
431
+
432
+ if (_error === '') {
433
+ const res = await CustomFetch(
434
+ `/ajax/forms/${dataId}`,
435
+ 'PUT',
436
+ {
437
+ ...data,
438
+ }
439
+ );
440
+
441
+ if (res.data.error === '') {
442
+ toast.success(
443
+ "You have successfully updated the form's detail."
444
+ );
445
+
446
+ handleCloseModalForm();
447
+ } else {
448
+ toast.error(String(res.data.error));
449
+ }
450
+ } else {
451
+ toast.error(<div>{parse(_error)}</div>);
452
+ }
453
+ }
454
+ } catch (err) {
455
+ toast.error(`Error: ${err}`);
456
+ }
457
+ };
458
+
459
+ const fetchData = async () => {
460
+ try {
461
+ const res = await CustomFetch(
462
+ `${fetchUrl}/${routeParams[urlParam]}`,
463
+ 'GET',
464
+ {}
465
+ );
466
+
467
+ setData(res.data);
468
+ } catch (err) {
469
+ toast.error(`Error: ${err}`);
470
+ }
471
+ };
472
+
473
+ const saveOnSort = async () => {
474
+ try {
475
+ const res = await CustomFetch(
476
+ `/ajax/forms/sort/${dataId}`,
477
+ 'POST',
478
+ {
479
+ detail: data.detail,
480
+ }
481
+ );
482
+
483
+ if (res.data.error !== '') {
484
+ toast.error(String(res.data.error));
485
+ }
486
+ } catch (err) {
487
+ toast.error(`Error: ${err}`);
488
+ }
489
+ };
490
+
491
+ useEffect(() => {
492
+ if (data.detail && data.detail.length > 0) {
493
+ saveOnSort();
494
+ }
495
+ }, [data.detail]);
496
+
497
+ useEffect(() => {
498
+ fetchData();
499
+ }, []);
500
+
501
+ return (
502
+ <div>
503
+ <div className="grid">
504
+ <div className="grid__row">
505
+ <div className="grid__full crmtitle">
506
+ <h1>
507
+ <Link to="/forms">Form</Link>{' '}
508
+ <CircleChevronRight strokeWidth={2} size={18} />{' '}
509
+ {data.label}
510
+ </h1>
511
+ </div>
512
+ </div>
513
+ </div>
514
+ <div className="grid">
515
+ <div className="grid__subrow">
516
+ <div className="grid__subnav">
517
+ {data.detail && data.detail.length > 0 ? (
518
+ <SortableList
519
+ handleClick={handleEdit}
520
+ handleDelete={handleDeleteField}
521
+ items={data.detail}
522
+ onSortEnd={onSortEnd}
523
+ axis="xy"
524
+ helperClass="dragitem"
525
+ transitionDuration={250}
526
+ showImage={false}
527
+ useDragHandle
528
+ />
529
+ ) : null}
530
+ </div>
531
+ <div className="grid__subcontent">
532
+ <div className="formSplit">
533
+ <div className="gridtxt__header">
534
+ <span>Form Preview</span>
535
+ </div>
536
+ {data.detail && data.detail.length > 0 ? (
537
+ <div className="modal__content">
538
+ <div className="formcontainer">
539
+ <form className="modalForm">
540
+ {data.detail.map((a, b) => (
541
+ <div
542
+ key={`form-preview-field-${b}`}
543
+ className={renderClassName(
544
+ a
545
+ )}
546
+ >
547
+ {renderField(a)}
548
+ </div>
549
+ ))}
550
+ </form>
551
+ </div>
552
+ </div>
553
+ ) : null}
554
+ </div>
555
+ <div className="polActions">
556
+ <button className="btn" onClick={handleOpenModal}>
557
+ Add Field
558
+ </button>
559
+ <button
560
+ className="btn"
561
+ onClick={handleOpenModalForm}
562
+ >
563
+ Edit Form
564
+ </button>
565
+ </div>
566
+ </div>
567
+ </div>
568
+ </div>
569
+
570
+ <Popup
571
+ open={modalShow}
572
+ onClose={handleCloseModal}
573
+ closeOnDocumentClick={false}
574
+ >
575
+ <div className="modalwrap top--modal">
576
+ <div className="modal">
577
+ <div className="modal__header">
578
+ <h1>
579
+ {modalType.type === 'create'
580
+ ? 'Add new Field'
581
+ : 'Update existing Field'}
582
+ </h1>
583
+ <button
584
+ className="modal__close"
585
+ onClick={handleCloseModal}
586
+ >
587
+ <CircleX strokeWidth={1} size={24} />
588
+ </button>
589
+ </div>
590
+ <div className="modal__content">
591
+ <div className="formcontainer">
592
+ <form className="modalForm">
593
+ <div className="formItem">
594
+ <label className="fi__label">
595
+ <select
596
+ name="type"
597
+ value={dataField.type}
598
+ onChange={handleChangeForm}
599
+ >
600
+ <option>
601
+ Please Select an Option
602
+ </option>
603
+ <option value="checkbox">
604
+ Checkbox
605
+ </option>
606
+ <option value="date">
607
+ Date
608
+ </option>
609
+ <option value="datetime">
610
+ Date & Time
611
+ </option>
612
+ <option value="dropdown">
613
+ Dropdown
614
+ </option>
615
+ <option value="dynamicdata">
616
+ Dynamic Data
617
+ </option>
618
+ <option value="file">
619
+ File
620
+ </option>
621
+ <option value="plaintextheading">
622
+ Heading
623
+ </option>
624
+ <option value="image">
625
+ Image
626
+ </option>
627
+ <option value="number">
628
+ Number
629
+ </option>
630
+ <option value="plaintext">
631
+ Plain Text
632
+ </option>
633
+ <option value="text">
634
+ Text
635
+ </option>
636
+ <option value="textarea">
637
+ Textarea
638
+ </option>
639
+ <option value="time">
640
+ Time
641
+ </option>
642
+ <option value="toggle">
643
+ Toggle
644
+ </option>
645
+ </select>
646
+ <span className="fi__span">
647
+ Type *
648
+ </span>
649
+ </label>
650
+ </div>
651
+ <div className="formItem">
652
+ <label className="fi__label">
653
+ <input
654
+ type="text"
655
+ name="label"
656
+ value={
657
+ dataField.label
658
+ ? dataField.label
659
+ : ''
660
+ }
661
+ onChange={handleChangeForm}
662
+ />
663
+ <span className="fi__span">
664
+ Label *
665
+ </span>
666
+ </label>
667
+ </div>
668
+ {dataField.type === 'dynamicdata' && (
669
+ <div className="formItem fwItem">
670
+ <label className="fi__label">
671
+ <select
672
+ name="dynamicfield"
673
+ value={
674
+ dataField.dynamicfield
675
+ }
676
+ onChange={handleChangeForm}
677
+ >
678
+ <option value="">
679
+ Please select an option
680
+ </option>
681
+ {fields.map((category) => (
682
+ <optgroup
683
+ label={
684
+ category.label
685
+ }
686
+ key={`dynamic-field-category-${category.id}`}
687
+ >
688
+ {category.data.map(
689
+ (field) => (
690
+ <option
691
+ value={`${category.id}::${field.value}`}
692
+ key={`dynamic-field-category-${category.id}-${field.value}`}
693
+ >
694
+ {
695
+ field.label
696
+ }
697
+ </option>
698
+ )
699
+ )}
700
+ </optgroup>
701
+ ))}
702
+ </select>
703
+ <span className="fi__span">
704
+ Dynamic Field *
705
+ </span>
706
+ </label>
707
+ </div>
708
+ )}
709
+ <div className="formItem">
710
+ <label className="fi__label">
711
+ <select
712
+ name="size"
713
+ value={dataField.size}
714
+ onChange={handleChangeForm}
715
+ >
716
+ <option>
717
+ Please Select an Option
718
+ </option>
719
+ <option value="quarter">
720
+ Quarter
721
+ </option>
722
+ <option value="half">
723
+ Half
724
+ </option>
725
+ <option value="full">
726
+ Full
727
+ </option>
728
+ </select>
729
+ <span className="fi__span">
730
+ Size *
731
+ </span>
732
+ </label>
733
+ </div>
734
+ <div className="formItem">
735
+ <label className="fi__label">
736
+ <select
737
+ name="required"
738
+ value={dataField.required}
739
+ onChange={handleChangeForm}
740
+ >
741
+ <option>
742
+ Please Select an Option
743
+ </option>
744
+ <option value="no">No</option>
745
+ <option value="yes">Yes</option>
746
+ </select>
747
+ <span className="fi__span">
748
+ Required? *
749
+ </span>
750
+ </label>
751
+ </div>
752
+ {dataField.type === 'plaintext' && (
753
+ <div className="formItem fwItem">
754
+ <label className="fi__label">
755
+ <Editor
756
+ apiKey={
757
+ userProfile.settings.api
758
+ .tinymce
759
+ }
760
+ onEditorChange={(
761
+ value,
762
+ e
763
+ ) => {
764
+ handleChangeFormRichEditor(
765
+ e,
766
+ value,
767
+ 'description'
768
+ );
769
+ }}
770
+ onInit={(evt, editor) =>
771
+ (editorRef.current =
772
+ editor)
773
+ }
774
+ value={
775
+ dataField.description ||
776
+ ''
777
+ }
778
+ init={{
779
+ branding: false,
780
+ height: 500,
781
+ menubar: false,
782
+ plugins: [
783
+ 'advlist',
784
+ 'autolink',
785
+ 'lists',
786
+ 'link',
787
+ 'image',
788
+ 'charmap',
789
+ 'preview',
790
+ 'anchor',
791
+ 'searchreplace',
792
+ 'visualblocks',
793
+ 'code',
794
+ 'fullscreen',
795
+ 'insertdatetime',
796
+ 'media',
797
+ 'table',
798
+ 'code',
799
+ ],
800
+ toolbar:
801
+ 'undo redo | blocks | ' +
802
+ 'bold italic forecolor | alignleft aligncenter ' +
803
+ 'alignright alignjustify | bullist numlist outdent indent | ' +
804
+ 'removeformat | table',
805
+ content_style:
806
+ 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }',
807
+ }}
808
+ />
809
+ <span className="fi__span prefocus">
810
+ Description
811
+ </span>
812
+ </label>
813
+ </div>
814
+ )}
815
+
816
+ {dataField.type === 'checkbox' ||
817
+ dataField.type === 'dropdown' ? (
818
+ <div className="formItem fwItem">
819
+ <table className="content-table">
820
+ <thead className="grid-headers">
821
+ <tr>
822
+ <th
823
+ style={{
824
+ width: '450px',
825
+ }}
826
+ >
827
+ Label
828
+ </th>
829
+ <th></th>
830
+ </tr>
831
+ </thead>
832
+ <tbody>
833
+ {dataField.options.length >
834
+ 0 ? (
835
+ dataField.options.map(
836
+ (
837
+ option,
838
+ optionKey
839
+ ) => (
840
+ <tr
841
+ key={`option-${optionKey}`}
842
+ >
843
+ <td>
844
+ {
845
+ option.label
846
+ }
847
+ </td>
848
+ <td
849
+ style={{
850
+ textAlign:
851
+ 'center',
852
+ }}
853
+ >
854
+ <button
855
+ className="btn"
856
+ style={{
857
+ padding:
858
+ '5px 20px',
859
+ }}
860
+ onClick={
861
+ handleDeleteOption
862
+ }
863
+ data-counter={
864
+ optionKey
865
+ }
866
+ data-tooltip-id="system-tooltip"
867
+ data-tooltip-content={
868
+ 'Delete Option'
869
+ }
870
+ >
871
+ <TrashCan
872
+ strokeWidth={
873
+ 2
874
+ }
875
+ size={
876
+ 12
877
+ }
878
+ />
879
+ </button>
880
+ </td>
881
+ </tr>
882
+ )
883
+ )
884
+ ) : (
885
+ <tr>
886
+ <td colSpan="2">
887
+ No{' '}
888
+ {dataField.type}{' '}
889
+ options have
890
+ been added
891
+ </td>
892
+ </tr>
893
+ )}
894
+ </tbody>
895
+ <tfoot>
896
+ <tr>
897
+ <td>
898
+ <input
899
+ type="text"
900
+ style={{
901
+ padding:
902
+ '5px',
903
+ }}
904
+ name="label"
905
+ onChange={
906
+ handleDataOption
907
+ }
908
+ value={
909
+ dataOption.label
910
+ }
911
+ />
912
+ </td>
913
+ <td
914
+ style={{
915
+ textAlign:
916
+ 'center',
917
+ }}
918
+ >
919
+ <button
920
+ className="btn"
921
+ style={{
922
+ padding:
923
+ '5px 20px',
924
+ }}
925
+ onClick={
926
+ handleAddOption
927
+ }
928
+ data-tooltip-id="system-tooltip"
929
+ data-tooltip-content={
930
+ 'Add Option'
931
+ }
932
+ >
933
+ <CirclePlus
934
+ strokeWidth={
935
+ 2
936
+ }
937
+ size={12}
938
+ />
939
+ </button>
940
+ </td>
941
+ </tr>
942
+ </tfoot>
943
+ </table>
944
+ </div>
945
+ ) : null}
946
+ <div className="formItem fwItem lastItem">
947
+ <button
948
+ className="btn modalsave"
949
+ onClick={handleSaveField}
950
+ >
951
+ Save
952
+ </button>
953
+ </div>
954
+ </form>
955
+ </div>
956
+ </div>
957
+ </div>
958
+ </div>
959
+ </Popup>
960
+
961
+ <Popup
962
+ open={modalFormShow}
963
+ onClose={handleCloseModalForm}
964
+ closeOnDocumentClick={false}
965
+ >
966
+ <div className="modalwrap top--modal">
967
+ <div className="modal">
968
+ <div className="modal__header">
969
+ <h1>Update Form Detail</h1>
970
+ <button
971
+ className="modal__close"
972
+ onClick={handleCloseModalForm}
973
+ >
974
+ <CircleX strokeWidth={1} size={24} />
975
+ </button>
976
+ </div>
977
+ <div className="modal__content">
978
+ <div className="formcontainer">
979
+ <form className="modalForm">
980
+ <div className="formItem">
981
+ <label className="fi__label">
982
+ <input
983
+ type="text"
984
+ name="label"
985
+ value={
986
+ data.label ? data.label : ''
987
+ }
988
+ onChange={handleChange}
989
+ />
990
+ <span className="fi__span">
991
+ Label *
992
+ </span>
993
+ </label>
994
+ </div>
995
+ <div className="formItem fwItem lastItem">
996
+ <button
997
+ className="btn modalsave"
998
+ onClick={handleSubmit}
999
+ >
1000
+ Save
1001
+ </button>
1002
+ </div>
1003
+ </form>
1004
+ </div>
1005
+ </div>
1006
+ </div>
1007
+ </div>
1008
+ </Popup>
1009
+ </div>
1010
+ );
1011
+ }
1012
+
1013
+ export default GenericFormBuilder;