mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 07:10:57 +00:00
83 lines
3.0 KiB
TypeScript
83 lines
3.0 KiB
TypeScript
'use client';
|
|
|
|
import { isSupportAttachmentImage } from '@edr/types';
|
|
import { Download, ExternalLink, FileText } from 'lucide-react';
|
|
import { useCallback, useState } from 'react';
|
|
|
|
import Modal from '@/components/ui/Modal';
|
|
|
|
/** The minimal file shape the preview needs. */
|
|
export interface PreviewableFile {
|
|
name: string;
|
|
/**
|
|
* A blob object URL, not the attachment's API path — the API guard reads the
|
|
* bearer token from the `Authorization` header, which `<img>` and `<a>` can't
|
|
* send. Callers fetch the bytes first (see `useAttachmentObjectUrl`).
|
|
*/
|
|
url: string;
|
|
mimeType: string;
|
|
}
|
|
|
|
/**
|
|
* Drives a single shared preview modal for the page: call `view(file)` from any
|
|
* attachment, render `viewer` once near the page root.
|
|
*
|
|
* Mirrors the shape of `useFileViewer` from `@edr/ui-common`, which the freight
|
|
* backoffice uses. That hook can't be used here: it renders `@mantine/core`
|
|
* components, and this app is Tailwind-only with no `MantineProvider` mounted —
|
|
* its Modal would throw at runtime. Kept deliberately narrow (images inline,
|
|
* everything else handed to the browser) rather than reimplementing the shared
|
|
* viewer's pdf/office/video handling; swap this for the shared hook if this app
|
|
* ever adopts Mantine.
|
|
*/
|
|
export function useFilePreview() {
|
|
const [file, setFile] = useState<PreviewableFile | null>(null);
|
|
|
|
const view = useCallback((f: PreviewableFile) => setFile(f), []);
|
|
const close = useCallback(() => setFile(null), []);
|
|
|
|
const viewer = (
|
|
<Modal isOpen={file !== null} onClose={close} title={file?.name ?? ''} size="xl">
|
|
{file && (
|
|
<div className="flex flex-col items-center gap-4">
|
|
{isSupportAttachmentImage(file.mimeType) ? (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img
|
|
src={file.url}
|
|
alt={file.name}
|
|
className="max-h-[70vh] w-auto max-w-full rounded-lg object-contain"
|
|
/>
|
|
) : (
|
|
<div className="flex flex-col items-center gap-3 py-10 text-muted-foreground">
|
|
<FileText size={48} />
|
|
<p className="text-sm">No inline preview for this file type.</p>
|
|
</div>
|
|
)}
|
|
<div className="flex gap-2">
|
|
<a
|
|
href={file.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="flex items-center gap-2 rounded-lg border border-border px-3 py-1.5 text-xs font-medium text-foreground transition hover:bg-muted"
|
|
>
|
|
<ExternalLink size={14} />
|
|
Open in new tab
|
|
</a>
|
|
<a
|
|
href={file.url}
|
|
download={file.name}
|
|
className="flex items-center gap-2 rounded-lg px-3 py-1.5 text-xs font-medium text-white transition hover:opacity-90"
|
|
style={{ background: 'rgb(20 113 76)' }}
|
|
>
|
|
<Download size={14} />
|
|
Download
|
|
</a>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</Modal>
|
|
);
|
|
|
|
return { view, close, viewer };
|
|
}
|