'use client'; import { useState, type DragEvent, type RefObject } from 'react'; import { Upload, File, CheckCircle, XCircle, Loader2, Copy, ExternalLink, Trash2, Globe, AlertTriangle, } from 'lucide-react'; import { formatBytes } from '@/lib/helpers'; import { getSettings } from '@/lib/storage'; export interface FileEntry { id: string; file: File; preview?: string; status: 'pending' | 'uploading' | 'done' | 'error'; result?: { cid: string; size: number }; errorMsg?: string; date?: string; } interface QuickUploadProps { files: FileEntry[]; dragOver: boolean; uploading: boolean; uploadIndex: number; uploadDone: boolean; copied: string | null; inputRef: RefObject; onAddFiles: (files: FileList | File[]) => void; onRemoveFile: (id: string) => void; onDragOver: (e: DragEvent) => void; onDragLeave: () => void; onDrop: (e: DragEvent) => void; onBrowse: () => void; onInputChange: (e: React.ChangeEvent) => void; onStartUpload: () => void; onCopyCid: (cid: string) => void; onCopyShareLink: (cid: string) => void; onClearAll: () => void; gatewayLink: (cid: string) => string; } export default function QuickUpload({ files, dragOver, uploading, uploadIndex, uploadDone, copied, inputRef, onAddFiles, onRemoveFile, onDragOver, onDragLeave, onDrop, onBrowse, onInputChange, onStartUpload, onCopyCid, onCopyShareLink, onClearAll, gatewayLink, }: QuickUploadProps) { const s = getSettings(); const maxFiles = s.maxFiles; const maxFileSize = s.maxFileSize; const allowedExts = s.allowedFileTypes ? s.allowedFileTypes.split(',').map(e => e.trim().toLowerCase()).filter(Boolean) : null; const [fileTypeError, setFileTypeError] = useState(null); const doneCount = files.filter(f => f.status === 'done').length; const errorCount = files.filter(f => f.status === 'error').length; const totalCount = files.length; const allDone = files.every(f => f.status === 'done' || f.status === 'error'); function filterAllowedFiles(fileList: File[]): { accepted: File[]; rejected: string[] } { if (!allowedExts) return { accepted: fileList, rejected: [] }; const accepted: File[] = []; const rejected: string[] = []; for (const f of fileList) { const ext = f.name.split('.').pop()?.toLowerCase(); if (ext && allowedExts.includes(ext)) { accepted.push(f); } else { rejected.push(f.name); } } return { accepted, rejected }; } function handleLocalDrop(e: DragEvent) { e.preventDefault(); onDragLeave(); if (e.dataTransfer.files.length > 0) { const fileArr = Array.from(e.dataTransfer.files); const { accepted, rejected } = filterAllowedFiles(fileArr); if (rejected.length > 0) { setFileTypeError(`${rejected.length} bestand(en) overgeslagen (type niet toegestaan): ${rejected.join(', ')}`); setTimeout(() => setFileTypeError(null), 5000); } if (accepted.length > 0) onAddFiles(accepted); } } function handleLocalInputChange(e: React.ChangeEvent) { if (e.target.files && e.target.files.length > 0) { const fileArr = Array.from(e.target.files); const { accepted, rejected } = filterAllowedFiles(fileArr); if (rejected.length > 0) { setFileTypeError(`${rejected.length} bestand(en) overgeslagen (type niet toegestaan): ${rejected.join(', ')}`); setTimeout(() => setFileTypeError(null), 5000); } if (accepted.length > 0) onAddFiles(accepted); } e.target.value = ''; } return (
{/* File type error warning */} {fileTypeError && (
{fileTypeError}
)} {/* Drop zone */} {!uploading && !uploadDone && (
= maxFiles} />

Click to browse or drag & drop files

Up to {maxFiles} files, max {formatBytes(maxFileSize)} each

)} {/* File list */} {files.length > 0 && (
{totalCount} file{totalCount !== 1 ? 's' : ''} selected {uploading && <> · Uploading {uploadIndex}/{totalCount}} {!uploading && !allDone && ( )}
{uploading && (
)}
{files.map((entry, idx) => (
{entry.preview ? ( ) : ( )}
{entry.file.name} {entry.status === 'done' && entry.result && ( )} {entry.status === 'error' && ( )}
{formatBytes(entry.file.size)} {entry.status === 'uploading' && ( Uploading… )} {entry.status === 'done' && entry.result?.cid && ( {entry.result.cid.slice(0, 16)}… )} {entry.status === 'error' && ( {entry.errorMsg} )}
{entry.status === 'done' && entry.result && ( <> )} {entry.status === 'pending' && !uploading && ( )}
))}
)} {/* Action buttons */} {files.length > 0 && !allDone && (
)} {/* Results summary */} {uploadDone && (
{errorCount === 0 ? ( ) : ( )} {doneCount}/{totalCount} files uploaded
{/* Per-file result details */} {files.filter(f => f.status === 'done').map(entry => entry.result?.cid && (
{entry.file.name} {entry.result.cid.slice(0, 16)}… {formatBytes(entry.result.size ?? 0)}
))}
)} {/* Empty state */} {files.length === 0 && !uploading && (

Drag files above or click to browse. No crypto payment needed for quick uploads.

)}
); }