import {FormEvent, useRef, useState} from 'react' import {Plus, Trash2} from 'lucide-react' import type {FieldSchema, ServiceSchema} from '@/types/schema' interface DynamicFormRendererProps { schema: ServiceSchema fields?: FieldSchema[] initialValues?: Record isSubmitting: boolean submitLabel?: string pendingLabel?: string submitError?: string | null onCancel?: () => void onSubmit: (values: Record) => void } export function DynamicFormRenderer({ schema, fields, initialValues, isSubmitting, submitLabel = 'Create', pendingLabel = 'Creating', submitError, onCancel, onSubmit, }: DynamicFormRendererProps) { const activeFields = fields ?? schema.fields const [values, setValues] = useState>(() => getInitialFormValues(activeFields, initialValues), ) const [errors, setErrors] = useState>({}) const visibleFields = activeFields.filter((field) => !field.visibleWhen || field.visibleWhen.values.includes(values[field.visibleWhen.field] ?? '')) function submit(event: FormEvent) { event.preventDefault() const nextErrors = validateValues(visibleFields, values) setErrors(nextErrors) if (Object.keys(nextErrors).length > 0) return onSubmit(values) } return (
{visibleFields.map((field) => ( { setValues((prev) => withDependentDefaults(activeFields, prev, field.name, value)) setErrors((prev) => { const next = {...prev} delete next[field.name] return next }) }} /> ))}
{onCancel && ( )}
{submitError &&
{submitError}
} ) } function FieldRow({field, required, maxLength, value, error, onChange}: {field: FieldSchema; required: boolean; maxLength?: number; value: string; error?: string; onChange: (value: string) => void}) { return ( <> {field.group &&
{field.group}
} ) } function FieldInput({field, required, maxLength, value, invalid, messageId, onChange}: {field: FieldSchema; required: boolean; maxLength?: number; value: string; invalid: boolean; messageId: string; onChange: (value: string) => void}) { if (field.type === 'select') { return ( ) } if (field.type === 'textarea') { return (