"use client"; import { useEffect, useEffectEvent, useState } from "react"; import { toast } from "sonner"; export type AutosaveState = "saved" | "unsaved" | "saving" | "incomplete" | "error"; interface SaveResult { status: string; message?: string; version?: number; } export function useAutosave({ value, valid, initialVersion, persist, delay = 900, }: { value: T; valid: boolean; initialVersion: number; persist: (value: T, expectedVersion: number) => Promise; delay?: number; }) { const fingerprint = JSON.stringify(value); const [savedFingerprint, setSavedFingerprint] = useState(fingerprint); const [errorFingerprint, setErrorFingerprint] = useState(null); const [saving, setSaving] = useState(false); const [version, setVersion] = useState(initialVersion); const save = useEffectEvent(async (snapshot: T, snapshotFingerprint: string) => { setSaving(true); setErrorFingerprint(null); try { const result = await persist(snapshot, version); if (result.status === "error") { setErrorFingerprint(snapshotFingerprint); toast.error(result.message ?? "บันทึกอัตโนมัติไม่สำเร็จ"); return; } if (result.version) setVersion(result.version); setSavedFingerprint(snapshotFingerprint); } catch (cause) { setErrorFingerprint(snapshotFingerprint); toast.error(cause instanceof Error ? cause.message : "บันทึกอัตโนมัติไม่สำเร็จ"); } finally { setSaving(false); } }); useEffect(() => { if (!valid || saving || fingerprint === savedFingerprint || fingerprint === errorFingerprint) return; const timer = window.setTimeout(() => { void save(JSON.parse(fingerprint) as T, fingerprint); }, delay); return () => window.clearTimeout(timer); }, [delay, errorFingerprint, fingerprint, savedFingerprint, saving, valid]); if (!valid) return "incomplete"; if (saving) return "saving"; if (fingerprint === errorFingerprint) return "error"; if (fingerprint !== savedFingerprint) return "unsaved"; return "saved"; }