Untitled

 avatar
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