import { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, } from "@/components/ui/combobox"; import type { NormalizedPackerCategory } from "@/lib/packer-schema"; type PackerComboboxProps = { categories: NormalizedPackerCategory[]; value?: string; onValueChange: (value: string) => void; placeholder?: string; emptyText?: string; disabled?: boolean; }; type PreparedPacker = { name: string; label: string; searchText: string; }; type PreparedCategory = { name: string; label: string; packers: PreparedPacker[]; }; export function PackerCombobox({ categories, value, onValueChange, placeholder, emptyText, disabled, }: Readonly) { const { t } = useTranslation("common"); const [open, setOpen] = useState(false); const [query, setQuery] = useState(""); const preparedCategories = useMemo( () => categories.map((category) => { const categoryLabel = t(category.name, { defaultValue: category.name }); return { name: category.name, label: categoryLabel, packers: category.packers.map((packer) => { const packerLabel = t(packer.name, { defaultValue: packer.name }); return { name: packer.name, label: packerLabel, searchText: `${packer.name} ${packerLabel} ${category.name} ${categoryLabel}`.toLowerCase(), }; }), }; }), [categories, t], ); const selectedLabel = useMemo(() => { if (!value) { return ""; } for (const category of preparedCategories) { const found = category.packers.find((packer) => packer.name === value); if (found) { return found.label; } } return value; }, [preparedCategories, value]); const filteredCategories = useMemo(() => { const normalizedQuery = query.trim().toLowerCase(); if (!normalizedQuery) { return preparedCategories; } return preparedCategories .map((category) => ({ ...category, packers: category.packers.filter((packer) => packer.searchText.includes(normalizedQuery), ), })) .filter((category) => category.packers.length > 0); }, [preparedCategories, query]); const resolvedPlaceholder = placeholder ?? t("selectPacker", { defaultValue: "Select packer" }); return ( { setOpen(nextOpen); setQuery(""); }} inputValue={open ? query : selectedLabel} onInputValueChange={(nextValue) => { if (open) { setQuery(nextValue); } }} onValueChange={(nextValue) => { if (typeof nextValue === "string") { onValueChange(nextValue); } setOpen(false); setQuery(""); }} autoComplete="none" autoHighlight={true} > {filteredCategories.map((category) => ( {category.label} {category.packers.map((packer) => ( {packer.label} ))} ))} ); }