import { useState, useRef, useEffect, useMemo } from 'react'; import { ChevronDown, Loader2, Package } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import type { SpoolmanFilamentEntry } from '../../api/client'; interface SpoolmanFilamentPickerProps { filaments: SpoolmanFilamentEntry[]; isLoading: boolean; selectedId: number | null; onSelect: (filament: SpoolmanFilamentEntry) => void; } export function SpoolmanFilamentPicker({ filaments, isLoading, selectedId, onSelect, }: SpoolmanFilamentPickerProps) { const { t } = useTranslation(); const [isOpen, setIsOpen] = useState(false); const [search, setSearch] = useState(''); const containerRef = useRef(null); const inputRef = useRef(null); const selected = useMemo( () => filaments.find((f) => f.id === selectedId) ?? null, [filaments, selectedId] ); useEffect(() => { const handleClick = (e: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(e.target as Node)) { setIsOpen(false); setSearch(''); } }; document.addEventListener('mousedown', handleClick); return () => document.removeEventListener('mousedown', handleClick); }, []); const filtered = useMemo(() => { const q = search.toLowerCase().trim(); if (!q) return filaments; return filaments.filter( (f) => f.name.toLowerCase().includes(q) || (f.material?.toLowerCase().includes(q) ?? false) || (f.vendor?.name.toLowerCase().includes(q) ?? false) || (f.color_name?.toLowerCase().includes(q) ?? false) ); }, [filaments, search]); useEffect(() => { if (isOpen) inputRef.current?.focus(); }, [isOpen]); const handleOpen = () => { setIsOpen(true); setSearch(''); }; const handleSelect = (filament: SpoolmanFilamentEntry) => { onSelect(filament); setIsOpen(false); setSearch(''); }; const colorStyle = (hex: string | null): string => hex ? `#${hex.replace('#', '')}` : '#808080'; return (
{/* Trigger button */} {/* Dropdown */} {isOpen && (
{/* Search */}
setSearch(e.target.value)} placeholder={t('inventory.pickFromSpoolmanCatalog')} className="w-full px-2 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm placeholder-bambu-gray focus:outline-none focus:border-bambu-green" />
{/* Items */}
    {isLoading ? (
  • {t('common.loading', 'Loading…')}
  • ) : filtered.length === 0 ? (
  • {t('inventory.noSpoolmanFilaments')}
  • ) : ( filtered.map((f) => (
  • )) )}
)}
); }