import { useEffect, useRef, useState } from 'react' import { Facets, formatInt, ORIGIN_KEYS, ORIGIN_LABELS } from '../api' export interface FilterValues { q: string category: string region: string origins: string[] priceMin: string priceMax: string sort: string } interface BodyProps { facets: Facets | null values: FilterValues onChange: (patch: Partial) => void /** Prefix for input ids so desktop + sheet instances don't collide. */ idPrefix?: string } interface Props extends BodyProps { onReset: () => void } const SORT_OPTIONS: { value: string; label: string }[] = [ { value: 'recent', label: 'Plus récents' }, { value: 'price_asc', label: 'Prix croissant' }, { value: 'price_desc', label: 'Prix décroissant' }, { value: 'title', label: 'Titre (A–Z)' }, ] export function countActiveFilters(values: FilterValues): number { return ( (values.q ? 1 : 0) + (values.category ? 1 : 0) + (values.region ? 1 : 0) + values.origins.length + (values.priceMin ? 1 : 0) + (values.priceMax ? 1 : 0) ) } /** * The filter controls themselves — rendered inside the desktop sidebar * and inside the mobile bottom sheet. */ export function FiltersBody({ facets, values, onChange, idPrefix = '' }: BodyProps) { const [search, setSearch] = useState(values.q) const debounceRef = useRef(undefined) const firstRender = useRef(true) // Keep local search in sync when URL changes externally (back button, chips…) useEffect(() => { setSearch(values.q) }, [values.q]) // Debounced propagation of the search input (300 ms) useEffect(() => { if (firstRender.current) { firstRender.current = false return } window.clearTimeout(debounceRef.current) debounceRef.current = window.setTimeout(() => { if (search !== values.q) onChange({ q: search }) }, 300) return () => window.clearTimeout(debounceRef.current) // eslint-disable-next-line react-hooks/exhaustive-deps }, [search]) function toggleOrigin(key: string) { const next = values.origins.includes(key) ? values.origins.filter((o) => o !== key) : [...values.origins, key] onChange({ origins: next }) } return (
setSearch(e.target.value)} placeholder="Mot-clé…" />
Catégories
  • {(facets?.categories ?? []).map((c) => (
  • ))}
Origine {ORIGIN_KEYS.map((key) => ( ))}
Prix
onChange({ priceMin: e.target.value })} /> onChange({ priceMax: e.target.value })} />
) } /** * Desktop sidebar (hidden on mobile — the bottom sheet takes over there). */ export default function Filters({ facets, values, onChange, onReset }: Props) { const activeCount = countActiveFilters(values) return ( ) }