"use client"; import React, { useState, useRef } from 'react'; import { UploadCloud, X, Check, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { useSession } from 'next-auth/react'; import { toast } from '@/components/ui/use-toast'; interface FileUploadProps { type: 'logo' | 'attachment'; missionId: string; onUploadComplete?: (data: any) => void; maxSize?: number; // in bytes, default 5MB acceptedFileTypes?: string; } export function FileUpload({ type, missionId, onUploadComplete, maxSize = 5 * 1024 * 1024, // 5MB acceptedFileTypes = type === 'logo' ? 'image/*' : '.pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png' }: FileUploadProps) { const { data: session } = useSession(); const [isDragging, setIsDragging] = useState(false); const [isUploading, setIsUploading] = useState(false); const [progress, setProgress] = useState(0); const [file, setFile] = useState(null); const [error, setError] = useState(null); const fileInputRef = useRef(null); // Handle drag events const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(true); }; const handleDragLeave = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); }; const validateFile = (file: File): boolean => { // Check file size if (file.size > maxSize) { setError(`File size exceeds the limit of ${maxSize / (1024 * 1024)}MB`); return false; } // Check file type for logo if (type === 'logo' && !file.type.startsWith('image/')) { setError('Only image files are allowed for logo'); return false; } // For attachments, check file extension if (type === 'attachment') { const ext = file.name.split('.').pop()?.toLowerCase(); const allowedExt = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'jpg', 'jpeg', 'png']; if (ext && !allowedExt.includes(ext)) { setError(`File type .${ext} is not allowed. Allowed types: ${allowedExt.join(', ')}`); return false; } } setError(null); return true; }; const handleFileDrop = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { const droppedFile = e.dataTransfer.files[0]; if (validateFile(droppedFile)) { setFile(droppedFile); } } }; const handleFileChange = (e: React.ChangeEvent) => { if (e.target.files && e.target.files.length > 0) { const selectedFile = e.target.files[0]; if (validateFile(selectedFile)) { setFile(selectedFile); } } }; const handleUpload = async () => { if (!file || !session?.user?.id || !missionId) return; setIsUploading(true); setProgress(0); try { // Create form data const formData = new FormData(); formData.append('file', file); formData.append('missionId', missionId); formData.append('type', type); // Upload the file const response = await fetch('/api/missions/upload', { method: 'POST', body: formData }); if (!response.ok) { const error = await response.json(); throw new Error(error.error || 'Upload failed'); } const result = await response.json(); setProgress(100); // Reset file after successful upload setTimeout(() => { setFile(null); setIsUploading(false); setProgress(0); // Call the callback if provided if (onUploadComplete) { onUploadComplete(result); } toast({ title: 'File uploaded successfully', description: type === 'logo' ? 'Logo has been updated' : `${file.name} has been added to attachments`, variant: 'default', }); }, 1000); } catch (error) { console.error('Upload error:', error); setIsUploading(false); toast({ title: 'Upload failed', description: error instanceof Error ? error.message : 'An error occurred during upload', variant: 'destructive', }); } }; const handleCancel = () => { setFile(null); setError(null); }; return (
{!file ? (

{type === 'logo' ? 'Upload logo image' : 'Upload attachment'}

Drag and drop or click to browse

{error && (

{error}

)}
) : (
{type === 'logo' ? ( Preview ) : (
{file.name.split('.').pop()?.toUpperCase()}
)}

{file.name}

{(file.size / 1024).toFixed(2)} KB

{isUploading ? (
{progress}%
) : ( <> )}
{isUploading && (
)}
)}
); }