'use client' /** * ThemenSuche - Autocomplete search for Abitur themes * Features debounced API calls, suggestion display, and keyboard navigation */ import { useState, useEffect, useRef, useCallback } from 'react' import { Search, X, Loader2 } from 'lucide-react' import type { ThemaSuggestion } from '@/lib/education/abitur-archiv-types' import { POPULAR_THEMES } from '@/lib/education/abitur-archiv-types' interface ThemenSucheProps { onSearch: (query: string) => void onClear: () => void placeholder?: string } export function ThemenSuche({ onSearch, onClear, placeholder = 'Thema suchen (z.B. Gedichtanalyse, Eroerterung, Drama...)' }: ThemenSucheProps) { const [query, setQuery] = useState('') const [suggestions, setSuggestions] = useState([]) const [loading, setLoading] = useState(false) const [showDropdown, setShowDropdown] = useState(false) const [selectedIndex, setSelectedIndex] = useState(-1) const inputRef = useRef(null) const dropdownRef = useRef(null) // Debounced API call for suggestions useEffect(() => { const timer = setTimeout(async () => { if (query.length >= 2) { setLoading(true) try { const res = await fetch(`/api/education/abitur-archiv/suggest?q=${encodeURIComponent(query)}`) const data = await res.json() setSuggestions(data.suggestions || []) setShowDropdown(true) } catch (error) { console.error('Suggest error:', error) // Fallback to popular themes setSuggestions(POPULAR_THEMES.filter(t => t.label.toLowerCase().includes(query.toLowerCase()) )) } finally { setLoading(false) } } else if (query.length === 0) { setSuggestions(POPULAR_THEMES) } else { setSuggestions([]) } }, 300) return () => clearTimeout(timer) }, [query]) // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (e: MouseEvent) => { if ( dropdownRef.current && !dropdownRef.current.contains(e.target as Node) && inputRef.current && !inputRef.current.contains(e.target as Node) ) { setShowDropdown(false) } } document.addEventListener('mousedown', handleClickOutside) return () => document.removeEventListener('mousedown', handleClickOutside) }, []) const handleKeyDown = useCallback((e: React.KeyboardEvent) => { if (!showDropdown || suggestions.length === 0) return switch (e.key) { case 'ArrowDown': e.preventDefault() setSelectedIndex(prev => Math.min(prev + 1, suggestions.length - 1)) break case 'ArrowUp': e.preventDefault() setSelectedIndex(prev => Math.max(prev - 1, -1)) break case 'Enter': e.preventDefault() if (selectedIndex >= 0) { handleSelectSuggestion(suggestions[selectedIndex]) } else if (query.trim()) { handleSearch() } break case 'Escape': setShowDropdown(false) setSelectedIndex(-1) break } }, [showDropdown, suggestions, selectedIndex, query]) const handleSelectSuggestion = (suggestion: ThemaSuggestion) => { setQuery(suggestion.label) setShowDropdown(false) setSelectedIndex(-1) onSearch(suggestion.label) } const handleSearch = () => { if (query.trim()) { onSearch(query.trim()) setShowDropdown(false) } } const handleClear = () => { setQuery('') setSuggestions(POPULAR_THEMES) setShowDropdown(false) setSelectedIndex(-1) onClear() inputRef.current?.focus() } const handleFocus = () => { if (query.length === 0) { setSuggestions(POPULAR_THEMES) } setShowDropdown(true) } return (
{/* Search Input */}
{loading ? ( ) : ( )}
{ setQuery(e.target.value) setSelectedIndex(-1) }} onKeyDown={handleKeyDown} onFocus={handleFocus} placeholder={placeholder} className="w-full pl-12 pr-24 py-3 text-lg border border-slate-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white shadow-sm" />
{query && ( )}
{/* Suggestions Dropdown */} {showDropdown && suggestions.length > 0 && (
{query.length === 0 && (
Beliebte Themen
)} {suggestions.map((suggestion, index) => ( ))}
)} {/* Quick Theme Tags */} {!showDropdown && query.length === 0 && (
Vorschlaege: {POPULAR_THEMES.slice(0, 5).map((theme) => ( ))}
)}
) }