'use client' import { useState, useEffect, useCallback, useRef } from 'react' interface UseSearchOptions { debounceMs?: number onSearch?: (query: string) => void | Promise } interface UseSearchReturn { query: string setQuery: (query: string) => void debouncedQuery: string isDebouncing: boolean clearSearch: () => void } /** * Custom hook for managing search state with debouncing * Validates: Requirements 6.4, 8.3 */ export function useSearch(options: UseSearchOptions = {}): UseSearchReturn { const { debounceMs = 300, onSearch } = options const [query, setQuery] = useState('') const [debouncedQuery, setDebouncedQuery] = useState('') const [isDebouncing, setIsDebouncing] = useState(false) const timeoutRef = useRef(null) // Debounce the query useEffect(() => { // If query is empty, update immediately if (!query.trim()) { setDebouncedQuery('') setIsDebouncing(false) return } setIsDebouncing(true) // Clear existing timeout if (timeoutRef.current) { clearTimeout(timeoutRef.current) } // Set new timeout timeoutRef.current = setTimeout(() => { setDebouncedQuery(query) setIsDebouncing(false) }, debounceMs) // Cleanup return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current) } } }, [query, debounceMs]) // Call onSearch callback when debounced query changes useEffect(() => { if (onSearch) { onSearch(debouncedQuery) } }, [debouncedQuery, onSearch]) // Clear search function const clearSearch = useCallback(() => { setQuery('') setDebouncedQuery('') setIsDebouncing(false) if (timeoutRef.current) { clearTimeout(timeoutRef.current) } }, []) return { query, setQuery, debouncedQuery, isDebouncing, clearSearch } }