import { useEffect, useState } from "react"; import { ByteSize } from "~/client/components/bytes-size"; import { Card } from "~/client/components/ui/card"; import { Progress } from "~/client/components/ui/progress"; import { type BackupProgressEvent, useServerEvents } from "~/client/hooks/use-server-events"; import { formatDuration } from "~/utils/utils"; import { formatBytes } from "~/utils/format-bytes"; type Props = { scheduleShortId: string; }; export const BackupProgressCard = ({ scheduleShortId }: Props) => { const { addEventListener } = useServerEvents(); const [progress, setProgress] = useState(null); useEffect(() => { const abortController = new AbortController(); addEventListener( "backup:progress", (progressData) => { if (progressData.scheduleId === scheduleShortId) { setProgress(progressData); } }, { signal: abortController.signal }, ); addEventListener( "backup:completed", (completedData) => { if (completedData.scheduleId === scheduleShortId) { setProgress(null); } }, { signal: abortController.signal }, ); return () => abortController.abort(); }, [addEventListener, scheduleShortId]); const percentDone = progress ? Math.round(progress.percent_done * 100) : 0; const currentFile = progress?.current_files[0] || ""; const fileName = currentFile.split("/").pop() || currentFile; const speed = progress ? formatBytes(progress.bytes_done / progress.seconds_elapsed) : null; return (
Backup in progress
{progress ? `${percentDone}%` : "—"}

Files

{progress ? ( <> {progress.files_done.toLocaleString()} / {progress.total_files.toLocaleString()} ) : ( "—" )}

Data

{progress ? ( <>  /  ) : ( "—" )}

Elapsed

{progress ? formatDuration(progress.seconds_elapsed) : "—"}

Speed

{progress ? (progress.seconds_elapsed > 0 ? `${speed?.text} ${speed?.unit}/s` : "Calculating...") : "—"}

Current file

{fileName || "—"}

); };