infoalloggi-monorepo/apps/infoalloggi/src/components/chat/chat-attachments.tsx

186 lines
5.3 KiB
TypeScript
Raw Normal View History

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";
import { useChatContext } from "~/providers/ChatProvider";
import { useTranslation } from "~/providers/I18nProvider";
import { api } from "~/utils/api";
export const ChatAttachments = () => {
const { session, userinfo } = useChatContext();
const { t } = useTranslation();
const {
data: attachments,
isLoading: attachmentsLoading,
refetch,
} = api.storage.retrieveUserFileData.useQuery(
{ userId: userinfo.id },
{ 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">
<UploadComponent isAdmin={session.isAdmin} userId={userinfo.id} />
<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");
};