import { useEffect, useMemo, useRef, useState } from 'react' import { ChevronDown, Search, X } from 'lucide-react' import { useLocale } from '@meshkee/dashboard-ui' import { useT } from '../i18n/useT' import styles from './SearchableSelect.module.css' export interface ProductSearchOption { id: string title: string nameFa: string } interface ProductSearchSelectProps { options: ProductSearchOption[] value: string onChange: (value: string) => void placeholder?: string disabled?: boolean id?: string minSearchLength?: number 'aria-label'?: string } function formatProductLabel(option: ProductSearchOption, preferFa: boolean) { if (preferFa && option.nameFa) { return option.title ? `${option.nameFa} / ${option.title}` : option.nameFa } return option.nameFa ? `${option.title} / ${option.nameFa}` : option.title } export function ProductSearchSelect({ options, value, onChange, placeholder = 'Search products...', disabled = false, id, minSearchLength = 3, 'aria-label': ariaLabel, }: ProductSearchSelectProps) { const t = useT() const { locale } = useLocale() const preferFa = locale === 'fa' const [open, setOpen] = useState(false) const [query, setQuery] = useState('') const containerRef = useRef(null) const inputRef = useRef(null) const selected = options.find((option) => option.id === value) const selectedLabel = selected ? formatProductLabel(selected, preferFa) : '' const filtered = useMemo(() => { const trimmed = query.trim() if (trimmed.length < minSearchLength) return [] const q = trimmed.toLowerCase() return options.filter( (option) => option.title.toLowerCase().includes(q) || option.nameFa.includes(trimmed), ) }, [options, query, minSearchLength]) useEffect(() => { if (!open) return const onClickOutside = (e: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(e.target as Node)) { setOpen(false) setQuery('') } } document.addEventListener('mousedown', onClickOutside) return () => document.removeEventListener('mousedown', onClickOutside) }, [open]) function selectOption(id: string) { onChange(id) setOpen(false) setQuery('') } function handleFocus() { if (!disabled) setOpen(true) } const showDropdown = open && query.trim().length >= minSearchLength return (
{ setQuery(e.target.value) if (!open) setOpen(true) if (value) onChange('') }} onFocus={handleFocus} disabled={disabled} aria-label={ariaLabel ?? placeholder} dir={preferFa ? 'rtl' : 'ltr'} /> {value && !open && ( )}
{showDropdown && (
    {filtered.length === 0 ? (
  • {options.length === 0 ? t('storeItems.search.noProducts') : t('storeItems.search.noMatch')}
  • ) : ( filtered.map((option) => (
  • )) )}
)} {open && query.trim().length > 0 && query.trim().length < minSearchLength && (
  • {t('storeItems.search.minChars', { count: minSearchLength })}
)}
) }