diff --git a/app/schedule/page.tsx b/app/schedule/page.tsx
index e563699..de28b3d 100644
--- a/app/schedule/page.tsx
+++ b/app/schedule/page.tsx
@@ -10,22 +10,25 @@ import { isOnboardingComplete } from "@/lib/userStore"
export default function Schedule() {
const { data: session, status } = useSession()
const router = useRouter()
- const [isLoading, setIsLoading] = useState(true)
+ const [mounted, setMounted] = useState(false)
+
+ useEffect(() => {
+ // eslint-disable-next-line react-hooks/set-state-in-effect
+ setMounted(true)
+ }, [])
+
+ const email = session?.user?.email;
+ const isRedirecting = status === "unauthenticated" || (status === "authenticated" && !!email && !isOnboardingComplete(email))
useEffect(() => {
if (status === "unauthenticated") {
router.push("/login")
- } else if (status === "authenticated" && session?.user?.email) {
- const email = session?.user?.email;
- if (email && !isOnboardingComplete(email)) {
- router.push("/onboarding")
- } else {
- setIsLoading(false)
- }
+ } else if (status === "authenticated" && email && !isOnboardingComplete(email)) {
+ router.push("/onboarding")
}
- }, [status, session, router])
+ }, [status, email, router])
- if (status === "loading" || isLoading) {
+ if (status === "loading" || isRedirecting || !mounted) {
return (
diff --git a/components/ThemeProvider.tsx b/components/ThemeProvider.tsx
index 6f75f31..e83e171 100644
--- a/components/ThemeProvider.tsx
+++ b/components/ThemeProvider.tsx
@@ -14,23 +14,32 @@ interface ThemeContextType {
const ThemeContext = createContext(undefined)
export function ThemeProvider({ children }: { children: React.ReactNode }) {
- const [theme, setThemeState] = useState("dark")
+ const [themeState, setThemeState] = useState(null)
const [mounted, setMounted] = useState(false)
// Initialize theme from localStorage or system preference
useEffect(() => {
- const savedTheme = localStorage.getItem("theme") as Theme | null
- if (savedTheme) {
- setThemeState(savedTheme)
- } else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
- setThemeState("dark")
- } else {
- setThemeState("light")
- }
+ // eslint-disable-next-line react-hooks/set-state-in-effect
setMounted(true)
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
+ let derivedTheme: Theme = "dark"
+ if (mounted) {
+ if (themeState) {
+ derivedTheme = themeState
+ } else {
+ const savedTheme = localStorage.getItem("theme") as Theme | null
+ if (savedTheme) {
+ derivedTheme = savedTheme
+ } else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
+ derivedTheme = "dark"
+ } else {
+ derivedTheme = "light"
+ }
+ }
+ }
+ const theme = derivedTheme;
+
// Apply theme class to document
useEffect(() => {
if (!mounted) return
diff --git a/lib/i18n.tsx b/lib/i18n.tsx
index 3ebccd5..b6a8095 100644
--- a/lib/i18n.tsx
+++ b/lib/i18n.tsx
@@ -823,17 +823,18 @@ const translations: Record> = {
// ... (translations object remains unchanged) ...
export function LanguageProvider({ children }: { children: React.ReactNode }) {
- const [language, setLanguageState] = useState("English")
+ const [languageState, setLanguageState] = useState(null)
+ const [mounted, setMounted] = useState(false)
// Load from storage on mount
useEffect(() => {
- const profile = getUserProfile()
- if (profile?.language) {
- setLanguageState(profile.language)
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
+ // eslint-disable-next-line react-hooks/set-state-in-effect
+ setMounted(true)
}, [])
+ const profile = mounted ? getUserProfile() : null
+ const language = languageState || profile?.language || "English"
+
const setLanguage = (lang: Language) => {
setLanguageState(lang)
// Persistence is handled by the calling component (Profile page) or we could move it here