Fix sidebar hydration flash
This commit is contained in:
32
components/providers/sidebar-preference-provider.tsx
Normal file
32
components/providers/sidebar-preference-provider.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
'use client';
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
type SidebarPreferenceContextValue = {
|
||||
initialSidebarCollapsed: boolean;
|
||||
};
|
||||
|
||||
const SidebarPreferenceContext =
|
||||
createContext<SidebarPreferenceContextValue>({
|
||||
initialSidebarCollapsed: false
|
||||
});
|
||||
|
||||
type SidebarPreferenceProviderProps = {
|
||||
children: React.ReactNode;
|
||||
initialSidebarCollapsed: boolean;
|
||||
};
|
||||
|
||||
export function SidebarPreferenceProvider({
|
||||
children,
|
||||
initialSidebarCollapsed
|
||||
}: SidebarPreferenceProviderProps) {
|
||||
return (
|
||||
<SidebarPreferenceContext.Provider value={{ initialSidebarCollapsed }}>
|
||||
{children}
|
||||
</SidebarPreferenceContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useSidebarPreference() {
|
||||
return useContext(SidebarPreferenceContext);
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { TaskDetailModal } from "@/components/notifications/task-detail-modal";
|
||||
import { TaskNotificationsTrigger } from "@/components/notifications/task-notifications-trigger";
|
||||
import { useSidebarPreference } from "@/components/providers/sidebar-preference-provider";
|
||||
import {
|
||||
companyAnalysisQueryOptions,
|
||||
companyFinancialStatementsQueryOptions,
|
||||
@@ -37,6 +38,7 @@ import { buildGraphingHref } from "@/lib/graphing/catalog";
|
||||
import type { ActiveContext, NavGroup, NavItem } from "@/lib/types";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useTaskNotificationsCenter } from "@/hooks/use-task-notifications-center";
|
||||
import { SIDEBAR_PREFERENCE_KEY } from "@/lib/sidebar-preference";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type AppShellProps = {
|
||||
@@ -148,8 +150,6 @@ const GROUP_LABELS: Record<NavGroup, string> = {
|
||||
portfolio: "Portfolio",
|
||||
};
|
||||
|
||||
const SIDEBAR_PREFERENCE_KEY = "fiscal-shell-sidebar-collapsed";
|
||||
|
||||
function normalizeTicker(value: string | null | undefined) {
|
||||
const normalized = value?.trim().toUpperCase() ?? "";
|
||||
return normalized.length > 0 ? normalized : null;
|
||||
@@ -260,12 +260,16 @@ export function AppShell({
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const queryClient = useQueryClient();
|
||||
const { initialSidebarCollapsed } = useSidebarPreference();
|
||||
|
||||
const [isSigningOut, setIsSigningOut] = useState(false);
|
||||
const [isMoreOpen, setIsMoreOpen] = useState(false);
|
||||
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
|
||||
const [hasLoadedSidebarPreference, setHasLoadedSidebarPreference] =
|
||||
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(
|
||||
initialSidebarCollapsed,
|
||||
);
|
||||
const [hasResolvedSidebarPreference, setHasResolvedSidebarPreference] =
|
||||
useState(false);
|
||||
const [hasMounted, setHasMounted] = useState(false);
|
||||
const notifications = useTaskNotificationsCenter();
|
||||
const { data: session } = authClient.useSession();
|
||||
const sessionUser = (session?.user ?? null) as {
|
||||
@@ -433,14 +437,14 @@ export function AppShell({
|
||||
const storedPreference = window.localStorage.getItem(
|
||||
SIDEBAR_PREFERENCE_KEY,
|
||||
);
|
||||
if (storedPreference === "true") {
|
||||
setIsSidebarCollapsed(true);
|
||||
if (storedPreference === "true" || storedPreference === "false") {
|
||||
setIsSidebarCollapsed(storedPreference === "true");
|
||||
}
|
||||
setHasLoadedSidebarPreference(true);
|
||||
setHasResolvedSidebarPreference(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasLoadedSidebarPreference) {
|
||||
if (!hasResolvedSidebarPreference) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -448,7 +452,12 @@ export function AppShell({
|
||||
SIDEBAR_PREFERENCE_KEY,
|
||||
String(isSidebarCollapsed),
|
||||
);
|
||||
}, [hasLoadedSidebarPreference, isSidebarCollapsed]);
|
||||
document.cookie = `${SIDEBAR_PREFERENCE_KEY}=${String(isSidebarCollapsed)}; path=/; max-age=31536000; samesite=lax`;
|
||||
}, [hasResolvedSidebarPreference, isSidebarCollapsed]);
|
||||
|
||||
useEffect(() => {
|
||||
setHasMounted(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const browserWindow = window as Window & {
|
||||
@@ -520,7 +529,8 @@ export function AppShell({
|
||||
>
|
||||
<aside
|
||||
className={cn(
|
||||
"hidden shrink-0 flex-col gap-4 border-r border-[color:var(--line-weak)] transition-[width,padding] duration-200 lg:flex",
|
||||
"hidden shrink-0 flex-col gap-4 border-r border-[color:var(--line-weak)] lg:flex",
|
||||
hasMounted ? "transition-[width,padding] duration-200" : "",
|
||||
isSidebarCollapsed ? "w-16 pr-1" : "w-72 pr-4",
|
||||
)}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user