2025-08-23 11:57:48 +00:00
|
|
|
import {
|
2026-03-18 16:38:40 +00:00
|
|
|
Field,
|
|
|
|
|
FieldDescription,
|
|
|
|
|
FieldError,
|
|
|
|
|
FieldLabel,
|
2025-08-23 11:57:48 +00:00
|
|
|
FormControl,
|
|
|
|
|
Select,
|
|
|
|
|
SelectContent,
|
|
|
|
|
SelectItem,
|
|
|
|
|
SelectTrigger,
|
|
|
|
|
SelectValue,
|
|
|
|
|
} from "@repo/shadcn-ui/components";
|
|
|
|
|
import { cn } from "@repo/shadcn-ui/lib/utils";
|
2026-03-18 16:38:40 +00:00
|
|
|
import {
|
|
|
|
|
type Control,
|
|
|
|
|
Controller,
|
|
|
|
|
type FieldPath,
|
|
|
|
|
type FieldValues,
|
|
|
|
|
useController,
|
|
|
|
|
useFormState,
|
|
|
|
|
} from "react-hook-form";
|
|
|
|
|
|
2025-08-23 11:57:48 +00:00
|
|
|
import { useTranslation } from "../../locales/i18n.ts";
|
|
|
|
|
|
|
|
|
|
type SelectFieldProps<TFormValues extends FieldValues> = {
|
|
|
|
|
control: Control<TFormValues>;
|
|
|
|
|
name: FieldPath<TFormValues>;
|
|
|
|
|
label?: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
disabled?: boolean;
|
|
|
|
|
required?: boolean;
|
|
|
|
|
readOnly?: boolean;
|
2026-03-18 16:38:40 +00:00
|
|
|
|
|
|
|
|
placeholder?: string;
|
|
|
|
|
items: Array<{ value: string; label: string }>;
|
|
|
|
|
|
|
|
|
|
orientation?: "vertical" | "horizontal" | "responsive";
|
|
|
|
|
|
2025-08-23 11:57:48 +00:00
|
|
|
className?: string;
|
2026-03-18 16:38:40 +00:00
|
|
|
inputClassName?: string;
|
2025-08-23 11:57:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function SelectField<TFormValues extends FieldValues>({
|
|
|
|
|
control,
|
|
|
|
|
name,
|
|
|
|
|
items,
|
|
|
|
|
label,
|
|
|
|
|
placeholder,
|
|
|
|
|
description,
|
|
|
|
|
disabled = false,
|
|
|
|
|
required = false,
|
|
|
|
|
readOnly = false,
|
2026-03-18 16:38:40 +00:00
|
|
|
|
|
|
|
|
orientation = "vertical",
|
|
|
|
|
|
2025-08-23 11:57:48 +00:00
|
|
|
className,
|
2026-03-18 16:38:40 +00:00
|
|
|
inputClassName,
|
2025-08-23 11:57:48 +00:00
|
|
|
}: SelectFieldProps<TFormValues>) {
|
|
|
|
|
const { t } = useTranslation();
|
2025-09-21 19:10:05 +00:00
|
|
|
|
2026-03-18 16:38:40 +00:00
|
|
|
const { isSubmitting } = useFormState({ control, name });
|
2025-09-21 19:10:05 +00:00
|
|
|
const { field, fieldState } = useController({ control, name });
|
|
|
|
|
|
2025-08-23 11:57:48 +00:00
|
|
|
const isDisabled = disabled || readOnly;
|
|
|
|
|
|
|
|
|
|
return (
|
2026-03-18 16:38:40 +00:00
|
|
|
<Controller
|
2025-08-23 11:57:48 +00:00
|
|
|
control={control}
|
|
|
|
|
name={name}
|
2026-03-18 16:38:40 +00:00
|
|
|
render={({ field, fieldState }) => {
|
|
|
|
|
return (
|
|
|
|
|
<Field
|
|
|
|
|
className={cn("gap-1", className)}
|
|
|
|
|
data-invalid={fieldState.invalid}
|
|
|
|
|
orientation={orientation}
|
|
|
|
|
>
|
|
|
|
|
{label && <FieldLabel htmlFor={name}>{label}</FieldLabel>}
|
|
|
|
|
|
|
|
|
|
<Select defaultValue={field.value} disabled={isDisabled} onValueChange={field.onChange}>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<SelectTrigger
|
|
|
|
|
className={cn(
|
|
|
|
|
"w-full h-8",
|
|
|
|
|
"font-medium bg-muted/50 hover:bg-inherit hover:border-ring hover:ring-ring/50 hover:ring-[2px]",
|
|
|
|
|
inputClassName
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
<SelectValue
|
|
|
|
|
className={"placeholder:font-normal placeholder:italic"}
|
|
|
|
|
placeholder={placeholder}
|
|
|
|
|
/>
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
{items.map((item) => (
|
|
|
|
|
<SelectItem key={`key-${item.value}`} value={item.value}>
|
|
|
|
|
{item.label}
|
|
|
|
|
</SelectItem>
|
|
|
|
|
))}
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
2025-08-23 11:57:48 +00:00
|
|
|
|
2026-03-18 16:38:40 +00:00
|
|
|
<FieldDescription>{description || "\u00A0"}</FieldDescription>
|
|
|
|
|
<FieldError errors={[fieldState.error]} />
|
|
|
|
|
</Field>
|
|
|
|
|
);
|
|
|
|
|
}}
|
2025-08-23 11:57:48 +00:00
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|