mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-11-04 22:38:43 +00:00
Merge branch 'master' into limitStreamListeners-#5090.1
This commit is contained in:
@@ -1,30 +1,15 @@
|
|||||||
import './editPage.less';
|
import './editPage.less';
|
||||||
|
|
||||||
// Common imports
|
// Common imports
|
||||||
import React, { useState, useEffect, useRef, useEffectEvent } from 'react';
|
import React from 'react';
|
||||||
import request from '../../utils/request-middleware.js';
|
import request from '../../utils/request-middleware.js';
|
||||||
|
import _ from 'lodash';
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js';
|
|
||||||
|
|
||||||
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
|
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
|
||||||
|
import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js';
|
||||||
import Nav from '@navbar/nav.jsx';
|
|
||||||
|
|
||||||
// Page specific imports
|
// Page specific imports
|
||||||
import { md5 } from 'hash-wasm';
|
|
||||||
import { gzipSync, strToU8 } from 'fflate';
|
import { gzipSync, strToU8 } from 'fflate';
|
||||||
import { makePatches, stringifyPatches } from '@sanity/diff-match-patch';
|
|
||||||
|
|
||||||
import { updateHistory, versionHistoryGarbageCollection } from '../../utils/versionHistory.js';
|
import { updateHistory, versionHistoryGarbageCollection } from '../../utils/versionHistory.js';
|
||||||
import googleDriveIcon from '../../googleDrive.svg';
|
|
||||||
|
|
||||||
const useLocalStorage = false;
|
|
||||||
const sandbox = false;
|
|
||||||
const showFloatingButtons = false;
|
|
||||||
const showEditorButtons = true;
|
|
||||||
const pageName = 'editPage';
|
|
||||||
|
|
||||||
const EditPage = (props)=>{
|
const EditPage = (props)=>{
|
||||||
props = {
|
props = {
|
||||||
@@ -32,75 +17,19 @@ const EditPage = (props)=>{
|
|||||||
...props
|
...props
|
||||||
};
|
};
|
||||||
|
|
||||||
const [currentBrew, setCurrentBrew] = useState(props.brew);
|
|
||||||
const [saveGoogle, setSaveGoogle] = useState(!!props.brew.googleId);
|
|
||||||
const [error, setError] = useState(null);
|
|
||||||
const [alertTrashedGoogleBrew, setAlertTrashedGoogleBrew] = useState(props.brew.trashed);
|
|
||||||
const [alertNoGoogleToTransfer, setAlertNoGoogleToTransfer] = useState(false);
|
|
||||||
const [alertOwnershipToTransfer, setAlertOwnershipToTransfer] = useState(false);
|
|
||||||
const [confirmGoogleTransfer, setConfirmGoogleTransfer] = useState(false);
|
|
||||||
|
|
||||||
const lastSavedBrew = useRef(_.cloneDeep(props.brew));
|
|
||||||
|
|
||||||
const handleGoogleClick = ()=>{
|
|
||||||
if(currentBrew.authors.length > 0 && global.account?.username !== currentBrew.authors[0]) {
|
|
||||||
setAlertOwnershipToTransfer(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(!global.account?.googleId) {
|
|
||||||
setAlertNoGoogleToTransfer(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setConfirmGoogleTransfer((prev)=>!prev);
|
|
||||||
setError(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeAlerts = (e)=>{
|
|
||||||
e.stopPropagation(); //Only handle click once so alert doesn't reopen
|
|
||||||
setAlertTrashedGoogleBrew(false);
|
|
||||||
setAlertNoGoogleToTransfer(false);
|
|
||||||
setConfirmGoogleTransfer(false);
|
|
||||||
setAlertOwnershipToTransfer(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleGoogleStorage = (e)=>{
|
|
||||||
closeAlerts(e);
|
|
||||||
const newSaveGoogle = !saveGoogle;
|
|
||||||
setSaveGoogle((prev)=>!prev);
|
|
||||||
setError(null);
|
|
||||||
trySave(true, true, newSaveGoogle);
|
|
||||||
};
|
|
||||||
|
|
||||||
const save = async (brew, saveToGoogle)=>{
|
const save = async (brew, saveToGoogle)=>{
|
||||||
await updateHistory(brew).catch(console.error);
|
await updateHistory(brew).catch(console.error);
|
||||||
await versionHistoryGarbageCollection().catch(console.error);
|
await versionHistoryGarbageCollection().catch(console.error);
|
||||||
|
|
||||||
//Prepare content to send to server
|
const compressedBrew = gzipSync(strToU8(JSON.stringify(brew)));
|
||||||
const brewToSave = {
|
|
||||||
...brew,
|
|
||||||
text : brew.text.normalize('NFC'),
|
|
||||||
pageCount : ((brew.renderer === 'legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/gm)) || []).length + 1,
|
|
||||||
patches : stringifyPatches(makePatches(encodeURI(lastSavedBrew.current.text.normalize('NFC')), encodeURI(brew.text.normalize('NFC')))),
|
|
||||||
hash : await md5(lastSavedBrew.current.text.normalize('NFC')),
|
|
||||||
textBin : undefined,
|
|
||||||
version : lastSavedBrew.current.version
|
|
||||||
};
|
|
||||||
|
|
||||||
const compressedBrew = gzipSync(strToU8(JSON.stringify(brewToSave)));
|
|
||||||
const transfer = saveToGoogle === _.isNil(brew.googleId);
|
const transfer = saveToGoogle === _.isNil(brew.googleId);
|
||||||
const params = transfer ? `?${saveToGoogle ? 'saveToGoogle' : 'removeFromGoogle'}=true` : '';
|
const params = transfer ? `?${saveToGoogle ? 'saveToGoogle' : 'removeFromGoogle'}=true` : '';
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.put(`/api/update/${brewToSave.editId}${params}`)
|
.put(`/api/update/${brew.editId}${params}`)
|
||||||
.set('Content-Encoding', 'gzip')
|
.set('Content-Encoding', 'gzip')
|
||||||
.set('Content-Type', 'application/json')
|
.set('Content-Type', 'application/json')
|
||||||
.send(compressedBrew)
|
.send(compressedBrew);
|
||||||
.catch((err)=>{
|
|
||||||
console.error('Error Updating Local Brew');
|
|
||||||
setError(err);
|
|
||||||
});
|
|
||||||
if(!res) return;
|
|
||||||
|
|
||||||
const updatedFields = {
|
const updatedFields = {
|
||||||
googleId : res.body.googleId ?? null, //TODO: investigate if we can set googleId:null in server/update instead of undefined
|
googleId : res.body.googleId ?? null, //TODO: investigate if we can set googleId:null in server/update instead of undefined
|
||||||
@@ -116,70 +45,18 @@ const EditPage = (props)=>{
|
|||||||
history.replaceState(null, null, `/edit/${savedBrew.editId}`);;
|
history.replaceState(null, null, `/edit/${savedBrew.editId}`);;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderGoogleDriveIcon = ()=>(
|
|
||||||
<Nav.item className='googleDriveStorage' onClick={handleGoogleClick}>
|
|
||||||
<img src={googleDriveIcon} className={saveGoogle ? '' : 'inactive'} alt='Google Drive icon' />
|
|
||||||
|
|
||||||
{alertOwnershipToTransfer && (
|
|
||||||
<div className='errorContainer'>
|
|
||||||
You must be the Owner to transfer between the Homebrewery and Google Drive!
|
|
||||||
The owner of this file is {currentBrew.authors[0]}.
|
|
||||||
<br></br>
|
|
||||||
<div className='confirm' onClick={closeAlerts}> Okay </div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{alertNoGoogleToTransfer && (
|
|
||||||
<div className='errorContainer'>
|
|
||||||
You must be signed in to a Google account to transfer between the Homebrewery and Google Drive!
|
|
||||||
<a target='_blank' rel='noopener noreferrer' href={`https://www.naturalcrit.com/login?redirect=${window.location.href}`}>
|
|
||||||
<div className='confirm' onClick={closeAlerts}> Sign In </div>
|
|
||||||
</a>
|
|
||||||
<div className='deny' onClick={closeAlerts}> Not Now </div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{alertTrashedGoogleBrew && (
|
|
||||||
<div className='errorContainer'>
|
|
||||||
This brew is currently in your Trash folder on Google Drive!<br />
|
|
||||||
If you want to keep it, make sure to move it before it is deleted permanently!<br />
|
|
||||||
<div className='confirm' onClick={toggleGoogleStorage}> Save my brew </div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{confirmGoogleTransfer && (
|
|
||||||
<div className='errorContainer'>
|
|
||||||
{saveGoogle
|
|
||||||
? 'Would you like to transfer this brew from your Google Drive storage back to the Homebrewery?'
|
|
||||||
: 'Would you like to transfer this brew from the Homebrewery to your personal Google Drive storage?'}
|
|
||||||
<br />
|
|
||||||
<div className='confirm' onClick={toggleGoogleStorage}> Yes </div>
|
|
||||||
<div className='deny' onClick={closeAlerts}> No </div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Nav.item>
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
renderPanels,
|
renderPanels,
|
||||||
trySave,
|
|
||||||
} = useCommonEditPageFunctions({
|
} = useCommonEditPageFunctions({
|
||||||
saveGoogle,
|
useLocalStorage : false,
|
||||||
setSaveGoogle,
|
sandbox : false,
|
||||||
error,
|
showFloatingButtons : false,
|
||||||
setError,
|
showEditorButtons : true,
|
||||||
currentBrew,
|
pageName : 'newPage',
|
||||||
setCurrentBrew,
|
brew : props.brew,
|
||||||
useLocalStorage,
|
userThemes : props.userThemes,
|
||||||
sandbox,
|
|
||||||
showFloatingButtons,
|
|
||||||
lastSavedBrew,
|
|
||||||
save,
|
save,
|
||||||
onSaveSuccess,
|
onSaveSuccess,
|
||||||
pageName,
|
|
||||||
showEditorButtons,
|
|
||||||
renderGoogleDriveIcon,
|
|
||||||
userThemes : props.userThemes
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return renderPanels();
|
return renderPanels();
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
import './homePage.less';
|
import './homePage.less';
|
||||||
|
|
||||||
// Common imports
|
// Common imports
|
||||||
import React, { useState, useEffect, useRef, useEffectEvent } from 'react';
|
import React from 'react';
|
||||||
import request from '../../utils/request-middleware.js';
|
import request from '../../utils/request-middleware.js';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
|
|
||||||
|
|
||||||
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
|
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
|
||||||
|
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
|
||||||
// Page specific imports
|
|
||||||
const useLocalStorage = false;
|
|
||||||
const sandbox = true;
|
|
||||||
const showFloatingButtons = true;
|
|
||||||
const showEditorButtons = false;
|
|
||||||
const pageName = 'homePage';
|
|
||||||
|
|
||||||
const HomePage =(props)=>{
|
const HomePage =(props)=>{
|
||||||
props = {
|
props = {
|
||||||
@@ -22,21 +13,10 @@ const HomePage =(props)=>{
|
|||||||
...props
|
...props
|
||||||
};
|
};
|
||||||
|
|
||||||
const [currentBrew, setCurrentBrew] = useState(props.brew);
|
|
||||||
const [saveGoogle, setSaveGoogle] = useState(global.account?.googleId ? true : false);
|
|
||||||
const [error, setError] = useState(undefined);
|
|
||||||
|
|
||||||
const lastSavedBrew = useRef(_.cloneDeep(props.brew));
|
|
||||||
|
|
||||||
const save = async (brew, saveToGoogle)=>{
|
const save = async (brew, saveToGoogle)=>{
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api${saveGoogle ? '?saveToGoogle=true' : ''}`)
|
.post(`/api${saveToGoogle ? '?saveToGoogle=true' : ''}`)
|
||||||
.send(brew)
|
.send(brew);
|
||||||
.catch((err)=>{
|
|
||||||
console.error('Error Updating Local Brew');
|
|
||||||
setError(err);
|
|
||||||
});
|
|
||||||
if(!res) return;
|
|
||||||
|
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
@@ -49,21 +29,15 @@ const HomePage =(props)=>{
|
|||||||
const {
|
const {
|
||||||
renderPanels
|
renderPanels
|
||||||
} = useCommonEditPageFunctions({
|
} = useCommonEditPageFunctions({
|
||||||
saveGoogle,
|
useLocalStorage : false,
|
||||||
setSaveGoogle,
|
sandbox : true,
|
||||||
error,
|
showFloatingButtons : true,
|
||||||
setError,
|
showEditorButtons : false,
|
||||||
currentBrew,
|
pageName : 'homePage',
|
||||||
setCurrentBrew,
|
brew : props.brew,
|
||||||
useLocalStorage,
|
userThemes : {},
|
||||||
sandbox,
|
|
||||||
showFloatingButtons,
|
|
||||||
lastSavedBrew,
|
|
||||||
save,
|
save,
|
||||||
onSaveSuccess,
|
onSaveSuccess,
|
||||||
pageName,
|
|
||||||
showEditorButtons,
|
|
||||||
userThemes : {}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return renderPanels();
|
return renderPanels();
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
import './newPage.less';
|
import './newPage.less';
|
||||||
|
|
||||||
// Common imports
|
// Common imports
|
||||||
import React, { useState, useEffect, useRef, useEffectEvent } from 'react';
|
import React from 'react';
|
||||||
import request from '../../utils/request-middleware.js';
|
import request from '../../utils/request-middleware.js';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
|
|
||||||
|
|
||||||
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
|
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
|
||||||
|
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
|
||||||
// Page specific imports
|
|
||||||
const useLocalStorage = true;
|
|
||||||
const sandbox = true;
|
|
||||||
const showFloatingButtons = false;
|
|
||||||
const showEditorButtons = true;
|
|
||||||
const pageName = 'newPage';
|
|
||||||
|
|
||||||
const NewPage = (props)=>{
|
const NewPage = (props)=>{
|
||||||
props = {
|
props = {
|
||||||
@@ -22,29 +13,10 @@ const NewPage = (props)=>{
|
|||||||
...props
|
...props
|
||||||
};
|
};
|
||||||
|
|
||||||
const [currentBrew, setCurrentBrew] = useState(props.brew);
|
|
||||||
const [saveGoogle, setSaveGoogle] = useState(global.account?.googleId ? true : false);
|
|
||||||
const [error, setError] = useState(null);
|
|
||||||
|
|
||||||
const lastSavedBrew = useRef(_.cloneDeep(props.brew));
|
|
||||||
|
|
||||||
const save = async (brew, saveToGoogle)=>{
|
const save = async (brew, saveToGoogle)=>{
|
||||||
//Prepare content to send to server
|
|
||||||
const brewToSave = {
|
|
||||||
...brew,
|
|
||||||
text : brew.text.normalize('NFC'),
|
|
||||||
pageCount : ((brew.renderer === 'legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/gm)) || []).length + 1,
|
|
||||||
textBin : undefined
|
|
||||||
};
|
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api${saveGoogle ? '?saveToGoogle=true' : ''}`)
|
.post(`/api${saveToGoogle ? '?saveToGoogle=true' : ''}`)
|
||||||
.send(brewToSave)
|
.send(brew);
|
||||||
.catch((err)=>{
|
|
||||||
console.error('Error Updating Local Brew');
|
|
||||||
setError(err);
|
|
||||||
});
|
|
||||||
if(!res) return;
|
|
||||||
|
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
@@ -57,21 +29,15 @@ const NewPage = (props)=>{
|
|||||||
const {
|
const {
|
||||||
renderPanels
|
renderPanels
|
||||||
} = useCommonEditPageFunctions({
|
} = useCommonEditPageFunctions({
|
||||||
saveGoogle,
|
useLocalStorage : true,
|
||||||
setSaveGoogle,
|
sandbox : true,
|
||||||
error,
|
showFloatingButtons : false,
|
||||||
setError,
|
showEditorButtons : true,
|
||||||
currentBrew,
|
pageName : 'newPage',
|
||||||
setCurrentBrew,
|
brew : props.brew,
|
||||||
useLocalStorage,
|
userThemes : props.userThemes,
|
||||||
sandbox,
|
|
||||||
showFloatingButtons,
|
|
||||||
lastSavedBrew,
|
|
||||||
save,
|
save,
|
||||||
onSaveSuccess,
|
onSaveSuccess,
|
||||||
pageName,
|
|
||||||
showEditorButtons,
|
|
||||||
userThemes : props.userThemes
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return renderPanels();
|
return renderPanels();
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import React, { useState, useEffect, useEffectEvent, useRef } from 'react';
|
|||||||
import { printCurrentBrew, fetchThemeBundle } from '@shared/helpers.js';
|
import { printCurrentBrew, fetchThemeBundle } from '@shared/helpers.js';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { hbfm } from 'marked-hbfm';
|
import { hbfm } from 'marked-hbfm';
|
||||||
|
import { md5 } from 'hash-wasm';
|
||||||
|
import { makePatches, stringifyPatches } from '@sanity/diff-match-patch';
|
||||||
|
|
||||||
import Headtags from '@vitreum/headtags.js';
|
import Headtags from '@vitreum/headtags.js';
|
||||||
import SplitPane from '@components/splitPane/splitPane.jsx';
|
import SplitPane from '@components/splitPane/splitPane.jsx';
|
||||||
@@ -22,6 +24,7 @@ import PrintNavItem from '@navbar/print.navitem.jsx';
|
|||||||
import ShareNavItem from '@navbar/share.navitem.jsx';
|
import ShareNavItem from '@navbar/share.navitem.jsx';
|
||||||
import RecentNavItems from '@navbar/recent.navitem.jsx';
|
import RecentNavItems from '@navbar/recent.navitem.jsx';
|
||||||
const { both: RecentNavItem } = RecentNavItems;
|
const { both: RecentNavItem } = RecentNavItems;
|
||||||
|
import googleDriveIcon from '../googleDrive.svg';
|
||||||
|
|
||||||
const AUTOSAVE_KEY = 'HB_editor_autoSaveOn';
|
const AUTOSAVE_KEY = 'HB_editor_autoSaveOn';
|
||||||
const BREWKEY = 'HB_newPage_content';
|
const BREWKEY = 'HB_newPage_content';
|
||||||
@@ -36,24 +39,18 @@ const UNSAVED_WARNING_POPUP_TIMEOUT = 4000; //Show the warning for 4 seconds
|
|||||||
|
|
||||||
export default function useCommonEditPageFunctions(dependencies) {
|
export default function useCommonEditPageFunctions(dependencies) {
|
||||||
const {
|
const {
|
||||||
saveGoogle,
|
brew,
|
||||||
setSaveGoogle,
|
|
||||||
error,
|
|
||||||
setError,
|
|
||||||
currentBrew,
|
|
||||||
setCurrentBrew,
|
|
||||||
useLocalStorage,
|
useLocalStorage,
|
||||||
sandbox,
|
sandbox,
|
||||||
showFloatingButtons,
|
showFloatingButtons,
|
||||||
lastSavedBrew,
|
|
||||||
save,
|
save,
|
||||||
onSaveSuccess,
|
onSaveSuccess,
|
||||||
pageName,
|
pageName,
|
||||||
renderGoogleDriveIcon = ()=>{},
|
|
||||||
showEditorButtons,
|
showEditorButtons,
|
||||||
userThemes = {}
|
userThemes = {}
|
||||||
} = dependencies;
|
} = dependencies;
|
||||||
|
|
||||||
|
const [currentBrew, setCurrentBrew] = useState(brew);
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [lastSavedTime, setLastSavedTime] = useState(new Date());
|
const [lastSavedTime, setLastSavedTime] = useState(new Date());
|
||||||
const [autoSaveEnabled, setAutoSaveEnabled] = useState(!sandbox);
|
const [autoSaveEnabled, setAutoSaveEnabled] = useState(!sandbox);
|
||||||
@@ -61,6 +58,13 @@ export default function useCommonEditPageFunctions(dependencies) {
|
|||||||
const [unsavedChanges, setUnsavedChanges] = useState(false);
|
const [unsavedChanges, setUnsavedChanges] = useState(false);
|
||||||
const [themeBundle, setThemeBundle] = useState({});
|
const [themeBundle, setThemeBundle] = useState({});
|
||||||
const [HTMLErrors, setHTMLErrors] = useState(hbfm.validate(currentBrew.text));
|
const [HTMLErrors, setHTMLErrors] = useState(hbfm.validate(currentBrew.text));
|
||||||
|
const [saveGoogle, setSaveGoogle] = useState(currentBrew.googleId);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
|
const [alertTrashedGoogleBrew, setAlertTrashedGoogleBrew] = useState(currentBrew.trashed);
|
||||||
|
const [alertNoGoogleToTransfer, setAlertNoGoogleToTransfer] = useState(false);
|
||||||
|
const [alertOwnershipToTransfer, setAlertOwnershipToTransfer] = useState(false);
|
||||||
|
const [confirmGoogleTransfer, setConfirmGoogleTransfer] = useState(false);
|
||||||
|
|
||||||
const [currentEditorViewPageNum, setCurrentEditorViewPageNum] = useState(1);
|
const [currentEditorViewPageNum, setCurrentEditorViewPageNum] = useState(1);
|
||||||
const [currentEditorCursorPageNum, setCurrentEditorCursorPageNum] = useState(1);
|
const [currentEditorCursorPageNum, setCurrentEditorCursorPageNum] = useState(1);
|
||||||
@@ -68,6 +72,7 @@ export default function useCommonEditPageFunctions(dependencies) {
|
|||||||
|
|
||||||
const unsavedChangesRef = useRef(unsavedChanges); // onBeforeUnload lives outside React and needs ref to unsavedChanges
|
const unsavedChangesRef = useRef(unsavedChanges); // onBeforeUnload lives outside React and needs ref to unsavedChanges
|
||||||
const warnUnsavedTimeout = useRef(null); // timers live outside React and need ref to consistently track time
|
const warnUnsavedTimeout = useRef(null); // timers live outside React and need ref to consistently track time
|
||||||
|
const lastSavedBrew = useRef(_.cloneDeep(currentBrew));
|
||||||
const saveTimeout = useRef(null);
|
const saveTimeout = useRef(null);
|
||||||
const editorRef = useRef(null);
|
const editorRef = useRef(null);
|
||||||
|
|
||||||
@@ -202,12 +207,27 @@ export default function useCommonEditPageFunctions(dependencies) {
|
|||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
setHTMLErrors(hbfm.validate(currentBrew.text));
|
setHTMLErrors(hbfm.validate(currentBrew.text));
|
||||||
const brewToSave = currentBrew;
|
|
||||||
let savedBrew = await save(brewToSave, saveToGoogle)
|
//Prepare content to send to server
|
||||||
.catch((err)=>{setError(err);});
|
const snapshotBrewBeforeSave = currentBrew;
|
||||||
|
const brewToSave = {
|
||||||
|
...currentBrew,
|
||||||
|
text : currentBrew.text.normalize('NFC'),
|
||||||
|
pageCount : ((currentBrew.renderer === 'legacy' ? currentBrew.text.match(/\\page/g) : currentBrew.text.match(/^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/gm)) || []).length + 1,
|
||||||
|
patches : stringifyPatches(makePatches(encodeURI(lastSavedBrew.current.text.normalize('NFC')), encodeURI(currentBrew.text.normalize('NFC')))),
|
||||||
|
hash : await md5(lastSavedBrew.current.text.normalize('NFC')),
|
||||||
|
textBin : undefined,
|
||||||
|
version : lastSavedBrew.current.version
|
||||||
|
};
|
||||||
|
|
||||||
|
const savedBrew = await save(brewToSave, saveToGoogle)
|
||||||
|
.catch((err)=>{
|
||||||
|
console.error('Error Updating Local Brew');
|
||||||
|
setError(err);
|
||||||
|
});
|
||||||
if(savedBrew) {
|
if(savedBrew) {
|
||||||
lastSavedBrew.current = {
|
lastSavedBrew.current = {
|
||||||
...brewToSave,
|
...snapshotBrewBeforeSave,
|
||||||
...savedBrew
|
...savedBrew
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -217,11 +237,11 @@ export default function useCommonEditPageFunctions(dependencies) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
if(useLocalStorage) clearLocalStorage();
|
if(useLocalStorage) clearLocalStorage();
|
||||||
|
setLastSavedTime(new Date());
|
||||||
|
if(!autoSaveEnabled) resetWarnUnsavedTimer();
|
||||||
onSaveSuccess(savedBrew);
|
onSaveSuccess(savedBrew);
|
||||||
}
|
}
|
||||||
setIsSaving(false);
|
setIsSaving(false);
|
||||||
setLastSavedTime(new Date());
|
|
||||||
if(!autoSaveEnabled) resetWarnUnsavedTimer();
|
|
||||||
}, newTimeout);
|
}, newTimeout);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -262,18 +282,94 @@ export default function useCommonEditPageFunctions(dependencies) {
|
|||||||
snippets : newData.snippets
|
snippets : newData.snippets
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
//======----- Google Toggle Button -----======
|
||||||
|
const closeAlerts = (e)=>{
|
||||||
|
e.stopPropagation(); //Only handle click once so alert doesn't reopen
|
||||||
|
setAlertTrashedGoogleBrew(false);
|
||||||
|
setAlertNoGoogleToTransfer(false);
|
||||||
|
setConfirmGoogleTransfer(false);
|
||||||
|
setAlertOwnershipToTransfer(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGoogleClick = ()=>{
|
||||||
|
if(currentBrew.authors.length > 0 && global.account?.username !== currentBrew.authors[0]) {
|
||||||
|
setAlertOwnershipToTransfer(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!global.account?.googleId) {
|
||||||
|
setAlertNoGoogleToTransfer(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setConfirmGoogleTransfer((prev)=>!prev);
|
||||||
|
setError(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleGoogleStorage = (e)=>{
|
||||||
|
closeAlerts(e);
|
||||||
|
const newSaveGoogle = !saveGoogle;
|
||||||
|
setSaveGoogle((prev)=>!prev);
|
||||||
|
setError(null);
|
||||||
|
trySave(true, true, newSaveGoogle);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderGoogleDriveIcon = ()=>(
|
||||||
|
<Nav.item className='googleDriveStorage' onClick={handleGoogleClick}>
|
||||||
|
<img src={googleDriveIcon} className={saveGoogle ? '' : 'inactive'} alt='Google Drive icon' />
|
||||||
|
|
||||||
|
{alertOwnershipToTransfer && (
|
||||||
|
<div className='errorContainer'>
|
||||||
|
You must be the Owner to transfer between the Homebrewery and Google Drive!
|
||||||
|
The owner of this file is {currentBrew.authors[0]}.
|
||||||
|
<br></br>
|
||||||
|
<div className='confirm' onClick={closeAlerts}> Okay </div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{alertNoGoogleToTransfer && (
|
||||||
|
<div className='errorContainer'>
|
||||||
|
You must be signed in to a Google account to transfer between the Homebrewery and Google Drive!
|
||||||
|
<a target='_blank' rel='noopener noreferrer' href={`https://www.naturalcrit.com/login?redirect=${window.location.href}`}>
|
||||||
|
<div className='confirm' onClick={closeAlerts}> Sign In </div>
|
||||||
|
</a>
|
||||||
|
<div className='deny' onClick={closeAlerts}> Not Now </div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{alertTrashedGoogleBrew && (
|
||||||
|
<div className='errorContainer'>
|
||||||
|
This brew is currently in your Trash folder on Google Drive!<br />
|
||||||
|
If you want to keep it, make sure to move it before it is deleted permanently!<br />
|
||||||
|
<div className='confirm' onClick={toggleGoogleStorage}> Save my brew </div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{confirmGoogleTransfer && (
|
||||||
|
<div className='errorContainer'>
|
||||||
|
{saveGoogle
|
||||||
|
? 'Would you like to transfer this brew from your Google Drive storage back to the Homebrewery?'
|
||||||
|
: 'Would you like to transfer this brew from the Homebrewery to your personal Google Drive storage?'}
|
||||||
|
<br />
|
||||||
|
<div className='confirm' onClick={toggleGoogleStorage}> Yes </div>
|
||||||
|
<div className='deny' onClick={closeAlerts}> No </div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Nav.item>
|
||||||
|
);
|
||||||
|
|
||||||
|
//======----- Navbar -----======
|
||||||
const renderNavbar = ()=>(
|
const renderNavbar = ()=>(
|
||||||
<Navbar>
|
<Navbar>
|
||||||
<Nav.section>
|
<Nav.section>
|
||||||
<Nav.item className='brewTitle'>{currentBrew.title}</Nav.item>
|
<Nav.item className='brewTitle'>{currentBrew.title}</Nav.item>
|
||||||
</Nav.section>
|
</Nav.section>
|
||||||
<Nav.section>
|
<Nav.section>
|
||||||
{renderGoogleDriveIcon()}
|
{(pageName == 'editPage') && renderGoogleDriveIcon()}
|
||||||
{error
|
{error
|
||||||
? <ErrorNavItem error={error} clearError={clearError} />
|
? <ErrorNavItem error={error} clearError={clearError} />
|
||||||
: <Nav.dropdown className='save-menu'>
|
: <Nav.dropdown className='save-menu'>
|
||||||
{renderSaveButton()}
|
{renderSaveButton()}
|
||||||
{pageName == 'editPage' && renderAutoSaveButton()}
|
{(pageName == 'editPage') && renderAutoSaveButton()}
|
||||||
</Nav.dropdown>}
|
</Nav.dropdown>}
|
||||||
<NewBrewItem />
|
<NewBrewItem />
|
||||||
<PrintNavItem />
|
<PrintNavItem />
|
||||||
|
|||||||
Generated
+7
-7
@@ -25,7 +25,7 @@
|
|||||||
"@codemirror/search": "^6.6.0",
|
"@codemirror/search": "^6.6.0",
|
||||||
"@codemirror/state": "^6.7.6",
|
"@codemirror/state": "^6.7.6",
|
||||||
"@codemirror/view": "^6.43.13",
|
"@codemirror/view": "^6.43.13",
|
||||||
"@googleapis/drive": "^26.0.1",
|
"@googleapis/drive": "^26.0.2",
|
||||||
"@lezer/highlight": "^1.2.4",
|
"@lezer/highlight": "^1.2.4",
|
||||||
"@oddbird/css-anchor-positioning": "^0.10.2",
|
"@oddbird/css-anchor-positioning": "^0.10.2",
|
||||||
"@sanity/diff-match-patch": "^3.2.1",
|
"@sanity/diff-match-patch": "^3.2.1",
|
||||||
@@ -2516,9 +2516,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@googleapis/drive": {
|
"node_modules/@googleapis/drive": {
|
||||||
"version": "26.0.1",
|
"version": "26.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-26.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-26.0.2.tgz",
|
||||||
"integrity": "sha512-q1U+WNS2OPAS3Prn3FD0otYNudnv+feXX9DP8qrDqGGwIVU90OBnP6NV66aTc0qJrqeJvnrCYcnjddjm4h23iQ==",
|
"integrity": "sha512-VeKVZvzgH4ioczJZrZ5sy73RJbHrYLI1XZIZ3ZqGKQhC4U03XsOOOiBHKqvH4F9vbXrxR2LawmktoIJuTJhzYg==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"googleapis-common": "^9.0.0"
|
"googleapis-common": "^9.0.0"
|
||||||
@@ -13740,9 +13740,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
|
||||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
"integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
|
|||||||
+1
-1
@@ -102,7 +102,7 @@
|
|||||||
"@codemirror/search": "^6.6.0",
|
"@codemirror/search": "^6.6.0",
|
||||||
"@codemirror/state": "^6.7.6",
|
"@codemirror/state": "^6.7.6",
|
||||||
"@codemirror/view": "^6.43.13",
|
"@codemirror/view": "^6.43.13",
|
||||||
"@googleapis/drive": "^26.0.1",
|
"@googleapis/drive": "^26.0.2",
|
||||||
"@lezer/highlight": "^1.2.4",
|
"@lezer/highlight": "^1.2.4",
|
||||||
"@oddbird/css-anchor-positioning": "^0.10.2",
|
"@oddbird/css-anchor-positioning": "^0.10.2",
|
||||||
"@sanity/diff-match-patch": "^3.2.1",
|
"@sanity/diff-match-patch": "^3.2.1",
|
||||||
|
|||||||
Reference in New Issue
Block a user