Files
ColaFlow-Web/components/layout/Header.tsx
Yaojia Wang e60b70de52 feat(frontend): Implement complete authentication system
Implemented comprehensive JWT-based authentication with token refresh mechanism, user state management, and protected routes.

Changes:
- Upgraded API client from fetch to Axios with automatic token refresh interceptors
- Created API configuration with centralized endpoint definitions
- Implemented Zustand auth store for user state management with persistence
- Created React Query hooks for login, register, logout, and current user
- Built login and registration pages with form validation (Zod + React Hook Form)
- Implemented AuthGuard component for route protection
- Enhanced Header with user dropdown menu and logout functionality
- Updated Sidebar with user information display at bottom
- Added Team navigation item to sidebar
- Configured environment variables for API base URL

Technical Details:
- JWT token storage in localStorage with secure key names
- Automatic token refresh on 401 responses
- Request queueing during token refresh to prevent race conditions
- TypeScript strict typing throughout
- ESLint compliant code (fixed type safety issues)
- Proper error handling with user-friendly messages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 09:09:09 +01:00

75 lines
2.5 KiB
TypeScript

'use client';
import { Menu, Bell, LogOut, User } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useUIStore } from '@/stores/ui-store';
import { useLogout } from '@/lib/hooks/useAuth';
import { useAuthStore } from '@/stores/authStore';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
export function Header() {
const toggleSidebar = useUIStore((state) => state.toggleSidebar);
const { mutate: logout } = useLogout();
const user = useAuthStore((state) => state.user);
return (
<header className="sticky top-0 z-50 w-full border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="flex h-14 items-center px-4">
<Button
variant="ghost"
size="icon"
className="mr-4"
onClick={toggleSidebar}
>
<Menu className="h-5 w-5" />
<span className="sr-only">Toggle sidebar</span>
</Button>
<div className="flex items-center gap-2">
<h1 className="text-lg font-semibold">ColaFlow</h1>
</div>
<div className="ml-auto flex items-center gap-4">
<Button variant="ghost" size="icon">
<Bell className="h-5 w-5" />
<span className="sr-only">Notifications</span>
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<User className="h-5 w-5" />
<span className="sr-only">User menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>
<div className="flex flex-col space-y-1">
<p className="text-sm font-medium leading-none">
{user?.fullName}
</p>
<p className="text-xs leading-none text-muted-foreground">
{user?.email}
</p>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => logout()}>
<LogOut className="mr-2 h-4 w-4" />
<span>Log out</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</header>
);
}