infoalloggi-monorepo/apps/infoalloggi/src/providers/RicercaProvider.tsx

207 lines
4.8 KiB
TypeScript
Raw Normal View History

2025-08-04 17:45:44 +02:00
"use client";
import {
2025-08-28 18:27:07 +02:00
parseAsBoolean,
parseAsInteger,
parseAsString,
parseAsStringLiteral,
useQueryState,
2025-08-04 17:45:44 +02:00
} from "nuqs";
2025-08-28 18:27:07 +02:00
import {
createContext,
type FC,
type ReactNode,
useContext,
useMemo,
useTransition,
} from "react";
2025-08-04 17:45:44 +02:00
type RicercaContextType = {
2025-08-28 18:27:07 +02:00
map: boolean;
setMap: (
value: boolean | ((old: boolean) => boolean | null) | null,
) => Promise<URLSearchParams>;
tipo: string;
setTipo: (
value: string | ((old: string) => string | null) | null,
) => Promise<URLSearchParams>;
comune: string;
setComune: (
value: string | ((old: string) => string | null) | null,
) => Promise<URLSearchParams>;
consegna: number | null;
setConsegna: (
value: number | ((old: number | null) => number | null) | null,
) => Promise<URLSearchParams>;
sort: SortTypes;
setSort: (
value: SortTypes | ((old: SortTypes) => SortTypes | null) | null,
) => Promise<URLSearchParams>;
comuniOptions: string[];
tipologieOptions: string[];
consegnaOptions: number[];
sortOptions: typeof sortOptions;
page: number;
setPage: (
value: number | ((old: number | null) => number | null) | null,
) => Promise<URLSearchParams>;
ResetParams: () => Promise<void>;
annunciNumber: number;
setAnnunciNumber: (
value: number | ((old: number) => number | null) | null,
) => Promise<URLSearchParams>;
2025-08-28 18:27:07 +02:00
nFiltri: number;
isLoading: boolean;
2025-08-04 17:45:44 +02:00
};
const sortOptions = ["Recenti", "Prezzo", "Consegna", "Mq"] as const;
2025-08-04 17:45:44 +02:00
//sort as string union
export type SortTypes = (typeof sortOptions)[number];
export type AnnunciOptions = {
2025-08-28 18:27:07 +02:00
comune: string;
tipo: string;
consegna: number;
2025-08-04 17:45:44 +02:00
}[];
const RicercaContext = createContext<RicercaContextType | undefined>(undefined);
export const useRicerca = () => {
2025-08-28 18:27:07 +02:00
const context = useContext(RicercaContext);
if (!context) {
throw new Error("useRicerca must be used within a RicercaProvider");
}
return context;
2025-08-04 17:45:44 +02:00
};
export const RicercaProvider: FC<{
2025-08-28 18:27:07 +02:00
children: ReactNode;
options: AnnunciOptions;
2025-08-04 17:45:44 +02:00
}> = ({ children, options }) => {
2025-08-28 18:27:07 +02:00
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")
2025-08-28 18:27:07 +02:00
.withOptions({ startTransition }),
);
const [page, setPage] = useQueryState(
"p",
parseAsInteger.withDefault(0).withOptions({ clearOnDefault: true }),
);
const [annunciNumber, setAnnunciNumber] = useQueryState(
"n",
parseAsInteger.withDefault(1000).withOptions({ startTransition }),
);
2025-08-28 18:27:07 +02:00
const tipologieOptions = useMemo(() => {
const set = new Set<string>();
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<string>();
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));
2025-08-28 18:27:07 +02:00
}, [options, tipo, consegna]);
const consegnaOptions = useMemo(() => {
const set = new Set<number>();
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;
});
2025-08-28 18:27:07 +02:00
}, [options, tipo, comune]);
const ResetParams = async () => {
await setTipo("");
await setComune("");
await setConsegna(null);
await setSort("Recenti");
//await setPage(0);
2025-08-28 18:27:07 +02:00
};
const nFiltri =
[tipo, comune].reduce(
2025-08-28 18:27:07 +02:00
(count, item) => (item !== "" ? count + 1 : count),
0,
) +
(consegna !== null ? 1 : 0) +
(sort !== "Recenti" ? 1 : 0);
2025-08-28 18:27:07 +02:00
return (
<RicercaContext.Provider
value={{
comune,
comuniOptions,
2025-08-29 16:18:32 +02:00
consegna,
2025-08-28 18:27:07 +02:00
consegnaOptions,
2025-08-29 16:18:32 +02:00
isLoading,
map,
nFiltri,
2025-08-28 18:27:07 +02:00
page,
ResetParams,
2025-08-29 16:18:32 +02:00
setComune,
setConsegna,
setMap,
setPage,
setSort,
setTipo,
sort,
sortOptions: sortOptions,
tipo,
tipologieOptions,
annunciNumber,
setAnnunciNumber,
2025-08-28 18:27:07 +02:00
}}
>
{children}
</RicercaContext.Provider>
);
2025-08-04 17:45:44 +02:00
};