From da2a1211d663b00b8c05e8d3f9fc524e39959b5c Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Mon, 13 Oct 2025 07:59:24 +0000 Subject: [PATCH] Add ability to upload multiple images to the media library at once Enable multiple file uploads in the media library component, allowing users to upload several images simultaneously. This commit modifies the `useDropzone` configuration to accept multiple files and updates the `onDrop` function to handle parallel uploads. It also introduces UI feedback for ongoing uploads. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/nlpElis --- client/src/components/media-upload.tsx | 99 ++++++++++++++++++++------ 1 file changed, 78 insertions(+), 21 deletions(-) diff --git a/client/src/components/media-upload.tsx b/client/src/components/media-upload.tsx index 78e818e..c33e865 100644 --- a/client/src/components/media-upload.tsx +++ b/client/src/components/media-upload.tsx @@ -19,6 +19,8 @@ export default function MediaUpload() { queryKey: ["/api/media"], }); + const [uploadingCount, setUploadingCount] = useState(0); + const uploadMutation = useMutation({ mutationFn: async (file: File) => { const formData = new FormData(); @@ -33,25 +35,61 @@ export default function MediaUpload() { onSuccess: (data) => { queryClient.invalidateQueries({ queryKey: ["/api/media"] }); setSelectedFile(data); - toast({ - title: "Succès", - description: "Média téléchargé et traité avec succès", - }); - }, - onError: () => { - toast({ - title: "Erreur", - description: "Impossible de télécharger le média", - variant: "destructive", - }); }, }); - const onDrop = useCallback((acceptedFiles: File[]) => { - if (acceptedFiles.length > 0) { - uploadMutation.mutate(acceptedFiles[0]); + const onDrop = useCallback(async (acceptedFiles: File[]) => { + if (acceptedFiles.length === 0) return; + + setUploadingCount(acceptedFiles.length); + let successCount = 0; + let errorCount = 0; + + // Upload tous les fichiers en parallèle + const uploadPromises = acceptedFiles.map(async (file) => { + try { + const formData = new FormData(); + formData.append("file", file); + const response = await fetch("/api/media/upload", { + method: "POST", + body: formData, + }); + if (!response.ok) throw new Error("Upload failed"); + successCount++; + return response.json(); + } catch (error) { + errorCount++; + throw error; + } + }); + + try { + await Promise.all(uploadPromises); + queryClient.invalidateQueries({ queryKey: ["/api/media"] }); + + toast({ + title: "Succès", + description: `${successCount} média(s) téléchargé(s) avec succès`, + }); + } catch (error) { + if (successCount > 0) { + queryClient.invalidateQueries({ queryKey: ["/api/media"] }); + toast({ + title: "Partiellement réussi", + description: `${successCount} média(s) téléchargé(s), ${errorCount} échec(s)`, + variant: "destructive", + }); + } else { + toast({ + title: "Erreur", + description: "Impossible de télécharger les médias", + variant: "destructive", + }); + } + } finally { + setUploadingCount(0); } - }, []); + }, [toast]); const { getRootProps, getInputProps, isDragActive, open } = useDropzone({ onDrop, @@ -60,6 +98,7 @@ export default function MediaUpload() { "video/*": [".mp4", ".mov"], }, maxSize: 52428800, + multiple: true, }); const deleteMutation = useMutation({ @@ -126,18 +165,36 @@ export default function MediaUpload() { className={` border-2 border-dashed rounded-2xl p-12 text-center cursor-pointer transition-all ${isDragActive ? "border-primary bg-primary/5 shadow-lg" : "border-border/50 hover:border-primary hover:bg-accent/30"} + ${uploadingCount > 0 ? "pointer-events-none opacity-50" : ""} `} data-testid="dropzone-upload" >
- + {uploadingCount > 0 ? ( + + ) : ( + + )}
-

- {isDragActive ? "Déposez vos fichiers ici" : "Glissez-déposez vos fichiers"} -

-

ou cliquez pour parcourir

-

PNG, JPG, MP4 jusqu'à 50MB

+ {uploadingCount > 0 ? ( + <> +

+ Téléchargement en cours... +

+

+ {uploadingCount} fichier(s) en cours de traitement +

+ + ) : ( + <> +

+ {isDragActive ? "Déposez vos fichiers ici" : "Glissez-déposez vos fichiers"} +

+

ou cliquez pour parcourir

+

PNG, JPG, MP4 jusqu'à 50MB

+ + )}