refactor: remove unused components and enhance navigation flow in user views
This commit is contained in:
parent
51affdc7a8
commit
72a2935797
9 changed files with 51 additions and 414 deletions
|
|
@ -6,7 +6,6 @@ import {
|
|||
Paperclip,
|
||||
Search,
|
||||
ShoppingBag,
|
||||
Tickets,
|
||||
UserCog,
|
||||
UserPen,
|
||||
} from "lucide-react";
|
||||
|
|
@ -81,16 +80,6 @@ export const UserViewHeader = () => {
|
|||
<UserCog /> Profilo
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href={`/area-riservata/admin/user-view/servizio/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("servizio") ? "secondary" : "outline"}
|
||||
>
|
||||
<Tickets /> Servizi
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href={`/area-riservata/admin/user-view/ricerca/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import type { GetServerSideProps } from "next";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { AreaRiservataLayoutUserView } from "~/components/Layout";
|
||||
import { TabServizio } from "~/components/tables/servizio-table";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { FormNewServizio, type FormValues } from "~/forms/FormNewServizio";
|
||||
import type { Servizio } from "~/schemas/public/Servizio";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import { api } from "~/utils/api";
|
||||
import { Button } from "../ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
|
|
@ -11,36 +12,17 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "~/components/ui/dialog";
|
||||
import { FormNewServizio, type FormValues } from "~/forms/FormNewServizio";
|
||||
import type { NextPageWithLayout } from "~/pages/_app";
|
||||
import type { Servizio } from "~/schemas/public/Servizio";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper";
|
||||
import { zUserId } from "~/server/utils/zod_types";
|
||||
import { api } from "~/utils/api";
|
||||
} from "../ui/dialog";
|
||||
|
||||
type ServizioUserProps = {
|
||||
userId: UsersId;
|
||||
};
|
||||
const ServizioUser: NextPageWithLayout<ServizioUserProps> = ({
|
||||
userId,
|
||||
}: ServizioUserProps) => {
|
||||
export const ServiziHeader = ({ userId }: { userId: UsersId }) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [editData, setEditData] = useState<Servizio | undefined>(undefined);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-8xl grow space-y-4">
|
||||
<div className="flex justify-between">
|
||||
<h3 className="font-bold text-2xl">Servizi Utente</h3>
|
||||
<NewServizioModal
|
||||
editData={editData}
|
||||
open={open}
|
||||
setEditData={setEditData}
|
||||
setOpen={setOpen}
|
||||
userId={userId}
|
||||
/>
|
||||
</div>
|
||||
<TabServizio
|
||||
<div className="flex items-center justify-end">
|
||||
<NewServizioModal
|
||||
editData={editData}
|
||||
open={open}
|
||||
setEditData={setEditData}
|
||||
setOpen={setOpen}
|
||||
userId={userId}
|
||||
|
|
@ -48,45 +30,6 @@ const ServizioUser: NextPageWithLayout<ServizioUserProps> = ({
|
|||
</div>
|
||||
);
|
||||
};
|
||||
export default ServizioUser;
|
||||
|
||||
export const getServerSideProps = (async (context) => {
|
||||
const userId = context.params?.userId;
|
||||
if (typeof userId !== "string") {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
|
||||
const parsed = zUserId.safeParse(userId);
|
||||
|
||||
if (!parsed.success) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
const access_token = context.req.cookies.access_token;
|
||||
|
||||
const helpers = await TrpcAuthedFetchingIstance({ access_token });
|
||||
if (helpers) {
|
||||
await helpers.trpc.servizio.getUserServizi.prefetch({
|
||||
userId: parsed.data,
|
||||
});
|
||||
|
||||
return {
|
||||
props: {
|
||||
userId: parsed.data,
|
||||
trpcState: helpers.trpc.dehydrate(),
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}) satisfies GetServerSideProps<ServizioUserProps>;
|
||||
ServizioUser.getLayout = function getLayout(page) {
|
||||
return <AreaRiservataLayoutUserView>{page}</AreaRiservataLayoutUserView>;
|
||||
};
|
||||
|
||||
const NewServizioModal = ({
|
||||
userId,
|
||||
|
|
@ -111,6 +54,7 @@ const NewServizioModal = ({
|
|||
onSuccess: async () => {
|
||||
toast.success("Servizio creato con successo");
|
||||
await utils.servizio.getUserServizi.invalidate();
|
||||
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
||||
setEditData(undefined);
|
||||
setOpen(false);
|
||||
},
|
||||
|
|
@ -9,6 +9,7 @@ import {
|
|||
Info,
|
||||
Plus,
|
||||
SlidersHorizontal,
|
||||
Trash2,
|
||||
UserCircle,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
|
@ -61,6 +62,7 @@ import type { AnnunciId } from "~/schemas/public/Annunci";
|
|||
import type { ServizioServizioId } from "~/schemas/public/Servizio";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import { api } from "~/utils/api";
|
||||
import { Confirm } from "../confirm";
|
||||
import { Progress } from "../ui/progress";
|
||||
|
||||
export const ServizioActions = () => {
|
||||
|
|
@ -229,7 +231,8 @@ const ServizioPacksInfos = () => {
|
|||
</div>
|
||||
);
|
||||
};
|
||||
export const AddAnnuncio = ({
|
||||
|
||||
const AddAnnuncio = ({
|
||||
servizioId,
|
||||
userId,
|
||||
}: {
|
||||
|
|
@ -501,6 +504,16 @@ const EditServizioAdmin = () => {
|
|||
setOpen(false);
|
||||
},
|
||||
});
|
||||
const { mutate: remove } = api.servizio.deleteServizio.useMutation({
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
onSuccess: async () => {
|
||||
toast.success("Servizio rimosso con successo");
|
||||
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
||||
await utils.servizio.getServizio.invalidate({ servizioId });
|
||||
},
|
||||
});
|
||||
|
||||
function onSubmit(fields: EditFormValues) {
|
||||
update({
|
||||
|
|
@ -546,6 +559,18 @@ const EditServizioAdmin = () => {
|
|||
})()}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
<Confirm
|
||||
description="Sei sicuro di voler eliminare questo servizio? L'azione è irreversibile."
|
||||
onConfirm={() => {
|
||||
remove({ servizioId });
|
||||
}}
|
||||
title="Elimina servizio"
|
||||
>
|
||||
<Button aria-label="Elimina Servizio" variant="destructive">
|
||||
<Trash2 className="size-6" />
|
||||
Elimina Servizio
|
||||
</Button>
|
||||
</Confirm>
|
||||
</CredenzaBody>
|
||||
</CredenzaContent>
|
||||
</Credenza>
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ const Row = ({
|
|||
<div className="flex items-center gap-2 font-semibold text-primary sm:text-lg">
|
||||
<Building className="size-6 fill-background" />
|
||||
Affitto {servizio.tipologia}
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{`- del ${servizio.created_at.toLocaleDateString("it")}`}
|
||||
</span>
|
||||
</div>
|
||||
<div className="float-end flex items-center justify-start pl-2 text-primary">
|
||||
{isOpen ? <ChevronUp /> : <ChevronDown />}
|
||||
|
|
|
|||
|
|
@ -1,311 +0,0 @@
|
|||
import {
|
||||
Copy,
|
||||
EllipsisVertical,
|
||||
ExternalLink,
|
||||
Trash2,
|
||||
Wrench,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import toast from "react-hot-toast";
|
||||
import { LoadingPage } from "~/components/loading";
|
||||
import { AddAnnuncio } from "~/components/servizio/servizio_actions";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "~/components/ui/dropdown-menu";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCaption,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "~/components/ui/table";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "~/components/ui/tooltip";
|
||||
import { env } from "~/env";
|
||||
import type { AnnunciId } from "~/schemas/public/Annunci";
|
||||
import type { Servizio, ServizioServizioId } from "~/schemas/public/Servizio";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
export const TabServizio = ({
|
||||
userId,
|
||||
setEditData,
|
||||
setOpen,
|
||||
}: {
|
||||
userId: UsersId;
|
||||
setEditData: (data: Servizio | undefined) => void;
|
||||
setOpen: (open: boolean) => void;
|
||||
}) => {
|
||||
const { data } = api.servizio.getUserServizi.useQuery({ userId });
|
||||
const utils = api.useUtils();
|
||||
const { mutate: remove } = api.servizio.deleteServizio.useMutation({
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
onSuccess: async () => {
|
||||
toast.success("Servizio rimosso con successo");
|
||||
await utils.servizio.getUserServizi.invalidate();
|
||||
},
|
||||
});
|
||||
|
||||
const { mutate: update } = api.servizio.updateServizio.useMutation({
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
onSuccess: async (data) => {
|
||||
toast.success("Servizio modificato con successo");
|
||||
await utils.servizio.getUserServizi.invalidate();
|
||||
await utils.servizio.getPacksSolution.invalidate({
|
||||
servizioId: data.servizio_id,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
if (!data) return <LoadingPage />;
|
||||
return (
|
||||
<Table>
|
||||
<TableCaption>
|
||||
{data.length > 0
|
||||
? "Lista dai servizi dell'utente"
|
||||
: "Nessun servizio attualmente inserito"}
|
||||
</TableCaption>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Id</TableHead>
|
||||
<TableHead>Tipologia</TableHead>
|
||||
<TableHead>Creato Il</TableHead>
|
||||
<TableHead>Inviato</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead></TableHead>
|
||||
<TableHead></TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.map((servizio) => {
|
||||
const onboardDone =
|
||||
servizio.isInterrotto ||
|
||||
servizio.isOkAcconto ||
|
||||
servizio.decorrenza !== null;
|
||||
return (
|
||||
<TableRow key={servizio.servizio_id}>
|
||||
<TableCell className="max-w-20 truncate font-medium">
|
||||
{servizio.servizio_id}
|
||||
</TableCell>
|
||||
<TableCell>{servizio.tipologia}</TableCell>
|
||||
<TableCell>
|
||||
{new Date(servizio.created_at).toLocaleDateString("it-IT", {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric",
|
||||
})}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{servizio.isSent ? (
|
||||
<span className="text-green-500">Inviato</span>
|
||||
) : (
|
||||
<span className="text-neutral-500">Non inviato</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{(() => {
|
||||
if (servizio.isInterrotto)
|
||||
return <span className="text-red-500">Interrotto</span>;
|
||||
if (servizio.isOkAcconto && servizio.decorrenza !== null)
|
||||
return <span className="text-green-500">Attivo</span>;
|
||||
return <span className="text-neutral-500">Inattivo</span>;
|
||||
})()}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<AnnunciSection
|
||||
selectedAnnunci={servizio.annunci}
|
||||
servizioId={servizio.servizio_id}
|
||||
userId={userId}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button aria-label="Servizio Actions" variant="outline">
|
||||
<EllipsisVertical />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
aria-label="Apri Onboarding Servizio"
|
||||
className="!p-0"
|
||||
href={`/area-riservata/admin/user-view/onboard/${servizio.servizio_id}`}
|
||||
>
|
||||
<Button
|
||||
className="flex w-full justify-start gap-3 px-2 font-normal"
|
||||
disabled={onboardDone}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
>
|
||||
<ExternalLink className="size-5 stroke-foreground" />
|
||||
Apri Onboarding
|
||||
</Button>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Button
|
||||
aria-label="Invia Email Servizio"
|
||||
className="flex w-full justify-start gap-3 px-2 font-normal"
|
||||
disabled={onboardDone}
|
||||
onClick={async () => {
|
||||
await navigator.clipboard.writeText(
|
||||
`${env.NEXT_PUBLIC_BASE_URL}/servizio/pre-onboard/${servizio.servizio_id}`,
|
||||
);
|
||||
toast.success("Copiato negli appunti", {
|
||||
icon: "📋",
|
||||
});
|
||||
}}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
>
|
||||
<Copy className="size-5 stroke-foreground" />
|
||||
Copia Link
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger className="flex items-center gap-3 hover:cursor-pointer">
|
||||
<Wrench className="size-5 stroke-foreground" />
|
||||
<span className="text-foreground">Status Servizio</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuRadioGroup
|
||||
onValueChange={(v) => {
|
||||
console.log(v);
|
||||
|
||||
update({
|
||||
data: {
|
||||
decorrenza: v === "true" ? new Date() : null,
|
||||
isOkAcconto: v === "true",
|
||||
},
|
||||
servizioId: servizio.servizio_id,
|
||||
});
|
||||
}}
|
||||
value={String(servizio.isOkAcconto)}
|
||||
>
|
||||
<DropdownMenuRadioItem value="true">
|
||||
Attivo
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="false">
|
||||
Disattiva
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger className="flex items-center gap-3 hover:cursor-pointer">
|
||||
<Wrench className="size-5 stroke-foreground" />
|
||||
<span className="text-foreground">Interruzione</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuRadioGroup
|
||||
onValueChange={(v) => {
|
||||
update({
|
||||
data: {
|
||||
isInterrotto: v === "true",
|
||||
},
|
||||
servizioId: servizio.servizio_id,
|
||||
});
|
||||
}}
|
||||
value={servizio.isInterrotto.toString()}
|
||||
>
|
||||
<DropdownMenuRadioItem value="true">
|
||||
Interrotto
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="false">
|
||||
Non Interrotto
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
aria-label="Modifica Parametri Servizio"
|
||||
className="flex items-center gap-3 hover:cursor-pointer"
|
||||
onClick={() => {
|
||||
setEditData(servizio);
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
<Wrench className="size-5 stroke-foreground" />
|
||||
Modifica parametri
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
aria-label="Elimina Servizio"
|
||||
className="flex items-center gap-3 hover:cursor-pointer"
|
||||
onClick={() =>
|
||||
confirm("Sei sicuro di voler eliminare il servizio?") &&
|
||||
remove({ servizioId: servizio.servizio_id })
|
||||
}
|
||||
>
|
||||
<Trash2 className="size-5 stroke-foreground" />
|
||||
Elimina Servizio
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
};
|
||||
|
||||
const AnnunciSection = ({
|
||||
selectedAnnunci,
|
||||
servizioId,
|
||||
userId,
|
||||
}: {
|
||||
selectedAnnunci: { codice: string; annunci_id: AnnunciId }[];
|
||||
servizioId: ServizioServizioId;
|
||||
userId: UsersId;
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex items-center gap-3">
|
||||
<Tooltip>
|
||||
<TooltipTrigger className="w-5">
|
||||
{selectedAnnunci?.length}
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{selectedAnnunci?.length > 0 ? (
|
||||
<ul>
|
||||
{selectedAnnunci?.map((annuncio) => (
|
||||
<li key={annuncio.annunci_id}>{annuncio.codice}</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<span>Nessun annuncio associato</span>
|
||||
)}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<AddAnnuncio servizioId={servizioId} userId={userId} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -7,7 +7,6 @@ import {
|
|||
Paperclip,
|
||||
Search,
|
||||
ShoppingBag,
|
||||
Tickets,
|
||||
User,
|
||||
UserCog,
|
||||
} from "lucide-react";
|
||||
|
|
@ -186,15 +185,7 @@ export const UsersTable = (props: { data: UserWChatInfo[] }) => {
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuLabel>Azioni</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<Link
|
||||
aria-label="Visualizza Servizio"
|
||||
className="flex w-full items-center gap-2"
|
||||
href={`/area-riservata/admin/user-view/servizio/${user.id}`}
|
||||
>
|
||||
<Tickets /> Servizio
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem>
|
||||
<Link
|
||||
aria-label="Visualizza Ricerca"
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ export const getServerSideProps = (async (context) => {
|
|||
) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: `/area-riservata/admin/user-view/servizio/${servizio.user_id}`,
|
||||
destination: `/area-riservata/dashboard`,
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { GetServerSideProps } from "next";
|
||||
import { AreaRiservataLayoutUserView } from "~/components/Layout";
|
||||
import { ServiziHeader } from "~/components/servizio/servizi_header";
|
||||
import { AnnunciRichiesti } from "~/components/servizio/servizio_annunci_accordions";
|
||||
import { TabRicerca } from "~/components/tables/ricerca-table";
|
||||
import type { NextPageWithLayout } from "~/pages/_app";
|
||||
|
|
@ -15,16 +16,10 @@ const RicercaUser: NextPageWithLayout<RicercaUserProps> = ({
|
|||
userId,
|
||||
}: RicercaUserProps) => {
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<div className="items-center justify-between md:flex">
|
||||
<div className="flex items-center gap-3">
|
||||
<h3 className="font-bold text-2xl">Le tue ricerche</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-5">
|
||||
<AnnunciRichiesti userId={userId} />
|
||||
<TabRicerca isAdmin userId={userId} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-5">
|
||||
<ServiziHeader userId={userId} />
|
||||
<AnnunciRichiesti userId={userId} />
|
||||
<TabRicerca isAdmin userId={userId} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -104,8 +104,9 @@ const ConfirmSection = ({
|
|||
await router.push(
|
||||
`/area-riservata/admin/user-view/ricerca/${data.userId}`,
|
||||
);
|
||||
} else {
|
||||
await router.push("/area-riservata/dashboard");
|
||||
}
|
||||
await router.push("/area-riservata/dashboard");
|
||||
},
|
||||
});
|
||||
return (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue