|
1 | 1 | "use client" |
2 | 2 |
|
3 | 3 | import { lazy, Suspense, useCallback, useEffect, useRef, useState } from "react" |
| 4 | + |
| 5 | +/** Delay before showing unauthenticated overlay/redirect so auth persistence can restore (avoids sidebar flash). */ |
| 6 | +const AUTH_SETTLE_MS = 220 |
4 | 7 | import { usePathname } from "next/navigation" |
5 | 8 | import { Sidebar } from "@/components/app/Sidebar" |
6 | 9 | import { ErrorBoundary } from "@/components/app/ErrorBoundary" |
@@ -34,11 +37,29 @@ function readCachedOnboardingSnapshot(): { required: boolean; memory: Record<str |
34 | 37 | function AuthGate({ children }: { children: React.ReactNode }) { |
35 | 38 | const COLORS = useThemeColors() |
36 | 39 | const { user, loading } = useAuth() |
| 40 | + const [showUnauthOverlay, setShowUnauthOverlay] = useState(false) |
| 41 | + const settleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null) |
37 | 42 |
|
38 | 43 | useEffect(() => { |
39 | | - if (!loading && !user) { |
| 44 | + if (loading || user) { |
| 45 | + if (settleTimerRef.current) { |
| 46 | + clearTimeout(settleTimerRef.current) |
| 47 | + settleTimerRef.current = null |
| 48 | + } |
| 49 | + setShowUnauthOverlay(false) |
| 50 | + return |
| 51 | + } |
| 52 | + settleTimerRef.current = setTimeout(() => { |
| 53 | + settleTimerRef.current = null |
| 54 | + setShowUnauthOverlay(true) |
40 | 55 | try { sessionStorage.setItem("fp-auth-redirect", window.location.pathname) } catch {} |
41 | 56 | window.location.href = "/" |
| 57 | + }, AUTH_SETTLE_MS) |
| 58 | + return () => { |
| 59 | + if (settleTimerRef.current) { |
| 60 | + clearTimeout(settleTimerRef.current) |
| 61 | + settleTimerRef.current = null |
| 62 | + } |
42 | 63 | } |
43 | 64 | }, [loading, user]) |
44 | 65 |
|
@@ -67,13 +88,13 @@ function AuthGate({ children }: { children: React.ReactNode }) { |
67 | 88 | </div> |
68 | 89 | ) |
69 | 90 |
|
70 | | - // Always render the shell (sidebar, main, topbar, input) so it stays in the DOM and cached — |
71 | | - // no unmount on auth loading, so no black flash or sidebar disappearing when switching pages. |
72 | | - // Only overlay the redirect message when we're sure the user is not authenticated. |
| 91 | + // Always render the shell (sidebar, main, topbar, input) so it stays visible and cached. |
| 92 | + // Only show redirect overlay after auth has "settled" as unauthenticated (short delay |
| 93 | + // so Firebase persistence can restore the session and we don't flash-hide the sidebar). |
73 | 94 | return ( |
74 | 95 | <> |
75 | 96 | {children} |
76 | | - {!loading && !user ? renderGateStatus("Redirecting to sign-in...") : null} |
| 97 | + {showUnauthOverlay ? renderGateStatus("Redirecting to sign-in...") : null} |
77 | 98 | </> |
78 | 99 | ) |
79 | 100 | } |
|
0 commit comments