"use client"; import { useState, useEffect } from "react"; import Sidebar from "@/components/Sidebar"; import Topbar from "@/components/Topbar"; import ReadOnlyAccessNotice from "@/components/ReadOnlyAccessNotice"; import ReadOnlyActionScope from "@/components/ReadOnlyActionScope"; import { useCurrentUser, useRequireAuth } from "@/lib/auth-state"; import { addPreferencesListener, getStoredPanelName } from "@/lib/preferences"; import { getRoleCapabilities } from "@/lib/rbac"; interface DashboardLayoutProps { children: React.ReactNode; title: string; subtitle?: string; } export default function DashboardLayout({ children, title, subtitle, }: DashboardLayoutProps) { const isAuthenticated = useRequireAuth(); const currentUser = useCurrentUser(); const roleCapabilities = getRoleCapabilities(currentUser?.role); const [collapsed, setCollapsed] = useState(false); const [isMobile, setIsMobile] = useState(false); const [mobileOpen, setMobileOpen] = useState(false); useEffect(() => { const checkMobile = () => { const mobile = window.innerWidth < 768; setIsMobile(mobile); if (mobile) setCollapsed(true); }; checkMobile(); window.addEventListener("resize", checkMobile); return () => window.removeEventListener("resize", checkMobile); }, []); useEffect(() => { const syncTitle = () => { document.title = `${title} | ${getStoredPanelName()}`; }; syncTitle(); return addPreferencesListener(syncTitle); }, [title]); if (!isAuthenticated) { return null; } return (
{/* Floating particles */}
{[...Array(8)].map((_, i) => (
))}
{/* Sidebar — handles its own backdrop overlay for mobile */} setCollapsed(!collapsed)} isMobile={isMobile} mobileOpen={mobileOpen} onMobileClose={() => setMobileOpen(false)} /> {/* Main content area */}
setMobileOpen(!mobileOpen) : undefined } />
{roleCapabilities.isReadOnly ? : null} {children}
); }