'use client' import { useCallback, useEffect, useState } from 'react' import { useTranslations } from 'next-intl' import { ExternalLink, FileText, ImageIcon, Paperclip } from 'lucide-react' import { Sheet, SheetContent, SheetHeader, SheetTitle, } from '@/components/ui/sheet' import { Skeleton } from '@/components/ui/skeleton' interface DocumentRecord { id: string file_name: string file_size_bytes: number mime_type: string | null storage_path: string created_at: string download_url?: string } interface AttachmentPreviewSheetProps { entryId: string | null open: boolean onOpenChange: (open: boolean) => void } function isImageType(type: string | null): boolean { return type?.startsWith('image/') ?? false } function isPdfType(type: string | null): boolean { return type === 'application/pdf' } function formatFileSize(bytes: number): string { if (bytes < 1024) return `${bytes} B` if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` return `${(bytes / (1024 * 1024)).toFixed(1)} MB` } export default function AttachmentPreviewSheet({ entryId, open, onOpenChange, }: AttachmentPreviewSheetProps) { const t = useTranslations('attachment_preview_sheet') const [documents, setDocuments] = useState([]) const [loading, setLoading] = useState(false) const fetchAttachments = useCallback(async (id: string) => { setLoading(true) try { const res = await fetch( `/api/documents?journal_entry_id=${id}¤t_only=true` ) const { data } = await res.json() const list: DocumentRecord[] = data || [] // Pull a signed download_url for each — used by the // "open in new tab" link. The iframe/img sources use the // same-origin inline proxy and do not need download_url. const enriched = await Promise.all( list.map(async (doc) => { try { const r = await fetch(`/api/documents/${doc.id}`) const { data: detail } = await r.json() return detail?.download_url ? { ...doc, download_url: detail.download_url as string } : doc } catch { return doc } }) ) setDocuments(enriched) } catch { setDocuments([]) } finally { setLoading(false) } }, []) useEffect(() => { if (open && entryId) { fetchAttachments(entryId) } else if (!open) { // Reset state when closed so the next open starts fresh setDocuments([]) } }, [open, entryId, fetchAttachments]) return ( {t('title')} {loading ? (
) : documents.length === 0 ? (

{t('empty')}

) : (
{documents.map((doc) => { const inlineSrc = `/api/documents/${doc.id}/inline` const previewable = isImageType(doc.mime_type) || isPdfType(doc.mime_type) return (
{isImageType(doc.mime_type) ? ( ) : ( )}

{doc.file_name}

{formatFileSize(doc.file_size_bytes)}

{doc.download_url && ( {t('open_in_new_tab')} )}
{isPdfType(doc.mime_type) && (