import { useEffect, useRef, useState } from 'react'; import { Plus, Search } from 'lucide-react'; import { useTranslation } from 'react-i18next'; export interface PickablePrinter { id: number; name: string; location?: string | null; } interface PrinterSearchPickerProps { /** Printers that can still be picked. */ printers: PickablePrinter[]; onPick: (printer: PickablePrinter) => void; /** Text of the button that opens the picker. */ label: string; disabled?: boolean; } /** * A button that opens a searchable list of printers and hands back the one * clicked. Made for farms: with 120 printers a plain select is a long scroll, * so the list filters by name and location as you type. */ export function PrinterSearchPicker({ printers, onPick, label, disabled }: PrinterSearchPickerProps) { const { t } = useTranslation(); const [open, setOpen] = useState(false); const [query, setQuery] = useState(''); const rootRef = useRef(null); useEffect(() => { if (!open) return; const onPointerDown = (e: PointerEvent) => { if (rootRef.current && !rootRef.current.contains(e.target as Node)) setOpen(false); }; document.addEventListener('pointerdown', onPointerDown); return () => document.removeEventListener('pointerdown', onPointerDown); }, [open]); const needle = query.trim().toLowerCase(); const matches = printers.filter(p => !needle || p.name.toLowerCase().includes(needle) || (p.location ?? '').toLowerCase().includes(needle), ); const close = () => { setOpen(false); setQuery(''); }; return (
{open && (
{ if (e.key === 'Escape') close(); }} >
setQuery(e.target.value)} placeholder={t('settings.printerPickerSearch')} aria-label={t('settings.printerPickerSearch')} className="w-full pl-7 pr-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none" />
    {matches.length === 0 && (
  • {t('settings.printerPickerNoMatch')}
  • )} {matches.map(p => (
  • ))}
)}
); }