diff --git a/frontend/bun.lockb b/frontend/bun.lockb index b395d0d..61279ec 100755 Binary files a/frontend/bun.lockb and b/frontend/bun.lockb differ diff --git a/frontend/package.json b/frontend/package.json index 3957269..cf44602 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,6 +8,7 @@ "@testing-library/user-event": "^13.5.0", "axios": "^1.7.3", "react": "^18.3.1", + "react-confetti": "^6.1.0", "react-dom": "^18.3.1", "react-router-dom": "^6.26.0", "react-scripts": "5.0.1", diff --git a/frontend/src/components/DownloadForm.js b/frontend/src/components/DownloadForm.js index 8259ab5..99fc7c2 100644 --- a/frontend/src/components/DownloadForm.js +++ b/frontend/src/components/DownloadForm.js @@ -1,29 +1,41 @@ -import React, { useState } from "react"; +import React, { useState, useRef, useEffect } from "react"; import axios from "axios"; +import { v4 as uuidv4 } from "uuid"; +import Confetti from "react-confetti"; const DownloadForm = () => { const [url, setUrl] = useState(""); const [quality, setQuality] = useState("720p"); const [message, setMessage] = useState(""); + const [progress, setProgress] = useState(0); + const [isProcessing, setIsProcessing] = useState(false); + const [showConfetti, setShowConfetti] = useState(false); + const confettiRef = useRef(null); const handleDownload = async (e) => { e.preventDefault(); - setMessage("Downloading..."); + setMessage("Processing..."); + setProgress(0); + setIsProcessing(true); try { const response = await axios.post( `${process.env.REACT_APP_BACKEND_URL}/downlink/download`, { url, quality }, { - responseType: "blob", // Ensure the response is treated as a file + responseType: "blob", + onDownloadProgress: (progressEvent) => { + const total = progressEvent.total; + const current = progressEvent.loaded; + setProgress(Math.round((current / total) * 100)); + }, }, ); - // Extract the filename from the Content-Disposition header if present const disposition = response.headers["content-disposition"]; const filename = disposition ? disposition.split("filename=")[1].replace(/"/g, "") - : "video.mp4"; // Default filename + : `${uuidv4()}.mp4`; const link = document.createElement("a"); link.href = window.URL.createObjectURL(new Blob([response.data])); @@ -31,14 +43,47 @@ const DownloadForm = () => { link.click(); setMessage("Download complete"); + setIsProcessing(false); + setShowConfetti(true); } catch (error) { setMessage("Download failed"); console.error(error); + setIsProcessing(false); } }; + const getBarClass = () => { + if (message === "Download complete") return "bg-green-500"; + if (message === "Download failed") return "bg-red-500"; + return "bg-blue-500"; // Default color when not processing + }; + + const getBarStyle = () => { + if (message === "Download complete" || message === "Download failed") { + return { transition: "width 0.5s ease-in-out" }; + } + return { transition: "width 0.5s ease-in-out" }; + }; + + const getAnimationStyle = () => { + if (message === "Download complete" || message === "Download failed") { + return { animation: "none" }; + } + return { animation: "loading 1.5s infinite" }; + }; + + useEffect(() => { + if (showConfetti) { + const timer = setTimeout(() => { + setShowConfetti(false); + }, 5000); + + return () => clearTimeout(timer); + } + }, [showConfetti]); + return ( -