'use client' import { useState, useEffect, useCallback, useRef } from 'react' import { Button } from '@/components/ui/button' import { FileText, ImageIcon, Download, ChevronDown, ChevronUp, Plus } from 'lucide-react' import DocumentUploadZone from '@/components/bookkeeping/DocumentUploadZone' import type { UploadedFile } from '@/components/bookkeeping/DocumentUploadZone' 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 JournalEntryAttachmentsProps { journalEntryId: string onCountChange?: (count: number) => void } 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` } function isImageType(type: string | null): boolean { return type?.startsWith('image/') ?? false } export default function JournalEntryAttachments({ journalEntryId, onCountChange, }: JournalEntryAttachmentsProps) { const [documents, setDocuments] = useState([]) const [loading, setLoading] = useState(true) const [expandedImage, setExpandedImage] = useState(null) const [showUpload, setShowUpload] = useState(false) const [uploadFiles, setUploadFiles] = useState([]) const onCountChangeRef = useRef(onCountChange) onCountChangeRef.current = onCountChange const fetchDocuments = useCallback(async () => { try { const res = await fetch( `/api/documents?journal_entry_id=${journalEntryId}¤t_only=true` ) const { data } = await res.json() setDocuments(data || []) onCountChangeRef.current?.(data?.length || 0) } catch { console.error('Failed to fetch documents') } finally { setLoading(false) } }, [journalEntryId]) useEffect(() => { fetchDocuments() }, [fetchDocuments]) // Refresh documents when uploads complete useEffect(() => { const allDone = uploadFiles.length > 0 && uploadFiles.every((f) => f.status !== 'uploading') const hasUploaded = uploadFiles.some((f) => f.status === 'uploaded') if (allDone && hasUploaded) { fetchDocuments() setUploadFiles([]) setShowUpload(false) } }, [uploadFiles, fetchDocuments]) const handleDownload = async (docId: string) => { try { const res = await fetch(`/api/documents/${docId}`) const { data } = await res.json() if (data?.download_url) { window.open(data.download_url, '_blank') } } catch { console.error('Failed to get download URL') } } const handlePreviewToggle = async (doc: DocumentRecord) => { if (expandedImage === doc.id) { setExpandedImage(null) return } // Fetch signed URL for preview if not already loaded if (!doc.download_url) { try { const res = await fetch(`/api/documents/${doc.id}`) const { data } = await res.json() if (data?.download_url) { setDocuments((prev) => prev.map((d) => (d.id === doc.id ? { ...d, download_url: data.download_url } : d)) ) } } catch { console.error('Failed to get preview URL') return } } setExpandedImage(doc.id) } if (loading) { return (
Laddar underlag...
) } return (

Underlag {documents.length > 0 && `(${documents.length})`}

{/* Upload zone */} {showUpload && (
)} {/* Document list */} {documents.length === 0 && !showUpload ? (

Inga underlag bifogade.

) : (
{documents.map((doc) => (
{isImageType(doc.mime_type) ? ( ) : ( )} {isImageType(doc.mime_type) && expandedImage !== doc.id && ( )} {doc.file_name} {formatFileSize(doc.file_size_bytes)}
{/* Image preview */} {expandedImage === doc.id && doc.download_url && (
{doc.file_name}
)}
))}
)}
) }