infoalloggi-monorepo/apps/infoalloggi/src/pages/area-riservata/allegato-view/[allegatoId].tsx
Marco Pedone 50ba1d4c5d Add documentation comments for admin and user-facing pages
- Added descriptive comments for various admin management pages including announcements, banners, blacklist, chats, and more.
- Documented user-facing pages such as chat, communications, dashboard, and profile.
- Included comments for authentication-related pages like password reset and invite acceptance.
- Enhanced clarity on the purpose and routing of each page in the application.
2026-03-09 17:33:02 +01:00

240 lines
6.1 KiB
TypeScript

import { Download, Pen, Trash } from "lucide-react";
import type { GetServerSideProps } from "next";
import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { type FormEvent, useState } from "react";
import toast from "react-hot-toast";
import z from "zod";
import { AllegatoIframe } from "~/components/allegato-iframe";
import { Confirm } from "~/components/confirm";
import { DocNotFoundPage } from "~/components/doc_not_found";
import { AreaRiservataLayout } from "~/components/Layout";
import { LoadingPage } from "~/components/loading";
import { Button } from "~/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "~/components/ui/dialog";
import { Input } from "~/components/ui/input";
import { getStorageUrl } from "~/lib/storage_utils";
import type { NextPageWithLayout } from "~/pages/_app";
import { useTranslation } from "~/providers/I18nProvider";
import { useEnforcedSession } from "~/providers/SessionProvider";
import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper";
import { api } from "~/utils/api";
type AllegatoViewProps = {
allegatoId: string;
};
/**
* Pagina di visualizzazione dell'allegato: /area-riservata/allegato/[allegatoId]
*/
const AllegatoView: NextPageWithLayout<AllegatoViewProps> = ({
allegatoId,
}: AllegatoViewProps) => {
const { t } = useTranslation();
const session = useEnforcedSession();
const { data: fileInfos, isLoading } = api.storage.getFileInfos.useQuery({
storageId: allegatoId,
});
const utils = api.useUtils();
const router = useRouter();
const { mutate: deleteFile } = api.storage.deleteFile.useMutation({
onMutate: () => {
const toastId = toast.loading(t.caricamento, {
icon: "🪛",
});
return { toastId };
},
onSuccess: async (_error, _variables, context) => {
await utils.storage.retrieveUserFileData.invalidate();
toast.success(t.allegati.allegato_rimosso, {
icon: "🗑️",
id: context?.toastId,
});
await router.push("/area-riservata/admin/storage");
},
});
if (isLoading) return <LoadingPage />;
if (!fileInfos) return <DocNotFoundPage />;
return (
<>
<Head>
<title>Infoalloggi.it | {fileInfos.originalName}</title>
</Head>
<div className="flex h-full w-full grow flex-col md:flex-row">
<div className="flex grow flex-col justify-center space-y-2 p-4">
<div className="mx-auto flex flex-wrap items-center gap-4">
<span>{fileInfos.originalName}</span>
<span>
caricato il {new Date(fileInfos.uploadedAt).toLocaleString("it")}
</span>
<Link
href={getStorageUrl({
storageId: fileInfos.id,
params: { mode: "download" },
})}
>
<Button className="flex gap-2">
<Download size={16} />
Download
</Button>
</Link>
<RinominaDialog
allegatoId={allegatoId}
filename={fileInfos.originalName}
/>
{session.user.isAdmin && (
<Confirm
description="Sei sicuro di voler eliminare questo allegato?"
onConfirm={() => deleteFile({ storageId: allegatoId })}
title="Elimina allegato"
>
<Button className="flex gap-2" variant="destructive">
<Trash size={16} />
Elimina
</Button>
</Confirm>
)}
</div>
<AllegatoIframe allegato={fileInfos} />
</div>
</div>
</>
);
};
AllegatoView.getLayout = function getLayout(page) {
return <AreaRiservataLayout noSidebar>{page}</AreaRiservataLayout>;
};
export const getServerSideProps = (async (context) => {
const allegatoId = context.params?.allegatoId;
if (!allegatoId || typeof allegatoId !== "string") {
return {
notFound: true,
};
}
const parsedStorageId = z.string().safeParse(allegatoId);
if (!parsedStorageId.success) {
return {
notFound: true,
};
}
const access_token = context.req.cookies.access_token;
const helper = await TrpcAuthedFetchingIstance({ access_token });
if (helper) {
await helper.trpc.storage.getFileInfos.prefetch({
storageId: parsedStorageId.data,
});
return {
props: {
allegatoId: parsedStorageId.data,
trpcState: helper.trpc.dehydrate(),
},
};
}
return {
redirect: {
destination: "/500",
permanent: false,
},
};
}) satisfies GetServerSideProps<AllegatoViewProps>;
export default AllegatoView;
const RinominaDialog = ({
allegatoId,
filename,
}: {
allegatoId: string;
filename: string | null;
}) => {
const { t } = useTranslation();
const utils = api.useUtils();
const [editOpen, setEditOpen] = useState(false);
const { mutate: renameFile } = api.storage.renameFile.useMutation({
onMutate: () => {
setEditOpen(false);
const toastId = toast.loading(t.caricamento, {
icon: "🪛",
});
return { toastId };
},
onSuccess: async (_error, _variables, context) => {
await utils.storage.getFileInfos.invalidate({
storageId: allegatoId,
});
toast.success(t.successo, {
icon: "👍",
id: context?.toastId,
});
},
});
const handleEditSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const form = e.currentTarget;
const formData = new FormData(form);
if (!formData.get("filename")) {
return;
}
renameFile({
fileId: allegatoId,
name: formData.get("filename") as string,
});
};
return (
<Dialog onOpenChange={setEditOpen} open={editOpen}>
<DialogTrigger asChild>
<Button
className="flex gap-2"
onClick={() => console.log("rinomina")}
variant="info"
>
<Pen size={16} />
Rinomina
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>{t.modifica}</DialogTitle>
<DialogDescription className="sr-only">modifica</DialogDescription>
</DialogHeader>
<form method="post" onSubmit={handleEditSubmit}>
<div className="flex items-center gap-3">
<Input
className="mt-0"
defaultValue={filename || undefined}
minLength={5}
name="filename"
placeholder="Modifica messaggio"
type="text"
/>
<Button type="submit">{t.salva}</Button>
</div>
</form>
</DialogContent>
</Dialog>
);
};