/** * T079: Search bar with debounced queries and dropdown results */ import { useState, useEffect, useCallback } from 'react'; import { Search, X } from 'lucide-react'; import { Command, CommandGroup, CommandItem, CommandList, } from '@/components/ui/command'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { searchNotes } from '@/services/api'; import type { SearchResult } from '@/types/search'; interface SearchBarProps { onSelectNote: (path: string) => void; } export function SearchBar({ onSelectNote }: SearchBarProps) { const [query, setQuery] = useState(''); const [debouncedQuery, setDebouncedQuery] = useState(''); const [results, setResults] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isOpen, setIsOpen] = useState(false); // Debounce search query (300ms) useEffect(() => { const timer = setTimeout(() => { setDebouncedQuery(query); }, 300); return () => clearTimeout(timer); }, [query]); // Execute search when debounced query changes useEffect(() => { if (!debouncedQuery.trim()) { setResults([]); setIsOpen(false); return; } const performSearch = async () => { setIsLoading(true); try { const searchResults = await searchNotes(debouncedQuery); setResults(searchResults); setIsOpen(searchResults.length > 0); } catch (error) { console.error('Search error:', error); setResults([]); setIsOpen(false); } finally { setIsLoading(false); } }; performSearch(); }, [debouncedQuery]); const handleSelectResult = useCallback( (path: string) => { onSelectNote(path); setQuery(''); setResults([]); setIsOpen(false); }, [onSelectNote] ); const handleClear = useCallback(() => { setQuery(''); setResults([]); setIsOpen(false); }, []); return (
setQuery(e.target.value)} onFocus={() => { if (results.length > 0) { setIsOpen(true); } }} /> {query && ( )}
{isOpen && results.length > 0 && (
{results.map((result) => ( handleSelectResult(result.note_path)} className="cursor-pointer" >
{result.title}
{result.snippet}
{result.note_path}
))}
)} {isLoading && (
Searching...
)}
); }