'use client' import { useEffect, useRef, useState, useCallback } from 'react' interface AutoSaveConfig { /** Serialized representation of current content for change comparison */ serializedContent: string /** Function to call when auto-saving (receives isManual flag) */ onSave: (isManual: boolean) => Promise /** Auto-save delay in milliseconds (default: 30000) */ delay?: number } interface AutoSaveState { saving: boolean setSaving: (saving: boolean) => void lastSaved: Date | null setLastSaved: (date: Date | null) => void hasUnsavedChanges: boolean /** Update the saved-content snapshot (call after loading or saving a draft) */ snapshotContent: (serialized: string) => void /** Format the last saved time as a human-readable string */ formatLastSaved: () => string | null } export function useAutoSave({ serializedContent, onSave, delay = 30000, }: AutoSaveConfig): AutoSaveState { const [saving, setSaving] = useState(false) const [lastSaved, setLastSaved] = useState(null) const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false) const autoSaveTimerRef = useRef(null) const lastSavedContentRef = useRef('') const snapshotContent = useCallback((s: string) => { lastSavedContentRef.current = s }, []) const formatLastSaved = useCallback(() => { if (!lastSaved || isNaN(lastSaved.getTime())) return null const diff = Date.now() - lastSaved.getTime() if (diff < 60000) return 'just now' if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago` return lastSaved.toLocaleTimeString() }, [lastSaved]) // Track changes and trigger auto-save useEffect(() => { if (autoSaveTimerRef.current) { clearTimeout(autoSaveTimerRef.current) } const hasChanges = serializedContent !== lastSavedContentRef.current setHasUnsavedChanges(hasChanges) if (hasChanges) { autoSaveTimerRef.current = setTimeout(() => { onSave(false) }, delay) } return () => { if (autoSaveTimerRef.current) { clearTimeout(autoSaveTimerRef.current) } } }, [serializedContent, onSave, delay]) // Warn on leave with unsaved changes useEffect(() => { const handleBeforeUnload = (e: BeforeUnloadEvent) => { if (hasUnsavedChanges) { e.preventDefault() e.returnValue = '' } } window.addEventListener('beforeunload', handleBeforeUnload) return () => window.removeEventListener('beforeunload', handleBeforeUnload) }, [hasUnsavedChanges]) return { saving, setSaving, lastSaved, setLastSaved, hasUnsavedChanges, snapshotContent, formatLastSaved, } }