-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsource-actions.tsx
More file actions
38 lines (35 loc) · 2.05 KB
/
Copy pathsource-actions.tsx
File metadata and controls
38 lines (35 loc) · 2.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
"use client";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { RefreshCw, Trash2 } from "lucide-react";
async function message(response: Response) {
const body = await response.json();
if (!response.ok) throw new Error(body.error?.message ?? "Request failed");
return body.data;
}
export function SourceActions({ sourceId, canSync = true }: { sourceId: string; canSync?: boolean }) {
const router = useRouter();
const [busy, setBusy] = useState(false);
const [status, setStatus] = useState<string | null>(null);
async function sync() {
setBusy(true); setStatus(null);
try {
const job = await message(await fetch(`/api/sources/${sourceId}/sync`, { method: "POST" }));
setStatus("Sync queued");
for (;;) {
await new Promise((resolve) => setTimeout(resolve, 1500));
const current = await message(await fetch(`/api/jobs/${job.id}`, { cache: "no-store" }));
if (["complete", "failed", "cancelled"].includes(current.status)) { setStatus(current.status === "complete" ? "Sync complete" : current.error ?? "Sync failed"); break; }
}
router.refresh();
} catch (error) { setStatus(error instanceof Error ? error.message : "Sync failed"); }
finally { setBusy(false); }
}
async function remove() {
if (!window.confirm("Remove this source? Downloaded media will be preserved.")) return;
setBusy(true);
try { await message(await fetch(`/api/sources/${sourceId}`, { method: "DELETE" })); router.push("/sources"); router.refresh(); }
catch (error) { setStatus(error instanceof Error ? error.message : "Delete failed"); setBusy(false); }
}
return <div className="toolbar">{canSync ? <button className="button secondary" disabled={busy} onClick={sync}><RefreshCw size={15} className={busy ? "animate-spin" : ""} /> Sync Now</button> : null}<button className="button secondary" disabled={busy} onClick={remove} aria-label="Delete source"><Trash2 size={15} /></button>{status && <span className={status.includes("complete") ? "success" : "muted"}>{status}</span>}</div>;
}