From 597f859e08c023771f678b357cecc79a7a0ec54d Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Wed, 9 Apr 2025 00:47:22 +0000 Subject: [PATCH] Enhance theme switching to handle missing context Replit-Commit-Author: Agent Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/70b9c0b1-a5f0-4a27-9a6a-5bb48b9d90b1.jpg --- client/src/components/theme-toggle.tsx | 18 +++++++ client/src/hooks/use-theme.tsx | 61 ++++++++++++++++++++- client/src/pages/settings-page.tsx | 74 +++++++++++++++++++++----- 3 files changed, 137 insertions(+), 16 deletions(-) diff --git a/client/src/components/theme-toggle.tsx b/client/src/components/theme-toggle.tsx index 60fa977..8bcce77 100644 --- a/client/src/components/theme-toggle.tsx +++ b/client/src/components/theme-toggle.tsx @@ -9,7 +9,25 @@ import { } from "@/components/ui/dropdown-menu"; import { useTheme } from "@/hooks/use-theme"; +// Fallback toggle without context dependency export function ThemeToggle() { + // Try/catch block to handle possible context errors + try { + return ; + } catch (error) { + console.error("Theme context error:", error); + // Fallback rendering without context + return ( + + ); + } +} + +// Component that uses the theme context +function ThemeToggleWithContext() { const { theme, setTheme } = useTheme(); return ( diff --git a/client/src/hooks/use-theme.tsx b/client/src/hooks/use-theme.tsx index ba42e4e..4c242d5 100644 --- a/client/src/hooks/use-theme.tsx +++ b/client/src/hooks/use-theme.tsx @@ -59,8 +59,65 @@ export function ThemeProvider({ export const useTheme = (): ThemeContextType => { const context = useContext(ThemeContext); - if (context === undefined) - throw new Error('useTheme must be used within a ThemeProvider'); + if (context === undefined) { + // Fallback implementation that doesn't rely on context + // This prevents crashes but won't sync across components + const storageKey = 'ad-management-theme'; + const defaultTheme = 'system'; + + // Create a fallback state using localStorage + const getThemeFromStorage = (): Theme => { + try { + const storedTheme = localStorage.getItem(storageKey); + return (storedTheme as Theme) || defaultTheme; + } catch (e) { + return defaultTheme; + } + }; + + const currentTheme = getThemeFromStorage(); + + const applyThemeToDOM = (newTheme: Theme) => { + try { + const root = window.document.documentElement; + root.classList.remove('light', 'dark'); + + if (newTheme === 'system') { + const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches + ? 'dark' + : 'light'; + root.classList.add(systemTheme); + } else { + root.classList.add(newTheme); + } + } catch (e) { + console.error('Error applying theme to DOM:', e); + } + }; + + // Apply the theme immediately for this component + applyThemeToDOM(currentTheme); + + // Return a fallback implementation + return { + theme: currentTheme, + setTheme: (newTheme: Theme) => { + try { + localStorage.setItem(storageKey, newTheme); + applyThemeToDOM(newTheme); + + // We can't update state here because we're not in a React component + // but we can apply the theme directly to the DOM + console.warn( + 'Theme changed outside of ThemeProvider context. ' + + 'This change won\'t be synced between components.' + ); + } catch (e) { + console.error('Error setting theme:', e); + } + } + }; + } return context; }; \ No newline at end of file diff --git a/client/src/pages/settings-page.tsx b/client/src/pages/settings-page.tsx index ac1cdc8..c7cf6d2 100644 --- a/client/src/pages/settings-page.tsx +++ b/client/src/pages/settings-page.tsx @@ -1,3 +1,4 @@ +import { useState, useEffect } from "react"; import { DashboardLayout } from "@/layouts/dashboard-layout"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Switch } from "@/components/ui/switch"; @@ -14,6 +15,64 @@ import { SelectValue } from "@/components/ui/select"; import { Separator } from "@/components/ui/separator"; +import { Moon, Sun, Laptop } from "lucide-react"; + +// Safe theme selector that doesn't throw errors if ThemeProvider is missing +function ThemeSelector() { + const [currentTheme, setCurrentTheme] = useState(() => { + // Read from localStorage or default to system + return localStorage.getItem("ad-management-theme") || "system"; + }); + + const handleThemeChange = (value: string) => { + setCurrentTheme(value); + + try { + // Handle theme change manually if context is missing + localStorage.setItem("ad-management-theme", value); + + const root = window.document.documentElement; + root.classList.remove("light", "dark"); + + if (value === "system") { + const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + root.classList.add(systemTheme); + } else { + root.classList.add(value); + } + } catch (error) { + console.error("Error changing theme:", error); + } + }; + + return ( + +
+ + +
+
+ + +
+
+ + +
+
+ ); +} export default function SettingsPage() { return ( @@ -43,20 +102,7 @@ export default function SettingsPage() {
- -
- - -
-
- - -
-
- - -
-
+