import { useCallback, useEffect, useRef, useState, type UIEvent } from "react"; import { useQuery } from "@tanstack/react-query"; import { BookOpen } from "lucide-react"; import { Outlet } from "react-router-dom"; import { CompanyRail } from "./CompanyRail"; import { Sidebar } from "./Sidebar"; import { SidebarNavItem } from "./SidebarNavItem"; import { BreadcrumbBar } from "./BreadcrumbBar"; import { PropertiesPanel } from "./PropertiesPanel"; import { CommandPalette } from "./CommandPalette"; import { NewIssueDialog } from "./NewIssueDialog"; import { NewProjectDialog } from "./NewProjectDialog"; import { NewGoalDialog } from "./NewGoalDialog"; import { NewAgentDialog } from "./NewAgentDialog"; import { OnboardingWizard } from "./OnboardingWizard"; import { ToastViewport } from "./ToastViewport"; import { MobileBottomNav } from "./MobileBottomNav"; import { useDialog } from "../context/DialogContext"; import { usePanel } from "../context/PanelContext"; import { useCompany } from "../context/CompanyContext"; import { useSidebar } from "../context/SidebarContext"; import { useKeyboardShortcuts } from "../hooks/useKeyboardShortcuts"; import { useCompanyPageMemory } from "../hooks/useCompanyPageMemory"; import { healthApi } from "../api/health"; import { queryKeys } from "../lib/queryKeys"; import { cn } from "../lib/utils"; export function Layout() { const { sidebarOpen, setSidebarOpen, toggleSidebar, isMobile } = useSidebar(); const { openNewIssue, openOnboarding } = useDialog(); const { panelContent, closePanel } = usePanel(); const { companies, loading: companiesLoading, setSelectedCompanyId } = useCompany(); const onboardingTriggered = useRef(false); const lastMainScrollTop = useRef(0); const [mobileNavVisible, setMobileNavVisible] = useState(true); const { data: health } = useQuery({ queryKey: queryKeys.health, queryFn: () => healthApi.get(), retry: false, }); useEffect(() => { if (companiesLoading || onboardingTriggered.current) return; if (health?.deploymentMode === "authenticated") return; if (companies.length === 0) { onboardingTriggered.current = true; openOnboarding(); } }, [companies, companiesLoading, openOnboarding, health?.deploymentMode]); const togglePanel = useCallback(() => { if (panelContent) closePanel(); }, [panelContent, closePanel]); // Cmd+1..9 to switch companies const switchCompany = useCallback( (index: number) => { if (index < companies.length) { setSelectedCompanyId(companies[index]!.id); } }, [companies, setSelectedCompanyId], ); useCompanyPageMemory(); useKeyboardShortcuts({ onNewIssue: () => openNewIssue(), onToggleSidebar: toggleSidebar, onTogglePanel: togglePanel, onSwitchCompany: switchCompany, }); useEffect(() => { if (!isMobile) { setMobileNavVisible(true); return; } lastMainScrollTop.current = 0; setMobileNavVisible(true); }, [isMobile]); const handleMainScroll = useCallback( (event: UIEvent) => { if (!isMobile) return; const currentTop = event.currentTarget.scrollTop; const delta = currentTop - lastMainScrollTop.current; if (currentTop <= 24) { setMobileNavVisible(true); } else if (delta > 8) { setMobileNavVisible(false); } else if (delta < -8) { setMobileNavVisible(true); } lastMainScrollTop.current = currentTop; }, [isMobile], ); return (
{/* Mobile backdrop */} {isMobile && sidebarOpen && (
setSidebarOpen(false)} /> )} {/* Combined sidebar area: company rail + inner sidebar + docs bar */} {isMobile ? (
) : (
)} {/* Main content */}
{isMobile && }
); }