/** * [F11-S1] SearchBar — Debounced text search input with result count badge * * Features: * - 200ms debounced input * - Clear button * - "N of M results" counter */ import React, { useCallback, useEffect, useRef, useState } from 'react'; export interface SearchBarProps { onQueryChange: (query: string) => void; resultCount: number; totalCount: number; placeholder?: string; } export function SearchBar({ onQueryChange, resultCount, totalCount, placeholder = 'Search events…', }: SearchBarProps): React.ReactElement { const [inputValue, setInputValue] = useState(''); const timerRef = useRef | null>(null); const handleChange = useCallback( (e: React.ChangeEvent) => { const val = e.target.value; setInputValue(val); if (timerRef.current) clearTimeout(timerRef.current); timerRef.current = setTimeout(() => { onQueryChange(val); }, 200); }, [onQueryChange], ); const handleClear = useCallback(() => { setInputValue(''); if (timerRef.current) clearTimeout(timerRef.current); onQueryChange(''); }, [onQueryChange]); useEffect(() => { return () => { if (timerRef.current) clearTimeout(timerRef.current); }; }, []); const hasQuery = inputValue.length > 0; return (
🔍 {hasQuery && ( )}
{hasQuery && ( {resultCount} {' of '} {totalCount} {' results'} )}
); }