"use client"; import { useCallback, useEffect, useState } from "react"; import { useRouter, useSearchParams, usePathname } from "next/navigation"; import { Icon } from "@iconify/react"; export function SearchBar({ placeholder = "Search…", paramName = "_q", }: { placeholder?: string; paramName?: string; }) { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); const [value, setValue] = useState(searchParams.get(paramName) ?? ""); // Sync when URL changes externally useEffect(() => { setValue(searchParams.get(paramName) ?? ""); }, [searchParams, paramName]); const push = useCallback( (q: string) => { const sp = new URLSearchParams(searchParams.toString()); if (q.trim()) { sp.set(paramName, q.trim()); } else { sp.delete(paramName); } sp.set("_page", "1"); router.push(`${pathname}?${sp.toString()}`); }, [router, pathname, searchParams, paramName] ); // Debounce: push URL 300ms after typing stops useEffect(() => { const timer = setTimeout(() => { const current = searchParams.get(paramName) ?? ""; if (value.trim() !== current) push(value); }, 300); return () => clearTimeout(timer); }, [value]); // eslint-disable-line react-hooks/exhaustive-deps return (
setValue(e.target.value)} placeholder={placeholder} className="h-10 w-full min-w-0 rounded-md border border-input bg-background pl-8 pr-3 text-base text-foreground placeholder:text-muted-foreground focus:border-ring focus:outline-none focus:ring-[3px] focus:ring-ring/50 sm:h-9 sm:text-sm [touch-action:manipulation]" />
); }