"use client"; import { parseAsBoolean, parseAsInteger, parseAsString, parseAsStringLiteral, useQueryState, } from "nuqs"; import { createContext, type FC, type ReactNode, useContext, useMemo, useTransition, } from "react"; type RicercaContextType = { map: boolean; setMap: ( value: boolean | ((old: boolean) => boolean | null) | null, ) => Promise; tipo: string; setTipo: ( value: string | ((old: string) => string | null) | null, ) => Promise; comune: string; setComune: ( value: string | ((old: string) => string | null) | null, ) => Promise; consegna: number | null; setConsegna: ( value: number | ((old: number | null) => number | null) | null, ) => Promise; sort: SortTypes; setSort: ( value: SortTypes | ((old: SortTypes) => SortTypes | null) | null, ) => Promise; comuniOptions: string[]; tipologieOptions: string[]; consegnaOptions: number[]; sortOptions: typeof sortOptions; page: number; setPage: ( value: number | ((old: number | null) => number | null) | null, ) => Promise; ResetParams: () => Promise; nFiltri: number; isLoading: boolean; }; const sortOptions = ["Recenti", "Prezzo", "Consegna", "Mq"] as const; //sort as string union export type SortTypes = (typeof sortOptions)[number]; export type AnnunciOptions = { comune: string; tipo: string; consegna: number; }[]; const RicercaContext = createContext(undefined); export const useRicerca = () => { const context = useContext(RicercaContext); if (!context) { throw new Error("useRicerca must be used within a RicercaProvider"); } return context; }; export const RicercaProvider: FC<{ children: ReactNode; options: AnnunciOptions; }> = ({ children, options }) => { const [isLoading, startTransition] = useTransition(); const [map, setMap] = useQueryState( "map", parseAsBoolean.withDefault(false).withOptions({ startTransition }), ); const [tipo, setTipo] = useQueryState( "tipo", parseAsString.withDefault("").withOptions({ startTransition }), ); const [comune, setComune] = useQueryState( "comune", parseAsString.withDefault("").withOptions({ startTransition }), ); const [consegna, setConsegna] = useQueryState( "consegna", parseAsInteger.withOptions({ startTransition }), ); const [sort, setSort] = useQueryState( "sort", parseAsStringLiteral(sortOptions) .withDefault("Recenti") .withOptions({ startTransition }), ); const [page, setPage] = useQueryState( "p", parseAsInteger.withDefault(0).withOptions({ clearOnDefault: true }), ); const tipologieOptions = useMemo(() => { const set = new Set(); options.forEach((item) => { if (!comune || item.comune === comune) { if (!consegna || item.consegna === consegna) { set.add(item.tipo); } } }); return Array.from(set); }, [options, comune, consegna]); const comuniOptions = useMemo(() => { const set = new Set(); options.forEach((item) => { if (!tipo || item.tipo === tipo) { if (!consegna || item.consegna === consegna) { set.add(item.comune); } } }); return Array.from(set).sort((a, b) => a.localeCompare(b)); }, [options, tipo, consegna]); const consegnaOptions = useMemo(() => { const set = new Set(); options.forEach((item) => { if (!tipo || item.tipo === tipo) { if (!comune || item.comune === comune) { set.add(item.consegna); } } }); const currentMonth = new Date().getMonth() + 1; // 1-12 return Array.from(set).sort((a, b) => { // Calculate distance from current month (wrapping around) const distA = (a - currentMonth + 12) % 12; const distB = (b - currentMonth + 12) % 12; return distA - distB; }); }, [options, tipo, comune]); const ResetParams = async () => { await setTipo(""); await setComune(""); await setConsegna(null); await setSort("Recenti"); await setPage(0); }; const nFiltri = [tipo, comune].reduce( (count, item) => (item !== "" ? count + 1 : count), 0, ) + (consegna !== null ? 1 : 0) + (sort !== "Recenti" ? 1 : 0); return ( {children} ); };