feat: add admin contact details dialog and streamline cache invalidation in AnnuncioEditForm

This commit is contained in:
Marco Pedone 2026-03-12 16:55:06 +01:00
parent 41d743c97f
commit 300c9edfc4
3 changed files with 94 additions and 16 deletions

View file

@ -1,9 +1,19 @@
import { Toolbox } from "lucide-react"; import { Info, Toolbox } from "lucide-react";
import Image from "next/image"; import Image from "next/image";
import { import {
AdminActions, AdminActions,
UserActions, UserActions,
} from "~/components/servizio/annuncio_actions"; } from "~/components/servizio/annuncio_actions";
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "~/components/ui/alert-dialog";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { handleConsegna } from "~/lib/annuncio_details"; import { handleConsegna } from "~/lib/annuncio_details";
import { getStorageUrl } from "~/lib/storage_utils"; import { getStorageUrl } from "~/lib/storage_utils";
@ -11,6 +21,7 @@ import { cn, formatCurrency } from "~/lib/utils";
import { useTranslation } from "~/providers/I18nProvider"; import { useTranslation } from "~/providers/I18nProvider";
import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider"; import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider";
import type { AnnuncioRicerca } from "~/server/controllers/annunci.controller"; import type { AnnuncioRicerca } from "~/server/controllers/annunci.controller";
import { api } from "~/utils/api";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { import {
Collapsible, Collapsible,
@ -97,6 +108,7 @@ export const AnnuncioDisplay = ({
data: AnnuncioRicerca; data: AnnuncioRicerca;
className?: string; className?: string;
}) => { }) => {
const { isAdmin } = useServizio();
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
@ -146,9 +158,71 @@ export const AnnuncioDisplay = ({
{formatCurrency(data.prezzo / 1e2)} {formatCurrency(data.prezzo / 1e2)}
</span> </span>
</div> </div>
<div className="col-span-2 w-full max-w-xl md:col-span-1 md:pr-8"> <div
className={cn(
"col-span-2 grid w-full max-w-xl items-center gap-2 md:col-span-1 md:pr-8",
isAdmin && "grid-cols-2",
)}
>
<AnnuncioDettaglio data={data} /> <AnnuncioDettaglio data={data} />
{isAdmin && <AdminAnnuncioContatti />}
</div> </div>
</div> </div>
); );
}; };
const AdminAnnuncioContatti = () => {
const { data } = useServizioAnnuncio();
const { data: annuncio, isLoading } = api.annunci.getAnnuncioFull.useQuery({
id: data.id,
});
return (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button className="" variant="outline">
<Info />
<span>Dati Contatto</span>
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Contatti Annuncio {data.codice}</AlertDialogTitle>
<AlertDialogDescription className="sr-only">
desc
</AlertDialogDescription>
</AlertDialogHeader>
<div className="flex w-full flex-col gap-4">
<div>
<span className="font-semibold">Contatti Aperti il: </span>
{data.open_contatti_at
? new Date(data.open_contatti_at).toLocaleString("it-IT")
: "Non ancora aperti"}
</div>
{isLoading ? (
<div className="flex h-24 w-full items-center justify-center">
Loading...
</div>
) : (
<>
<div>
<span className="font-semibold">Locatore/Incaricato: </span>
{annuncio?.locatore || "N/A"}
</div>
<div>
<span className="font-semibold">Email: </span>
{annuncio?.email || "N/A"}
</div>
<div>
<span className="font-semibold">Telefono: </span>
{annuncio?.numero || "N/A"}
</div>
</>
)}
</div>
<AlertDialogFooter>
<AlertDialogCancel>Chiudi</AlertDialogCancel>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

View file

@ -120,11 +120,8 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithMedia }) => {
const { mutate: edit } = api.annunci.editAnnuncio.useMutation({ const { mutate: edit } = api.annunci.editAnnuncio.useMutation({
onSettled: async () => { onSettled: async () => {
await utils.annunci.getAnnuncio.invalidate({ cod: data.codice }); await utils.annunci.invalidate();
await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({
id: data.id,
});
await utils.annunci.getAnnunciList.invalidate();
toast.success("Annuncio modificato con successo"); toast.success("Annuncio modificato con successo");
}, },
}); });
@ -132,10 +129,7 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithMedia }) => {
const { mutateAsync: revalidate } = const { mutateAsync: revalidate } =
api.revalidation.revalidateAnnuncio.useMutation({ api.revalidation.revalidateAnnuncio.useMutation({
onSettled: async () => { onSettled: async () => {
await utils.annunci.getAnnuncio.invalidate({ cod: data.codice }); await utils.annunci.invalidate();
await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({
id: data.id,
});
toast.success("Revalidazione completata"); toast.success("Revalidazione completata");
}, },
}); });
@ -147,10 +141,7 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithMedia }) => {
}); });
}, },
onSettled: async () => { onSettled: async () => {
await utils.annunci.getAnnuncio.invalidate({ cod: data.codice }); await utils.annunci.invalidate();
await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({
id: data.id,
});
toast.success("Aggiornamento completato", { toast.success("Aggiornamento completato", {
id: "update-annuncio", id: "update-annuncio",
}); });

View file

@ -52,7 +52,7 @@ export const annunciRouter = createTRPCRouter({
getAnnunciOptions: publicProcedure.query(async () => { getAnnunciOptions: publicProcedure.query(async () => {
return await getOptions_AnnunciHandler(); return await getOptions_AnnunciHandler();
}), }),
/** TODO da limitare per evitare leak */
getAnnuncio: publicProcedure getAnnuncio: publicProcedure
.input( .input(
z.object({ z.object({
@ -62,6 +62,19 @@ export const annunciRouter = createTRPCRouter({
.query(async ({ input }) => { .query(async ({ input }) => {
return await getAnnunciByCod({ ...input }); return await getAnnunciByCod({ ...input });
}), }),
getAnnuncioFull: adminProcedure
.input(
z.object({
id: zAnnuncioId,
}),
)
.query(async ({ input }) => {
return await db
.selectFrom("annunci")
.selectAll()
.where("id", "=", input.id)
.executeTakeFirst();
}),
getAnnuncioById_rawImgUrls: publicProcedure getAnnuncioById_rawImgUrls: publicProcedure
.input( .input(
z.object({ z.object({