From 170380fe09357bb64756683ad0826b25b7441678 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Wed, 9 Jul 2025 21:27:00 -0600 Subject: [PATCH] bust storage update --- .../ui/layouts/AppSplitter/AppSplitter.tsx | 2 +- apps/web/src/hooks/useLocalStorageState.tsx | 35 ++++++++++--------- .../ChatLayout/ChatLayout/ChatLayout.tsx | 4 ++- .../FileContainer/FileContainer.tsx | 9 ++++- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/apps/web/src/components/ui/layouts/AppSplitter/AppSplitter.tsx b/apps/web/src/components/ui/layouts/AppSplitter/AppSplitter.tsx index 4e5dbd371..4ccf6b6dd 100644 --- a/apps/web/src/components/ui/layouts/AppSplitter/AppSplitter.tsx +++ b/apps/web/src/components/ui/layouts/AppSplitter/AppSplitter.tsx @@ -37,7 +37,7 @@ interface IAppSplitterProps { hideSplitter?: boolean; leftPanelClassName?: string; rightPanelClassName?: string; - bustStorageOnInit?: boolean; + bustStorageOnInit?: boolean | ((preservedSideValue: number | null) => boolean); renderLeftPanel?: boolean; renderRightPanel?: boolean; } diff --git a/apps/web/src/hooks/useLocalStorageState.tsx b/apps/web/src/hooks/useLocalStorageState.tsx index e95abf72f..9f7cf4584 100644 --- a/apps/web/src/hooks/useLocalStorageState.tsx +++ b/apps/web/src/hooks/useLocalStorageState.tsx @@ -19,7 +19,7 @@ interface Options { serializer?: (value: T) => string; deserializer?: (value: string) => T; onError?: (error: unknown) => void; - bustStorageOnInit?: boolean; + bustStorageOnInit?: boolean | ((layout: T) => boolean); expirationTime?: number; } @@ -38,15 +38,20 @@ export function useLocalStorageState( // Get initial value from localStorage or use default const getInitialValue = useMemoizedFn((): T | undefined => { - // If bustStorageOnInit is true, ignore localStorage and use default value - if (bustStorageOnInit) { + const letsBusterTheStorageBaby = () => { + window.localStorage.removeItem(key); return typeof defaultValue === 'function' ? (defaultValue as () => T)() : defaultValue; + }; + + // If bustStorageOnInit is true, ignore localStorage and use default value + if (bustStorageOnInit === true) { + return letsBusterTheStorageBaby(); } try { const item = window.localStorage.getItem(key); if (item === null) { - return typeof defaultValue === 'function' ? (defaultValue as () => T)() : defaultValue; + return letsBusterTheStorageBaby(); } // Parse the stored data which includes value and timestamp @@ -60,8 +65,7 @@ export function useLocalStorageState( !('timestamp' in storageData) ) { // If the data doesn't have the expected structure (legacy data), treat as expired - window.localStorage.removeItem(key); - return typeof defaultValue === 'function' ? (defaultValue as () => T)() : defaultValue; + return letsBusterTheStorageBaby(); } // Check if the data has expired @@ -70,21 +74,20 @@ export function useLocalStorageState( if (timeDifference > expirationTime) { // Data has expired, remove it and return default value - window.localStorage.removeItem(key); - return typeof defaultValue === 'function' ? (defaultValue as () => T)() : defaultValue; + return letsBusterTheStorageBaby(); } // Data is still valid, deserialize and return the value - return deserializer(JSON.stringify(storageData.value)); + const deserializedValue = deserializer(JSON.stringify(storageData.value)); + + if (typeof bustStorageOnInit === 'function' && bustStorageOnInit(deserializedValue)) { + return letsBusterTheStorageBaby(); + } + + return deserializedValue; } catch (error) { onError?.(error); - // If there's an error, clean up the invalid data and return default - try { - window.localStorage.removeItem(key); - } catch (cleanupError) { - onError?.(cleanupError); - } - return typeof defaultValue === 'function' ? (defaultValue as () => T)() : defaultValue; + return letsBusterTheStorageBaby(); } }); diff --git a/apps/web/src/layouts/ChatLayout/ChatLayout/ChatLayout.tsx b/apps/web/src/layouts/ChatLayout/ChatLayout/ChatLayout.tsx index 3991e727b..03e979613 100644 --- a/apps/web/src/layouts/ChatLayout/ChatLayout/ChatLayout.tsx +++ b/apps/web/src/layouts/ChatLayout/ChatLayout/ChatLayout.tsx @@ -38,7 +38,9 @@ export const ChatLayout: React.FC = ({ children }) => { const rightPanelMaxSize = selectedLayout === 'chat-only' ? '0px' : undefined; const renderLeftPanel = selectedLayout !== 'file-only'; const renderRightPanel = selectedLayout !== 'chat-only'; - const bustStorageOnInit = selectedLayout === 'chat-only' || selectedLayout === 'file-only'; + const secondaryFileView = chatLayoutProps.secondaryView; + const bustStorageOnInit = + selectedLayout === 'chat-only' || selectedLayout === 'file-only' || !!secondaryFileView; useMount(() => { setMounted(true); //we need to wait for the app splitter to be mounted because this is nested in the app splitter diff --git a/apps/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx b/apps/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx index 88981d393..854f2a722 100644 --- a/apps/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx +++ b/apps/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx @@ -89,6 +89,13 @@ export const FileContainer: React.FC = ({ children }) => { }, 20); }, [isOpenSecondary]); + const bustStorageOnInit = useMemoizedFn((layout: number | null) => { + if (selectedFileViewRenderSecondary && !layout) { + return true; + } + return !debouncedSelectedFileViewSecondary; + }); + return ( = ({ children }) => { preserveSide={'right'} rightPanelMinSize={250} rightPanelMaxSize={385} - bustStorageOnInit={!debouncedSelectedFileViewSecondary} + bustStorageOnInit={bustStorageOnInit} /> );