"use client"; import { useRef, useCallback, useEffect } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import { useTranslation } from "../../lib/i18n/context"; interface FieldDef { name: string; type: "text" | "select"; placeholder?: string; label: string; options?: { value: string; label: string }[]; className?: string; } interface LiveSearchFormProps { fields: FieldDef[]; basePath: string; debounceMs?: number; } export function LiveSearchForm({ fields, basePath, debounceMs = 300 }: LiveSearchFormProps) { const router = useRouter(); const searchParams = useSearchParams(); const { t } = useTranslation(); const timerRef = useRef | null>(null); const formRef = useRef(null); const buildUrl = useCallback((): string => { if (!formRef.current) return basePath; const formData = new FormData(formRef.current); const params = new URLSearchParams(); for (const [key, value] of formData.entries()) { const str = value.toString().trim(); if (str) params.set(key, str); } const qs = params.toString(); return qs ? `${basePath}?${qs}` : basePath; }, [basePath]); const navigate = useCallback((immediate: boolean) => { if (timerRef.current) clearTimeout(timerRef.current); if (immediate) { router.replace(buildUrl() as any); } else { timerRef.current = setTimeout(() => { router.replace(buildUrl() as any); }, debounceMs); } }, [router, buildUrl, debounceMs]); useEffect(() => { return () => { if (timerRef.current) clearTimeout(timerRef.current); }; }, []); const hasFilters = fields.some((f) => { const val = searchParams.get(f.name); return val && val.trim() !== ""; }); return (
{ e.preventDefault(); if (timerRef.current) clearTimeout(timerRef.current); router.replace(buildUrl() as any); }} className="flex flex-col sm:flex-row gap-3 items-start sm:items-end" > {fields.map((field) => field.type === "text" ? (
navigate(false)} className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2" />
) : (
) )} {hasFilters && ( )}
); }