Untitled
unknown
plain_text
23 days ago
6.9 kB
4
Indexable
// /components/download-all.tsx import { useState } from "react"; import { Download } from "lucide-react"; import { motion } from "framer-motion"; import { useParams } from "next/navigation"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Progress } from "@/components/ui/progress"; interface DownloadAllProps { isSelectionView?: boolean; visibleImages?: { src: string; alt: string; }[]; } export function DownloadAll({ isSelectionView = false, visibleImages = [] }: DownloadAllProps) { const [isDownloading, setIsDownloading] = useState(false); const [progress, setProgress] = useState(0); const params = useParams(); const clientId = params.clientId as string; const handleRegularDownload = async () => { try { setIsDownloading(true); setProgress(20); // Direct URL to the pre-generated ZIP file const zipUrl = `${process.env.NEXT_PUBLIC_R2_PUBLIC_URL}/${clientId}/images.zip`; toast.info("Download wird vorbereitet", { description: "Bitte warten Sie, während die Datei vorbereitet wird." }); // Start download setProgress(50); // Create a temporary link to download the file const link = document.createElement('a'); link.href = zipUrl; link.download = `${clientId}-fotos.zip`; // Append to the document and click document.body.appendChild(link); link.click(); // Cleanup the link document.body.removeChild(link); setProgress(100); toast.success("Download gestartet", { description: "Die Datei wird jetzt heruntergeladen." }); // Reset after a delay setTimeout(() => { setIsDownloading(false); setProgress(0); }, 3000); } catch (error) { console.error("Download failed:", error); setIsDownloading(false); setProgress(0); toast.error("Download fehlgeschlagen", { description: "Bitte versuchen Sie es später erneut." }); } }; const handleSelectionDownload = async () => { try { setIsDownloading(true); setProgress(10); if (visibleImages.length === 0) { toast.error("Keine Bilder zum Herunterladen gefunden"); setIsDownloading(false); setProgress(0); return; } // Show initial toast toast.info(`Download von ${visibleImages.length} Bildern wird gestartet...`); let downloadedCount = 0; let failedCount = 0; const totalImages = visibleImages.length; // Download files one by one with small delay to prevent browser throttling for (const image of visibleImages) { try { await new Promise(resolve => setTimeout(resolve, 300)); // Small delay between downloads const response = await fetch(image.src, { method: 'GET', headers: { 'Cache-Control': 'no-cache' } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const blob = await response.blob(); if (blob.size === 0) { throw new Error('Downloaded file is empty'); } const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; // Extract filename from src URL const filename = image.src.split('/').pop() || `bild-${downloadedCount + 1}.jpg`; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); downloadedCount++; // Update progress const newProgress = Math.floor((downloadedCount / totalImages) * 100); setProgress(newProgress); // Update progress toast every few files or for the last one if (downloadedCount % 3 === 0 || downloadedCount === totalImages) { toast.info(`${downloadedCount} von ${totalImages} Bildern heruntergeladen...`); } } catch (error) { console.error(`Failed to download image:`, error); failedCount++; } } // Show final toast if (failedCount > 0) { toast.warning(`${downloadedCount} von ${totalImages} Bildern heruntergeladen, ${failedCount} fehlgeschlagen.`); } else { toast.success(`Alle ${totalImages} Bilder erfolgreich heruntergeladen!`); } // Reset after a short delay setTimeout(() => { setIsDownloading(false); setProgress(0); }, 2000); } catch (error) { console.error("Download failed:", error); setIsDownloading(false); setProgress(0); toast.error("Download fehlgeschlagen", { description: "Bitte versuchen Sie es später erneut." }); } }; const handleDownloadAll = isSelectionView ? handleSelectionDownload : handleRegularDownload; return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="mb-12 rounded-lg border bg-card p-4 text-card-foreground shadow-sm" > <div className="flex flex-col items-center gap-4 text-center sm:flex-row sm:justify-between sm:text-left"> <div> <h2 className="text-lg font-semibold">Alle Fotos herunterladen</h2> <p className="text-sm text-muted-foreground hidden sm:block"> {isSelectionView ? `Erhalten Sie alle ${visibleImages.length} ausgewählten Fotos in Originalqualität` : "Erhalten Sie alle Fotos in Originalqualität in einer einzigen Datei" } </p> </div> <div className="flex flex-col gap-2 min-w-[200px]"> {isDownloading ? ( <div className="space-y-2"> <Progress value={progress} className="w-full" /> <p className="text-sm text-muted-foreground text-center"> {progress === 100 ? isSelectionView ? "Alle Bilder heruntergeladen!" : "Download gestartet!" : `Download läuft (${progress}%)...` } </p> </div> ) : ( <Button size="lg" onClick={handleDownloadAll}> <Download className="mr-2 h-4 w-4" /> Alle herunterladen </Button> )} </div> </div> </motion.div> ); } export default DownloadAll;
Editor is loading...
Leave a Comment