import { useEffect, useRef, useState } from 'react'; /** * Autosave a long form so it isn't lost on navigation or reload. * * - Persists `snapshot` to localStorage under `` (content-debounced: * the serialized string only changes when the draft actually changes). * - A saved draft is only offered as **resumable** when it *differs* from the * current form state — so merely opening an existing record (whose prefill * matches the saved draft) never shows a spurious "resume" banner, and a * draft can never silently clobber a freshly loaded record. * - Call `clear()` after a successful publish. * * Used by the Lab profile forms (`useLabDraft`) and the create-spot form. */ export function useFormDraft( prefix: string, key: string, snapshot: T, apply: (draft: T) => void, ) { const storageKey = prefix + key; const [loaded, setLoaded] = useState(null); const firstRun = useRef(true); const serialized = JSON.stringify(snapshot); // Load any saved draft once. useEffect(() => { try { const raw = localStorage.getItem(storageKey); if (raw) setLoaded(JSON.parse(raw) as T); } catch { // ignore malformed/blocked storage } }, [storageKey]); // Persist on change (skip the initial empty paint). useEffect(() => { if (firstRun.current) { firstRun.current = false; return; } try { localStorage.setItem(storageKey, serialized); } catch { // storage may be full/blocked — a lost draft is not fatal } }, [serialized, storageKey]); const resume = () => { if (!loaded) return; apply(loaded); setLoaded(null); }; const discard = () => { setLoaded(null); try { localStorage.removeItem(storageKey); } catch { /* ignore */ } }; const clear = () => { try { localStorage.removeItem(storageKey); } catch { /* ignore */ } }; const resumable = loaded !== null && JSON.stringify(loaded) !== serialized; return { resumable, resume, discard, clear }; }