'use client' import { useState, useCallback, useRef } from 'react' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Upload, FileText, ImageIcon, X, Loader2 } from 'lucide-react' export interface UploadedFile { id?: string file: File status: 'pending' | 'uploading' | 'uploaded' | 'error' error?: string fileName: string fileSize: number } interface DocumentUploadZoneProps { files: UploadedFile[] onFilesChange: (files: UploadedFile[]) => void journalEntryId?: string maxFiles?: number disabled?: boolean compact?: boolean } const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10 MB const ACCEPTED_TYPES = ['application/pdf', 'image/jpeg', 'image/png', 'image/webp'] const ACCEPTED_EXTENSIONS = '.pdf,.jpg,.jpeg,.png,.webp' 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): boolean { return type.startsWith('image/') } export default function DocumentUploadZone({ files, onFilesChange, journalEntryId, maxFiles = 5, disabled = false, compact = false, }: DocumentUploadZoneProps) { const [isDragging, setIsDragging] = useState(false) const inputRef = useRef(null) const uploadFile = useCallback(async (file: UploadedFile): Promise => { const formData = new FormData() formData.append('file', file.file) formData.append('upload_source', 'file_upload') if (journalEntryId) { formData.append('journal_entry_id', journalEntryId) } try { const res = await fetch('/api/documents', { method: 'POST', body: formData, }) const result = await res.json() if (result.error) { return { ...file, status: 'error', error: result.error } } return { ...file, status: 'uploaded', id: result.data?.id } } catch { return { ...file, status: 'error', error: 'Uppladdning misslyckades' } } }, [journalEntryId]) const handleFiles = useCallback(async (newFiles: File[]) => { const remaining = maxFiles - files.length if (remaining <= 0) return const validFiles: UploadedFile[] = [] for (const file of newFiles.slice(0, remaining)) { if (!ACCEPTED_TYPES.includes(file.type)) { validFiles.push({ file, status: 'error', error: 'Filtypen stöds inte', fileName: file.name, fileSize: file.size, }) continue } if (file.size > MAX_FILE_SIZE) { validFiles.push({ file, status: 'error', error: 'Filen är för stor (max 10 MB)', fileName: file.name, fileSize: file.size, }) continue } validFiles.push({ file, status: 'uploading', fileName: file.name, fileSize: file.size, }) } let currentFiles = [...files, ...validFiles] onFilesChange(currentFiles) // Upload files that passed validation for (const f of validFiles.filter((f) => f.status === 'uploading')) { const result = await uploadFile(f) currentFiles = currentFiles.map((cf) => cf.fileName === result.fileName && cf.status === 'uploading' ? result : cf ) onFilesChange([...currentFiles]) } }, [files, maxFiles, onFilesChange, uploadFile]) const handleDragOver = useCallback((e: React.DragEvent) => { e.preventDefault() if (!disabled) setIsDragging(true) }, [disabled]) const handleDragLeave = useCallback((e: React.DragEvent) => { e.preventDefault() setIsDragging(false) }, []) const handleDrop = useCallback((e: React.DragEvent) => { e.preventDefault() setIsDragging(false) if (disabled) return const droppedFiles = Array.from(e.dataTransfer.files) handleFiles(droppedFiles) }, [disabled, handleFiles]) const handleInputChange = useCallback((e: React.ChangeEvent) => { const selectedFiles = e.target.files if (selectedFiles) { handleFiles(Array.from(selectedFiles)) } // Reset input so the same file can be re-selected if (inputRef.current) inputRef.current.value = '' }, [handleFiles]) const removeFile = useCallback((index: number) => { onFilesChange(files.filter((_, i) => i !== index)) }, [files, onFilesChange]) const isUploading = files.some((f) => f.status === 'uploading') return (
{/* Drop zone */}
inputRef.current?.click()} >

{compact ? 'Dra och släpp eller klicka' : 'Dra och släpp filer här'}

{!compact && (

PDF, bilder (max 10 MB)

)}
{/* File list */} {files.length > 0 && (
{files.map((file, index) => (
{isImageType(file.file.type) ? ( ) : ( )} {file.fileName} {formatFileSize(file.fileSize)} {file.status === 'uploading' && ( )} {file.status === 'uploaded' && ( Uppladdad )} {file.status === 'error' && ( <> Fel {file.error && ( {file.error} )} )}
))}
)} {isUploading && (

Laddar upp...

)}
) }