// * Packages import { usePage } from "@inertiajs/react"; import { useEffect, useState } from "react"; import { CheckIcon, ChevronsUpDownIcon, SearchIcon, XIcon } from "lucide-react"; // * Components shadcn import { Label } from "@/components/ui/label"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; // * Other import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip"; import InputError from "@/back/Components/InputError"; import { AppEnv } from "@/back/types/global"; import { cn } from "@/lib/utils"; import useTrans from "@/hooks/use-translations"; import str from "@/hooks/use-string"; type EnumSelectProps = { name: string; label: string; options?: Record; placeholder?: string; exclude?: number[]; selected?: number | null; required?: boolean; disabled?: boolean; parentErrors?: Record | null; // eslint-disable-next-line no-unused-vars setData: (name: string, value: number | null) => void; // eslint-disable-next-line no-unused-vars onSelectValue?: (value: number | null) => void; }; export default function EnumSelect({ name, label, options = {}, placeholder = "ex: Magnifique libellé", exclude = [], selected = null, required = true, disabled = false, parentErrors = null, setData, onSelectValue, }: EnumSelectProps) { const { locale } = usePage().props.appEnv as AppEnv; const { errors } = usePage().props; const localErrors = parentErrors ?? errors; // List of options. const initalOptions = Object.fromEntries( Object.entries(options).filter( ([, item]) => !exclude.includes(item.value), ), ); const [currentOptions, setCurrentOptions] = useState< Record >(initalOptions); // Model key selected. const initial = selected === 0 || selected === null || selected === undefined ? null : Number(selected); const [selectedEnum, setSelectedEnum] = useState(initial); // String research in models collection. const [search, setSearch] = useState(""); // Component states. const [open, setOpen] = useState(false); const transNoResults = useTrans("back.table_no_results"); const transDelete = useTrans("crud.actions.delete"); /** * Get the identification field of specific option. * @param value number * @return string */ const getEnumLabel = (value: number): string => { const targetEnum = Object.values(initalOptions).find( (option) => option.value === value, ); if (!targetEnum) return String(value); if (typeof value === "object") return String( targetEnum.label[locale as keyof typeof targetEnum.label] ?? "", ); return targetEnum.label; }; /** * Updates when selecting new value. * @param value number * @return void */ const handleSelect = (value: number) => { setSelectedEnum(value); setData(name, value); onSelectValue?.(value); setOpen(false); }; /** * Updates when clear the selected value. * @return void */ const handleClear = () => { setSelectedEnum(null); setData(name, null); onSelectValue?.(null); }; /** * Reset the search. * @return void */ const handleClearSearch = () => { setSearch(""); }; // Fetch with debounce. useEffect(() => { // Reset options list if empty search or null if (search.length === 0) { setCurrentOptions(initalOptions); return; } const optionsFiltered = Object.fromEntries( Object.entries(initalOptions).filter(([, item]) => item.label.toLowerCase().includes(search), ), ); // Get updated options list with search. setCurrentOptions(optionsFiltered); // eslint-disable-next-line react-hooks/exhaustive-deps }, [search, options]); return (
setSearch(e.target.value)} className="w-[calc(100%-2.5rem-40px)] border-0 mx-9" /> } tooltipContent={

{str(useTrans("crud.actions.delete")) .ucFirst() .value()}

} type="button" variant="ghost" size="icon" className="absolute top-1/2 right-0 transform -translate-y-1/2 text-muted-foreground" onClick={handleClearSearch} disabled={search.length < 1 || disabled} />
5 ? "h-[225px]" : "h-auto"}`, )} > {Object.values(currentOptions).length === 0 && (

{transNoResults}

)}
{Object.values(currentOptions).map((option) => ( ))}
{!required && selectedEnum !== null && ( } tooltipContent={

{str(transDelete).ucFirst().value()}

} type="button" variant="destructive" size="icon" onClick={handleClear} /> )}
); }