'use client' import { useState, useCallback, useEffect, useRef } from 'react' import dynamic from 'next/dynamic' import { formatUpdatedAgo } from '@ciphera-net/ui' import { SidebarSimple } from '@phosphor-icons/react' import { SidebarProvider, useSidebar } from '@/lib/sidebar-context' import { useRealtime } from '@/lib/swr/dashboard' import ContentHeader from './ContentHeader' // Load sidebar only on the client โ€” prevents SSR flash const Sidebar = dynamic(() => import('./Sidebar'), { ssr: false, loading: () => (
), }) function GlassTopBar({ siteId }: { siteId: string }) { const { collapsed, toggle } = useSidebar() const { data: realtime } = useRealtime(siteId) const lastUpdatedRef = useRef(null) const [, setTick] = useState(0) useEffect(() => { if (realtime) lastUpdatedRef.current = Date.now() }, [realtime]) useEffect(() => { if (lastUpdatedRef.current == null) return const timer = setInterval(() => setTick((t) => t + 1), 1000) return () => clearInterval(timer) }, [realtime]) return (
{/* Collapse toggle โ€” mirrors sidebar AppLauncher row sizing for pixel alignment */} {/* Realtime indicator */} {lastUpdatedRef.current != null && (
Live ยท {formatUpdatedAgo(lastUpdatedRef.current)}
)}
) } export default function DashboardShell({ siteId, children, }: { siteId: string children: React.ReactNode }) { const [mobileOpen, setMobileOpen] = useState(false) const closeMobile = useCallback(() => setMobileOpen(false), []) const openMobile = useCallback(() => setMobileOpen(true), []) return (
{/* Glass top bar โ€” above content only, collapse icon reaches back into sidebar column */} {/* Content panel */}
{children}
) }