anycoder-e2723b42 / components /Downloader.js
Ezequield's picture
Upload components/Downloader.js with huggingface_hub
1d7f851 verified
Raw History Blame Contribute Delete
6 kB
import { useState } from 'react';
import toast from 'react-hot-toast';
export default function Downloader() {
const [url, setUrl] = useState('');
const [loading, setLoading] = useState(false);
const [progress, setProgress] = useState('');
const [downloadLink, setDownloadLink] = useState(null);
const isValidUrl = (string) => {
try {
new URL(string);
return string.includes('deviantart.com');
} catch (_) {
return false;
}
};
const handleProcess = async (e) => {
e.preventDefault();
if (!url.trim()) {
toast.error('Please enter a DeviantArt URL');
return;
}
if (!isValidUrl(url)) {
toast.error('Please enter a valid DeviantArt URL');
return;
}
setLoading(true);
setProgress('Initializing...');
setDownloadLink(null);
try {
const response = await fetch('/api/process', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ url }),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Failed to process request');
}
// Simulate progress updates if the backend is fast
setProgress('Downloading images...');
await new Promise(r => setTimeout(r, 800));
setProgress('Creating ZIP archive...');
await new Promise(r => setTimeout(r, 800));
setProgress('Uploading to MediaFire...');
await new Promise(r => setTimeout(r, 800));
const data = await response.json();
if (data.success) {
setDownloadLink(data.downloadUrl);
setProgress('Complete!');
toast.success('ZIP file generated successfully!');
} else {
throw new Error(data.error || 'Unknown error occurred');
}
} catch (error) {
console.error(error);
toast.error(error.message || 'Something went wrong');
setProgress('Error occurred');
} finally {
setLoading(false);
}
};
return (
<div className="bg-gray-800/50 border border-gray-700 rounded-2xl p-6 md:p-8 shadow-xl">
<form onSubmit={handleProcess} className="space-y-6">
<div>
<label htmlFor="url" className="block text-sm font-medium text-gray-300 mb-2">
DeviantArt Artwork URL
</label>
<div className="relative">
<input
type="url"
id="url"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="https://www.deviantart.com/username/art/artwork-title"
disabled={loading}
className="w-full bg-gray-900 border border-gray-600 rounded-lg px-4 py-3 text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-brand-500 focus:border-transparent transition-all disabled:opacity-50 disabled:cursor-not-allowed"
/>
{url && (
<button
type="button"
onClick={() => setUrl('')}
disabled={loading}
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-white transition-colors"
>
✕
</button>
)}
</div>
<p className="mt-2 text-xs text-gray-500">
Paste the direct link to the DeviantArt artwork page.
</p>
</div>
<button
type="submit"
disabled={loading}
className="w-full bg-gradient-to-r from-brand-600 to-brand-500 hover:from-brand-500 hover:to-brand-400 text-white font-semibold py-3 px-6 rounded-lg shadow-lg shadow-brand-500/20 transform hover:-translate-y-0.5 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"
>
{loading ? 'Processing...' : 'Download & Zip'}
</button>
</form>
{loading && (
<div className="mt-8 space-y-4">
<div className="flex items-center justify-between text-sm">
<span className="text-gray-400">Status</span>
<span className="text-brand-400 font-medium animate-pulse">{progress}</span>
</div>
<div className="h-2 bg-gray-700 rounded-full overflow-hidden">
<div className="h-full bg-gradient-to-r from-brand-600 to-purple-500 w-2/3 animate-[shimmer_1.5s_infinite]"></div>
</div>
</div>
)}
{downloadLink && !loading && (
<div className="mt-8 p-4 bg-green-900/20 border border-green-700/50 rounded-lg">
<div className="flex items-start gap-3">
<div className="flex-shrink-0 w-6 h-6 rounded-full bg-green-500/20 flex items-center justify-center mt-0.5">
<svg className="w-4 h-4 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
</div>
<div className="flex-grow">
<h4 className="text-green-400 font-medium mb-1">Ready for Download</h4>
<p className="text-sm text-gray-400 mb-3">
Your image has been packaged and is ready to be downloaded.
</p>
<a
href={downloadLink}
download="deviantart-image.zip"
className="inline-flex items-center gap-2 bg-green-600 hover:bg-green-500 text-white text-sm font-medium py-2 px-4 rounded transition-colors"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
Download ZIP
</a>
</div>
</div>
</div>
)}
</div>
);
}