snow-editor

small markdown and org-mode editor
Log | Files | Refs | README

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 }