From 4e2b5bd2d03ef4eb7489019d7c4d310ce74a464e Mon Sep 17 00:00:00 2001 From: bandinopla <71508858+bandinopla@users.noreply.github.com> Date: Sun, 21 Jul 2024 12:37:08 +0000 Subject: [PATCH] autosave on jeditor --- public/changelog.txt | 3 ++ src/codemirror/LogTextEditor.js | 24 ++++++++-- src/componentes/journal/editor-autosave.ts | 56 ++++++++++++++++++++++ src/componentes/journal/editor.js | 15 ++++++ src/version.json | 2 +- 5 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 src/componentes/journal/editor-autosave.ts diff --git a/public/changelog.txt b/public/changelog.txt index ff62897..36ba58b 100644 --- a/public/changelog.txt +++ b/public/changelog.txt @@ -1,3 +1,6 @@ +- 2.30.0 : 2024-07-21 + + Added an auto-save mechanic on the log's editor. As pointed by @jimr1603 sometimes the browser will refresh the page if you leave it on too long and all logged data will be lost. Now, the editor will save whatever you type and if you open it again it will detect previously autosaved data and ask you if you want to use that. + - 2.29.1 : 2024-04-28 * bug fix in backend: thanks to @Kandrase for pointing this out. Some journals failed to load due to trying to access an undefined property (Cannot read property) diff --git a/src/codemirror/LogTextEditor.js b/src/codemirror/LogTextEditor.js index d1144f4..233ebb5 100644 --- a/src/codemirror/LogTextEditor.js +++ b/src/codemirror/LogTextEditor.js @@ -341,7 +341,7 @@ const __lintEditor = { } }; -export const LogTextEditor = ({ usekg, exercises, tags, value, getDocRef, getShowErrorRef, defaultYMD, utags, hintTriggerRef })=> { +export const LogTextEditor = ({ usekg, exercises, tags, value, getDocRef, getShowErrorRef, defaultYMD, utags, hintTriggerRef, onCodeMirrorReady, valueAsTextHook })=> { const classes = useStyles(); const txt = useRef(); @@ -353,14 +353,28 @@ export const LogTextEditor = ({ usekg, exercises, tags, value, getDocRef, getSho */ const valueAsText = useMemo( ()=>{ + let txt = ""; + if( typeof value == 'string' ) { - return value; + txt = value; + } + else if( typeof value == 'object') + { + txt = __convertJEditorDataToText(value, usekg, utags); } - if( !value ) return ""; + if( valueAsTextHook ) + { + let txtHooked = valueAsTextHook(txt); + + if( txtHooked ) + { + return txtHooked; + } + } - return __convertJEditorDataToText(value, usekg, utags); + return txt; }, [value] ); @@ -433,6 +447,8 @@ export const LogTextEditor = ({ usekg, exercises, tags, value, getDocRef, getSho myCodeMirror.focus(); + onCodeMirrorReady && onCodeMirrorReady(myCodeMirror) + // // on dismount... // diff --git a/src/componentes/journal/editor-autosave.ts b/src/componentes/journal/editor-autosave.ts new file mode 100644 index 0000000..593ef87 --- /dev/null +++ b/src/componentes/journal/editor-autosave.ts @@ -0,0 +1,56 @@ +import { useEffect, useRef, useState } from "react" + +export type AutoSaveConfig = { + cacheKey:string +} + +export type AutoSaveReturn = { + config:AutoSaveConfig, + autosave: (text:string)=>void, + getAutosavedText: ()=>string +} + +export function useEditorAutosave( config:AutoSaveConfig ):AutoSaveReturn { + + let interval = useRef() + + useEffect(()=>{ + + return () => { + clearTimeout( interval.current ); + } + + }, []); + + return { + config, + autosave: text => { + + clearTimeout( interval.current ); + + interval.current = window.setTimeout(()=>{ + try + { + localStorage.setItem( config.cacheKey, text ); + } + catch(error) { + + // if (error instanceof DOMException && error.name === 'QuotaExceededError') { + // console.error('LocalStorage quota exceeded'); + // } else { + // console.error('An error occurred while accessing localStorage', error); + // } + + } + + }, 1000 ); + + }, + getAutosavedText: ()=> { + let text = localStorage.getItem( config.cacheKey ) || "" + //localStorage.removeItem( config.cacheKey ); + return text; + } + } + +} \ No newline at end of file diff --git a/src/componentes/journal/editor.js b/src/componentes/journal/editor.js index aec1f7b..cdc1060 100644 --- a/src/componentes/journal/editor.js +++ b/src/componentes/journal/editor.js @@ -16,6 +16,7 @@ import { OpenConfirmModal } from "../Dialog"; import { useGetSession } from "../../session/session-handler"; import { OpenJeditorSaveBackdrop } from "./editor-save-backdrop"; import LoadCopyOfWorkoutModal from "./editor-copy-journal"; +import { useEditorAutosave } from "./editor-autosave"; const $jeditorError = makeVar(); @@ -34,6 +35,10 @@ export const JEditor = ({ ymd, range, onClose, saveTrigger, hintTriggerRef, onLo const saveError = useReactiveVar($jeditorError); const [jeditorData, setJeditorData] = useState(); + const { autosave, getAutosavedText } = useEditorAutosave({ + cacheKey: `${session.user.id}-autosave` + }); + const [saveEditor, {client}] = useSaveJEditorMutation(); const { data, loading, error, refetch } = useGetJEditorDataQuery({ @@ -263,6 +268,16 @@ export const JEditor = ({ ymd, range, onClose, saveTrigger, hintTriggerRef, onLo getShowErrorRef={showDocError} hintTriggerRef={hintTriggerRef} utags={jeditorData.jeditor.utags} + onCodeMirrorReady = { cm =>cm.on("change", ()=>autosave(cm.getValue()) ) } + valueAsTextHook = { value => { + + let saved = getAutosavedText(); + + if( saved!=="" && saved!==value && window.confirm("An autosaved text is available. Would you like to load it?")) + { + return saved; + } + }} /> { saveError && {parseError(saveError)} } diff --git a/src/version.json b/src/version.json index faeac5f..6a5f89f 100644 --- a/src/version.json +++ b/src/version.json @@ -1 +1 @@ -{"buildMajor":"2","buildMinor":29,"buildRevision":1,"buildTag":"RELEASE","when":"Sun, 28 Apr 2024 11:41:43 GMT"} \ No newline at end of file +{"buildMajor":"2","buildMinor":30,"buildRevision":0,"buildTag":"RELEASE","when":"Sun, 21 Jul 2024 12:32:10 GMT"} \ No newline at end of file