From 5865e5adfd93f98b1360b3da1a3abef4700672b9 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 9 Sep 2026 18:42:39 +0000 Subject: [PATCH] Extract common "handlePageChange" to a reusable hook --- client/homebrew/pages/editPage/editPage.jsx | 61 +++++++++---------- client/homebrew/pages/homePage/homePage.jsx | 58 ++++++++---------- client/homebrew/pages/newPage/newPage.jsx | 58 ++++++++---------- .../homebrew/utils/commonEditPageFunctions.js | 43 +++++++++++++ package-lock.json | 15 ----- 5 files changed, 125 insertions(+), 110 deletions(-) create mode 100644 client/homebrew/utils/commonEditPageFunctions.js diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 36df0f1bb..29f215e08 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -10,18 +10,20 @@ import _ from 'lodash'; import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js'; import { printCurrentBrew, fetchThemeBundle } from '@shared/helpers.js'; +import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.js' + import SplitPane from '@components/splitPane/splitPane.jsx'; import Editor from '../../editor/editor.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; -import Nav from '@navbar/nav.jsx'; -import Navbar from '@navbar/navbar.jsx'; -import NewBrewItem from '@navbar/newbrew.navitem.jsx'; -import AccountNavItem from '@navbar/account.navitem.jsx'; -import ErrorNavItem from '@navbar/error-navitem.jsx'; -import HelpNavItem from '@navbar/help.navitem.jsx'; -import VaultNavItem from '@navbar/vault.navitem.jsx'; -import PrintNavItem from '@navbar/print.navitem.jsx'; +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import NewBrewItem from '@navbar/newbrew.navitem.jsx'; +import AccountNavItem from '@navbar/account.navitem.jsx'; +import ErrorNavItem from '@navbar/error-navitem.jsx'; +import HelpNavItem from '@navbar/help.navitem.jsx'; +import VaultNavItem from '@navbar/vault.navitem.jsx'; +import PrintNavItem from '@navbar/print.navitem.jsx'; import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; @@ -41,7 +43,6 @@ const SAVE_TIMEOUT = 10000; const UNSAVED_WARNING_TIMEOUT = 900000; //Warn user afer 15 minutes of unsaved changes const UNSAVED_WARNING_POPUP_TIMEOUT = 4000; //Show the warning for 4 seconds - const AUTOSAVE_KEY = 'HB_editor_autoSaveOn'; const BREWKEY = 'HB_newPage_content'; const STYLEKEY = 'HB_newPage_style'; @@ -49,7 +50,7 @@ const SNIPKEY = 'HB_newPage_snippets'; const METAKEY = 'HB_newPage_meta'; const useLocalStorage = false; -const neverSaved = false; +const neverSaved = false; const EditPage = (props)=>{ props = { @@ -82,6 +83,23 @@ const EditPage = (props)=>{ const trySaveRef = useRef(null); // 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 { + handleBrewChange + } = useCommonEditPageFunctions({ + setError, + setThemeBundle, + HTMLErrors, + setHTMLErrors, + setCurrentBrew, + useLocalStorage, + BREWKEY, + STYLEKEY, + SNIPKEY, + METAKEY, + fetchThemeBundle, + hbfm + }); + useEffect(()=>{ const autoSavePref = JSON.parse(localStorage.getItem(AUTOSAVE_KEY) ?? true); setAutoSaveEnabled(autoSavePref); @@ -126,29 +144,6 @@ const EditPage = (props)=>{ editorRef.current?.update(); }; - const handleBrewChange = (field)=>(value, subfield)=>{ //'text', 'style', 'snippets', 'metadata' - if(subfield == 'renderer' || subfield == 'theme') - fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme); - - //If there are HTML errors, run the validator on every change to give quick feedback - if(HTMLErrors.length && (field == 'text' || field == 'snippets')) - setHTMLErrors(hbfm.validate(value)); - - if(field == 'metadata') setCurrentBrew((prev)=>({ ...prev, ...value })); - else setCurrentBrew((prev)=>({ ...prev, [field]: value })); - - if(useLocalStorage) { - if(field == 'text') localStorage.setItem(BREWKEY, value); - if(field == 'style') localStorage.setItem(STYLEKEY, value); - if(field == 'snippets') localStorage.setItem(SNIPKEY, value); - if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({ - renderer : value.renderer, - theme : value.theme, - lang : value.lang - })); - } - }; - const updateBrew = (newData)=>setCurrentBrew((prevBrew)=>({ ...prevBrew, style : newData.style, diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 4dc505ea9..34c2937f1 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -10,18 +10,20 @@ import _ from 'lodash'; import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; import { printCurrentBrew, fetchThemeBundle } from '@shared/helpers.js'; +import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.js' + import SplitPane from '@components/splitPane/splitPane.jsx'; import Editor from '../../editor/editor.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; -import Nav from '@navbar/nav.jsx'; -import Navbar from '@navbar/navbar.jsx'; -import NewBrewItem from '@navbar/newbrew.navitem.jsx'; -import AccountNavItem from '@navbar/account.navitem.jsx'; -import ErrorNavItem from '@navbar/error-navitem.jsx'; -import HelpNavItem from '@navbar/help.navitem.jsx'; -import VaultNavItem from '@navbar/vault.navitem.jsx'; -import PrintNavItem from '@navbar/print.navitem.jsx'; +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import NewBrewItem from '@navbar/newbrew.navitem.jsx'; +import AccountNavItem from '@navbar/account.navitem.jsx'; +import ErrorNavItem from '@navbar/error-navitem.jsx'; +import HelpNavItem from '@navbar/help.navitem.jsx'; +import VaultNavItem from '@navbar/vault.navitem.jsx'; +import PrintNavItem from '@navbar/print.navitem.jsx'; import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; @@ -60,6 +62,23 @@ const HomePage =(props)=>{ const lastSavedBrew = useRef(_.cloneDeep(props.brew)); const unsavedChangesRef = useRef(unsavedChanges); + const { + handleBrewChange + } = useCommonEditPageFunctions({ + setError, + setThemeBundle, + HTMLErrors, + setHTMLErrors, + setCurrentBrew, + useLocalStorage, + BREWKEY, + STYLEKEY, + SNIPKEY, + METAKEY, + fetchThemeBundle, + hbfm + }); + useEffect(()=>{ fetchThemeBundle(setError, setThemeBundle, currentBrew.renderer, currentBrew.theme); @@ -112,29 +131,6 @@ const HomePage =(props)=>{ editorRef.current.update(); }; - const handleBrewChange = (field)=>(value, subfield)=>{ //'text', 'style', 'snippets', 'metadata' - if(subfield == 'renderer' || subfield == 'theme') - fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme); - - //If there are HTML errors, run the validator on every change to give quick feedback - if(HTMLErrors.length && (field == 'text' || field == 'snippets')) - setHTMLErrors(hbfm.validate(value)); - - if(field == 'metadata') setCurrentBrew((prev)=>({ ...prev, ...value })); - else setCurrentBrew((prev)=>({ ...prev, [field]: value })); - - if(useLocalStorage) { - if(field == 'text') localStorage.setItem(BREWKEY, value); - if(field == 'style') localStorage.setItem(STYLEKEY, value); - if(field == 'snippets') localStorage.setItem(SNIPKEY, value); - if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({ - renderer : value.renderer, - theme : value.theme, - lang : value.lang - })); - } - }; - const renderSaveButton = ()=>{ // #1 - Currently saving, show SAVING if(isSaving) diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index c45090fb7..e55434f5c 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -10,18 +10,20 @@ import _ from 'lodash'; import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '@shared/helpers.js'; +import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.js' + import SplitPane from '@components/splitPane/splitPane.jsx'; import Editor from '../../editor/editor.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; -import Nav from '@navbar/nav.jsx'; -import Navbar from '@navbar/navbar.jsx'; -import NewBrewItem from '@navbar/newbrew.navitem.jsx'; -import AccountNavItem from '@navbar/account.navitem.jsx'; -import ErrorNavItem from '@navbar/error-navitem.jsx'; -import HelpNavItem from '@navbar/help.navitem.jsx'; -import VaultNavItem from '@navbar/vault.navitem.jsx'; -import PrintNavItem from '@navbar/print.navitem.jsx'; +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import NewBrewItem from '@navbar/newbrew.navitem.jsx'; +import AccountNavItem from '@navbar/account.navitem.jsx'; +import ErrorNavItem from '@navbar/error-navitem.jsx'; +import HelpNavItem from '@navbar/help.navitem.jsx'; +import VaultNavItem from '@navbar/vault.navitem.jsx'; +import PrintNavItem from '@navbar/print.navitem.jsx'; import RecentNavItems from '@navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; @@ -61,6 +63,23 @@ const NewPage = (props)=>{ const trySaveRef = useRef(null); // 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 { + handleBrewChange + } = useCommonEditPageFunctions({ + setError, + setThemeBundle, + HTMLErrors, + setHTMLErrors, + setCurrentBrew, + useLocalStorage, + BREWKEY, + STYLEKEY, + SNIPKEY, + METAKEY, + fetchThemeBundle, + hbfm + }); + useEffect(()=>{ loadBrew(); fetchThemeBundle(setError, setThemeBundle, currentBrew.renderer, currentBrew.theme); @@ -127,29 +146,6 @@ const NewPage = (props)=>{ editorRef.current.update(); }; - const handleBrewChange = (field)=>(value, subfield)=>{ //'text', 'style', 'snippets', 'metadata' - if(subfield == 'renderer' || subfield == 'theme') - fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme); - - //If there are HTML errors, run the validator on every change to give quick feedback - if(HTMLErrors.length && (field == 'text' || field == 'snippets')) - setHTMLErrors(hbfm.validate(value)); - - if(field == 'metadata') setCurrentBrew((prev)=>({ ...prev, ...value })); - else setCurrentBrew((prev)=>({ ...prev, [field]: value })); - - if(useLocalStorage) { - if(field == 'text') localStorage.setItem(BREWKEY, value); - if(field == 'style') localStorage.setItem(STYLEKEY, value); - if(field == 'snippets') localStorage.setItem(SNIPKEY, value); - if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({ - renderer : value.renderer, - theme : value.theme, - lang : value.lang - })); - } - }; - const trySave = async ()=>{ setIsSaving(true); diff --git a/client/homebrew/utils/commonEditPageFunctions.js b/client/homebrew/utils/commonEditPageFunctions.js new file mode 100644 index 000000000..bf397e334 --- /dev/null +++ b/client/homebrew/utils/commonEditPageFunctions.js @@ -0,0 +1,43 @@ +export default function useCommonEditPageFunctions(dependencies) { + const { + setError, + setThemeBundle, + HTMLErrors, + setHTMLErrors, + setCurrentBrew, + useLocalStorage, + BREWKEY, + STYLEKEY, + SNIPKEY, + METAKEY, + fetchThemeBundle, + hbfm + } = dependencies; + + const handleBrewChange = (field)=>(value, subfield)=>{ //'text', 'style', 'snippets', 'metadata' + if(subfield == 'renderer' || subfield == 'theme') + fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme); + + //If there are HTML errors, run the validator on every change to give quick feedback + if(HTMLErrors.length && (field == 'text' || field == 'snippets')) + setHTMLErrors(hbfm.validate(value)); + + if(field == 'metadata') setCurrentBrew((prev)=>({ ...prev, ...value })); + else setCurrentBrew((prev)=>({ ...prev, [field]: value })); + + if(useLocalStorage) { + if(field == 'text') localStorage.setItem(BREWKEY, value); + if(field == 'style') localStorage.setItem(STYLEKEY, value); + if(field == 'snippets') localStorage.setItem(SNIPKEY, value); + if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({ + renderer : value.renderer, + theme : value.theme, + lang : value.lang + })); + } + }; + + return { + handleBrewChange + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8309fba77..f7d138beb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12085,21 +12085,6 @@ "url": "https://opencollective.com/mongoose" } }, - "node_modules/mongoose/node_modules/gcp-metadata": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", - "integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/mongoose/node_modules/mongodb": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.5.0.tgz",