mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-03-30 01:08:11 +00:00
Make renderSaveButton identical between new and edit page
This commit is contained in:
@@ -28,6 +28,9 @@ const { both: RecentNavItem } = RecentNavItems;
|
|||||||
// Page specific imports
|
// Page specific imports
|
||||||
import { Meta } from 'vitreum/headtags';
|
import { Meta } from 'vitreum/headtags';
|
||||||
|
|
||||||
|
const UNSAVED_WARNING_TIMEOUT = 9000; //Warn user afer 15 minutes of unsaved changes
|
||||||
|
const UNSAVED_WARNING_POPUP_TIMEOUT = 4000; //Show the warning for 4 seconds
|
||||||
|
|
||||||
const BREWKEY = 'HB_newPage_content';
|
const BREWKEY = 'HB_newPage_content';
|
||||||
const STYLEKEY = 'HB_newPage_style';
|
const STYLEKEY = 'HB_newPage_style';
|
||||||
const METAKEY = 'HB_newPage_metadata';
|
const METAKEY = 'HB_newPage_metadata';
|
||||||
@@ -35,7 +38,7 @@ const SNIPKEY = 'HB_newPage_snippets';
|
|||||||
const SAVEKEYPREFIX = 'HB_editor_defaultSave_';
|
const SAVEKEYPREFIX = 'HB_editor_defaultSave_';
|
||||||
|
|
||||||
const useLocalStorage = true;
|
const useLocalStorage = true;
|
||||||
const neverSaved = true;
|
let neverSaved = true;
|
||||||
|
|
||||||
const NewPage = (props)=>{
|
const NewPage = (props)=>{
|
||||||
props = {
|
props = {
|
||||||
@@ -45,6 +48,7 @@ const NewPage = (props)=>{
|
|||||||
|
|
||||||
const [currentBrew , setCurrentBrew ] = useState(props.brew);
|
const [currentBrew , setCurrentBrew ] = useState(props.brew);
|
||||||
const [isSaving , setIsSaving ] = useState(false);
|
const [isSaving , setIsSaving ] = useState(false);
|
||||||
|
const [lastSavedTime , setLastSavedTime ] = useState(new Date());
|
||||||
const [saveGoogle , setSaveGoogle ] = useState(global.account?.googleId ? true : false);
|
const [saveGoogle , setSaveGoogle ] = useState(global.account?.googleId ? true : false);
|
||||||
const [error , setError ] = useState(null);
|
const [error , setError ] = useState(null);
|
||||||
const [HTMLErrors , setHTMLErrors ] = useState(Markdown.validate(props.brew.text));
|
const [HTMLErrors , setHTMLErrors ] = useState(Markdown.validate(props.brew.text));
|
||||||
@@ -54,11 +58,12 @@ const NewPage = (props)=>{
|
|||||||
const [themeBundle , setThemeBundle ] = useState({});
|
const [themeBundle , setThemeBundle ] = useState({});
|
||||||
const [unsavedChanges , setUnsavedChanges ] = useState(false);
|
const [unsavedChanges , setUnsavedChanges ] = useState(false);
|
||||||
const [autoSaveEnabled , setAutoSaveEnabled ] = useState(false);
|
const [autoSaveEnabled , setAutoSaveEnabled ] = useState(false);
|
||||||
|
const [warnUnsavedChanges , setWarnUnsavedChanges ] = useState(true);
|
||||||
|
|
||||||
const editorRef = useRef(null);
|
const editorRef = useRef(null);
|
||||||
const lastSavedBrew = useRef(_.cloneDeep(props.brew));
|
const lastSavedBrew = useRef(_.cloneDeep(props.brew));
|
||||||
// const saveTimeout = useRef(null);
|
// const saveTimeout = useRef(null);
|
||||||
// const warnUnsavedTimeout = useRef(null);
|
const warnUnsavedTimeout = useRef(null);
|
||||||
const trySaveRef = useRef(trySave); // CTRL+S listener lives outside React and needs ref to use trySave with latest copy of brew
|
const trySaveRef = useRef(trySave); // CTRL+S listener lives outside React and needs ref to use trySave with latest copy of brew
|
||||||
const unsavedChangesRef = useRef(unsavedChanges); // Similarly, onBeforeUnload lives outside React and needs ref to unsavedChanges
|
const unsavedChangesRef = useRef(unsavedChanges); // Similarly, onBeforeUnload lives outside React and needs ref to unsavedChanges
|
||||||
|
|
||||||
@@ -95,13 +100,18 @@ const NewPage = (props)=>{
|
|||||||
brew.renderer = metaStorage?.renderer ?? brew.renderer;
|
brew.renderer = metaStorage?.renderer ?? brew.renderer;
|
||||||
brew.theme = metaStorage?.theme ?? brew.theme;
|
brew.theme = metaStorage?.theme ?? brew.theme;
|
||||||
brew.lang = metaStorage?.lang ?? brew.lang;
|
brew.lang = metaStorage?.lang ?? brew.lang;
|
||||||
|
|
||||||
|
lastSavedBrew.current = brew;
|
||||||
|
}
|
||||||
|
else { // Brew was cloned, so assume user may want to save immediately without making edits
|
||||||
|
neverSaved = false;
|
||||||
|
lastSavedBrew.current = DEFAULT_BREW;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SAVEKEY = `${SAVEKEYPREFIX}${global.account?.username}`;
|
const SAVEKEY = `${SAVEKEYPREFIX}${global.account?.username}`;
|
||||||
const saveStorage = localStorage.getItem(SAVEKEY) || 'HOMEBREWERY';
|
const saveStorage = localStorage.getItem(SAVEKEY) || 'HOMEBREWERY';
|
||||||
|
|
||||||
setCurrentBrew(brew);
|
setCurrentBrew(brew);
|
||||||
lastSavedBrew.current = brew;
|
|
||||||
setSaveGoogle(saveStorage == 'GOOGLE-DRIVE' && saveGoogle);
|
setSaveGoogle(saveStorage == 'GOOGLE-DRIVE' && saveGoogle);
|
||||||
|
|
||||||
localStorage.setItem(BREWKEY, brew.text);
|
localStorage.setItem(BREWKEY, brew.text);
|
||||||
@@ -151,8 +161,14 @@ const NewPage = (props)=>{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetWarnUnsavedTimer = ()=>{
|
||||||
|
setTimeout(()=>setWarnUnsavedChanges(false), UNSAVED_WARNING_POPUP_TIMEOUT); // Hide the warning after 4 seconds
|
||||||
|
clearTimeout(warnUnsavedTimeout.current);
|
||||||
|
warnUnsavedTimeout.current = setTimeout(()=>setWarnUnsavedChanges(true), UNSAVED_WARNING_TIMEOUT); // 15 minutes between unsaved work warnings
|
||||||
|
};
|
||||||
|
|
||||||
const trySave = async ()=>{
|
const trySave = async ()=>{
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
|
|
||||||
const updatedBrew = { ...currentBrew };
|
const updatedBrew = { ...currentBrew };
|
||||||
splitTextStyleAndMetadata(updatedBrew);
|
splitTextStyleAndMetadata(updatedBrew);
|
||||||
@@ -180,25 +196,27 @@ const NewPage = (props)=>{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderSaveButton = ()=>{
|
const renderSaveButton = ()=>{
|
||||||
|
const elapsedTime = Math.round((new Date() - lastSavedTime) / 1000 / 60);
|
||||||
|
const warningTimer = elapsedTime >= UNSAVED_WARNING_TIMEOUT / 1000 / 60;
|
||||||
|
|
||||||
// #1 - Currently saving, show SAVING
|
// #1 - Currently saving, show SAVING
|
||||||
if(isSaving)
|
if(isSaving)
|
||||||
return <Nav.item className='save' icon='fas fa-spinner fa-spin'>saving...</Nav.item>;
|
return <Nav.item className='save' icon='fas fa-spinner fa-spin'>saving...</Nav.item>;
|
||||||
|
|
||||||
// #2 - Unsaved changes exist, autosave is OFF and warning timer has expired, show AUTOSAVE WARNING
|
// #2 - Unsaved changes exist, autosave is OFF and warning timer has expired, show save reminder
|
||||||
// if(unsavedChanges && warnUnsavedChanges) {
|
if(unsavedChanges && warnUnsavedChanges && warningTimer) {
|
||||||
// resetWarnUnsavedTimer();
|
resetWarnUnsavedTimer();
|
||||||
// const elapsedTime = Math.round((new Date() - lastSavedTime) / 1000 / 60);
|
const text = neverSaved
|
||||||
// const text = elapsedTime === 0
|
? `This document has been open for ${elapsedTime} minutes but has never been saved. Click "Save Now" to avoid losing your work.`
|
||||||
// ? 'Autosave is OFF.'
|
: `Autosave is OFF, and you haven't saved for ${elapsedTime} minutes.`;
|
||||||
// : `Autosave is OFF, and you haven't saved for ${elapsedTime} minutes.`;
|
|
||||||
|
|
||||||
// return <Nav.item className='save error' icon='fas fa-exclamation-circle'>
|
return <Nav.item className='save error' icon='fas fa-exclamation-circle'>
|
||||||
// Reminder...
|
Reminder...
|
||||||
// <div className='errorContainer'>{text}</div>
|
<div className='errorContainer'>{text}</div>
|
||||||
// </Nav.item>;
|
</Nav.item>;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #3 - Unsaved changes exist, click to save, show SAVE NOW
|
// #3 - Unsaved changes exist, or never saved, click to save, show SAVE NOW
|
||||||
if(unsavedChanges)
|
if(unsavedChanges)
|
||||||
return <Nav.item className='save' onClick={trySave} color='blue' icon='fas fa-save'>save now</Nav.item>;
|
return <Nav.item className='save' onClick={trySave} color='blue' icon='fas fa-save'>save now</Nav.item>;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user