"use client"; /** * SaveOfflineButton — sits beside "Copy link to this page" in PageHeader. * * Saves the current page (and, for transcripts, its audio) for offline * reading/listening via lib/offline. Shows idle → saving(%) → saved states and * lets the user remove a saved copy. Renders nothing when the browser can't * support offline storage. */ import { useEffect, useRef, useState } from "react"; import { Check, Download, Loader2, Trash2 } from "lucide-react"; import { toast } from "sonner"; import { cn } from "@/lib/utils"; import { isSaved as isSavedFn, offlineSupported, pageKey, removeOffline, saveOffline, type OfflineDescriptor, } from "@/lib/offline"; type State = "idle" | "saving" | "saved"; export function SaveOfflineButton({ descriptor, }: { descriptor: OfflineDescriptor; }) { const [supported, setSupported] = useState(false); const [state, setState] = useState("idle"); const [pct, setPct] = useState(null); const keyRef = useRef(""); useEffect(() => { if (!offlineSupported()) return; setSupported(true); keyRef.current = pageKey(); let alive = true; isSavedFn(keyRef.current).then((saved) => { if (alive && saved) setState("saved"); }); return () => { alive = false; }; }, []); if (!supported) return null; async function onClick() { if (state === "saving") return; if (state === "saved") { // Toggle off — remove the offline copy. try { await removeOffline(keyRef.current); setState("idle"); toast("Removed from offline", { duration: 1800 }); } catch { toast.error("Couldn't remove the offline copy", { duration: 3000 }); } return; } setState("saving"); setPct(descriptor.audioUrl ? 0 : null); try { const res = await saveOffline(descriptor, (f) => setPct(Math.round(f * 100)), ); setState("saved"); if (res.audioError) { toast(res.audioError, { duration: 4000 }); } else { toast("Saved for offline", { duration: 1800 }); } } catch { setState("idle"); toast.error("Couldn't save this page offline", { duration: 3000 }); } finally { setPct(null); } } const label = state === "saving" ? pct !== null ? `Saving… ${pct}%` : "Saving…" : state === "saved" ? "Saved offline" : "Save offline"; return ( ); }