+
);
@@ -230,7 +250,7 @@ const DrowdownFilters = () => {
};
const RicercaHeader = () => {
- const { map, setMap } = useRicerca();
+ const { map, setAllParams } = useRicerca();
return (
@@ -240,7 +260,9 @@ const RicercaHeader = () => {
diff --git a/apps/infoalloggi/src/pages/index.tsx b/apps/infoalloggi/src/pages/index.tsx
index 2210e27..deea50e 100644
--- a/apps/infoalloggi/src/pages/index.tsx
+++ b/apps/infoalloggi/src/pages/index.tsx
@@ -1,14 +1,13 @@
-import { ArrowRight, Telescope } from "lucide-react";
+import { Telescope } from "lucide-react";
import type { NextPage } from "next";
import Head from "next/head";
import Link from "next/link";
import { AccordionComp } from "~/components/accordionComp";
import { CodiceBox } from "~/components/codiceRicerca";
import { ComeFunziona } from "~/components/expand_guida";
+import { FrequentSearches } from "~/components/frequent_searches";
import { PricingChoice } from "~/components/prezzi";
import { HeroSvg, LogoSvg } from "~/components/svgs";
-import { Button } from "~/components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { env } from "~/env";
import type { LangDict } from "~/i18n/locales";
import { useTranslation } from "~/providers/I18nProvider";
@@ -37,11 +36,11 @@ const Home: NextPage = () => {
/>
-
+
-
-
+
@@ -77,7 +76,7 @@ const TrovaCasaCTA = (props: { testi: LangDict }) => {
{testi.index.titolo_2}{" "}
{testi.index.titolo_3}
-
+
@@ -106,68 +105,3 @@ const TrovaCasaCTA = (props: { testi: LangDict }) => {
);
};
-
-const FrequentSearches = () => {
- const { locale } = useTranslation();
- return (
-
-
-
- {locale === "en" ? "Frequent Searches" : "Ricerche frequenti"}
-
-
-
-
-
- Transitori
-
-
-
-
-
- Stabili
-
-
-
-
-
- Bassano del Grappa
-
-
-
-
-
-
- Transitori Bassano
-
-
-
-
-
-
- Marostica
-
-
-
-
-
- );
-};
diff --git a/apps/infoalloggi/src/pages/sitemap.xml.ts b/apps/infoalloggi/src/pages/sitemap.xml.ts
index 2c9173a..f3c294a 100644
--- a/apps/infoalloggi/src/pages/sitemap.xml.ts
+++ b/apps/infoalloggi/src/pages/sitemap.xml.ts
@@ -1,5 +1,6 @@
import type { GetServerSideProps } from "next";
import { env } from "~/env";
+import { buildRicercaUrl } from "~/providers/RicercaProvider";
import { generateSSGHelper } from "~/server/utils/ssgHelper";
async function generateSiteMap() {
@@ -13,10 +14,11 @@ async function generateSiteMap() {
`${env.NEXT_PUBLIC_BASE_URL}/proprietari`,
`${env.NEXT_PUBLIC_BASE_URL}/guida`,
`${env.NEXT_PUBLIC_BASE_URL}/annunci`,
- `${env.NEXT_PUBLIC_BASE_URL}/annunci?t=Transitorio`,
- `${env.NEXT_PUBLIC_BASE_URL}/annunci?c=Bassano+del+Grappa`,
- `${env.NEXT_PUBLIC_BASE_URL}/annunci?t=Stabile`,
- `${env.NEXT_PUBLIC_BASE_URL}/annunci?c=Marostica`,
+ `${env.NEXT_PUBLIC_BASE_URL}${buildRicercaUrl({ tipo: "Transitorio" })}`,
+ `${env.NEXT_PUBLIC_BASE_URL}${buildRicercaUrl({ comune: "Bassano del Grappa" })}`,
+ `${env.NEXT_PUBLIC_BASE_URL}${buildRicercaUrl({ comune: "Bassano del Grappa", tipo: "Transitorio" })}`,
+ `${env.NEXT_PUBLIC_BASE_URL}${buildRicercaUrl({ tipo: "Stabile" })}`,
+ `${env.NEXT_PUBLIC_BASE_URL}${buildRicercaUrl({ comune: "Marostica" })}`,
];
const allUrls = [...staticUrls, ...dynamicUrls];
diff --git a/apps/infoalloggi/src/providers/RicercaProvider.tsx b/apps/infoalloggi/src/providers/RicercaProvider.tsx
index 952c3b2..83c9206 100644
--- a/apps/infoalloggi/src/providers/RicercaProvider.tsx
+++ b/apps/infoalloggi/src/providers/RicercaProvider.tsx
@@ -5,64 +5,85 @@ import {
parseAsInteger,
parseAsString,
parseAsStringLiteral,
- useQueryState,
+ useQueryStates,
} from "nuqs";
import {
createContext,
type FC,
type ReactNode,
+ useCallback,
useContext,
+ useEffect,
useMemo,
+ useState,
useTransition,
} from "react";
+const sortOptions = ["Recenti", "Prezzo", "Consegna", "Mq"] as const;
+export type SortTypes = (typeof sortOptions)[number];
+
+type RicercaUrlParams = {
+ map: boolean;
+ tipo: string;
+ comune: string;
+ consegna: number[];
+ minBudget: number;
+ maxBudget: number;
+ sort: SortTypes;
+};
+
+export const paramsMapping = {
+ map: "m",
+ tipo: "t",
+ comune: "c",
+ consegna: "f",
+ minBudget: "bmin",
+ maxBudget: "bmax",
+ sort: "s",
+} as const;
+
+export const buildRicercaUrl = (params: Partial
): string => {
+ const searchParams = new URLSearchParams();
+ Object.entries(params).forEach(([key, value]) => {
+ const mappedKey = paramsMapping[key as keyof typeof paramsMapping];
+ if (value !== undefined && value !== null) {
+ searchParams.set(mappedKey, value.toString());
+ }
+ });
+ const queryString = searchParams.toString();
+ return queryString ? `/annunci?${queryString}` : "/annunci";
+};
+
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;
-
- minBudget: number | null;
- setMinBudget: (
- value: number | ((old: number | null) => number | null) | null,
- ) => Promise;
- maxBudget: number | null;
- setMaxBudget: (
- value: number | ((old: number | null) => number | null) | null,
- ) => Promise;
-
+ tipo: RicercaUrlParams["tipo"];
+ comune: RicercaUrlParams["comune"] | null;
+ consegna: RicercaUrlParams["consegna"] | null;
+ minBudget: RicercaUrlParams["minBudget"] | null;
+ maxBudget: RicercaUrlParams["maxBudget"] | null;
sort: SortTypes;
- setSort: (
- value: SortTypes | ((old: SortTypes) => SortTypes | null) | null,
+
+ setAllParams: (
+ params: Partial<{
+ tipo: RicercaUrlParams["tipo"];
+ comune: RicercaUrlParams["comune"] | null;
+ consegna: RicercaUrlParams["consegna"] | null;
+ minBudget: RicercaUrlParams["minBudget"] | null;
+ maxBudget: RicercaUrlParams["maxBudget"] | null;
+ sort: RicercaUrlParams["sort"];
+ map: RicercaUrlParams["map"];
+ }>,
) => Promise;
+ reset: () => void;
comuniOptions: string[];
tipologieOptions: string[];
consegnaOptions: number[];
sortOptions: typeof sortOptions;
- 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;
@@ -84,39 +105,36 @@ export const RicercaProvider: FC<{
children: ReactNode;
options: AnnunciOptions;
}> = ({ children, options }) => {
+ const [nFiltri, setNFiltri] = useState(0);
const [isLoading, startTransition] = useTransition();
- const [map, setMap] = useQueryState(
- "m",
- parseAsBoolean.withDefault(false).withOptions({ startTransition }),
- );
- const [tipo, setTipo] = useQueryState(
- "t",
- parseAsString.withDefault("").withOptions({ startTransition }),
- );
- const [comune, setComune] = useQueryState(
- "c",
- parseAsString.withDefault("").withOptions({ startTransition }),
- );
- const [consegna, setConsegna] = useQueryState(
- "f",
- parseAsArrayOf(parseAsInteger).withOptions({ startTransition }),
- );
- const [minBudget, setMinBudget] = useQueryState(
- "bmin",
- parseAsInteger.withOptions({ startTransition }),
- );
- const [maxBudget, setMaxBudget] = useQueryState(
- "bmax",
- parseAsInteger.withOptions({ startTransition }),
- );
- const [sort, setSort] = useQueryState(
- "s",
- parseAsStringLiteral(sortOptions)
- .withDefault("Recenti")
- .withOptions({ startTransition }),
+ const [
+ { map, tipo, comune, consegna, minBudget, maxBudget, sort },
+ setAllParams,
+ ] = useQueryStates(
+ {
+ map: parseAsBoolean.withDefault(false),
+ tipo: parseAsString.withDefault(""),
+ comune: parseAsString.withDefault(""),
+ consegna: parseAsArrayOf(parseAsInteger),
+ minBudget: parseAsInteger,
+ maxBudget: parseAsInteger,
+ sort: parseAsStringLiteral(sortOptions).withDefault("Recenti"),
+ },
+ { startTransition, shallow: true, urlKeys: paramsMapping },
);
+ const reset = useCallback(() => {
+ setAllParams({
+ tipo: "",
+ comune: "",
+ consegna: null,
+ minBudget: null,
+ maxBudget: null,
+ sort: "Recenti",
+ });
+ }, []);
+
const tipologieOptions = useMemo(() => {
const set = new Set();
options.forEach((item) => {
@@ -172,56 +190,43 @@ export const RicercaProvider: FC<{
});
}, [options, tipo, comune, minBudget, maxBudget]);
- const ResetParams = async () => {
- await setTipo("");
- await setComune("");
- await setConsegna(null);
- await setMinBudget(null);
- await setMaxBudget(null);
- await setSort("Recenti");
+ const updateNFiltri = () => {
+ setNFiltri(
+ [tipo, comune].reduce(
+ (count, item) => (item !== "" ? count + 1 : count),
+ 0,
+ ) +
+ (consegna !== null ? 1 : 0) +
+ (sort !== "Recenti" ? 1 : 0) +
+ (minBudget !== null ? 1 : 0) +
+ (maxBudget !== null ? 1 : 0),
+ );
};
- const nFiltri =
- [tipo, comune].reduce(
- (count, item) => (item !== "" ? count + 1 : count),
- 0,
- ) +
- (consegna !== null ? 1 : 0) +
- (sort !== "Recenti" ? 1 : 0) +
- (minBudget !== null ? 1 : 0) +
- (maxBudget !== null ? 1 : 0);
+ useEffect(() => {
+ updateNFiltri();
+ }, [tipo, comune, consegna, minBudget, maxBudget, sort]);
return (
{children}
diff --git a/apps/infoalloggi/src/server/controllers/annunci.controller.ts b/apps/infoalloggi/src/server/controllers/annunci.controller.ts
index 3b0031b..2f94630 100644
--- a/apps/infoalloggi/src/server/controllers/annunci.controller.ts
+++ b/apps/infoalloggi/src/server/controllers/annunci.controller.ts
@@ -19,6 +19,7 @@ import { revalidate } from "../utils/revalidationHelper";
// analytics: true,
// });
export type AnnunciWithMedia = Annunci & {
+ tipo: string;
images: Pick[];
videos: Pick[];
};
@@ -82,14 +83,15 @@ export const getAnnunciByCod = async ({
.selectAll()
.select((_eb) => [withImages(), withVideos()])
.where("annunci.web", "=", true)
+ .where("tipo", "is not", null)
.where("codice", "=", cod)
.executeTakeFirst();
- if (!annuncio) {
+ if (!annuncio || annuncio.tipo === null) {
return null;
}
- return annuncio;
+ return annuncio as AnnunciWithMedia;
} catch (e) {
throw new TRPCError({
cause: (e as Error).cause,
@@ -151,15 +153,16 @@ export const getAnnunciById_rawImgUrls = async ({
.selectAll()
.select((_eb) => [withImages(), withVideos()])
.where("id", "=", id)
+ .where("tipo", "is not", null)
.executeTakeFirst();
- if (!annuncio) {
+ if (!annuncio || annuncio.tipo === null) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Annuncio non trovato",
});
}
- return annuncio;
+ return annuncio as AnnunciWithMedia;
} catch (e) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",