import React, { useState, useRef, useCallback } from 'react'; import { X, Upload, CheckCircle, AlertCircle, Loader } from 'lucide-react'; const UploadZone = () => { const [isDragging, setIsDragging] = useState(false); const [files, setFiles] = useState([]); const fileInputRef = useRef(null); const MAX_FILES = 10; // Limite stricte à 10 fichiers const MAX_FILE_SIZE = 100 * 1024 * 1024; const ALLOWED_EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'webm', 'mp4', 'wmv', 'mp3', 'flac', 'ogg', 'zip', 'css', 'pdf', 'rar', 'm3u', 'm3u8', 'txt']; const validateFile = useCallback((file) => { const extension = file.name.split('.').pop().toLowerCase(); if (!ALLOWED_EXTENSIONS.includes(extension)) { return { valid: false, error: `Extension .${extension} non autorisée` }; } if (file.size > MAX_FILE_SIZE) { return { valid: false, error: 'Fichier trop volumineux (max 100 Mo)' }; } return { valid: true, error: null }; }, []); const uploadFile = async (fileInfo) => { try { const formData = new FormData(); formData.append('file', fileInfo.file); formData.append('csrf_token', document.querySelector('input[name="csrf_token"]')?.value || ''); // Mettre le statut en uploading setFiles(files => files.map(f => f.id === fileInfo.id ? { ...f, status: 'uploading' } : f ) ); const response = await fetch('api.php', { method: 'POST', body: formData }); const result = await response.json(); if (!response.ok || !result.success) { throw new Error(result.error || 'Erreur lors du téléversement'); } setFiles(files => files.map(f => f.id === fileInfo.id ? { ...f, status: 'complete' } : f ) ); } catch (error) { setFiles(files => files.map(f => f.id === fileInfo.id ? { ...f, status: 'error', error: error.message } : f ) ); } }; const handleFiles = (newFiles) => { // Vérifier si on n'a pas déjà atteint la limite if (files.length >= MAX_FILES) { alert(`Vous pouvez téléverser uniquement ${MAX_FILES} fichiers à la fois`); return; } // Calculer combien de fichiers on peut encore ajouter const remainingSlots = MAX_FILES - files.length; const filesToAdd = Array.from(newFiles).slice(0, remainingSlots); if (filesToAdd.length < newFiles.length) { alert(`Seuls les ${remainingSlots} premiers fichiers seront traités. Maximum ${MAX_FILES} fichiers à la fois.`); } const processedFiles = filesToAdd.map(file => ({ file, id: Math.random().toString(36).substring(7), status: validateFile(file).valid ? 'pending' : 'error', error: validateFile(file).error })); setFiles(current => [...current, ...processedFiles]); // Lancer l'upload pour chaque fichier valide processedFiles .filter(f => f.status === 'pending') .forEach(uploadFile); }; const handleDrop = useCallback((e) => { e.preventDefault(); setIsDragging(false); handleFiles(e.dataTransfer.files); }, []); const removeFile = (id) => { setFiles(files => files.filter(f => f.id !== id)); }; return (
Glissez-déposez vos fichiers ici
ou cliquez pour sélectionner des fichiers
Maximum {MAX_FILES} fichiers à la fois · 100 Mo par fichier
Extensions : {ALLOWED_EXTENSIONS.join(', ')}
{fileInfo.file.name}
{(fileInfo.file.size / 1024 / 1024).toFixed(2)} Mo
{fileInfo.error && ({fileInfo.error}
)}