2026-04-22 19:17:54 +02:00
|
|
|
import { differenceInDays, differenceInMinutes, format } from "date-fns";
|
|
|
|
|
import { Paperclip } from "lucide-react";
|
|
|
|
|
import Link from "next/link";
|
|
|
|
|
import { ExtIcon } from "~/components/area-riservata/allegati";
|
|
|
|
|
import {
|
|
|
|
|
Credenza,
|
|
|
|
|
CredenzaBody,
|
|
|
|
|
CredenzaClose,
|
|
|
|
|
CredenzaContent,
|
|
|
|
|
CredenzaDescription,
|
|
|
|
|
CredenzaFooter,
|
|
|
|
|
CredenzaHeader,
|
|
|
|
|
CredenzaTitle,
|
|
|
|
|
CredenzaTrigger,
|
|
|
|
|
} from "~/components/custom_ui/credenza";
|
|
|
|
|
import { LoadingPage } from "~/components/loading";
|
|
|
|
|
import { Button, buttonVariants } from "~/components/ui/button";
|
|
|
|
|
import { UploadComponent } from "~/components/upload_modal";
|
|
|
|
|
import { cn } from "~/lib/utils";
|
2026-04-27 16:52:32 +02:00
|
|
|
import { useChatContext } from "~/providers/ChatProvider";
|
2026-04-22 19:17:54 +02:00
|
|
|
import { useTranslation } from "~/providers/I18nProvider";
|
|
|
|
|
import { api } from "~/utils/api";
|
|
|
|
|
|
2026-04-27 16:52:32 +02:00
|
|
|
export const ChatAttachments = () => {
|
|
|
|
|
const { session, userinfo } = useChatContext();
|
2026-04-22 19:17:54 +02:00
|
|
|
const { t } = useTranslation();
|
|
|
|
|
const {
|
|
|
|
|
data: attachments,
|
|
|
|
|
isLoading: attachmentsLoading,
|
|
|
|
|
refetch,
|
|
|
|
|
} = api.storage.retrieveUserFileData.useQuery(
|
2026-04-27 16:52:32 +02:00
|
|
|
{ userId: userinfo.id },
|
2026-04-22 19:17:54 +02:00
|
|
|
{ refetchOnMount: true },
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Credenza onOpenChange={(o) => o && refetch()}>
|
|
|
|
|
<CredenzaTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
aria-label="Allegati Chat"
|
|
|
|
|
className="relative size-9"
|
|
|
|
|
size="icon"
|
|
|
|
|
variant="ghost"
|
|
|
|
|
>
|
|
|
|
|
{attachments && attachments.length > 0 && (
|
|
|
|
|
<span className="absolute -top-1 right-0 rounded-full bg-blue-500 px-1 font-bold text-white text-xs">
|
|
|
|
|
{attachments.length}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
<Paperclip className="text-muted-foreground" size={20} />
|
|
|
|
|
</Button>
|
|
|
|
|
</CredenzaTrigger>
|
|
|
|
|
<CredenzaContent className="max-h-[90vh] md:max-w-xl">
|
|
|
|
|
<CredenzaHeader>
|
|
|
|
|
<CredenzaTitle className="sr-only">Allegati</CredenzaTitle>
|
|
|
|
|
<CredenzaDescription className="sr-only">
|
|
|
|
|
Chat Attachments
|
|
|
|
|
</CredenzaDescription>
|
|
|
|
|
</CredenzaHeader>
|
|
|
|
|
<CredenzaBody className="max-h-[80vh] space-y-5 overflow-auto pb-5 md:px-1">
|
2026-04-27 16:52:32 +02:00
|
|
|
<UploadComponent isAdmin={session.isAdmin} userId={userinfo.id} />
|
2026-04-22 19:17:54 +02:00
|
|
|
|
|
|
|
|
<div className="h-auto max-h-160 max-w-lg overflow-auto rounded-lg">
|
|
|
|
|
{attachmentsLoading ? (
|
|
|
|
|
<LoadingPage />
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
{!attachments || attachments.length === 0 ? (
|
|
|
|
|
<div className="flex h-full items-center justify-center">
|
|
|
|
|
<p className="text-center font-semibold text-gray-500 text-lg">
|
|
|
|
|
{t.allegati.nessun_allegato}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<ul className="px-2">
|
|
|
|
|
<h3 className="font-semibold text-gray-700 text-lg">
|
|
|
|
|
{t.allegati.allegati_recenti}
|
|
|
|
|
</h3>
|
|
|
|
|
{attachments?.map((file, idx) => {
|
|
|
|
|
if (idx >= 3) return null;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<li
|
|
|
|
|
className="flex flex-row items-center justify-between border-b py-1"
|
|
|
|
|
key={`${file.originalName}-${
|
|
|
|
|
// biome-ignore lint/suspicious/noArrayIndexKey: <ok>
|
|
|
|
|
idx
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Allegato"
|
|
|
|
|
href={`/area-riservata/allegato-view/${file.id}`}
|
|
|
|
|
onTouchStart={() => console.log("touching")}
|
|
|
|
|
target="_blank"
|
|
|
|
|
>
|
|
|
|
|
<Button
|
|
|
|
|
className="h-8 truncate p-0 text-base has-[>svg]:px-0"
|
|
|
|
|
variant="link"
|
|
|
|
|
>
|
|
|
|
|
<ExtIcon mimeType={file.mimeType} />
|
|
|
|
|
<span className="max-w-[60vw] truncate">
|
|
|
|
|
{file.originalName}
|
|
|
|
|
</span>
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
|
|
|
|
<span
|
|
|
|
|
className="text-muted-foreground text-xs"
|
|
|
|
|
key={new Date().toString()}
|
|
|
|
|
>
|
|
|
|
|
{TimeSince(new Date(file.uploadedAt))}
|
|
|
|
|
</span>
|
|
|
|
|
</li>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</ul>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Allegati"
|
|
|
|
|
className={cn(
|
|
|
|
|
buttonVariants({
|
|
|
|
|
variant: "outline",
|
|
|
|
|
}),
|
|
|
|
|
"relative w-full",
|
|
|
|
|
)}
|
|
|
|
|
href="/area-riservata/allegati"
|
|
|
|
|
>
|
|
|
|
|
<Paperclip /> {t.allegati.i_tuoi_allegati}
|
|
|
|
|
{attachments && attachments.length > 0 && (
|
|
|
|
|
<span className="absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full bg-red-600 text-white text-xs">
|
|
|
|
|
{attachments.length}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</Link>
|
|
|
|
|
</CredenzaBody>
|
|
|
|
|
<CredenzaFooter className="flex flex-col items-center justify-between gap-2">
|
|
|
|
|
<CredenzaClose asChild>
|
|
|
|
|
<Button className="w-full">{t.chiudi}</Button>
|
|
|
|
|
</CredenzaClose>
|
|
|
|
|
</CredenzaFooter>
|
|
|
|
|
</CredenzaContent>
|
|
|
|
|
</Credenza>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const TimeSince = (date: Date) => {
|
|
|
|
|
const minsSince = Math.abs(differenceInMinutes(date, new Date()));
|
|
|
|
|
const daysSince = Math.abs(differenceInDays(date, new Date()));
|
|
|
|
|
|
|
|
|
|
const relevantMinsIncrements = [1, 3, 5, 10, 15, 30, 60, 120];
|
|
|
|
|
|
|
|
|
|
if (daysSince === 0) {
|
|
|
|
|
if (minsSince < 1) {
|
|
|
|
|
return "ora";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const closestToNow = relevantMinsIncrements.reduce((prev, curr) => {
|
|
|
|
|
return Math.abs(curr - minsSince) < Math.abs(prev - minsSince)
|
|
|
|
|
? curr
|
|
|
|
|
: prev;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (closestToNow === 60) {
|
|
|
|
|
return "~1 ora fa";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (closestToNow === 120 && minsSince < 121) {
|
|
|
|
|
return "~2 ore fa";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return `~${closestToNow} min fa`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (daysSince === 1) {
|
|
|
|
|
return "ieri";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (daysSince < 30) {
|
|
|
|
|
return `${daysSince} giorni fa`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return format(date, "dd/MM/yyyy");
|
|
|
|
|
};
|