import { Checkbox, CheckboxGroup, FormControl, FormErrorMessage, Heading, HStack, Input, NumberDecrementStepper, NumberIncrementStepper, NumberInput, NumberInputField, NumberInputStepper, Radio, RadioGroup, Select, Stack, Textarea, } from "@chakra-ui/react"; import { type Dispatch, type SetStateAction, useState } from "react"; interface component { id: string; max_length?: number; options?: { default?: boolean; value: string }[]; required: boolean; title: string; type: string; value?: number | string | string[]; } export default function ({ components, read_only = true, }: { components: { [k: number]: component[] }; read_only: boolean; }) { function isNumberElemInvalid(e: HTMLInputElement): boolean { return !( e.value || isNaN(e.valueAsNumber) || e.valueAsNumber <= Number.MAX_SAFE_INTEGER || e.valueAsNumber >= Number.MIN_SAFE_INTEGER ); } function updateState( state: { [k: string]: string | string[] }, setState: Dispatch>, id: string, value: string, ) { const newState = { ...state }; newState[id] = value; setState(newState); } function renderCheckboxOptions( c: component, state: { [k: string]: string | string[] }, setState: Dispatch>, ) { if (!c.options) throw new Error("Options for checkbox are undefined"); const boxes = []; const checkedBoxes = []; for (const option of c.options) { if ( option.default || (read_only && Array.isArray(c.value) && c.value.includes(option.value)) ) checkedBoxes.push(option.value); boxes.push( { const newState = { ...state }; const groupValues = newState[c.id] ?? []; if (!Array.isArray(groupValues)) throw new Error("Expected CheckboxGroup values to be an array"); e.target.checked ? groupValues.push(e.target.value) : groupValues.splice( groupValues.findIndex((v) => v === e.target.value), 1, ); newState[c.id] = groupValues; setState(newState); }} value={option.value} > {option.value} , ); } return ( {boxes} ); } function renderRadioElements( c: component, state: { [k: string]: string | string[] }, setState: Dispatch>, ) { if (!c.options) throw new Error("Options for radio buttons are undefined!"); const buttons = []; for (const option of c.options) { buttons.push( {option.value} , ); } return ( { const newState = { ...state }; newState[c.id] = e; setState(newState); }} > {buttons} ); } function renderSelectElements( c: component, state: { [k: string]: string | string[] }, setState: Dispatch>, ) { if (!c.options) throw new Error("Options for select are undefined!"); const selectOptions = []; for (const option of c.options) { selectOptions.push(); } return ( ); } function generateReactComponents( components: component[], state: { [k: string]: string | string[] }, setState: Dispatch>, ): JSX.Element[] { const fragmentsList = []; for (const component of components) { fragmentsList.push( {component.title},
, ); switch (component.type) { case "checkbox": fragmentsList.push(renderCheckboxOptions(component, state, setState)); break; case "input": fragmentsList.push( updateState(state, setState, component.id, e.target.value) } placeholder="Your response" value={component.value} /> Field is required , ); break; case "number": fragmentsList.push( updateState(state, setState, component.id, e.target.value) } value={component.value} /> , ); break; case "radio": fragmentsList.push(renderRadioElements(component, state, setState)); break; case "select": fragmentsList.push(renderSelectElements(component, state, setState)); break; } fragmentsList.push(
,
,
); } return fragmentsList; } const pages = []; const [responses, setResponses] = useState({}); for (const [page, componentList] of Object.entries(components)) { pages.push(
{generateReactComponents(componentList, responses, setResponses)}
, ); } return <>; }