infoalloggi-monorepo/apps/infoalloggi/src/pages/area-riservata/allegato-view/[allegatoId].tsx

232 lines
5.9 KiB
TypeScript
Raw Normal View History

2025-08-04 17:45:44 +02:00
import { Download, Pen, Trash } from "lucide-react";
import type { GetServerSideProps } from "next";
import Head from "next/head";
2025-10-24 16:10:59 +02:00
import Link from "next/link";
2025-08-28 18:27:07 +02:00
import { useRouter } from "next/router";
import { type FormEvent, useState } from "react";
import toast from "react-hot-toast";
2025-10-24 16:10:59 +02:00
import z from "zod";
2025-08-28 18:27:07 +02:00
import { AllegatoIframe } from "~/components/allegato-iframe";
import { Confirm } from "~/components/confirm";
import { DocNotFoundPage } from "~/components/doc_not_found";
2025-08-04 17:45:44 +02:00
import { AreaRiservataLayout } from "~/components/Layout";
import { LoadingPage } from "~/components/loading";
import { Button } from "~/components/ui/button";
import {
2025-08-28 18:27:07 +02:00
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
2025-08-04 17:45:44 +02:00
} from "~/components/ui/dialog";
import { Input } from "~/components/ui/input";
2025-08-28 18:27:07 +02:00
import type { NextPageWithLayout } from "~/pages/_app";
import { useTranslation } from "~/providers/I18nProvider";
import { useEnforcedSession } from "~/providers/SessionProvider";
2025-08-04 17:45:44 +02:00
import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper";
2025-08-28 18:27:07 +02:00
import { api } from "~/utils/api";
2025-08-04 17:45:44 +02:00
type AllegatoViewProps = {
2025-10-24 16:10:59 +02:00
allegatoId: string;
2025-08-04 17:45:44 +02:00
};
const AllegatoView: NextPageWithLayout<AllegatoViewProps> = ({
2025-08-28 18:27:07 +02:00
allegatoId,
2025-08-04 17:45:44 +02:00
}: AllegatoViewProps) => {
2025-08-28 18:27:07 +02:00
const { t } = useTranslation();
const session = useEnforcedSession();
2025-10-24 16:10:59 +02:00
const { data: fileInfos, isLoading } = api.storage.getFileInfos.useQuery({
2025-08-28 18:27:07 +02:00
storageId: allegatoId,
});
const utils = api.useUtils();
const router = useRouter();
2025-10-24 16:10:59 +02:00
const { mutate: deleteFile } = api.storage.deleteFile.useMutation({
2025-08-28 18:27:07 +02:00
onMutate: () => {
const toastId = toast.loading(t.caricamento, {
icon: "🪛",
});
return { toastId };
},
onSuccess: async (_error, _variables, context) => {
2025-10-24 16:10:59 +02:00
await utils.storage.retrieveUserFileData.invalidate();
2025-08-28 18:27:07 +02:00
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>
2025-10-24 16:10:59 +02:00
<title>Infoalloggi.it | {fileInfos.originalName}</title>
2025-08-28 18:27:07 +02:00
</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">
2025-10-24 16:10:59 +02:00
<span>{fileInfos.originalName}</span>
<span>
caricato il {new Date(fileInfos.uploadedAt).toLocaleString("it")}
</span>
<Link href={`/storage-api/get/${fileInfos.id}?mode=download`}>
<Button className="flex gap-2">
<Download size={16} />
Download
</Button>
</Link>
2025-08-28 18:27:07 +02:00
<RinominaDialog
allegatoId={allegatoId}
2025-10-24 16:10:59 +02:00
filename={fileInfos.originalName}
2025-08-28 18:27:07 +02:00
/>
{session.user.isAdmin && (
<Confirm
2025-08-29 16:18:32 +02:00
description="Sei sicuro di voler eliminare questo allegato?"
2025-08-28 18:27:07 +02:00
onConfirm={() => deleteFile({ storageId: allegatoId })}
title="Elimina allegato"
>
2025-08-29 16:18:32 +02:00
<Button className="flex gap-2" variant="destructive">
2025-08-28 18:27:07 +02:00
<Trash size={16} />
Elimina
</Button>
</Confirm>
)}
</div>
2025-10-24 16:10:59 +02:00
<AllegatoIframe allegato={fileInfos} />
2025-08-28 18:27:07 +02:00
</div>
</div>
</>
);
2025-08-04 17:45:44 +02:00
};
AllegatoView.getLayout = function getLayout(page) {
2025-08-28 18:27:07 +02:00
return <AreaRiservataLayout noSidebar>{page}</AreaRiservataLayout>;
2025-08-04 17:45:44 +02:00
};
export const getServerSideProps = (async (context) => {
2025-08-28 18:27:07 +02:00
const allegatoId = context.params?.allegatoId;
if (!allegatoId || typeof allegatoId !== "string") {
return {
notFound: true,
};
}
2025-10-24 16:10:59 +02:00
const parsedStorageId = z.string().safeParse(allegatoId);
2025-08-28 18:27:07 +02:00
if (!parsedStorageId.success) {
return {
notFound: true,
};
}
const access_token = context.req.cookies.access_token;
const helper = await TrpcAuthedFetchingIstance({ access_token });
if (helper) {
2025-10-24 16:10:59 +02:00
await helper.trpc.storage.getFileInfos.prefetch({
2025-08-28 18:27:07 +02:00
storageId: parsedStorageId.data,
});
return {
props: {
allegatoId: parsedStorageId.data,
trpcState: helper.trpc.dehydrate(),
},
};
}
return {
redirect: {
destination: "/500",
permanent: false,
},
};
2025-08-04 17:45:44 +02:00
}) satisfies GetServerSideProps<AllegatoViewProps>;
export default AllegatoView;
const RinominaDialog = ({
2025-08-28 18:27:07 +02:00
allegatoId,
filename,
2025-08-04 17:45:44 +02:00
}: {
2025-10-24 16:10:59 +02:00
allegatoId: string;
2025-08-28 18:27:07 +02:00
filename: string | null;
2025-08-04 17:45:44 +02:00
}) => {
2025-08-28 18:27:07 +02:00
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) => {
2025-10-24 16:10:59 +02:00
await utils.storage.getFileInfos.invalidate({
2025-08-28 18:27:07 +02:00
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 (
2025-08-29 16:18:32 +02:00
<Dialog onOpenChange={setEditOpen} open={editOpen}>
2025-08-28 18:27:07 +02:00
<DialogTrigger asChild>
<Button
className="flex gap-2"
2025-08-29 16:18:32 +02:00
onClick={() => console.log("rinomina")}
variant="info"
2025-08-28 18:27:07 +02:00
>
<Pen size={16} />
Rinomina
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>{t.modifica}</DialogTitle>
<DialogDescription className="sr-only">modifica</DialogDescription>
</DialogHeader>
2025-08-29 16:18:32 +02:00
<form method="post" onSubmit={handleEditSubmit}>
2025-08-28 18:27:07 +02:00
<div className="flex items-center gap-3">
<Input
className="mt-0"
defaultValue={filename || undefined}
minLength={5}
2025-08-29 16:18:32 +02:00
name="filename"
placeholder="Modifica messaggio"
type="text"
2025-08-28 18:27:07 +02:00
/>
<Button type="submit">{t.salva}</Button>
</div>
</form>
</DialogContent>
</Dialog>
);
2025-08-04 17:45:44 +02:00
};