import { Control, FieldValues, Path, PathValue } from "react-hook-form"; import { FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { useState, useEffect, useRef } from "react"; import { useFormContext } from "react-hook-form"; import { generateFixedHash, isValidId } from "@/utils/stringUtil"; import { useTranslation } from "react-i18next"; type NameAndIdFieldsProps = { control: Control; type?: string; nameField: Path; idField: Path; nameLabel: string; nameDescription?: string; idLabel?: string; idDescription?: string; processId?: (name: string) => string; placeholderName?: string; placeholderId?: string; idVisible?: boolean; idDisabled?: boolean; }; export default function NameAndIdFields({ control, type, nameField, idField, nameLabel, nameDescription, idLabel, idDescription, processId, placeholderName, placeholderId, idVisible, idDisabled, }: NameAndIdFieldsProps) { const { t } = useTranslation(["common"]); const { watch, setValue, trigger, formState } = useFormContext(); const [isIdVisible, setIsIdVisible] = useState(idVisible ?? false); const hasUserTypedRef = useRef(false); const defaultProcessId = (name: string) => { const normalized = name.replace(/\s+/g, "_").toLowerCase(); if (isValidId(normalized)) { return normalized; } else { return generateFixedHash(name, type); } }; const effectiveProcessId = processId || defaultProcessId; useEffect(() => { if (idDisabled) { return; } const subscription = watch((value, { name }) => { if (name === nameField) { hasUserTypedRef.current = true; const processedId = effectiveProcessId(value[nameField] || ""); setValue(idField, processedId as PathValue>); trigger(idField); } }); return () => subscription.unsubscribe(); }, [ watch, setValue, trigger, nameField, idField, effectiveProcessId, idDisabled, ]); // Auto-expand if there's an error on the ID field after user has typed useEffect(() => { const idError = formState.errors[idField]; if (idError && hasUserTypedRef.current && !isIdVisible) { setIsIdVisible(true); } }, [formState.errors, idField, isIdVisible]); return ( <> (
{nameLabel} setIsIdVisible(!isIdVisible)} > {isIdVisible ? t("label.hide", { item: idLabel ?? t("label.ID") }) : t("label.show", { item: idLabel ?? t("label.ID"), })}
{nameDescription && ( {nameDescription} )}
)} /> {isIdVisible && ( ( {idLabel ?? t("label.ID")} {idDescription ?? t("field.internalID")} )} /> )} ); }