diff --git a/apps/infoalloggi/src/pages/_app.tsx b/apps/infoalloggi/src/pages/_app.tsx index 88707ba..875c82b 100644 --- a/apps/infoalloggi/src/pages/_app.tsx +++ b/apps/infoalloggi/src/pages/_app.tsx @@ -73,7 +73,10 @@ const MyApp = ({ `} - + {!router.pathname.startsWith("/annunci") && ( + + )} + {getLayout()} diff --git a/apps/infoalloggi/src/pages/annunci.tsx b/apps/infoalloggi/src/pages/annunci.tsx index f1973ab..cb5bb99 100644 --- a/apps/infoalloggi/src/pages/annunci.tsx +++ b/apps/infoalloggi/src/pages/annunci.tsx @@ -29,10 +29,7 @@ import { Status500 } from "~/components/status-page"; import { CodiceBox } from "~/components/codiceRicerca"; import { generateSSGHelper } from "~/server/utils/ssgHelper"; import { MapSection } from "~/components/annunci_map"; - import { api } from "~/utils/api"; -import { useRouter } from "next/router"; -import toast from "react-hot-toast"; import { DropdownMenu, DropdownMenuContent, @@ -47,6 +44,7 @@ import { } from "~/providers/RicercaProvider"; import { AccordionComp } from "~/components/accordionComp"; import { CTA_TipologiaModal } from "~/components/annunci_tutorial"; +import { keepPreviousData } from "@tanstack/react-query"; type AnnunciPageProps = { options: AnnunciOptions; @@ -265,7 +263,6 @@ const RicercaFilters = () => { }; const AnnunciList = () => { - const router = useRouter(); const { tipo, comune, @@ -274,68 +271,110 @@ const AnnunciList = () => { map, page, setPage, - lastPageCount, - setlastPageCount, isLoading: ricercaLoading, } = useRicerca(); - const { data, fetchNextPage, isLoading, hasNextPage } = - api.annunci.getWithCursor.useInfiniteQuery( + const { data, status, isPlaceholderData } = + api.annunci.getWithCursor.useQuery( { - limit: 6, + page, + pageSize: 6, tipologia: tipo || undefined, comune: comune || undefined, consegna: consegna || undefined, sort: sort || undefined, }, { - getNextPageParam: (lastPage) => lastPage.nextCursor, + placeholderData: keepPreviousData, enabled: !map, + staleTime: 5000, }, ); - - const handlePageReset = () => { - setPage(0); - }; - - const handleFetchNextPage = async () => { - try { - await fetchNextPage(); - setPage((prev) => prev + 1); - } catch { - await router.push("/annunci"); - toast.error("Errore caricamento annunci"); - } - }; - - const handleFetchPreviousPage = () => { - setPage((prev) => prev - 1); - }; - + const utils = api.useUtils(); useEffect(() => { - if ( - hasNextPage !== undefined && - hasNextPage === false && - lastPageCount === 100 - ) { - setlastPageCount(page); - } - }, [hasNextPage, page, lastPageCount]); + const prefetchData = async () => { + if (!isPlaceholderData && data?.hasMore) { + await utils.annunci.getWithCursor.prefetch({ + page: page + 1, + pageSize: 6, + tipologia: tipo || undefined, + comune: comune || undefined, + consegna: consegna || undefined, + sort: sort || undefined, + }); + } + }; + prefetchData().catch((err) => { + console.error("Error prefetching next page:", err); + }); + }, [data, isPlaceholderData, page]); - if (isLoading || ricercaLoading) return ; - if ((!isLoading && !data) || !data) return ; + if (ricercaLoading) return ; + if (status === "error") return ; return ( <> - + {status === "pending" ? ( + + ) : ( + + )}
- + +
+
+ +
+
+ +
+
+ + {page + 1} + +
+
+ +
+
); }; @@ -396,73 +435,3 @@ export const SelectFilter = ({ ); }; - -const PaginationHandler = ({ - handleFetchNextPage, - handleFetchPreviousPage, - handlePageReset, - page, - hasNextPage, -}: { - handleFetchNextPage: () => Promise; - handleFetchPreviousPage: () => void; - handlePageReset: () => void; - page: number; - hasNextPage: string | undefined; -}) => { - const [attivo, setAttivo] = useState(true); - const fetchNextPage = async () => { - setAttivo(false); - await handleFetchNextPage(); - setAttivo(true); - }; - - return ( -
-
- -
-
- -
-
- - {page + 1} - -
-
- -
-
- ); -}; diff --git a/apps/infoalloggi/src/providers/RicercaProvider.tsx b/apps/infoalloggi/src/providers/RicercaProvider.tsx index ef23fa1..e29dfd1 100644 --- a/apps/infoalloggi/src/providers/RicercaProvider.tsx +++ b/apps/infoalloggi/src/providers/RicercaProvider.tsx @@ -3,12 +3,9 @@ import { createContext, useContext, useMemo, - useState, useTransition, - type Dispatch, type FC, type ReactNode, - type SetStateAction, } from "react"; import { parseAsBoolean, @@ -45,9 +42,9 @@ type RicercaContextType = { consegnaOptions: number[]; sortOptions: typeof sortOptions; page: number; - setPage: Dispatch>; - lastPageCount: number; - setlastPageCount: Dispatch>; + setPage: ( + value: number | ((old: number | null) => number | null) | null, + ) => Promise; ResetParams: () => Promise; nFiltri: number; isLoading: boolean; @@ -103,8 +100,10 @@ export const RicercaProvider: FC<{ .withOptions({ startTransition }), ); - const [page, setPage] = useState(0); - const [lastPageCount, setlastPageCount] = useState(100); + const [page, setPage] = useQueryState( + "p", + parseAsInteger.withDefault(0).withOptions({ clearOnDefault: true }), + ); const tipologieOptions = useMemo(() => { const set = new Set(); @@ -147,7 +146,7 @@ export const RicercaProvider: FC<{ await setComune(""); await setConsegna(null); await setSort(""); - setPage(0); + await setPage(0); }; const nFiltri = @@ -176,8 +175,6 @@ export const RicercaProvider: FC<{ page, setPage, - lastPageCount, - setlastPageCount, ResetParams, nFiltri, isLoading, diff --git a/apps/infoalloggi/src/server/api/routers/annunci.ts b/apps/infoalloggi/src/server/api/routers/annunci.ts index 56517d8..27e6cab 100644 --- a/apps/infoalloggi/src/server/api/routers/annunci.ts +++ b/apps/infoalloggi/src/server/api/routers/annunci.ts @@ -57,8 +57,8 @@ export const annunciRouter = createTRPCRouter({ getWithCursor: publicProcedure .input( z.object({ - limit: z.number().min(1).max(100).optional(), - cursor: z.string().optional(), + page: z.number().optional(), + pageSize: z.number(), tipologia: z.string().optional(), comune: z.string().optional(), consegna: z.number().optional(), @@ -66,13 +66,9 @@ export const annunciRouter = createTRPCRouter({ }), ) .query(async ({ input }) => { - const { annunci, nextCursor } = await getCursor_AnnunciHandler({ - input, + return await getCursor_AnnunciHandler({ + ...input, }); - return { - annunci, - nextCursor, - }; }), getMapping: publicProcedure .input( diff --git a/apps/infoalloggi/src/server/controllers/annunci.controller.ts b/apps/infoalloggi/src/server/controllers/annunci.controller.ts index 3c07fa3..6920300 100644 --- a/apps/infoalloggi/src/server/controllers/annunci.controller.ts +++ b/apps/infoalloggi/src/server/controllers/annunci.controller.ts @@ -233,34 +233,20 @@ export type AnnuncioRicerca = Pick< >; export const getCursor_AnnunciHandler = async ({ - input, + page = 0, + pageSize, + tipologia, + comune, + consegna, + sort, }: { - input: { - limit?: number; - cursor?: string; - tipologia?: string; - comune?: string; - consegna?: number; - sort?: "Recenti" | "Prezzo" | "Consegna" | "Mq"; - }; -}): Promise<{ - annunci: AnnuncioRicerca[]; - nextCursor: string | undefined; -}> => { - const limit = input.limit ?? 50; - const [cursor, sortCursor] = input.cursor?.split("_") ?? [0, undefined]; - function sortType(sort: "Recenti" | "Prezzo" | "Consegna" | "Mq") { - switch (sort) { - case "Recenti": - return { col: "modificato_il", opr: "desc" }; - case "Prezzo": - return { col: "prezzo", opr: "asc" }; - case "Consegna": - return { col: "consegna", opr: "asc" }; - case "Mq": - return { col: "mq", opr: "asc" }; - } - } + page?: number; + pageSize: number; + tipologia?: string; + comune?: string; + consegna?: number; + sort?: "Recenti" | "Prezzo" | "Consegna" | "Mq"; +}) => { try { let query = db .selectFrom("annunci") @@ -283,35 +269,18 @@ export const getCursor_AnnunciHandler = async ({ .where("web", "=", true) .where("stato", "!=", "Sospeso"); - if (sortCursor && input.sort !== undefined) { - const { col: sortColumn, opr } = sortType(input.sort) as { - col: keyof Annunci; - opr: string; - }; - query = query.where((eb) => - eb.or([ - eb.and([ - eb("id", ">=", (cursor as AnnunciId) ?? 0), - eb(sortColumn, "=", sortCursor.toString()), - ]), - eb(sortColumn, opr === "desc" ? "<" : ">", sortCursor.toString()), - ]), - ); - } else { - query = query.where("id", ">=", (cursor as AnnunciId) ?? 0); - } - if (input.tipologia && input.tipologia !== "") { - query = query.where("tipo", "=", input.tipologia); + if (tipologia && tipologia !== "") { + query = query.where("tipo", "=", tipologia); } - if (input.comune && input.comune !== "") { - query = query.where("comune", "like", input.comune); + if (comune && comune !== "") { + query = query.where("comune", "like", comune); } - if (input.consegna) { - query = query.where("consegna", "=", input.consegna); + if (consegna) { + query = query.where("consegna", "=", consegna); } - if (input.sort) { - switch (input.sort) { + if (sort) { + switch (sort) { case "Recenti": query = query.orderBy("modificato_il", "desc"); break; @@ -328,32 +297,13 @@ export const getCursor_AnnunciHandler = async ({ } query = query.orderBy("id", "asc"); - const itemsraw = await query.limit(limit + 1).execute(); - const annunci = itemsraw; - let nextCursor: string | undefined = undefined; - - if (annunci.length > limit) { - const nextItem = annunci.pop(); // return the last item from the array - if (!nextItem) { - throw new TRPCError({ - code: "INTERNAL_SERVER_ERROR", - message: "Errore interno", - }); - } - if (!input.sort) { - nextCursor = nextItem.id.toString(); - } else { - const { col: sortColumn } = sortType(input.sort); - if (sortColumn === "modificato_il") { - if (!nextItem.modificato_il) { - nextCursor = `${nextItem.id.toString()}_1990-01-01`; - } else { - nextCursor = `${nextItem.id.toString()}_${nextItem.modificato_il.toISOString()}`; - } - } else { - nextCursor = `${nextItem.id.toString()}_${nextItem[sortColumn as keyof typeof nextItem]?.toString()}`; - } - } + const annunci = await query + .limit(pageSize + 1) + .offset(page * pageSize) + .execute(); + const hasMore = annunci.length > pageSize; + if (annunci.length > pageSize) { + annunci.pop(); // Remove the last item if it exceeds the page size } for (const annuncio of annunci) { @@ -361,9 +311,10 @@ export const getCursor_AnnunciHandler = async ({ ? createSrcset(annuncio.url_immagini) : []; } + return { annunci, - nextCursor, + hasMore, }; } catch { throw new TRPCError({