/** * Компонент глобального поиска с автодополнением */ 'use client'; import { useState, useEffect, useRef } from 'react'; import { useRouter } from 'next/navigation'; import { globalSearch, getSearchSuggestions, SearchResult } from '@/lib/search/global-search'; import { useSearchHistory } from '@/hooks/useSearchHistory'; import { useUrlParams } from '@/hooks/useUrlParams'; interface GlobalSearchProps { isOpen: boolean; onClose: () => void; data?: { aircraft?: any[]; risks?: any[]; organizations?: any[]; documents?: any[]; audits?: any[]; checklists?: any[]; applications?: any[]; }; } export default function GlobalSearch({ isOpen, onClose, data = {} }: GlobalSearchProps) { const router = useRouter(); const [query, setQuery] = useState(''); const [suggestions, setSuggestions] = useState([]); const [results, setResults] = useState([]); const [selectedIndex, setSelectedIndex] = useState(-1); const [showSuggestions, setShowSuggestions] = useState(false); const inputRef = useRef(null); const { addToHistory } = useSearchHistory(); const { setSearch } = useUrlParams(); useEffect(() => { if (isOpen && inputRef.current) { inputRef.current.focus(); } }, [isOpen]); useEffect(() => { if (query.length >= 2) { const suggestionsList = getSearchSuggestions(data, query, 5); setSuggestions(suggestionsList); setShowSuggestions(suggestionsList.length > 0); // Выполняем поиск const searchResults = globalSearch(data, query); setResults(searchResults); } else { setSuggestions([]); setResults([]); setShowSuggestions(false); } }, [query, data]); const handleSearch = (searchQuery: string = query) => { if (!searchQuery.trim()) { return; } addToHistory(searchQuery, results.length); setSearch(searchQuery); onClose(); // Переходим на страницу результатов или первую найденную страницу if (results.length > 0) { router.push(results[0].url); } }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { if (selectedIndex >= 0 && selectedIndex < suggestions.length) { const selectedSuggestion = suggestions[selectedIndex]; setQuery(selectedSuggestion); handleSearch(selectedSuggestion); } else { handleSearch(); } } else if (e.key === 'ArrowDown') { e.preventDefault(); setSelectedIndex((prev) => prev < suggestions.length - 1 ? prev + 1 : prev ); } else if (e.key === 'ArrowUp') { e.preventDefault(); setSelectedIndex((prev) => (prev > 0 ? prev - 1 : -1)); } else if (e.key === 'Escape') { onClose(); } }; const handleSuggestionClick = (suggestion: string) => { setQuery(suggestion); handleSearch(suggestion); }; const handleResultClick = (result: SearchResult) => { addToHistory(query, results.length); router.push(result.url); onClose(); }; if (!isOpen) { return null; } return (
e.stopPropagation()} > {/* Поле поиска */}
🔍 { setQuery(e.target.value); setSelectedIndex(-1); }} onKeyDown={handleKeyDown} placeholder="Поиск по ВС, рискам, организациям..." style={{ flex: 1, padding: '12px', border: '1px solid #ddd', borderRadius: '4px', fontSize: '16px', outline: 'none', }} /> {query && ( )}
{/* Результаты */}
{showSuggestions && suggestions.length > 0 && (
Предложения
{suggestions.map((suggestion, index) => (
handleSuggestionClick(suggestion)} style={{ padding: '12px 16px', cursor: 'pointer', backgroundColor: selectedIndex === index ? '#f5f5f5' : 'white', borderLeft: selectedIndex === index ? '3px solid #1e3a5f' : '3px solid transparent', }} > {suggestion}
))}
)} {results.length > 0 && (
Результаты ({results.length})
{results.slice(0, 10).map((result) => (
handleResultClick(result)} style={{ padding: '12px 16px', cursor: 'pointer', borderBottom: '1px solid #f0f0f0', display: 'flex', justifyContent: 'space-between', alignItems: 'center', }} onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = '#f5f5f5'; }} onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = 'white'; }} >
{result.title}
{result.subtitle && (
{result.subtitle}
)}
{result.type === 'aircraft' && '✈️'} {result.type === 'risk' && '⚠️'} {result.type === 'organization' && '🏢'} {result.type === 'document' && '📄'} {result.type === 'audit' && '🔍'} {result.type === 'checklist' && '✅'} {result.type === 'application' && '📋'}
))}
)} {query.length >= 2 && results.length === 0 && (
Ничего не найдено
)} {query.length < 2 && (
Введите минимум 2 символа для поиска
)}
{/* Подсказка */}
Нажмите Enter для поиска Esc для закрытия
); }