feat: update admin actions layout and add contact details dialog; modify user link path in UsersTable

This commit is contained in:
Marco Pedone 2026-03-12 17:02:35 +01:00
parent 300c9edfc4
commit d18aee8a95
3 changed files with 139 additions and 144 deletions

View file

@ -1,17 +1,27 @@
import { import {
ExternalLink,
Eye,
FileBadge, FileBadge,
FileText, FileText,
FolderKanban, FolderKanban,
Info,
Mail, Mail,
PackageCheck, PackageCheck,
Pointer, Pointer,
Printer, Printer,
Trash2, Trash2,
Wrench,
} from "lucide-react"; } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "~/components/ui/alert-dialog";
import { Button, type ButtonConfigs } from "~/components/ui/button"; import { Button, type ButtonConfigs } from "~/components/ui/button";
import { import {
Tooltip, Tooltip,
@ -49,75 +59,79 @@ export const AdminActions = () => {
if (!isAdmin) return null; if (!isAdmin) return null;
return ( return (
<div className="flex w-full max-w-fit flex-wrap justify-start gap-3"> <>
{<AdminSendScheda />} <h3 className="ml-1 font-semibold">Azioni Admin:</h3>
{data.user_confirmed_at != null && <AdminLavoraConferma />} <div className="flex w-full max-w-fit flex-wrap justify-start gap-3">
{data.accettato_conferma_at != null && ( <AdminAnnuncioContatti />
<> <AdminSendScheda />
<AdminContratto /> {data.user_confirmed_at != null && <AdminLavoraConferma />}
{data.gestionale_id && ( {data.accettato_conferma_at != null && (
<Link <>
aria-label="Open Gestionale" <AdminContratto />
href={`https://win-jk822fggr6b:480/id/${data.gestionale_id}`} {data.gestionale_id && (
target="_blank" <Link
> aria-label="Open Gestionale"
<Button size="sm"> href={`https://win-jk822fggr6b:480/id/${data.gestionale_id}`}
<FolderKanban /> Gestionale target="_blank"
</Button> >
</Link> <Button size="sm">
)} <FolderKanban /> Gestionale
</> </Button>
)} </Link>
<Link href={`/annuncio/${data.codice}`} target="_blank"> )}
</>
)}
{/* <Link href={`/annuncio/${data.codice}`} target="_blank">
<Button size="sm" type="button" variant="outline"> <Button size="sm" type="button" variant="outline">
<Eye /> pubblica <Eye /> pubblica
</Button> </Button>
</Link> </Link> */}
<Link <Link
href={`/area-riservata/admin/edit-annuncio/${annuncioId}`} href={`/area-riservata/admin/edit-annuncio/${annuncioId}`}
target="_blank" target="_blank"
>
<Button
aria-label="Edit Annuncio"
className="w-fit"
size="sm"
variant="secondary"
> >
<ExternalLink /> <Button
<span>Modifica</span> aria-label="Edit Annuncio"
</Button> className="w-fit"
</Link> size="sm"
variant="secondary"
>
<Wrench />
<span>Modifica Annuncio</span>
</Button>
</Link>
<Link <Link
href={`/area-riservata/scheda-annuncio-stampa/${data.id}`} href={`/area-riservata/scheda-annuncio-stampa/${data.id}`}
target="_blank" target="_blank"
>
<Button size="sm" type="button" variant="outline">
<Printer /> Scheda
</Button>
</Link>
<Confirm
description="Sei sicuro di voler eliminare l'annuncio?"
onConfirm={() => {
mutate({
annuncioId,
servizioId,
});
}}
title="Elimina annuncio"
>
<Button
aria-label="Delete Annuncio"
className="w-fit"
size="sm"
variant="destructive"
> >
<Trash2 /> <Button size="sm" type="button" variant="outline">
<span>Elimina</span> <Printer /> Scheda
</Button> </Button>
</Confirm> </Link>
</div>
<Confirm
description="Sei sicuro di voler eliminare l'annuncio?"
onConfirm={() => {
mutate({
annuncioId,
servizioId,
});
}}
title="Elimina annuncio"
>
<Button
aria-label="Delete Annuncio"
className="w-fit"
size="sm"
variant="destructive"
>
<Trash2 />
<span>Elimina</span>
</Button>
</Confirm>
</div>
</>
); );
}; };
@ -156,7 +170,7 @@ const AdminSendScheda = () => {
> >
<Button className="w-fit" size="sm" variant="outline"> <Button className="w-fit" size="sm" variant="outline">
<Mail /> <Mail />
<span>Invia email contatti</span> <span>Invia Scheda</span>
</Button> </Button>
</Confirm> </Confirm>
); );
@ -243,6 +257,61 @@ export const UserActions = () => {
</> </>
); );
}; };
const AdminAnnuncioContatti = () => {
const { data } = useServizioAnnuncio();
const { data: annuncio, isLoading } = api.annunci.getAnnuncioFull.useQuery({
id: data.id,
});
return (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button size="sm" 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>
);
};
const PostConfermaSection = () => { const PostConfermaSection = () => {
const { servizio, servizioId } = useServizio(); const { servizio, servizioId } = useServizio();

View file

@ -1,19 +1,9 @@
import { Info, Toolbox } from "lucide-react"; import { 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";
@ -21,7 +11,6 @@ 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,
@ -49,7 +38,7 @@ export const AnnuncioCard = ({ className }: { className?: string }) => {
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<Collapsible className="space-y-2"> <Collapsible className="space-y-2">
<CollapsibleTrigger asChild> <CollapsibleTrigger asChild>
<Button variant="outline"> <Button size="sm" variant="outline">
<Toolbox /> <Toolbox />
<span>Azioni Utente</span> <span>Azioni Utente</span>
</Button> </Button>
@ -108,7 +97,6 @@ export const AnnuncioDisplay = ({
data: AnnuncioRicerca; data: AnnuncioRicerca;
className?: string; className?: string;
}) => { }) => {
const { isAdmin } = useServizio();
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
@ -158,71 +146,9 @@ export const AnnuncioDisplay = ({
{formatCurrency(data.prezzo / 1e2)} {formatCurrency(data.prezzo / 1e2)}
</span> </span>
</div> </div>
<div <div className="col-span-2 w-full max-w-xl md:col-span-1 md:pr-8">
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

@ -135,7 +135,7 @@ export const UsersTable = (props: { data: UserWChatInfo[] }) => {
<Link <Link
aria-label="Visualizza Utente" aria-label="Visualizza Utente"
className="flex items-center gap-2" className="flex items-center gap-2"
href={`/area-riservata/admin/user-view/edit-user/${user.id}`} href={`/area-riservata/admin/user-view/ricerca/${user.id}`}
> >
<UserAvatar <UserAvatar
className="size-8" className="size-8"