/** * AppSidebar — vertical sidebar navigation for all protected pages. * * Nav items: Home / Records / Energy / Config * Utilities: ColorSchemeToggle + LogoutButton (at bottom) * * Current route is highlighted via useLocation(). * Mobile: burger button toggles the navbar open/closed (handled by AppShell context). */ import { NavLink, Stack, Divider, Tooltip, ActionIcon, useMantineColorScheme, useComputedColorScheme, AppShell, Text, Group } from '@mantine/core' import { Link, useLocation, useNavigate } from 'react-router-dom' import { Home, List, Settings, Sun, Moon, LogOut, Zap } from 'react-feather' import { useQueryClient } from '@tanstack/react-query' import apiClient from '../api/client' // --------------------------------------------------------------------------- // Individual nav entries // --------------------------------------------------------------------------- interface NavEntry { to: string label: string icon: React.ReactNode testId: string } const NAV_ENTRIES: NavEntry[] = [ { to: '/', label: 'Home', icon: , testId: 'nav-home', }, { to: '/records', label: 'Records', icon: , testId: 'nav-records', }, { to: '/energy', label: 'Energy', icon: , testId: 'nav-energy', }, { to: '/config', label: 'Config', icon: , testId: 'nav-config', }, ] // --------------------------------------------------------------------------- // Colour-scheme toggle // --------------------------------------------------------------------------- function ColorSchemeToggle() { const { setColorScheme } = useMantineColorScheme() const computed = useComputedColorScheme('light', { getInitialValueInEffect: true }) const isDark = computed === 'dark' return ( setColorScheme(isDark ? 'light' : 'dark')} data-testid="color-scheme-toggle" > {isDark ? : } ) } // --------------------------------------------------------------------------- // Logout button // --------------------------------------------------------------------------- function LogoutButton() { const navigate = useNavigate() const qc = useQueryClient() async function handleLogout() { try { await apiClient.POST('/api/auth/logout') } catch { // Ignore errors — clear session regardless. } await qc.invalidateQueries({ queryKey: ['session'] }) navigate('/login', { replace: true }) } return ( ) } // --------------------------------------------------------------------------- // Sidebar // --------------------------------------------------------------------------- interface AppSidebarProps { /** Called when a nav link is clicked on mobile (to close the navbar). */ onNavClick?: () => void } export function AppSidebar({ onNavClick }: AppSidebarProps) { const location = useLocation() return ( {/* App title */} Home Automation {/* Navigation links */} {NAV_ENTRIES.map(({ to, label, icon, testId }) => { // For the home route "/" we need an exact match; others prefix-match is fine. const isActive = to === '/' ? location.pathname === '/' : location.pathname.startsWith(to) return ( ) })} {/* Bottom utilities: theme toggle + logout */} ) }