add reusable component for combined name / internal name form field

This commit is contained in:
Josh Hawkins 2025-10-27 10:55:18 -05:00
parent 5ff7a47ba9
commit 26662784f6
2 changed files with 113 additions and 1 deletions

View File

@ -93,7 +93,14 @@
}
},
"label": {
"back": "Go back"
"back": "Go back",
"hide": "Hide {{item}}",
"show": "Show {{item}}",
"ID": "ID"
},
"field": {
"optional": "Optional",
"internalID": "The Internal ID Frigate uses in the configuration and database"
},
"button": {
"apply": "Apply",

View File

@ -0,0 +1,105 @@
import { Control } from "react-hook-form";
import {
FormField,
FormItem,
FormLabel,
FormControl,
FormDescription,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { useState, useEffect } from "react";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
type NameAndIdFieldsProps = {
control: Control;
nameField: string;
idField: string;
nameLabel: string;
nameDescription?: string;
idLabel?: string;
idDescription?: string;
processId: (name: string) => string;
placeholderName?: string;
placeholderId?: string;
};
export default function NameAndIdFields({
control,
nameField,
idField,
nameLabel,
nameDescription,
idLabel,
idDescription,
processId,
placeholderName,
placeholderId,
}: NameAndIdFieldsProps) {
const { t } = useTranslation(["common"]);
const { watch, setValue, trigger } = useFormContext();
const [isIdVisible, setIsIdVisible] = useState(false);
useEffect(() => {
const subscription = watch((value, { name }) => {
if (name === nameField) {
const processedId = processId(value[nameField] || "");
setValue(idField, processedId);
trigger(idField);
}
});
return () => subscription.unsubscribe();
}, [watch, setValue, trigger, nameField, idField, processId]);
return (
<>
<FormField
control={control}
name={nameField}
render={({ field }) => (
<FormItem>
<div className="flex items-center justify-between">
<FormLabel>{nameLabel}</FormLabel>
<span
className="cursor-pointer text-right text-xs text-muted-foreground hover:underline"
onClick={() => setIsIdVisible(!isIdVisible)}
>
(
{isIdVisible
? `${t("label.hide")} ${idLabel ?? t("label.ID")}`
: `${t("label.show")} ${idLabel ?? t("label.ID")}`}
)
</span>
</div>
<FormControl>
<Input placeholder={placeholderName} {...field} />
</FormControl>
{nameDescription && (
<FormDescription>{nameDescription}</FormDescription>
)}
<FormMessage />
</FormItem>
)}
/>
{isIdVisible && (
<FormField
control={control}
name={idField}
render={({ field }) => (
<FormItem>
<FormLabel>{idLabel}</FormLabel>
<FormControl>
<Input placeholder={placeholderId} {...field} />
</FormControl>
<FormDescription>
{idDescription ?? t("field.description")}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
)}
</>
);
}