diff --git a/frontend/src/FilterManager.jsx b/frontend/src/FilterManager.jsx index fe5aad9..1f14936 100644 --- a/frontend/src/FilterManager.jsx +++ b/frontend/src/FilterManager.jsx @@ -70,6 +70,222 @@ const countryToFlag = (code) => { return String.fromCodePoint(...codePoints); }; +// Компонент автокомплита для выбора Community +function CommunityAutocomplete({ label, value, onChange, communities = [], required = false, placeholder = 'Введите или выберите community...' }) { + const [inputValue, setInputValue] = useState(value || ''); + const [isOpen, setIsOpen] = useState(false); + const [highlightedIndex, setHighlightedIndex] = useState(-1); + const containerRef = useRef(null); + const inputRef = useRef(null); + + useEffect(() => { + setInputValue(value || ''); + }, [value]); + + // Фильтруем communities по введённому тексту + const filteredCommunities = communities.filter(c => { + const search = inputValue.toLowerCase(); + return ( + (c.value && c.value.toLowerCase().includes(search)) || + (c.name && c.name.toLowerCase().includes(search)) || + (c.description && c.description.toLowerCase().includes(search)) + ); + }); + + useEffect(() => { + const handleClickOutside = (e) => { + if (containerRef.current && !containerRef.current.contains(e.target)) { + setIsOpen(false); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + const handleInputChange = (e) => { + const val = e.target.value; + setInputValue(val); + onChange(val); + setIsOpen(true); + setHighlightedIndex(-1); + }; + + const handleSelect = (c) => { + setInputValue(c.value); + onChange(c.value); + setIsOpen(false); + setHighlightedIndex(-1); + }; + + const handleKeyDown = (e) => { + if (!isOpen) { + if (e.key === 'ArrowDown' || e.key === 'Enter') { + setIsOpen(true); + e.preventDefault(); + } + return; + } + + switch (e.key) { + case 'ArrowDown': + e.preventDefault(); + setHighlightedIndex(prev => Math.min(prev + 1, filteredCommunities.length - 1)); + break; + case 'ArrowUp': + e.preventDefault(); + setHighlightedIndex(prev => Math.max(prev - 1, 0)); + break; + case 'Enter': + e.preventDefault(); + if (highlightedIndex >= 0 && filteredCommunities[highlightedIndex]) { + handleSelect(filteredCommunities[highlightedIndex]); + } + break; + case 'Escape': + setIsOpen(false); + setHighlightedIndex(-1); + break; + } + }; + + const selectedCommunity = communities.find(c => c.value === value); + + // Группируем по категориям + const groupedCommunities = filteredCommunities.reduce((acc, c) => { + const cat = c.category || 'Другое'; + if (!acc[cat]) acc[cat] = []; + acc[cat].push(c); + return acc; + }, {}); + + return ( +
{c.value}
+ {c.name && — {c.name}}
+ {selectedCommunity.value}
+ {selectedCommunity.name && — {selectedCommunity.name}}
+