Alexis Bruneteau 14eff8d0da feat: Rebuild frontend with Next.js and shadcn/ui components
- Migrate from React CRA to Next.js 15 with modern architecture
- Implement comprehensive shadcn/ui component library
- Create complete dashboard system with layouts and navigation
- Build authentication pages (login, register) with proper forms
- Implement vote management pages (active, upcoming, history, archives)
- Add user profile management with security settings
- Configure Tailwind CSS with custom dark theme (accent: #e8704b)
- Setup TypeScript with strict type checking
- Backup old React-based frontend to .backups/frontend-old
- All pages compile successfully and build passes linting

Pages created:
- Home page with hero section and features
- Authentication (login/register)
- Dashboard with stats and vote cards
- Vote management (active, upcoming, history, archives)
- User profile with form validation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 17:02:14 +01:00

169 lines
7.2 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { LogOut, User, Menu, X } from 'lucide-react';
import { Button } from '../lib/ui';
export default function Header({ voter, onLogout }) {
const navigate = useNavigate();
const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false);
const handleLogout = () => {
onLogout();
navigate('/');
setMobileMenuOpen(false);
};
return (
<header className="sticky top-0 z-40 w-full border-b border-text-tertiary bg-bg-secondary/95 backdrop-blur supports-[backdrop-filter]:bg-bg-secondary/80">
<div className="container flex h-16 items-center justify-between">
{/* Logo */}
<Link to={voter ? '/dashboard' : '/'} className="flex items-center space-x-2 font-bold text-xl text-accent-warm hover:opacity-80 transition-opacity">
<span className="text-2xl">🗳</span>
<span>E-Voting</span>
</Link>
{/* Desktop Navigation */}
<nav className="hidden md:flex items-center space-x-1">
{voter ? (
<>
<Link to="/dashboard" className="px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors">
Tableau de Bord
</Link>
<Link to="/dashboard/actifs" className="px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors">
Votes Actifs
</Link>
<Link to="/dashboard/futurs" className="px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors">
Votes à Venir
</Link>
<Link to="/dashboard/historique" className="px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors">
Mon Historique
</Link>
<Link to="/archives" className="px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors">
Archives
</Link>
<div className="mx-2 h-6 w-px bg-text-tertiary"></div>
<Link to="/profile" className="px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors flex items-center gap-2">
<User size={18} />
{voter.nom}
</Link>
<Button
onClick={handleLogout}
variant="destructive"
size="sm"
className="ml-2 flex items-center gap-1"
>
<LogOut size={18} />
Déconnexion
</Button>
</>
) : (
<>
<Link to="/archives" className="px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors">
Archives
</Link>
<div className="mx-2 h-6 w-px bg-text-tertiary"></div>
<Button variant="ghost" size="sm" asChild>
<Link to="/login">Se Connecter</Link>
</Button>
<Button variant="default" size="sm" asChild>
<Link to="/register">S'inscrire</Link>
</Button>
</>
)}
</nav>
{/* Mobile Menu Button */}
<button
className="md:hidden inline-flex items-center justify-center rounded-md p-2 text-text-primary hover:bg-bg-overlay-light transition-colors"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
aria-label="Toggle menu"
>
{mobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
{/* Mobile Navigation */}
{mobileMenuOpen && (
<nav className="md:hidden border-t border-text-tertiary bg-bg-secondary">
<div className="container py-4 space-y-2">
{voter ? (
<>
<Link
to="/dashboard"
className="block px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
Tableau de Bord
</Link>
<Link
to="/dashboard/actifs"
className="block px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
Votes Actifs
</Link>
<Link
to="/dashboard/futurs"
className="block px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
Votes à Venir
</Link>
<Link
to="/dashboard/historique"
className="block px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
Mon Historique
</Link>
<Link
to="/archives"
className="block px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
Archives
</Link>
<div className="my-2 h-px bg-text-tertiary"></div>
<Link
to="/profile"
className="flex items-center gap-2 px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
<User size={18} />
{voter.nom}
</Link>
<Button
onClick={handleLogout}
variant="destructive"
size="sm"
className="w-full flex items-center justify-center gap-1 mt-2"
>
<LogOut size={18} />
Déconnexion
</Button>
</>
) : (
<>
<Link
to="/archives"
className="block px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-overlay-light rounded-md transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
Archives
</Link>
<div className="my-2 h-px bg-text-tertiary"></div>
<Button variant="ghost" size="sm" className="w-full" asChild>
<Link to="/login" onClick={() => setMobileMenuOpen(false)}>Se Connecter</Link>
</Button>
<Button variant="default" size="sm" className="w-full" asChild>
<Link to="/register" onClick={() => setMobileMenuOpen(false)}>S'inscrire</Link>
</Button>
</>
)}
</div>
</nav>
)}
</header>
);
}