"use client"; import { useEffect } from "react"; import { Button } from "yt-dlp-transcript-common/components/ui/button"; import type { SaveResult } from "../actions"; // Save, and the thing this page never had: a signal that there is something to // save. Editing the tree used to change nothing visible, so navigating away // silently discarded the work — the classic "I clicked Move to top and it did // nothing" report. // // The Save button itself is ALWAYS rendered, never gated on dirtiness. That is // deliberate: three e2e specs click "Save policy" by name, and a button that // appears only under a condition is a button that can vanish under a race. The // dirty state is carried by the rail, the wording and the Discard button beside // it, which is where it belongs anyway. export function SaveBar({ dirty, saving, result, onSave, onDiscard, }: { dirty: boolean; saving: boolean; result: SaveResult | null; onSave: () => void; onDiscard: () => void; }) { // The browser-level guard. Only armed while there is something to lose. useEffect(() => { if (!dirty) return; const onBeforeUnload = (e: BeforeUnloadEvent) => e.preventDefault(); window.addEventListener("beforeunload", onBeforeUnload); return () => window.removeEventListener("beforeunload", onBeforeUnload); }, [dirty]); return (