useServerAutosave.js (1714B)
1 import { useCallback, useEffect, useRef, useState } from 'react'; 2 import { ApiError, updateDocument } from '../lib/api.js'; 3 4 const AUTOSAVE_DEBOUNCE_MS = 1000; 5 6 export function useServerAutosave({ 7 editToken, 8 clientId, 9 lockToken, 10 enabled, 11 title, 12 mode, 13 content, 14 }) { 15 const [saveStatus, setSaveStatus] = useState('idle'); 16 const timerRef = useRef(null); 17 const lastSavedRef = useRef(''); 18 19 const saveNow = useCallback(async () => { 20 if (!enabled || !editToken || !clientId || !lockToken) { 21 setSaveStatus('no_permission'); 22 return false; 23 } 24 25 const snapshot = JSON.stringify({ title, mode, content }); 26 if (snapshot === lastSavedRef.current) { 27 setSaveStatus('saved'); 28 return true; 29 } 30 31 setSaveStatus('saving'); 32 try { 33 const result = await updateDocument(editToken, { 34 clientId, 35 lockToken, 36 title, 37 mode, 38 content, 39 }); 40 lastSavedRef.current = snapshot; 41 setSaveStatus('saved'); 42 return result; 43 } catch (error) { 44 if (error instanceof ApiError && (error.status === 403 || error.status === 423)) { 45 setSaveStatus('no_permission'); 46 } else { 47 setSaveStatus('error'); 48 } 49 return false; 50 } 51 }, [enabled, editToken, clientId, lockToken, title, mode, content]); 52 53 useEffect(() => { 54 if (!enabled) { 55 setSaveStatus('no_permission'); 56 return; 57 } 58 59 window.clearTimeout(timerRef.current); 60 timerRef.current = window.setTimeout(() => { 61 saveNow(); 62 }, AUTOSAVE_DEBOUNCE_MS); 63 64 return () => window.clearTimeout(timerRef.current); 65 }, [enabled, title, mode, content, saveNow]); 66 67 return { saveStatus, saveNow, setSaveStatus }; 68 }