import { Button } from '@/components/ui/button'; import { Command, CommandEmpty, CommandInput, CommandItem, CommandList, } from '@/components/ui/command'; import { Popover, PopoverContent, PopoverTrigger, } from '@/components/ui/popover'; import { cn } from '@/lib/utils'; import { type Category, getCategoryColorClasses } from '@/types/category'; import { Check, ChevronsUpDown, HelpCircle, type LucideIcon } from 'lucide-react'; import * as Icons from 'lucide-react'; import { memo, useState } from 'react'; const iconCache = new Map(); function getIconComponent(iconName?: string): LucideIcon | null { if (!iconName) return null; if (iconCache.has(iconName)) { return iconCache.get(iconName)!; } const icon = Icons[iconName as keyof typeof Icons] as LucideIcon | undefined; if (icon) { iconCache.set(iconName, icon); } return icon ?? null; } interface CategoryComboboxProps { value: string | null; onValueChange: (value: string) => void; categories: Category[]; disabled?: boolean; placeholder?: string; triggerClassName?: string; showUncategorized?: boolean; } export function CategoryCombobox({ value, onValueChange, categories, disabled = false, placeholder = 'Select category', triggerClassName, showUncategorized = true, }: CategoryComboboxProps) { const [open, setOpen] = useState(false); const selectedCategory = value && value !== 'null' ? categories.find((c) => c.id === value) : null; const sortedCategories = [...categories].sort((a, b) => a.name.localeCompare(b.name), ); return ( No category found. {showUncategorized && ( { onValueChange('null'); setOpen(false); }} >
Uncategorized
)} {sortedCategories.map((category) => ( { onValueChange(String(category.id)); setOpen(false); }} >
{category.name}
))}
); } const CategoryIcon = memo(function CategoryIcon({ category }: { category: Category }) { const colorClasses = getCategoryColorClasses(category.color); const iconName = category.icon; return (
); }); const DynamicIcon = memo(function DynamicIcon({ name, className }: { name?: string; className?: string }) { const Icon = getIconComponent(name); if (!Icon) return null; return ; });