import { ArrowCircleDown, ArrowCircleUp, Delete, Edit, EditNote, Save, } from "@mui/icons-material"; import { Box, Button, Checkbox, Chip, FormControlLabel, FormGroup, IconButton, Stack, TextField, Typography, } from "@mui/material"; import React, { useEffect, useId, useState } from "react"; import { NumberedSection } from "../components/form/numberedSection"; import { formElements as formElementsData } from "../data/pfa-fields"; import { EmptyState } from "../utility/emptyState"; type FormType = "text" | "email" | "textarea" | "select" | "checkbox" | "radio"; interface FormValue { label: string; value: string; } interface FormElement { id?: string; type: FormType; required: boolean; label: string; placeholder?: string; name: string; values?: FormValue[]; } interface FormBuilderProps { formValues: { [key: string]: string }; handleChange: (id: string, value: any) => void; } interface FormNodeEditorProps { field: FormElement; onChange: (field: FormElement) => void; onShift: (field: FormElement, direction: number) => void; onDelete: (field: FormElement) => void; } export const FormNodeEditor: React.FC = ({ field, onChange, onShift, onDelete, }): JSX.Element => { const nameId = useId(); const labelId = useId(); const placeholderId = useId(); const [options, setOptions] = useState([]); const [label, setLabel] = useState(""); const [placeholder, setPlaceholder] = useState(""); const [name, setName] = useState(""); const [required, setRequired] = useState(false); const [open, setOpen] = useState(false); useEffect(() => { setLabel(field.label); setPlaceholder(field.placeholder || ""); setName(field.name); setRequired(field.required); setOptions(field.values || []); if (field.name !== "" && field.name !== undefined) { setOpen(false); } else { setOpen(true); } }, [field]); const handleInputChange = ({ field, value }) => { let cleansedValue = value; switch (field) { case "label": setLabel(cleansedValue); break; case "placeholder": setPlaceholder(cleansedValue); break; case "name": cleansedValue = cleansedValue.toLowerCase().replace(/[^a-z0-9_-]/g, ""); setName(cleansedValue); break; case "required": setRequired(cleansedValue); break; default: console.error("Invalid field"); break; } }; const handleOptionChange = ( index: number, field: keyof FormValue, value: string, ) => { const newOptions = options.map((option, i) => { if (i === index) { return { ...option, [field]: value }; } return option; }); setOptions(newOptions); }; const handleAddOption = () => { setOptions([...options, { label: "", value: "" }]); }; const handleRemoveOption = (index: number) => { const newOptions = options.filter((_, i) => i !== index); setOptions(newOptions); }; const handleOpenToggle = (_field: FormElement) => { setOpen(!open); }; useEffect(() => { field.label = label; field.placeholder = placeholder; field.name = name; field.required = required; field.values = options; onChange(field); }, [label, placeholder, name, required, options]); return ( {field.name} {open ? ( ) : ( )} onShift(field, -1)} sx={{ p: 0, m: 0, }} > onShift(field, 1)} sx={{ p: 0, m: 0, }} > onDelete(field)} sx={{ p: 0, m: 0, ml: 2, }} > {open && ( <> {/* Required checkbox */} handleInputChange({ field: "required", value: event.target.checked, }) } /> } label="Required" /> {/* Name input */} handleInputChange({ field: "name", value: event.target.value }) } /> {/* Label input */} handleInputChange({ field: "label", value: event.target.value }) } /> {/* Placeholder input */} handleInputChange({ field: "placeholder", value: event.target.value, }) } /> {/* Options to be added */} {field.type === "select" || field.type === "radio" ? ( Options {options.map((option, index) => ( handleOptionChange(index, "label", event.target.value) } /> handleOptionChange(index, "value", event.target.value) } /> handleRemoveOption(index)} > ))} ) : null} )} ); }; export const FormBuilder: React.FC = ({ formValues, handleChange, }) => { const [formElements, setFormElements] = useState([]); const handleAddElement = (element: FormElement) => { element.id = Math.random().toString(36).substring(7); setFormElements([...formElements, element]); }; useEffect(() => { const iniitalValues = formValues[formElementsData.id]; if (iniitalValues) { const parsedValues = typeof iniitalValues === "string" ? JSON.parse(iniitalValues) : iniitalValues; const formElements = parsedValues.map((value) => { return { id: Math.random().toString(36).substring(7), type: value.type, required: value.required, label: value.label, placeholder: value.placeholder, name: value.name, values: value.values, }; }); setFormElements(formElements); } }, []); const generateFieldJSON = (field: FormElement) => { const json = { type: field.type, required: field.required, label: field.label, name: field.name, values: field.values, }; return json; }; const handleFieldChange = (field: FormElement) => { const index = formElements.findIndex((element) => element.id === field.id); if (index === -1) { console.error("Element not found"); return; } const newFormElements = [...formElements]; newFormElements[index] = field; setFormElements(newFormElements); }; const handleFieldDelete = (field: FormElement) => { const index = formElements.findIndex((element) => element.id === field.id); if (index === -1) { console.error("Element not found"); return; } const newFormElements = [...formElements]; newFormElements.splice(index, 1); setFormElements(newFormElements); }; const handleFieldShift = (field: FormElement, direction: number) => { const currentIndex = formElements.findIndex((f) => f.id === field.id); const newIndex = currentIndex + direction; if (newIndex >= 0 && newIndex < formElements.length) { const updatedFormElements = [...formElements]; const movedElement = updatedFormElements.splice(currentIndex, 1)[0]; updatedFormElements.splice(newIndex, 0, movedElement); setFormElements(updatedFormElements); } else { console.warn("Index out of bounds"); } }; useEffect(() => { const formJSON = formElements.map((element) => generateFieldJSON(element)); handleChange(formElementsData.id, formJSON); }, [formElements]); return ( } headline={ "Configure the inputs you would like to capture from your visitors in this lead capture form." } > {formElements.length === 0 && ( )} {formElements.map((element, _index) => ( { } ))} ); };