From e6ae9d6b1edbc84d4bdad6a01d113881014ef9aa Mon Sep 17 00:00:00 2001 From: Ryan Westfall Date: Wed, 29 Jul 2026 04:04:35 -0700 Subject: [PATCH] Fix mobile white screen: stop Outlet Date.now() remount loop (#54) (#56) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Follow-up for #54 (localStorage guard in #55 did not fix mobile white screen) - Confirmed in production bundle: `ProtectedRoutes` rendered `` - That remounts the entire authenticated tree on **every** parent re-render (account fetch, WebSocket connect/status, conversations, messages) - On mobile this shows as: brief UI flash → solid white page (matches screen recording) - Also memoize styled-components theme in `GlobalThemeWrapper` so `ParticleBackground` does not tear down/restart its canvas on unrelated re-renders ## Evidence Production JS currently contains: ```js e?(0,ma.jsx)(a.sv,{},Date.now()):(0,ma.jsx)(a.C5,{to:"/signin/",replace:!0}) ``` i.e. authenticated → `` ## Test plan - [ ] Mobile Vivaldi/Chrome: sign in on hesychia.ai → dashboard stays visible (header, conversations toggle, input) - [ ] Pull-to-refresh while logged in → UI returns and stays - [ ] Desktop login still works; switching conversations / WS reconnect does not blank the page - [ ] Open mobile menu / Conversations sidebar still worksReviewed-on: https://git.aimloperations.com/ai_ml_operations/chat_web_app/pulls/56 --- llm-fe/src/App.tsx | 2 +- .../GlobalThemeWrapper/GlobalThemeWrapper.tsx | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/llm-fe/src/App.tsx b/llm-fe/src/App.tsx index 50a46d8..884c2a5 100644 --- a/llm-fe/src/App.tsx +++ b/llm-fe/src/App.tsx @@ -34,7 +34,7 @@ const ProtectedRoutes = () => { if (!authenticated) return //if(!needsNewPassword) return - return + return } diff --git a/llm-fe/src/llm-fe/components/GlobalThemeWrapper/GlobalThemeWrapper.tsx b/llm-fe/src/llm-fe/components/GlobalThemeWrapper/GlobalThemeWrapper.tsx index 7264ead..2e8a688 100644 --- a/llm-fe/src/llm-fe/components/GlobalThemeWrapper/GlobalThemeWrapper.tsx +++ b/llm-fe/src/llm-fe/components/GlobalThemeWrapper/GlobalThemeWrapper.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import { ThemeProvider } from 'styled-components'; import { useMaterialUIController } from '../../ui-kit/context'; import palettes from '../../ui-kit/assets/theme/base/palettes'; @@ -11,21 +11,21 @@ const GlobalThemeWrapper = ({ children }: GlobalThemeWrapperProps): JSX.Element const [controller] = useMaterialUIController(); const { themeColor, darkMode } = controller; - // Default to blue if themeColor is not found - const selectedPalette = palettes[themeColor as keyof typeof palettes] || palettes.blue; - - const theme = { - main: selectedPalette.main, - focus: selectedPalette.focus, - darkMode: darkMode, - // Add other global theme variables here if needed - colors: { - background: darkMode ? '#1a2035' : '#f0f2f5', - text: darkMode ? '#ffffff' : '#344767', - cardBackground: darkMode ? 'rgba(0, 0, 0, 0.4)' : 'rgba(255, 255, 255, 0.8)', - cardBorder: darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.05)', - } - }; + // Stable theme ref — ParticleBackground restarts its canvas whenever theme identity changes. + const theme = useMemo(() => { + const selectedPalette = palettes[themeColor as keyof typeof palettes] || palettes.blue; + return { + main: selectedPalette.main, + focus: selectedPalette.focus, + darkMode: darkMode, + colors: { + background: darkMode ? '#1a2035' : '#f0f2f5', + text: darkMode ? '#ffffff' : '#344767', + cardBackground: darkMode ? 'rgba(0, 0, 0, 0.4)' : 'rgba(255, 255, 255, 0.8)', + cardBorder: darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.05)', + } + }; + }, [themeColor, darkMode]); return (