import { useEffect } from 'react'; import { createPortal } from 'react-dom'; import { HardDriveDownload, Check, X } from 'lucide-react'; import { useZipDownloadStore } from '@/features/offline/store/zipDownloadStore'; import { formatBytes } from '@/lib/format/formatBytes'; function ZipDownloadItem({ id }: { id: string }) { const dismiss = useZipDownloadStore(s => s.dismiss); const item = useZipDownloadStore(s => s.downloads.find(d => d.id === id)); // Auto-dismiss 3 s after completion or error. useEffect(() => { if (!item?.done && !item?.error) return; const timer = setTimeout(() => dismiss(id), 3000); return () => clearTimeout(timer); }, [item?.done, item?.error, id, dismiss]); if (!item) return null; const pct = item.total && item.total > 0 ? Math.min(100, (item.bytes / item.total) * 100) : null; const isIndeterminate = !item.done && !item.error && (item.total === null || item.total === 0); return (
{item.done ? : item.error ? : } {item.filename} {(item.done || item.error) && ( )}
{!item.done && !item.error && ( <>
{formatBytes(item.bytes)} {item.total !== null && item.total > 0 && ( <> / {formatBytes(item.total)}  ({pct!.toFixed(0)}%) )}
{!isIndeterminate && pct !== null && (
)}
)}
); } export default function ZipDownloadOverlay() { // Subscribe to the array reference directly — never derive a new array in the selector // (selector returning new array on every call causes an infinite re-render loop). const downloads = useZipDownloadStore(s => s.downloads); if (downloads.length === 0) return null; return createPortal(
{downloads.map(d => )}
, document.body, ); }