semblance-dev/src/components/Navigation.tsx
2025-08-04 09:07:59 -05:00

216 lines
7.9 KiB
TypeScript

import { useState } from 'react';
import { Link, useLocation, useNavigate } from 'react-router-dom';
import { Menu, X, LayoutDashboard, Users, MessageSquare, Home, LogIn, LogOut } from 'lucide-react';
import { cn } from '@/lib/utils';
import { useAuth } from '@/contexts/AuthContext';
export default function Navigation() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const location = useLocation();
const navigate = useNavigate();
const { isAuthenticated, logout } = useAuth();
const navigationItems = [
{
name: 'Home',
href: '/',
icon: Home,
},
{
name: 'Synthetic Personas',
href: '/synthetic-users',
icon: Users,
},
{
name: 'Focus Groups',
href: '/focus-groups',
icon: MessageSquare,
},
{
name: 'Dashboard',
href: '/dashboard',
icon: LayoutDashboard,
},
];
const toggleMobileMenu = () => {
setMobileMenuOpen(!mobileMenuOpen);
};
const isActive = (path: string) => {
return location.pathname === path;
};
// Handle navigation with authentication
const handleAuthNavigation = (path: string) => {
// Dispatch a custom event when navigating to the synthetic users page
// This helps components know when they should refresh data
if (path === '/synthetic-users') {
// Create and dispatch a custom event that the SyntheticUsers component can listen for
const event = new CustomEvent('syntheticUsersNavigation');
window.dispatchEvent(event);
}
// Always navigate normally - ProtectedRoute will handle auth check
navigate(path);
};
return (
<header className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200/80">
<div className="px-4 sm:px-6 lg:px-8">
<div className="flex h-16 items-center justify-between">
<div className="flex items-center">
<Link to="/" className="flex items-center">
<span className="font-sf text-2xl font-semibold text-gradient">Semblance</span>
</Link>
</div>
{/* Desktop Navigation */}
<nav className="hidden md:block">
<ul className="flex items-center space-x-8">
{navigationItems.map((item) => (
<li key={item.name}>
{item.href === '/' ? (
<Link
to={item.href}
className={cn(
"flex items-center px-1 py-2 text-sm font-medium hover-transition border-b-2",
isActive(item.href)
? "border-primary text-primary"
: "border-transparent text-slate-600 hover:text-slate-900 hover:border-slate-300"
)}
>
<item.icon className="mr-1 h-4 w-4" />
{item.name}
</Link>
) : (
<button
onClick={() => handleAuthNavigation(item.href)}
className={cn(
"flex items-center px-1 py-2 text-sm font-medium hover-transition border-b-2",
isActive(item.href)
? "border-primary text-primary"
: "border-transparent text-slate-600 hover:text-slate-900 hover:border-slate-300"
)}
>
<item.icon className="mr-1 h-4 w-4" />
{item.name}
</button>
)}
</li>
))}
{/* Authentication buttons */}
<li>
{isAuthenticated ? (
<button
onClick={() => {
logout();
navigate('/login');
}}
className="flex items-center px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 button-transition rounded-md hover:bg-slate-50"
>
<LogOut className="mr-1 h-4 w-4" />
Logout
</button>
) : (
<Link
to="/login"
className="flex items-center px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 button-transition rounded-md hover:bg-slate-50"
>
<LogIn className="mr-1 h-4 w-4" />
Login
</Link>
)}
</li>
</ul>
</nav>
{/* Mobile Menu Button */}
<div className="flex md:hidden">
<button
type="button"
className="inline-flex items-center justify-center rounded-md p-2 text-slate-700 hover:bg-slate-100 hover:text-slate-900 button-transition"
onClick={toggleMobileMenu}
>
<span className="sr-only">Open main menu</span>
{mobileMenuOpen ? (
<X className="block h-6 w-6" aria-hidden="true" />
) : (
<Menu className="block h-6 w-6" aria-hidden="true" />
)}
</button>
</div>
</div>
</div>
{/* Mobile Menu */}
{mobileMenuOpen && (
<div className="md:hidden glass-panel animate-fade-in">
<div className="space-y-1 px-4 pb-3 pt-2">
{navigationItems.map((item) => (
<div key={item.name}>
{item.href === '/' ? (
<Link
to={item.href}
className={cn(
"flex items-center rounded-md px-3 py-2 text-base font-medium button-transition",
isActive(item.href)
? "bg-primary text-white"
: "text-slate-600 hover:bg-slate-50 hover:text-slate-900"
)}
onClick={() => setMobileMenuOpen(false)}
>
<item.icon className="mr-3 h-5 w-5" />
{item.name}
</Link>
) : (
<button
className={cn(
"flex items-center rounded-md px-3 py-2 text-base font-medium button-transition w-full text-left",
isActive(item.href)
? "bg-primary text-white"
: "text-slate-600 hover:bg-slate-50 hover:text-slate-900"
)}
onClick={() => {
setMobileMenuOpen(false);
handleAuthNavigation(item.href);
}}
>
<item.icon className="mr-3 h-5 w-5" />
{item.name}
</button>
)}
</div>
))}
{/* Mobile Authentication options */}
{isAuthenticated ? (
<button
onClick={() => {
logout();
setMobileMenuOpen(false);
navigate('/login');
}}
className="flex items-center rounded-md px-3 py-2 text-base font-medium button-transition text-slate-600 hover:bg-slate-50 hover:text-slate-900 w-full"
>
<LogOut className="mr-3 h-5 w-5" />
Logout
</button>
) : (
<Link
to="/login"
className="flex items-center rounded-md px-3 py-2 text-base font-medium button-transition text-slate-600 hover:bg-slate-50 hover:text-slate-900"
onClick={() => setMobileMenuOpen(false)}
>
<LogIn className="mr-3 h-5 w-5" />
Login
</Link>
)}
</div>
</div>
)}
</header>
);
}