feat: update package dependencies and enhance UI components with badges; refactor service dialogs and remove unused components

This commit is contained in:
Marco Pedone 2025-11-07 17:03:08 +01:00
parent 23525d8f14
commit b7850f6994
12 changed files with 237 additions and 431 deletions

View file

@ -64,7 +64,7 @@
"nuqs": "^2.4.3",
"pg": "^8.16.3",
"postcss": "^8.5.6",
"radix-ui": "^1.4.2",
"radix-ui": "^1.4.3",
"react": "^19.1.0",
"react-colorful": "^5.6.1",
"react-day-picker": "^9.11.1",

View file

@ -75,7 +75,7 @@
"nuqs": "^2.4.3",
"pg": "^8.16.3",
"postcss": "^8.5.6",
"radix-ui": "^1.4.2",
"radix-ui": "^1.4.3",
"react": "^19.1.0",
"react-colorful": "^5.6.1",
"react-day-picker": "^9.11.1",

View file

@ -224,7 +224,7 @@ export const InteressatoButtonServizio = ({
variant="info"
>
<BadgePlus className="size-6" />
{isAdmin ? "Aggiungi annuncio" : "Sono interessato"}
{isAdmin ? "Aggiungi" : "Sono interessato"}
</LoadingButton>
);
};

View file

@ -230,17 +230,17 @@ export const CardAnnuncio = ({
)}
</div>
<div className="flex h-full grow flex-col gap-2">
<div
<Badge
className={cn(
"flex w-full items-center justify-center rounded-md",
"w-full font-semibold text-md",
tipo === "Transitorio" && "bg-transitorio",
tipo === "Stabile" && "bg-stabile",
tipo === "Cessione" && "bg-blue-400",
tipo === "Vendita" && "bg-green-400",
)}
>
<div className="font-semibold text-white">Affitto {tipo}</div>
</div>
Affitto {tipo}
</Badge>
<div className="flex flex-row justify-between gap-3 px-4">
<div className="w-full text-center">
<span className="sr-only">{t.card.codice}</span>

View file

@ -1,344 +0,0 @@
"use client";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import {
type ComponentPropsWithoutRef,
createContext,
type Dispatch,
type ElementRef,
forwardRef,
type HTMLAttributes,
type PointerEvent,
type ReactNode,
type SetStateAction,
useContext,
useEffect,
useRef,
useState,
} from "react";
import { cn } from "~/lib/utils";
interface DialogContextValue {
innerOpen: boolean;
setInnerOpen: Dispatch<SetStateAction<boolean>>;
}
const DialogContext = createContext<DialogContextValue | undefined>(undefined);
function Dialog({ children }: { children: ReactNode }) {
const [outerOpen, setOuterOpen] = useState(false);
const [innerOpen, setInnerOpen] = useState(false);
return (
<DialogContext.Provider value={{ innerOpen, setInnerOpen }}>
<DialogPrimitive.Root onOpenChange={setOuterOpen} open={outerOpen}>
{children}
</DialogPrimitive.Root>
</DialogContext.Provider>
);
}
const DialogTrigger = DialogPrimitive.Trigger;
const DialogPortal = DialogPrimitive.Portal;
const DialogClose = DialogPrimitive.Close;
const DialogOverlay = forwardRef<
ElementRef<typeof DialogPrimitive.Overlay>,
ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
className={cn(
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-background/40 backdrop-blur-sm data-[state=closed]:animate-out data-[state=open]:animate-in",
className,
)}
ref={ref}
{...props}
/>
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = forwardRef<
ElementRef<typeof DialogPrimitive.Content>,
ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => {
const context = useContext(DialogContext);
if (!context) throw new Error("DialogContent must be used within a Dialog");
return (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
className={cn(
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg",
context.innerOpen && "translate-y-[-55%] scale-[0.97]",
className,
)}
ref={ref}
{...props}
>
{children}
<DialogClose className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="size-4" />
<span className="sr-only">Close</span>
</DialogClose>
</DialogPrimitive.Content>
</DialogPortal>
);
});
DialogContent.displayName = DialogPrimitive.Content.displayName;
function InnerDialog({ children }: { children: ReactNode }) {
const context = useContext(DialogContext);
if (!context) throw new Error("InnerDialog must be used within a Dialog");
useEffect(() => {
const handleEscapeKeyDown = (event: KeyboardEvent) => {
if (event.key === "Escape" && context.innerOpen) {
context.setInnerOpen(false);
event.stopPropagation();
}
};
document.addEventListener("keydown", handleEscapeKeyDown);
return () => {
document.removeEventListener("keydown", handleEscapeKeyDown);
};
}, [context.innerOpen, context.setInnerOpen]);
return (
<DialogPrimitive.Root
onOpenChange={context.setInnerOpen}
open={context.innerOpen}
>
{children}
</DialogPrimitive.Root>
);
}
const InnerDialogTrigger = DialogPrimitive.Trigger;
const InnerDialogClose = DialogPrimitive.Close;
interface InnerDialogContentProps
extends ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
position?: "default" | "bottom" | "top" | "left" | "right";
draggable?: boolean;
}
const InnerDialogContent = forwardRef<
ElementRef<typeof DialogPrimitive.Content>,
InnerDialogContentProps
>(
(
{ className, children, position = "default", draggable = false, ...props },
ref,
) => {
const context = useContext(DialogContext);
if (!context)
throw new Error("InnerDialogContent must be used within a Dialog");
const [isDragging, setIsDragging] = useState(false);
const [startY, setStartY] = useState(0);
const [currentY, setCurrentY] = useState(0);
const [isClosingByDrag, setIsClosingByDrag] = useState(false);
const contentRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (context.innerOpen) {
setCurrentY(0);
setIsClosingByDrag(false);
}
}, [context.innerOpen]);
const handlePointerDown = (e: PointerEvent<HTMLDivElement>) => {
if (!draggable) return;
setIsDragging(true);
setStartY(e.clientY - currentY);
e.currentTarget.setPointerCapture(e.pointerId);
};
const handlePointerMove = (e: PointerEvent<HTMLDivElement>) => {
if (!isDragging || !draggable) return;
const newY = e.clientY - startY;
setCurrentY(newY > 0 ? newY : 0);
};
const handlePointerUp = () => {
if (!draggable) return;
setIsDragging(false);
if (currentY > (contentRef.current?.offsetHeight || 0) / 2) {
setIsClosingByDrag(true);
context.setInnerOpen(false);
} else {
setCurrentY(0);
}
};
return (
<DialogPortal>
<DialogPrimitive.Content
className={cn(
"fixed top-[50%] left-[50%] z-[60] grid w-full max-w-lg translate-x-[-50%] translate-y-[-45%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200",
isClosingByDrag
? "data-[state=closed]:fade-out-0 data-[state=closed]:animate-none"
: "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] data-[state=closed]:animate-out data-[state=open]:animate-in",
position === "default" &&
"data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
position === "bottom" &&
"data-[state=closed]:slide-out-to-bottom-full data-[state=open]:slide-in-from-bottom-full",
position === "top" &&
"data-[state=closed]:slide-out-to-top-full data-[state=open]:slide-in-from-top-full",
position === "left" &&
"data-[state=closed]:slide-out-to-left-full data-[state=open]:slide-in-from-left-full",
position === "right" &&
"data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-right-full",
draggable && "",
className,
)}
onPointerDown={handlePointerDown}
onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp}
ref={ref}
style={{
transform: `translate(-50%, calc(-50% + ${currentY}px))`,
transition: isDragging ? "none" : "transform 0.3s ease-out",
}}
{...props}
>
<div ref={contentRef}>{children}</div>
<InnerDialogClose className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="size-4" />
<span className="sr-only">Close</span>
</InnerDialogClose>
</DialogPrimitive.Content>
</DialogPortal>
);
},
);
InnerDialogContent.displayName = "InnerDialogContent";
const InnerDialogHeader = ({
className,
...props
}: HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className,
)}
{...props}
/>
);
InnerDialogHeader.displayName = "InnerDialogHeader";
const InnerDialogFooter = ({
className,
...props
}: HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("flex flex-col-reverse sm:flex-row sm:space-x-2", className)}
{...props}
/>
);
InnerDialogFooter.displayName = "InnerDialogFooter";
const InnerDialogTitle = forwardRef<
ElementRef<typeof DialogPrimitive.Title>,
ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
className={cn(
"font-semibold text-lg leading-none tracking-tight",
className,
)}
ref={ref}
{...props}
/>
));
InnerDialogTitle.displayName = "InnerDialogTitle";
const InnerDialogDescription = forwardRef<
ElementRef<typeof DialogPrimitive.Description>,
ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
className={cn("text-muted-foreground text-sm", className)}
ref={ref}
{...props}
/>
));
InnerDialogDescription.displayName = "InnerDialogDescription";
const DialogHeader = ({
className,
...props
}: HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className,
)}
{...props}
/>
);
DialogHeader.displayName = "DialogHeader";
const DialogFooter = ({
className,
...props
}: HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("flex flex-col-reverse sm:flex-row sm:space-x-2", className)}
{...props}
/>
);
DialogFooter.displayName = "DialogFooter";
const DialogTitle = forwardRef<
ElementRef<typeof DialogPrimitive.Title>,
ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
className={cn(
"font-semibold text-lg leading-none tracking-tight",
className,
)}
ref={ref}
{...props}
/>
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;
const DialogDescription = forwardRef<
ElementRef<typeof DialogPrimitive.Description>,
ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
className={cn("text-muted-foreground text-sm", className)}
ref={ref}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;
export type { InnerDialogContentProps };
export {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
DialogClose,
InnerDialog,
InnerDialogTrigger,
InnerDialogContent,
InnerDialogHeader,
InnerDialogFooter,
InnerDialogTitle,
InnerDialogDescription,
InnerDialogClose,
DialogPortal,
DialogOverlay,
};

View file

@ -29,6 +29,7 @@ import { cn, formatCurrency } from "~/lib/utils";
import { useTranslation } from "~/providers/I18nProvider";
import { useServizioAnnuncio } from "~/providers/ServizioProvider";
import type { Annunci } from "~/schemas/public/Annunci";
import { Badge } from "../ui/badge";
type AnnuncioData = Pick<
Annunci,
@ -138,17 +139,17 @@ export const BasicAnnuncioCard = ({
const TipoBadge = ({ tipo }: { tipo: Annunci["tipo"] }) => {
return (
<div
<Badge
className={cn(
"flex w-fit items-center justify-center rounded-md px-3",
tipo === "Transitorio" && "bg-orange-400",
tipo === "Stabile" && "bg-red-400",
"font-semibold text-md",
tipo === "Transitorio" && "bg-transitorio",
tipo === "Stabile" && "bg-stabile",
tipo === "Cessione" && "bg-blue-400",
tipo === "Vendita" && "bg-green-400",
)}
>
<div className="font-semibold text-white">{tipo}</div>
</div>
Affitto {tipo}
</Badge>
);
};

View file

@ -0,0 +1,195 @@
import { ExternalLink, UnfoldVertical } from "lucide-react";
import Link from "next/link";
import { replaceWithBr } from "~/lib/newlineToBr";
import { cn, formatCurrency } from "~/lib/utils";
import { useTranslation } from "~/providers/I18nProvider";
import { useServizio } from "~/providers/ServizioProvider";
import type { Annunci } from "~/schemas/public/Annunci";
import type { AnnuncioRicerca } from "~/server/controllers/annunci.controller";
import { api } from "~/utils/api";
import { CardAnnuncio, CarouselAnnuncio } from "../annuncio_card";
import { InteressatoButtonServizio } from "../annuncio-interactions/annuncio_interactions";
import { LoadingPage } from "../loading";
import { Badge } from "../ui/badge";
import { Button } from "../ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
export const AnnunciCompatibili = () => {
const { servizioId } = useServizio();
const { data, isLoading } = api.servizio.getCompatibileAnnunci.useQuery({
servizioId,
});
return (
<Dialog>
<DialogTrigger asChild>
<Button className="w-full bg-purple-500 sm:w-fit">
Esplora Annunci Compatibili
</Button>
</DialogTrigger>
<DialogContent className="max-w-xl p-2 sm:max-w-5xl sm:p-6 md:max-w-7xl">
<DialogHeader>
<DialogTitle className="pt-6">
Annunci compatibili con le preferenze del servizio
</DialogTitle>
<DialogDescription className="sr-only"></DialogDescription>
</DialogHeader>
<div className="flex max-h-[80vh] flex-col gap-2 overflow-y-auto p-0.5 sm:p-2">
{isLoading ? (
<LoadingPage />
) : (
<>
{!data || data.length === 0 ? (
<div className="flex items-center justify-center gap-1 rounded-md bg-white p-4 sm:flex">
<span>
Nessun annuncio compatibile trovato. Amplia la ricerca per
trovare annunci compatibili.
</span>
</div>
) : (
<div className="relative z-0 mx-auto grid max-w-7xl grid-flow-row grid-cols-1 gap-4 sm:grid-cols-2 sm:gap-6 sm:gap-y-8 lg:grid-cols-3">
{data.map((annuncio) => (
<div
className="flex flex-col justify-center gap-1"
key={annuncio.codice}
>
<CardAnnuncio
{...annuncio}
className="outline outline-neutral-500"
noLink
onlyFirstImage
/>
<div className="flex items-center justify-between gap-2">
<div className="w-full">
<AnnuncioDettaglio data={annuncio} />
</div>
<div className="w-full">
<InteressatoButtonServizio annuncioId={annuncio.id} />
</div>
</div>
</div>
))}
</div>
)}
</>
)}
</div>
<DialogFooter>
<DialogClose asChild></DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
};
const TipoBadge = ({ tipo }: { tipo: Annunci["tipo"] }) => {
return (
<Badge
className={cn(
"font-semibold text-md",
tipo === "Transitorio" && "bg-transitorio",
tipo === "Stabile" && "bg-stabile",
tipo === "Cessione" && "bg-blue-400",
tipo === "Vendita" && "bg-green-400",
)}
>
Affitto {tipo}
</Badge>
);
};
const AnnuncioDettaglio = ({ data }: { data: AnnuncioRicerca }) => {
const { locale, t } = useTranslation();
return (
<Dialog>
<DialogTrigger asChild>
<Button aria-label="Dettagli Annuncio" variant="outline">
<UnfoldVertical className="size-6" /> Dettagli annuncio
</Button>
</DialogTrigger>
<DialogContent className="max-h-[70vh] max-w-xl overflow-y-auto sm:max-w-6xl">
<DialogHeader className="flex-row items-center gap-4">
<DialogTitle className="text-xl">Annuncio {data.codice}</DialogTitle>
<Link href={`/annuncio/${data.codice}`} target="_blank">
<Button size="sm" variant="info">
<span>Vai alla pagina completa</span>{" "}
<ExternalLink className="size-4" />
</Button>
</Link>
<DialogDescription className="sr-only">
Annuncio {data.codice}
</DialogDescription>
</DialogHeader>
<div className="flex flex-col gap-2 px-2">
<div className="w-full contain-inline-size">
<CarouselAnnuncio
immagini={data.images.map((img) => img.img)}
updated_at={data.media_updated_at}
videos={data.url_video}
/>
</div>
<div>
<div className="flex items-center gap-4">
<TipoBadge tipo={data.tipo} />
{data.stato === "Trattativa" && (
<Badge className="bg-violet-500 font-semibold text-md">
Annuncio in Trattativa
</Badge>
)}
</div>
<div className="mt-1 space-y-2">
<div className="flex flex-row justify-around">
<div className="text-center">
<dt className="sr-only">{t.card.codice}</dt>
<dd className="font-semibold text-lg">Cod: {data.codice}</dd>
</div>
<div className="text-center">
<dt className="sr-only">{t.card.prezzo}</dt>
<dd className="font-semibold text-lg">
{formatCurrency(data.prezzo / 1e2)}
</dd>
</div>
</div>
<div className="mb-3">
<dt className="sr-only">{t.card.titolo}</dt>
<dd className="font-semibold text-base md:text-lg">
{locale === "it" ? data.titolo_it : data.titolo_en}
</dd>
</div>
<div className="mb-3">
<dd
className="text-base"
dangerouslySetInnerHTML={{
__html: replaceWithBr(
(locale === "it" ? data.desc_it : data.desc_en) || "",
),
}}
/>
</div>
</div>
</div>
</div>
<DialogFooter>
<DialogClose asChild></DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
};

View file

@ -22,8 +22,8 @@ import {
useServizio,
} from "~/providers/ServizioProvider";
import { api } from "~/utils/api";
import { AnnunciCompatibili } from "./compatibili_dialog";
import {
AnnunciCompatibili,
AnnunciSelezionatiAccordion,
AnnunciSelezionatiDialog,
} from "./servizio_annunci_accordions";
@ -210,9 +210,6 @@ export const ServizioContent = () => {
const annunciInConferma = servizio.annunci.filter(
(a) => a.user_confirmed_at !== null,
);
const annunciNotInConferma = servizio.annunci.filter(
(a) => a.user_confirmed_at === null,
);
return (
<ServizioCard

View file

@ -64,7 +64,7 @@ export const ServizioActions = () => {
return (
<div className="flex w-full flex-col flex-wrap justify-between gap-3 sm:flex-row">
{(isAdmin || canUserEdit) && (
<div className="flex items-center gap-3">
<div className="flex flex-wrap items-center gap-3">
{/* <span className="hidden sm:block">Azioni: </span> */}
<EditPreferenze />
<InterruzioneServizio />
@ -230,7 +230,7 @@ const InterruzioneServizio = () => {
servizio.annunci.some((a) => a.user_confirmed_at !== null))
}
>
<ClockAlert /> <span>Interruzione Servizio</span>
<ClockAlert /> <span>Richiedi Interruzione</span>
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
@ -302,7 +302,7 @@ const EditPreferenze = () => {
}
>
<Calculator />
Modifica Preferenze
Preferenze
</Button>
</CredenzaTrigger>
<CredenzaContent className="max-h-[90vh] w-full sm:max-w-5xl">

View file

@ -2,7 +2,6 @@ import { ExternalLink, Trash2 } from "lucide-react";
import Link from "next/link";
import type { ReactNode } from "react";
import toast from "react-hot-toast";
import { InteressatoButtonServizio } from "~/components/annuncio-interactions/annuncio_interactions";
import {
AnnuncioCard,
BasicAnnuncioCard,
@ -21,8 +20,6 @@ import {
import type { UsersId } from "~/schemas/public/Users";
import type { ServizioData } from "~/server/controllers/servizio.controller";
import { api } from "~/utils/api";
import { CardAnnuncio } from "../annuncio_card";
import { LoadingPage } from "../loading";
import {
Dialog,
DialogContent,
@ -44,7 +41,7 @@ const DialogServizio = ({
return (
<Dialog>
<DialogTrigger asChild>{trigger}</DialogTrigger>
<DialogContent className="p-2 sm:max-w-5xl sm:p-6 md:max-w-7xl">
<DialogContent className="max-w-xl p-2 sm:max-w-5xl sm:p-6 md:max-w-7xl">
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
<DialogDescription className="sr-only">
@ -245,58 +242,6 @@ export const AnnunciSelezionatiAccordion = ({
</Accordion>
);
};
export const AnnunciCompatibili = () => {
const { servizioId } = useServizio();
const { data, isLoading } = api.servizio.getCompatibileAnnunci.useQuery({
servizioId,
});
return (
<DialogServizio
title="Annunci compatibili con le preferenze del servizio"
trigger={
<Button className="w-full bg-purple-500 sm:w-fit">
Esplora Annunci Compatibili
</Button>
}
>
<div className="flex max-h-[80vh] flex-col gap-2 overflow-y-auto p-0.5 sm:p-2">
{isLoading ? (
<LoadingPage />
) : (
<>
{!data || data.length === 0 ? (
<div className="flex items-center justify-center gap-1 rounded-md bg-white p-4 sm:flex">
<span>
Nessun annuncio compatibile trovato. Amplia la ricerca per
trovare annunci compatibili.
</span>
</div>
) : (
<div className="relative z-0 mx-auto grid max-w-7xl grid-flow-row grid-cols-1 gap-4 sm:grid-cols-2 sm:gap-6 sm:gap-y-8 lg:grid-cols-3">
{data.map((annuncio) => (
<div
className="flex flex-col justify-center gap-1"
key={annuncio.codice}
>
<CardAnnuncio
{...annuncio}
className="outline outline-neutral-500"
noLink
onlyFirstImage
/>
<InteressatoButtonServizio annuncioId={annuncio.id} />
</div>
))}
</div>
)}
</>
)}
</div>
</DialogServizio>
);
};
export const AnnunciRichiesti = ({ userId }: { userId: UsersId }) => {
const { data, isLoading } = api.intrests.getUserInterestsAnnunci.useQuery({

View file

@ -2,7 +2,21 @@ import type { NextPage } from "next";
import Example from "~/components/KabanExample";
import { NoSSR } from "~/lib/nossr";
const Test: NextPage = () => {
return (
<div className="p-4">
<NoSSR>
<Example />
</NoSSR>
</div>
);
};
export default Test;
/*
ESEMPIO DI RICERCA IN NOMINATIM CON DEBOUNCE
import { useState } from "react";
import { useDebounce } from "react-use";
import z from "zod";
@ -147,14 +161,3 @@ const Test: NextPage = () => {
};
export default Test;
*/
const Test: NextPage = () => {
return (
<div className="p-4">
<NoSSR>
<Example />
</NoSSR>
</div>
);
};
export default Test;

View file

@ -208,6 +208,9 @@ export const get_AnnunciPositionsHandler = async ({
"tipo",
"titolo_it",
"titolo_en",
"desc_en",
"desc_it",
"web",
"modificato_il",
"stato",
"url_video",
@ -265,11 +268,14 @@ export type AnnuncioRicerca = Pick<
| "tipo"
| "titolo_it"
| "titolo_en"
| "desc_en"
| "desc_it"
| "modificato_il"
| "stato"
| "url_video"
| "media_updated_at"
| "homepage"
| "web"
> & {
images: Pick<ImagesRefs, "img" | "thumb">[];
};
@ -307,6 +313,9 @@ export const getCursor_AnnunciHandler = async ({
"tipo",
"titolo_it",
"titolo_en",
"desc_en",
"desc_it",
"web",
"modificato_il",
"stato",
"url_video",