import { useMemo } from 'react' import { AlertTriangle } from 'lucide-react' import { Input } from '@/components/ui/Input' import { Label } from '@/components/ui/Label' import { Select } from '@/components/ui/Select' import { Textarea } from '@/components/ui/Textarea' // FieldSpec schema — stored on ContractTemplate.FieldSpec as JSON string. // Designed to be human-authorable by admin in JSON textarea but also machine- // readable for the DynamicForm renderer below. // // { // "fieldKey": { // "label": "Tên Cty bên A", // "type": "text" | "textarea" | "number" | "date" | "currency" | "select", // "required": false, // "placeholder": "...", // "hint": "...", // "options": ["opt1", "opt2"] // only for type=select // } // } export type FieldDef = { label: string type?: 'text' | 'textarea' | 'number' | 'date' | 'currency' | 'select' required?: boolean placeholder?: string hint?: string options?: string[] } export type FieldSpec = Record export type DynamicFormValues = Record export function parseFieldSpec(json: string | null | undefined): { spec: FieldSpec | null; error: string | null } { if (!json || !json.trim()) return { spec: null, error: null } try { const obj = JSON.parse(json) if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) return { spec: null, error: 'FieldSpec phải là object JSON' } return { spec: obj as FieldSpec, error: null } } catch (e) { return { spec: null, error: `JSON lỗi: ${(e as Error).message}` } } } export function DynamicForm({ spec, values, onChange, }: { spec: FieldSpec values: DynamicFormValues onChange: (key: string, value: string | null) => void }) { const entries = useMemo(() => Object.entries(spec), [spec]) if (entries.length === 0) { return (
FieldSpec trống — thêm field vào spec JSON để hiện form.
) } return (
{entries.map(([key, def]) => { const type = def.type ?? 'text' const val = values[key] ?? '' const commonProps = { id: key, value: val, placeholder: def.placeholder, required: def.required, } const spanClass = type === 'textarea' ? 'md:col-span-2' : '' return (
{type === 'textarea' && (