Files
pn-new-crm/src/components/files/file-preview-dialog.tsx
Matt 0e8feb1073 chore: prettier format pass on branch files
Auto-format all files modified during the documents-hub-split feature
branch that were not yet aligned with the project's Prettier config
(single quotes, semicolons, trailing commas).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 13:01:47 +02:00

104 lines
3.0 KiB
TypeScript

'use client';
import { useEffect, useState } from 'react';
import { ExternalLink } from 'lucide-react';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { apiFetch } from '@/lib/api/client';
interface FilePreviewDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
fileId?: string;
fileName?: string;
mimeType?: string;
}
export function FilePreviewDialog({
open,
onOpenChange,
fileId,
fileName,
mimeType,
}: FilePreviewDialogProps) {
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!open || !fileId) {
setPreviewUrl(null);
setError(null);
return;
}
setLoading(true);
setError(null);
apiFetch<{ data: { url: string } }>(`/api/v1/files/${fileId}/preview`)
.then((res) => {
setPreviewUrl(res.data.url);
})
.catch(() => {
setError('Failed to load preview');
})
.finally(() => {
setLoading(false);
});
}, [open, fileId]);
const isImage = mimeType?.startsWith('image/');
const isPdf = mimeType === 'application/pdf';
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-4xl w-full h-[80vh] flex flex-col">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 truncate">
<span className="truncate">{fileName ?? 'Preview'}</span>
{previewUrl && (
<a
href={previewUrl}
target="_blank"
rel="noopener noreferrer"
className="shrink-0 text-muted-foreground hover:text-foreground"
>
<ExternalLink className="h-4 w-4" />
</a>
)}
</DialogTitle>
</DialogHeader>
<div className="flex-1 overflow-hidden rounded-lg border bg-muted/20">
{loading && (
<div className="flex h-full items-center justify-center text-sm text-muted-foreground">
Loading preview...
</div>
)}
{error && (
<div className="flex h-full items-center justify-center text-sm text-destructive">
{error}
</div>
)}
{!loading && !error && previewUrl && isImage && (
<div className="flex h-full items-center justify-center p-4">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={previewUrl}
alt={fileName ?? 'Preview'}
className="max-h-full max-w-full object-contain rounded"
/>
</div>
)}
{!loading && !error && previewUrl && isPdf && (
<iframe src={previewUrl} title={fileName ?? 'PDF Preview'} className="h-full w-full" />
)}
</div>
</DialogContent>
</Dialog>
);
}