"use client"; import React, { useState, useRef, useEffect } 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) { // Log props on init console.log('FileUpload component initialized with props:', { type, missionId, hasMissionId: !!missionId, maxSize, acceptedFileTypes }); 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); const isMounted = useRef(true); // Cleanup on unmount useEffect(() => { return () => { isMounted.current = false; }; }, []); // Log when session changes useEffect(() => { console.log('Session state in FileUpload:', { isSessionLoaded: !!session, hasUser: !!session?.user, userId: session?.user?.id }); }, [session]); // Log when missionId changes useEffect(() => { console.log('MissionId in FileUpload component:', missionId); }, [missionId]); // 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 () => { // Log all values to see what's missing console.log('Debug upload parameters:', { file, sessionUser: session?.user, userId: session?.user?.id, missionId }); // Check for missing parameters and provide specific feedback if (!file) { console.error('Upload failed: No file selected'); toast({ title: 'Upload failed', description: 'No file selected. Please select a file first.', variant: 'destructive', }); return; } if (!session?.user?.id) { console.error('Upload failed: No user session'); toast({ title: 'Authentication required', description: 'You need to be logged in to upload files. Please log in and try again.', variant: 'destructive', }); return; } if (!missionId) { console.error('Upload failed: Missing mission ID'); toast({ title: 'Upload failed', description: 'Missing mission ID. Please refresh the page and try again.', variant: 'destructive', }); return; } console.log('Starting upload process...', { fileName: file.name, fileSize: file.size, fileType: file.type, missionId, userId: session.user.id, uploadType: type }); setIsUploading(true); setProgress(0); try { // Create form data const formData = new FormData(); formData.append('file', file); formData.append('missionId', missionId); formData.append('type', type); console.log('FormData prepared, sending to API...'); // Upload the file const response = await fetch('/api/missions/upload', { method: 'POST', body: formData }); console.log('API response received:', { status: response.status, statusText: response.statusText, ok: response.ok }); if (!response.ok) { const errorData = await response.json(); console.error('API returned error:', errorData); throw new Error(errorData.error || 'Upload failed'); } const result = await response.json(); console.log('Upload successful, result:', result); // Only update state if the component is still mounted if (isMounted.current) { setProgress(100); // Reset file after successful upload setTimeout(() => { if (isMounted.current) { 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 details:', error); // Only update state if the component is still mounted if (isMounted.current) { 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 && (
)}
)}
); }