import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Search, X } from 'lucide-react'; import { HTMLAttributes, useState, useEffect, useRef } from 'react'; import { cn } from '@/lib/utils'; import { Link } from "@inertiajs/react"; interface NavigationArticle { id: number; title: string; slug: string; external?: boolean; active?: boolean; } interface NavigationCategory { id: number; name: string; type: 'category'; articles: NavigationArticle[]; } interface NavigationArticleItem { id: number; type: 'article'; article: NavigationArticle; } type NavigationItem = NavigationCategory | NavigationArticleItem; export function SearchInput({ className = '', ...props }: HTMLAttributes) { const [searchTerm, setSearchTerm] = useState(''); const [navigationItems, setNavigationItems] = useState([]); const [searchResults, setSearchResults] = useState>([]); const [isSearching, setIsSearching] = useState(false); const [showResults, setShowResults] = useState(false); const searchRef = useRef(null); const inputRef = useRef(null); useEffect(() => { fetch('/api/navigation-items') .then(res => res.json()) .then(data => setNavigationItems(data)); const handleClickOutside = (event: MouseEvent) => { if (searchRef.current && !searchRef.current.contains(event.target as Node)) { setShowResults(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); const handleSearch = () => { if (!searchTerm.trim()) { setSearchResults([]); setShowResults(false); return; } setIsSearching(true); const results: Array<{title: string, slug: string, external?: boolean, category?: string}> = []; const searchTermLower = searchTerm.toLowerCase(); const matchingCategories = navigationItems.filter( item => item.type === 'category' && item.name.toLowerCase().includes(searchTermLower) ); matchingCategories.forEach(category => { if (category.type === 'category' && category.articles) { category.articles.forEach(article => { if (article.active !== false) { results.push({ title: article.title, slug: article.slug, external: article.external, category: category.name }); } }); } }); navigationItems.forEach(item => { if (item.type === 'article' && item.article) { if (item.article.title.toLowerCase().includes(searchTermLower)) { const exists = results.some(r => r.slug === item.article.slug); if (!exists) { results.push({ title: item.article.title, slug: item.article.slug, external: item.article.external }); } } } else if (item.type === 'category' && item.articles) { if (!matchingCategories.includes(item)) { item.articles.forEach(article => { if (article.active !== false && article.title.toLowerCase().includes(searchTermLower)) { const exists = results.some(r => r.slug === article.slug); if (!exists) { results.push({ title: article.title, slug: article.slug, external: article.external, category: item.name }); } } }); } } }); setSearchResults(results); setShowResults(true); setIsSearching(false); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { e.preventDefault(); handleSearch(); } }; const clearSearch = () => { setSearchTerm(''); setSearchResults([]); setShowResults(false); inputRef.current?.focus(); }; return (
setSearchTerm(e.target.value)} onKeyDown={handleKeyDown} onFocus={() => searchTerm && setShowResults(true)} ref={inputRef} /> {searchTerm && ( )}
{showResults && (
{searchResults.length > 0 ? (
{(() => { const groupedResults: Record = {}; searchResults.forEach(result => { if (result.category) { if (!groupedResults[result.category]) { groupedResults[result.category] = []; } groupedResults[result.category].push(result); } }); const uncategorized = searchResults.filter(result => !result.category); if (uncategorized.length > 0) { groupedResults['Inne'] = uncategorized; } return Object.entries(groupedResults).map(([category, results], groupIndex) => (
{category}
)); })()}
) : (
Nie znaleziono wyników dla {searchTerm}
)}
)}
) }