BMS/frontend/components/layout/topbar.tsx
2026-03-19 11:32:17 +00:00

100 lines
3.4 KiB
TypeScript

"use client";
import { Bell, Menu, Moon, Sun } from "lucide-react";
import { SimulatorPanel } from "@/components/simulator/SimulatorPanel";
import { usePathname } from "next/navigation";
import Link from "next/link";
import { UserButton } from "@clerk/nextjs";
import { useTheme } from "next-themes";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { useAlarmCount } from "@/lib/alarm-context";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { Sidebar } from "./sidebar";
const pageTitles: Record<string, string> = {
"/dashboard": "Overview",
"/floor-map": "Floor Map",
"/power": "Power Management",
"/generator": "Generator & Transfer",
"/cooling": "Cooling & Optimisation",
"/environmental": "Environmental Monitoring",
"/leak": "Leak Detection",
"/fire": "Fire & Safety",
"/network": "Network Infrastructure",
"/assets": "Asset Management",
"/alarms": "Alarms & Events",
"/capacity": "Capacity Planning",
"/reports": "Reports",
"/energy": "Energy & Sustainability",
"/maintenance": "Maintenance Windows",
"/settings": "Settings",
};
export function Topbar() {
const pathname = usePathname();
const pageTitle = pageTitles[pathname] ?? "DemoBMS";
const { active: activeAlarms } = useAlarmCount();
const { theme, setTheme } = useTheme();
return (
<header className="sticky top-0 z-30 flex items-center justify-between h-14 px-4 border-b border-border bg-background/80 backdrop-blur-sm shrink-0">
{/* Left: mobile menu + page title */}
<div className="flex items-center gap-3">
<Sheet>
<SheetTrigger asChild>
<Button variant="ghost" size="icon" className="md:hidden" aria-label="Open menu">
<Menu className="w-4 h-4" />
</Button>
</SheetTrigger>
<SheetContent side="left" className="p-0 w-60">
<Sidebar />
</SheetContent>
</Sheet>
<h1 className="text-sm font-semibold text-foreground">{pageTitle}</h1>
</div>
{/* Right: alarm bell + user */}
<div className="flex items-center gap-2">
{/* Alarm bell — single canonical alarm indicator */}
<Button variant="ghost" size="icon" className="relative h-8 w-8" asChild>
<Link href="/alarms" aria-label={`Alarms${activeAlarms > 0 ? `${activeAlarms} active` : ""}`}>
<Bell className="w-4 h-4" />
{activeAlarms > 0 && (
<Badge
variant="destructive"
className="absolute -top-0.5 -right-0.5 h-4 min-w-4 px-1 text-[9px] leading-none"
>
{activeAlarms > 99 ? "99+" : activeAlarms}
</Badge>
)}
</Link>
</Button>
{/* Scenario simulator */}
<SimulatorPanel />
{/* Theme toggle */}
<Button
variant="ghost"
size="icon"
className="h-8 w-8"
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
aria-label="Toggle theme"
>
{theme === "dark" ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
</Button>
{/* Clerk user button */}
<UserButton
appearance={{
elements: {
avatarBox: "w-7 h-7",
},
}}
/>
</div>
</header>
);
}