import { useState, useRef, useEffect } from 'react'; import { Link, useLocation, useNavigate } from 'react-router-dom'; import { Menu, ChevronRight, Settings, LogOut, Sun, Moon, Building2 } from 'lucide-react'; import { useCurrentOrg } from '../../stores/currentOrg'; import { useAuth } from '../../contexts/AuthContext'; import { useTheme } from '../../hooks/useTheme'; import { Button } from '../ui/Button'; export interface HeaderProps { onToggleSidebar: () => void; } export function Header({ onToggleSidebar }: HeaderProps) { const [userMenuOpen, setUserMenuOpen] = useState(false); const { theme, toggleTheme } = useTheme(); const { user, logout, isLoading } = useAuth(); const { org, loading: orgLoading } = useCurrentOrg(); const location = useLocation(); const navigate = useNavigate(); const userMenuRef = useRef(null); // Close user menu when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (userMenuRef.current && !userMenuRef.current.contains(event.target as Node)) { setUserMenuOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); // Close user menu on escape useEffect(() => { const handleEscape = (event: KeyboardEvent) => { if (event.key === 'Escape' && userMenuOpen) { setUserMenuOpen(false); } }; document.addEventListener('keydown', handleEscape); return () => document.removeEventListener('keydown', handleEscape); }, [userMenuOpen]); // Generate breadcrumbs from current path const generateBreadcrumbs = () => { const pathSegments = location.pathname.split('/').filter(Boolean); if (pathSegments.length === 0) { return [{ label: 'Dashboard', path: '/' }]; } const breadcrumbs = [{ label: 'Dashboard', path: '/' }]; pathSegments.forEach((segment, index) => { const path = `/${ pathSegments.slice(0, index + 1).join('/')}`; const label = segment.charAt(0).toUpperCase() + segment.slice(1); breadcrumbs.push({ label, path }); }); return breadcrumbs; }; const breadcrumbs = generateBreadcrumbs(); const handleLogout = async () => { try { setUserMenuOpen(false); await logout(); navigate('/login'); } catch (error) { console.error('Logout failed:', error); // Force navigation to login even if logout fails navigate('/login'); } }; const getInitials = (name: string) => name .split(' ') .map(part => part.charAt(0).toUpperCase()) .join('') .slice(0, 2); return (
{/* Left section: Organization branding + Mobile menu button + Breadcrumbs */}
{/* Mobile menu button */} {/* Organization branding */} {!orgLoading && org ? (
{org.branding?.logoUrl ? ( {`${org.name} { // Hide image on error and show fallback const img = e.target as HTMLImageElement; img.style.display = 'none'; // Show monogram fallback const fallback = img.parentElement?.querySelector('.org-fallback'); if (fallback) fallback.classList.remove('hidden'); }} /> ) : null} {/* Fallback monogram when no logo */} {!org.branding?.logoUrl && (
{org.name.charAt(0).toUpperCase()}
)} {/* Hidden fallback for logo error */}
{org.name.charAt(0).toUpperCase()}

{org.name}

{org.domains?.length && (

{org.domains.find(d => d.primary)?.host || org.domains[0]?.host}

)}
) : orgLoading ? ( // Loading skeleton
) : ( // No organization fallback

Black Canyon Tickets

)} {/* Separator */} {org && (
)} {/* Breadcrumbs */}
{/* Right section: Theme toggle + User menu */}
{/* Theme toggle */} {/* User menu */} {user && (
{/* User dropdown menu */} {userMenuOpen && (

{user.name}

{user.email}

{user.role} {org && ( {org.name} )}
setUserMenuOpen(false)} > Account Settings {org && ( <>

Organization

setUserMenuOpen(false)} >
Branding Settings setUserMenuOpen(false)} >
Domains )}
)}
)}
); }