mirror of
https://github.com/arkorty/DownLink.git
synced 2026-03-17 16:51:45 +00:00
Add a processing + progress bar
This commit is contained in:
Binary file not shown.
@@ -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",
|
||||
|
||||
@@ -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 (
|
||||
<div className="p-4">
|
||||
<div className="p-4 relative">
|
||||
<form onSubmit={handleDownload} className="space-y-4">
|
||||
<div>
|
||||
<label
|
||||
@@ -77,13 +122,46 @@ const DownloadForm = () => {
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-black hover:bg-gray-700 hover:fg-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-black hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
Download
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{message && <p className="mt-4 text-sm text-gray-700">{message}</p>}
|
||||
<div className="w-full bg-white rounded-full mt-4 h-3 relative overflow-hidden">
|
||||
<div
|
||||
className={`h-3 ${getBarClass()} rounded-full`}
|
||||
style={{
|
||||
width: `${progress}%`,
|
||||
...getBarStyle(),
|
||||
}}
|
||||
></div>
|
||||
{isProcessing && (
|
||||
<div
|
||||
className={`absolute top-0 left-0 w-full h-full bg-blue-300 rounded-full`}
|
||||
style={getAnimationStyle()}
|
||||
></div>
|
||||
)}
|
||||
</div>
|
||||
{showConfetti && (
|
||||
<div className="fixed top-0 left-0 w-full h-full z-50">
|
||||
<Confetti
|
||||
ref={confettiRef}
|
||||
width={window.innerWidth}
|
||||
height={window.innerHeight}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<style jsx>{`
|
||||
@keyframes loading {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user