import React, { useState, useCallback } from 'react'; import { useLanguage } from '../../../providers/language/LanguageContext'; import styles from './DragDropOverlay.module.css'; import { IoFolderOpen } from 'react-icons/io5'; export interface DragDropConfig { enabled: boolean; onDrop?: (files: File[]) => Promise | void; accept?: string; // MIME types or file extensions multiple?: boolean; disabled?: boolean; overlayText?: string; overlaySubtext?: string; } interface DragDropOverlayProps { config: DragDropConfig; children: React.ReactNode; className?: string; } export function DragDropOverlay({ config, children, className = '' }: DragDropOverlayProps) { const { t } = useLanguage(); const [isDragOver, setIsDragOver] = useState(false); const [isProcessing, setIsProcessing] = useState(false); const handleDragEnter = useCallback((e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); if (config.disabled || !config.enabled) return; setIsDragOver(true); }, [config.disabled, config.enabled]); const handleDragLeave = useCallback((e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); // Only hide overlay if we're leaving the container entirely if (!e.currentTarget.contains(e.relatedTarget as Node)) { setIsDragOver(false); } }, []); const handleDragOver = useCallback((e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); }, []); const handleDrop = useCallback(async (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); if (config.disabled || !config.enabled) return; setIsDragOver(false); setIsProcessing(true); try { const files = Array.from(e.dataTransfer.files); // Filter files by accept type if specified let filteredFiles = files; if (config.accept && config.accept !== '*/*') { filteredFiles = files.filter(file => { const acceptTypes = config.accept!.split(',').map(type => type.trim()); return acceptTypes.some(acceptType => { // Handle MIME types if (acceptType.startsWith('.')) { return file.name.toLowerCase().endsWith(acceptType.toLowerCase()); } // Handle MIME types like "image/*" or "application/pdf" if (acceptType.includes('*')) { const baseType = acceptType.split('/')[0]; return file.type.startsWith(baseType); } return file.type === acceptType; }); }); } console.log('🔍 DragDropOverlay file filtering:', { originalFiles: files.length, filteredFiles: filteredFiles.length, accept: config.accept, fileDetails: files.map(f => ({ name: f.name, type: f.type })) }); // Respect multiple setting const filesToProcess = config.multiple ? filteredFiles : filteredFiles.slice(0, 1); if (filesToProcess.length > 0 && config.onDrop) { console.log('🎯 DragDropOverlay calling onDrop with files:', filesToProcess); await config.onDrop(filesToProcess); console.log('✅ DragDropOverlay onDrop completed'); } else { console.log('⚠️ DragDropOverlay: No files to process or no onDrop handler'); console.log('Files to process:', filesToProcess.length); console.log('Has onDrop:', !!config.onDrop); } } catch (error) { console.error(t('dragdrop.overlay.error', 'Error processing files'), error); } finally { setIsProcessing(false); } }, [config, t]); const handleFileInputChange = useCallback(async (e: React.ChangeEvent) => { if (config.disabled || !config.enabled) return; const files = Array.from(e.target.files || []); console.log('🔍 DragDropOverlay file input:', { fileCount: files.length, accept: config.accept, fileDetails: files.map(f => ({ name: f.name, type: f.type })) }); if (files.length > 0 && config.onDrop) { setIsProcessing(true); try { await config.onDrop(files); } catch (error) { console.error(t('dragdrop.overlay.error', 'Error processing files'), error); } finally { setIsProcessing(false); // Reset input e.target.value = ''; } } }, [config, t]); if (!config.enabled) { return <>{children}; } return (
{children} {/* Hidden file input for click-to-upload */} {/* Drag overlay */} {isDragOver && (
{config.overlayText || t('dragdrop.overlay.default_text', 'Drop files here')}
{(config.overlaySubtext || !config.overlayText) && (
{config.overlaySubtext || t('dragdrop.overlay.default_subtext', 'You can also click the upload button')}
)}
)} {/* Processing overlay */} {isProcessing && (
{t('dragdrop.overlay.processing', 'Processing files...')}
)}
); } export default DragDropOverlay;