| 'use client'; |
|
|
| import { useState } from 'react'; |
| import Link from 'next/link'; |
| import { usePathname, useRouter } from 'next/navigation'; |
| import { cn } from '@/lib/utils'; |
| import { |
| LayoutDashboard, |
| User, |
| LogOut, |
| LogIn, |
| Menu, |
| X, |
| } from 'lucide-react'; |
| import { useAuth } from '@/hooks/use-auth'; |
| import { Button } from '@/components/ui/button'; |
| import { Avatar, AvatarFallback } from '@/components/ui/avatar'; |
| import { |
| DropdownMenu, |
| DropdownMenuContent, |
| DropdownMenuItem, |
| DropdownMenuLabel, |
| DropdownMenuSeparator, |
| DropdownMenuTrigger, |
| } from '@/components/ui/dropdown-menu'; |
|
|
| interface NavItem { |
| href: string; |
| label: string; |
| icon: React.ComponentType<{ className?: string }>; |
| } |
|
|
| const navItems: NavItem[] = [ |
| { href: '/dashboard', label: 'Dashboard', icon: LayoutDashboard }, |
| { href: '/profile', label: 'Profile', icon: User }, |
| ]; |
|
|
| export function Navbar() { |
| const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); |
| const pathname = usePathname(); |
| const router = useRouter(); |
| const { user, logout, isAuthenticated } = useAuth(); |
|
|
| const handleLogout = async () => { |
| await logout(); |
| router.push('/login'); |
| }; |
|
|
| const handleLogin = () => { |
| router.push('/login'); |
| }; |
|
|
| |
| const getUserInitials = () => { |
| if (user?.name) { |
| return user.name |
| .split(' ') |
| .map((n: string) => n[0]) |
| .join('') |
| .toUpperCase() |
| .slice(0, 2); |
| } |
| return user?.email?.[0].toUpperCase() || 'U'; |
| }; |
|
|
| return ( |
| <nav className="sticky top-0 z-50 w-full border-b border-gray-200 dark:border-cyan-500/30 bg-white dark:bg-black/80 backdrop-blur-lg dark:shadow-[0_0_20px_rgba(6,182,212,0.2)]"> |
| <div className="flex h-16 items-center px-4"> |
| {/* Logo */} |
| <Link href="/dashboard" className="flex items-center space-x-2"> |
| <div className="flex h-8 w-8 items-center justify-center rounded-lg bg-primary dark:bg-gradient-to-br dark:from-cyan-500 dark:to-purple-500 text-primary-foreground dark:shadow-[0_0_15px_rgba(6,182,212,0.6)]"> |
| <span className="text-lg font-bold">✓</span> |
| </div> |
| <span className="font-bold text-lg dark:text-white dark:drop-shadow-[0_0_8px_rgba(6,182,212,0.8)]">Todo App</span> |
| </Link> |
| |
| {/* Desktop Navigation */} |
| <div className="hidden md:flex md:flex-1 md:items-center md:justify-end md:gap-1"> |
| {navItems.map((item) => { |
| const Icon = item.icon; |
| const isActive = pathname === item.href; |
| |
| return ( |
| <Link |
| key={item.href} |
| href={item.href} |
| className={cn( |
| 'flex items-center gap-2 px-4 py-2 rounded-lg transition-all', |
| isActive |
| ? 'bg-primary text-primary-foreground font-medium dark:bg-gradient-to-r dark:from-cyan-500 dark:to-purple-500 dark:shadow-[0_0_15px_rgba(6,182,212,0.6)]' |
| : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-cyan-500/10 dark:hover:shadow-[0_0_10px_rgba(6,182,212,0.3)]' |
| )} |
| > |
| <Icon className="h-4 w-4" /> |
| <span>{item.label}</span> |
| </Link> |
| ); |
| })} |
| </div> |
| |
| {/* User Profile - Desktop */} |
| <div className="hidden md:flex md:items-center md:gap-3 md:ml-4"> |
| <DropdownMenu> |
| <DropdownMenuTrigger asChild> |
| <Button variant="ghost" className="relative h-10 w-10 rounded-full"> |
| <Avatar className="h-9 w-9"> |
| <AvatarFallback className="bg-primary text-primary-foreground text-xs"> |
| {getUserInitials()} |
| </AvatarFallback> |
| </Avatar> |
| </Button> |
| </DropdownMenuTrigger> |
| <DropdownMenuContent align="end" className="w-56"> |
| <DropdownMenuLabel className="font-normal"> |
| <div className="flex flex-col space-y-1"> |
| <p className="text-sm font-medium leading-none"> |
| {user?.name || 'User'} |
| </p> |
| <p className="text-xs leading-none text-muted-foreground"> |
| {user?.email} |
| </p> |
| </div> |
| </DropdownMenuLabel> |
| <DropdownMenuSeparator /> |
| <DropdownMenuItem |
| className="cursor-pointer text-red-600 focus:text-red-600" |
| onClick={handleLogout} |
| > |
| <LogOut className="mr-2 h-4 w-4" /> |
| Logout |
| </DropdownMenuItem> |
| </DropdownMenuContent> |
| </DropdownMenu> |
| </div> |
| |
| {/* Mobile Menu Button */} |
| <div className="flex flex-1 items-center justify-end md:hidden"> |
| <Button |
| variant="ghost" |
| size="icon" |
| onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} |
| className="h-10 w-10" |
| > |
| {isMobileMenuOpen ? ( |
| <X className="h-5 w-5" /> |
| ) : ( |
| <Menu className="h-5 w-5" /> |
| )} |
| </Button> |
| </div> |
| </div> |
| |
| {/* Mobile Menu */} |
| {isMobileMenuOpen && ( |
| <div className="border-t border-gray-200 dark:border-gray-700 md:hidden"> |
| <div className="space-y-1 px-4 py-3"> |
| {navItems.map((item) => { |
| const Icon = item.icon; |
| const isActive = pathname === item.href; |
| |
| return ( |
| <Link |
| key={item.href} |
| href={item.href} |
| onClick={() => setIsMobileMenuOpen(false)} |
| className={cn( |
| 'flex items-center gap-3 px-3 py-2 rounded-lg transition-colors', |
| isActive |
| ? 'bg-primary text-primary-foreground font-medium' |
| : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700' |
| )} |
| > |
| <Icon className="h-5 w-5" /> |
| <span>{item.label}</span> |
| </Link> |
| ); |
| })} |
| |
| <div className="border-t border-gray-200 dark:border-gray-700 my-2 pt-2"> |
| <div className="flex items-center gap-3 px-3 py-2 rounded-lg bg-gray-50 dark:bg-gray-700/50"> |
| <Avatar className="h-9 w-9"> |
| <AvatarFallback className="bg-primary text-primary-foreground text-xs"> |
| {getUserInitials()} |
| </AvatarFallback> |
| </Avatar> |
| <div className="flex-1 min-w-0"> |
| <p className="text-sm font-medium truncate"> |
| {user?.name || 'User'} |
| </p> |
| <p className="text-xs text-gray-500 dark:text-gray-400 truncate"> |
| {user?.email} |
| </p> |
| </div> |
| </div> |
| <button |
| onClick={handleLogout} |
| className="flex items-center gap-3 w-full px-3 py-2 mt-1 rounded-lg text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors" |
| > |
| <LogOut className="h-5 w-5" /> |
| <span>Logout</span> |
| </button> |
| </div> |
| </div> |
| </div> |
| )} |
| </nav> |
| ); |
| } |
|
|