import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { useFieldDefinitions } from "../api/queries"; import { useConfig } from "../config/config-context"; import { FieldInput } from "./field-input"; import { pruneFields } from "./prune-fields"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; export type ObjectCore = { object_number: string; object_name: string; number_of_objects: number; brief_description: string | null; current_location: string | null; current_owner: string | null; recorder: string | null; recording_date: string | null; }; export type ObjectFormValues = { core: ObjectCore; visibility?: "draft" | "internal"; fields: Record; }; type FormShape = { core: ObjectCore; visibility: "draft" | "internal"; fields: Record; } & Record; const EMPTY_CORE: ObjectCore = { object_number: "", object_name: "", number_of_objects: 1, brief_description: null, current_location: null, current_owner: null, recorder: null, recording_date: null, }; export function ObjectForm({ mode, defaults, onSubmit, onCancel, formError, fieldErrorKey, fieldErrorCode, }: { mode: "create" | "edit"; defaults?: { core: ObjectCore; fields: Record }; onSubmit: (values: ObjectFormValues, opts?: { createAnother?: boolean }) => Promise | boolean; onCancel: () => void; formError?: string | null; fieldErrorKey?: string | null; fieldErrorCode?: string | null; }) { const { t } = useTranslation(); const { default_language } = useConfig(); const { data: definitions } = useFieldDefinitions(); const localizedTextKeys = new Set( (definitions ?? []).filter((d) => d.data_type === "localized_text").map((d) => d.key), ); const form = useForm({ defaultValues: { core: defaults?.core ?? EMPTY_CORE, visibility: "draft", fields: defaults?.fields ?? {}, }, }); const { register, handleSubmit, formState: { errors, isSubmitting } } = form; useEffect(() => { if (fieldErrorKey) { const codeKey = fieldErrorCode ? `form.fieldError.${fieldErrorCode}` : ""; const message = fieldErrorCode && t(codeKey) !== codeKey ? t(codeKey) : t("form.fieldRejected", { field: fieldErrorKey }); form.setError(`fields.${fieldErrorKey}` as never, { type: "server", message }); } }, [fieldErrorKey, fieldErrorCode, form, t]); const runSubmit = (createAnother: boolean) => handleSubmit(async (data) => { const fields = pruneFields(data.fields, localizedTextKeys, default_language); const values = mode === "create" ? { core: data.core, visibility: data.visibility, fields } : { core: data.core, fields }; const ok = await onSubmit(values, { createAnother }); if (ok && createAnother) { form.reset({ core: EMPTY_CORE, visibility: "draft", fields: {} }); document.getElementById("object_number")?.focus(); } }); const submit = runSubmit(false); const coreField = ( key: keyof ObjectCore, labelKey: string, opts?: { type?: string; required?: boolean; min?: number }, ) => (
{errors.core?.[key] && (

{errors.core[key]?.message || t("form.required")}

)}
); return (
{ if ((e.metaKey || e.ctrlKey) && e.key === "Enter") { e.preventDefault(); void submit(); } }} className="space-y-4 overflow-auto p-4" > {formError && (

{formError}

)} {coreField("object_number", "objectNumber", { required: true })} {coreField("object_name", "objectName", { required: true })} {coreField("number_of_objects", "count", { type: "number", required: true, min: 1 })} {coreField("brief_description", "briefDescription")} {coreField("current_location", "currentLocation")} {coreField("current_owner", "currentOwner")} {coreField("recorder", "recorder")} {coreField("recording_date", "recordingDate", { type: "date" })} {mode === "create" && (
)} {definitions && definitions.length > 0 && (
{t("form.flexibleHeading")} {definitions.map((def) => (
{errors.fields?.[def.key] && (

{errors.fields[def.key]?.message ?? t("form.required")}

)}
))}
)}
{mode === "create" && ( )}
); }