import { useEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { cn } from '@/lib/utils'; import { CheckIcon } from '@/components/icons'; import { ChevronDownIcon } from './DropdownSelect'; // ────────────────────────────────────────────────────────────────── // MultiSelectDropdown // // Pop-over multi-select used by AdminBulkActions filters (tariffs, // statuses, nodes, etc.). Closes on outside click; provides // select-all / deselect-all helpers. Pure controlled component. // ────────────────────────────────────────────────────────────────── export interface MultiSelectOption { value: number; label: string; } export interface MultiSelectDropdownProps { options: MultiSelectOption[]; selected: number[]; onChange: (ids: number[]) => void; placeholder: string; className?: string; } export function MultiSelectDropdown({ options, selected, onChange, placeholder, className, }: MultiSelectDropdownProps) { const { t } = useTranslation(); const [open, setOpen] = useState(false); const containerRef = useRef(null); useEffect(() => { if (!open) return; const handler = (e: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(e.target as Node)) { setOpen(false); } }; document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, [open]); const buttonLabel = useMemo(() => { if (selected.length === 0) return placeholder; if (selected.length <= 2) { return selected .map((id) => options.find((o) => o.value === id)?.label) .filter(Boolean) .join(', '); } return t('admin.bulkActions.filters.tariffsSelected', { count: selected.length }); }, [selected, options, placeholder, t]); const handleToggle = (value: number) => { if (selected.includes(value)) { onChange(selected.filter((id) => id !== value)); } else { onChange([...selected, value]); } }; const handleSelectAll = () => { onChange(options.map((o) => o.value)); }; const handleDeselectAll = () => { onChange([]); }; return (
{open && (
/
{options.map((option) => { const isChecked = selected.includes(option.value); return ( ); })}
)}
); }