From a7e3f6b8da6d70c93c4ced29f2d16e2cfd597da5 Mon Sep 17 00:00:00 2001 From: d-nieto246 Date: Fri, 14 Jun 2024 15:31:25 -0400 Subject: [PATCH 1/2] Second fix for back button The same pull request as https://github.com/vizhub-core/vzcode/pull/740 but in a new branch called "new-fix-back-button" so everything merged into main works along with my changes. --- src/client/useURLSync.ts | 108 +++++++++++++++------------------------ 1 file changed, 40 insertions(+), 68 deletions(-) diff --git a/src/client/useURLSync.ts b/src/client/useURLSync.ts index 5e81eec0..b5ca1d2d 100644 --- a/src/client/useURLSync.ts +++ b/src/client/useURLSync.ts @@ -10,65 +10,47 @@ import { // Synchronizes the tab state with the URL parameters. export const useURLSync = ({ - content, - openTab, - setActiveFileId, - tabList, - activeFileId, -}: { + content, + openTab, + setActiveFileId, + tabList, + activeFileId, + }: { content: VZCodeContent | null; openTab: (tabState: TabState) => void; setActiveFileId: (activeFileId: FileId) => void; tabList: Array; activeFileId: FileId | null; }) => { - // Use React router to get and set the search parameters. + // Use React router to get and set the search parameters. const [searchParams, setSearchParams] = useSearchParams(); // Extract the tab state parameters from the search parameters. const tabStateParams: TabStateParams = useMemo( - () => ({ - file: searchParams.get('file'), - tabs: searchParams.get('tabs'), - }), - [searchParams], + () => ({ + file: searchParams.get('file'), + tabs: searchParams.get('tabs'), + }), + [searchParams], ); - // `true` after the state is updated based on the - // initial search parameters from the URL. - const isInitialized = useRef(false); - // Initialize the state based on the search parameters. useEffect(() => { - // Do nothing if the state has already been initialized. - if (isInitialized.current) { - return; - } - // Wait for the content to be loaded. if (!content) { return; } // Decode the search parameters. - const { tabList, activeFileId } = decodeTabs({ + const { tabList: decodedTabList, activeFileId: decodedActiveFileId } = decodeTabs({ tabStateParams, content, }); - // Mark the state as initialized. - isInitialized.current = true; - // Update the state. - tabList.forEach(openTab); - setActiveFileId(activeFileId); - }, [ - content, - searchParams, - setActiveFileId, - openTab, - isInitialized, - ]); + decodedTabList.forEach(openTab); + setActiveFileId(decodedActiveFileId); + }, [content, tabStateParams, setActiveFileId, openTab]); // Track content in a ref so that we can use it in the // effect below without triggering the effect when @@ -78,7 +60,7 @@ export const useURLSync = ({ contentRef.current = content; }, [content]); - // track setSearchParams in a ref so that we can use it in the + // Track setSearchParams in a ref so that we can use it in the // effect below without triggering the effect on each render. // The definition of `setSearchParams` changes on every render. const setSearchParamsRef = useRef(setSearchParams); @@ -102,36 +84,26 @@ export const useURLSync = ({ }); // Update the URL if the search parameters have changed. - setSearchParamsRef.current( - (oldSearchParams: URLSearchParams) => { - // Create a copy of the old search params - const updatedSearchParams = new URLSearchParams( - oldSearchParams, - ); - - // Set the 'file' parameter - if (newTabStateParams.file) { - updatedSearchParams.set( - 'file', - newTabStateParams.file, - ); - } else { - updatedSearchParams.delete('file'); // Remove 'file' if it's not present in newTabStateParams - } - - // Set the 'tabs' parameter - if (newTabStateParams.tabs) { - updatedSearchParams.set( - 'tabs', - newTabStateParams.tabs, - ); - } else { - updatedSearchParams.delete('tabs'); // Remove 'tabs' if it's not present in newTabStateParams - } - - // Return the updated search params - return updatedSearchParams; - }, - ); - }, [tabList, activeFileId]); -}; + setSearchParamsRef.current((oldSearchParams: URLSearchParams) => { + // Create a copy of the old search params + const updatedSearchParams = new URLSearchParams(oldSearchParams); + + // Set the 'file' parameter + if (newTabStateParams.file) { + updatedSearchParams.set('file', newTabStateParams.file); + } else { + updatedSearchParams.delete('file'); // Remove 'file' if it's not present in newTabStateParams + } + + // Set the 'tabs' parameter + if (newTabStateParams.tabs) { + updatedSearchParams.set('tabs', newTabStateParams.tabs); + } else { + updatedSearchParams.delete('tabs'); // Remove 'tabs' if it's not present in newTabStateParams + } + + // Return the updated search params + return updatedSearchParams; + }); + }, [tabList, activeFileId, contentRef]); +}; \ No newline at end of file From d0a87cbfb1869dd28730759c1a65ece692546580 Mon Sep 17 00:00:00 2001 From: d-nieto246 Date: Fri, 21 Jun 2024 14:37:24 -0400 Subject: [PATCH 2/2] Third fix for Back Button The third fix for the back button. --- .idea/workspace.xml | 22 ++++++ src/client/useActions.ts | 40 ++++------ src/client/useURLSync.ts | 95 +++++++++++++++-------- src/client/vzReducer/index.ts | 18 +++-- src/client/vzReducer/setTabListReducer.ts | 13 ++++ 5 files changed, 119 insertions(+), 69 deletions(-) create mode 100644 .idea/workspace.xml create mode 100644 src/client/vzReducer/setTabListReducer.ts diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 00000000..5f8a93ef --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/client/useActions.ts b/src/client/useActions.ts index 2d9d21bf..12fc2392 100644 --- a/src/client/useActions.ts +++ b/src/client/useActions.ts @@ -18,14 +18,6 @@ export const useActions = ( [dispatch], ); - const setActiveFileLeft = useCallback(() => { - dispatch({ type: 'set_active_file_left' }); - }, [dispatch]); - - const setActiveFileRight = useCallback(() => { - dispatch({ type: 'set_active_file_right' }); - }, [dispatch]); - const openTab = useCallback( (tabState: TabState): void => { dispatch({ @@ -57,7 +49,6 @@ export const useActions = ( [dispatch], ); - // True to show the settings modal. const setIsSettingsOpen = useCallback( (value: boolean) => { dispatch({ @@ -68,24 +59,10 @@ export const useActions = ( [dispatch], ); - const setIsDocOpen = useCallback( - (value: boolean) => { - dispatch({ - type: 'set_is_doc_open', - value: value, - }); - }, - [dispatch], - ); - const closeSettings = useCallback(() => { setIsSettingsOpen(false); }, [setIsSettingsOpen]); - const closeDoc = useCallback(() => { - setIsDocOpen(false); - }, [setIsDocOpen]); - const editorNoLongerWantsFocus = useCallback(() => { dispatch({ type: 'editor_no_longer_wants_focus', @@ -102,18 +79,27 @@ export const useActions = ( [dispatch], ); + // New action function for setting the tab list + const setTabList = useCallback( + (tabList: Array) => { + dispatch({ + type: 'set_tab_list', + tabList, + }); + }, + [dispatch], + ); + return { setActiveFileId, - setActiveFileLeft, - setActiveFileRight, openTab, closeTabs, setTheme, setIsSettingsOpen, - setIsDocOpen, closeSettings, - closeDoc, editorNoLongerWantsFocus, setUsername, + setTabList, // Export the new action function }; }; + diff --git a/src/client/useURLSync.ts b/src/client/useURLSync.ts index b5ca1d2d..eae486f8 100644 --- a/src/client/useURLSync.ts +++ b/src/client/useURLSync.ts @@ -8,16 +8,15 @@ import { encodeTabs, } from './tabsSearchParameters'; -// Synchronizes the tab state with the URL parameters. export const useURLSync = ({ content, - openTab, + setTabList, setActiveFileId, tabList, activeFileId, }: { content: VZCodeContent | null; - openTab: (tabState: TabState) => void; + setTabList: (tabList: Array) => void; setActiveFileId: (activeFileId: FileId) => void; tabList: Array; activeFileId: FileId | null; @@ -27,15 +26,24 @@ export const useURLSync = ({ // Extract the tab state parameters from the search parameters. const tabStateParams: TabStateParams = useMemo( - () => ({ - file: searchParams.get('file'), - tabs: searchParams.get('tabs'), - }), - [searchParams], + () => ({ + file: searchParams.get('file'), + tabs: searchParams.get('tabs'), + }), + [searchParams], ); + // `true` after the state is updated based on the + // initial search parameters from the URL. + const isInitialized = useRef(false); + // Initialize the state based on the search parameters. useEffect(() => { + // Do nothing if the state has already been initialized. + if (isInitialized.current) { + return; + } + // Wait for the content to be loaded. if (!content) { return; @@ -47,10 +55,19 @@ export const useURLSync = ({ content, }); + // Mark the state as initialized. + isInitialized.current = true; + // Update the state. - decodedTabList.forEach(openTab); + setTabList(decodedTabList); setActiveFileId(decodedActiveFileId); - }, [content, tabStateParams, setActiveFileId, openTab]); + }, [ + content, + tabStateParams, + setTabList, + setActiveFileId, + isInitialized, + ]); // Track content in a ref so that we can use it in the // effect below without triggering the effect when @@ -60,7 +77,7 @@ export const useURLSync = ({ contentRef.current = content; }, [content]); - // Track setSearchParams in a ref so that we can use it in the + // track setSearchParams in a ref so that we can use it in the // effect below without triggering the effect on each render. // The definition of `setSearchParams` changes on every render. const setSearchParamsRef = useRef(setSearchParams); @@ -84,26 +101,36 @@ export const useURLSync = ({ }); // Update the URL if the search parameters have changed. - setSearchParamsRef.current((oldSearchParams: URLSearchParams) => { - // Create a copy of the old search params - const updatedSearchParams = new URLSearchParams(oldSearchParams); - - // Set the 'file' parameter - if (newTabStateParams.file) { - updatedSearchParams.set('file', newTabStateParams.file); - } else { - updatedSearchParams.delete('file'); // Remove 'file' if it's not present in newTabStateParams - } - - // Set the 'tabs' parameter - if (newTabStateParams.tabs) { - updatedSearchParams.set('tabs', newTabStateParams.tabs); - } else { - updatedSearchParams.delete('tabs'); // Remove 'tabs' if it's not present in newTabStateParams - } - - // Return the updated search params - return updatedSearchParams; - }); - }, [tabList, activeFileId, contentRef]); -}; \ No newline at end of file + setSearchParamsRef.current( + (oldSearchParams: URLSearchParams) => { + // Create a copy of the old search params + const updatedSearchParams = new URLSearchParams( + oldSearchParams, + ); + + // Set the 'file' parameter + if (newTabStateParams.file) { + updatedSearchParams.set( + 'file', + newTabStateParams.file, + ); + } else { + updatedSearchParams.delete('file'); // Remove 'file' if it's not present in newTabStateParams + } + + // Set the 'tabs' parameter + if (newTabStateParams.tabs) { + updatedSearchParams.set( + 'tabs', + newTabStateParams.tabs, + ); + } else { + updatedSearchParams.delete('tabs'); // Remove 'tabs' if it's not present in newTabStateParams + } + + // Return the updated search params + return updatedSearchParams; + }, + ); + }, [tabList, activeFileId]); +}; diff --git a/src/client/vzReducer/index.ts b/src/client/vzReducer/index.ts index 635ac1d0..3a1779cd 100644 --- a/src/client/vzReducer/index.ts +++ b/src/client/vzReducer/index.ts @@ -12,6 +12,7 @@ import { setIsDocOpenReducer } from './setIsDocOpenReducer'; import { setThemeReducer } from './setThemeReducer'; import { editorNoLongerWantsFocusReducer } from './editorNoLongerWantsFocusReducer'; import { setUsernameReducer } from './setUsernameReducer'; +import { setTabListReducer } from './setTabListReducer'; // Imported a new reducer export { createInitialState } from './createInitialState'; @@ -41,8 +42,8 @@ export type VZState = { // The shape of the actions that can be dispatched to the reducer. export type VZAction = - // `set_active_file_id` - // * Sets the active file ID. +// `set_active_file_id` +// * Sets the active file ID. | { type: 'set_active_file_id'; activeFileId: FileId } // `set_active_file_left' 'set_active_file_right` @@ -54,16 +55,16 @@ export type VZAction = // `open_tab` // * Opens a tab. // * Also serves to change an already open transient tab to persistent. - | { - type: 'open_tab'; - fileId: FileId; - isTransient?: boolean; - } + | { type: 'open_tab'; fileId: FileId; isTransient?: boolean; } // `close_tabs` // * Closes a set of tabs. | { type: 'close_tabs'; fileIdsToClose: Array } + // `set_tab_list` + // * Sets the tab list. + | { type: 'set_tab_list'; tabList: Array } + // `set_theme` // * Sets the theme. | { type: 'set_theme'; themeLabel: ThemeLabel } @@ -111,6 +112,7 @@ const reducers = [ setIsDocOpenReducer, editorNoLongerWantsFocusReducer, setUsernameReducer, + setTabListReducer, ]; export const vzReducer = ( @@ -121,4 +123,4 @@ export const vzReducer = ( (currentState, currentReducer) => currentReducer(currentState, action), state, - ); + ); \ No newline at end of file diff --git a/src/client/vzReducer/setTabListReducer.ts b/src/client/vzReducer/setTabListReducer.ts new file mode 100644 index 00000000..60997cfa --- /dev/null +++ b/src/client/vzReducer/setTabListReducer.ts @@ -0,0 +1,13 @@ +// setTabListReducer.ts +import { VZState, VZAction } from './index'; + +export const setTabListReducer = (state: VZState, action: VZAction): VZState => { + if (action.type !== 'set_tab_list') { + return state; + } + + return { + ...state, + tabList: action.tabList, + }; +};