56 lines
1.9 KiB
TypeScript
56 lines
1.9 KiB
TypeScript
'use client'
|
|
|
|
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
|
|
import { useTransition, useRef } from 'react'
|
|
|
|
export default function LiveFilterForm({ children }: { children: React.ReactNode }) {
|
|
const router = useRouter()
|
|
const pathname = usePathname()
|
|
const searchParams = useSearchParams()
|
|
const [isPending, startTransition] = useTransition()
|
|
const debounceTimer = useRef<NodeJS.Timeout | null>(null)
|
|
|
|
function updateRoute(form: HTMLFormElement) {
|
|
const formData = new FormData(form)
|
|
const params = new URLSearchParams(searchParams.toString())
|
|
|
|
const search = formData.get('search') as string
|
|
const neighborhood = formData.get('neighborhood') as string
|
|
const price = formData.get('price') as string
|
|
const approved = formData.get('approved') as string
|
|
|
|
if (search) params.set('search', search)
|
|
else params.delete('search')
|
|
|
|
if (neighborhood) params.set('neighborhood', neighborhood)
|
|
else params.delete('neighborhood')
|
|
|
|
if (price) params.set('price', price)
|
|
else params.delete('price')
|
|
|
|
if (approved) params.set('approved', 'true')
|
|
else params.delete('approved')
|
|
|
|
startTransition(() => {
|
|
router.push(`${pathname}?${params.toString()}`, { scroll: false })
|
|
})
|
|
}
|
|
|
|
function onChange(e: React.FormEvent<HTMLFormElement>) {
|
|
const form = e.currentTarget
|
|
if (debounceTimer.current) clearTimeout(debounceTimer.current)
|
|
debounceTimer.current = setTimeout(() => {
|
|
updateRoute(form)
|
|
}, 300)
|
|
}
|
|
|
|
return (
|
|
<form onChange={onChange} onSubmit={(e) => { e.preventDefault(); updateRoute(e.currentTarget); }} className="grid grid-cols-1 sm:grid-cols-4 gap-4 items-end relative">
|
|
{children}
|
|
{isPending && (
|
|
<div className="absolute inset-0 bg-stone/20 backdrop-blur-[1px] flex items-center justify-center z-10 rounded-xl transition-all" />
|
|
)}
|
|
</form>
|
|
)
|
|
}
|