333 lines
12 KiB
TypeScript
333 lines
12 KiB
TypeScript
'use client';
|
|
|
|
import Link from 'next/link';
|
|
import { useAuth } from '@/contexts/AuthContext';
|
|
import Button from './Button';
|
|
import Logo from './Logo';
|
|
import { ROUTES } from '@/utils/constants';
|
|
import { useState, useRef, useEffect } from 'react';
|
|
|
|
export default function Header() {
|
|
const { user, isAuthenticated, logout } = useAuth();
|
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
const [isParticiperDropdownOpen, setIsParticiperDropdownOpen] = useState(false);
|
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
|
|
const toggleMobileMenu = () => {
|
|
setIsMobileMenuOpen(!isMobileMenuOpen);
|
|
};
|
|
|
|
// Close dropdown when clicking outside
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
|
setIsParticiperDropdownOpen(false);
|
|
}
|
|
};
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
return () => {
|
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
};
|
|
}, []);
|
|
|
|
const getDashboardRoute = () => {
|
|
if (!user) return ROUTES.HOME;
|
|
switch (user.role) {
|
|
case 'admin':
|
|
return ROUTES.ADMIN_DASHBOARD;
|
|
case 'employee':
|
|
return ROUTES.EMPLOYEE_DASHBOARD;
|
|
default:
|
|
return ROUTES.CLIENT_DASHBOARD;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<header className="bg-white border-b border-gray-200 sticky top-0 z-50 shadow-sm">
|
|
{/* Main Header */}
|
|
<div className="container mx-auto px-4">
|
|
<div className="flex items-center justify-between h-18">
|
|
{/* Logo */}
|
|
<Link href={ROUTES.HOME} className="group">
|
|
<Logo size="md" showText={true} className="group-hover:scale-105 transition-transform" />
|
|
</Link>
|
|
|
|
{/* Desktop Navigation */}
|
|
<nav className="hidden md:flex items-center gap-6">
|
|
<Link
|
|
href={ROUTES.HOME}
|
|
className="text-gray-700 hover:text-primary-600 font-medium transition-colors"
|
|
>
|
|
Accueil
|
|
</Link>
|
|
<Link
|
|
href={ROUTES.GAME}
|
|
className="text-gray-700 hover:text-primary-600 font-medium transition-colors"
|
|
>
|
|
Jeu
|
|
</Link>
|
|
<Link
|
|
href={ROUTES.LOTS}
|
|
className="text-gray-700 hover:text-primary-600 font-medium transition-colors"
|
|
>
|
|
Gains
|
|
</Link>
|
|
<Link
|
|
href="/about"
|
|
className="text-gray-700 hover:text-primary-600 font-medium transition-colors"
|
|
>
|
|
À propos
|
|
</Link>
|
|
<Link
|
|
href="/contact"
|
|
className="text-gray-700 hover:text-primary-600 font-medium transition-colors"
|
|
>
|
|
Contact
|
|
</Link>
|
|
|
|
{/* Participer with Dropdown - Green Button */}
|
|
{isAuthenticated ? (
|
|
<Link
|
|
href={ROUTES.GAME}
|
|
className="bg-green-600 hover:bg-green-700 text-white font-semibold px-4 py-2 rounded-lg transition-all hover:shadow-lg"
|
|
>
|
|
🎯 Participer
|
|
</Link>
|
|
) : (
|
|
<div className="relative" ref={dropdownRef}>
|
|
<button
|
|
onClick={() => setIsParticiperDropdownOpen(!isParticiperDropdownOpen)}
|
|
className="bg-green-600 hover:bg-green-700 text-white font-semibold px-4 py-2 rounded-lg transition-all hover:shadow-lg flex items-center gap-2"
|
|
>
|
|
🎯 Participer
|
|
<svg
|
|
className={`w-4 h-4 transition-transform ${isParticiperDropdownOpen ? 'rotate-180' : ''}`}
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
</svg>
|
|
</button>
|
|
|
|
{isParticiperDropdownOpen && (
|
|
<div className="absolute right-0 mt-2 w-56 bg-white rounded-lg shadow-xl border border-gray-200 py-2 z-50 animate-fadeIn">
|
|
<Link
|
|
href={ROUTES.LOGIN}
|
|
onClick={() => setIsParticiperDropdownOpen(false)}
|
|
className="block px-4 py-3 text-gray-700 hover:bg-green-50 hover:text-green-700 transition-colors"
|
|
>
|
|
<span className="font-medium block">Connexion</span>
|
|
<p className="text-xs text-gray-500 mt-0.5">J'ai déjà un compte</p>
|
|
</Link>
|
|
<div className="border-t border-gray-100 my-1"></div>
|
|
<Link
|
|
href={ROUTES.REGISTER}
|
|
onClick={() => setIsParticiperDropdownOpen(false)}
|
|
className="block px-4 py-3 text-gray-700 hover:bg-green-50 hover:text-green-700 transition-colors"
|
|
>
|
|
<span className="font-medium block">Inscription</span>
|
|
<p className="text-xs text-gray-500 mt-0.5">Créer un nouveau compte</p>
|
|
</Link>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</nav>
|
|
|
|
{/* Desktop Auth Buttons */}
|
|
<div className="hidden md:flex items-center gap-3">
|
|
{isAuthenticated && (
|
|
<>
|
|
<Link href={ROUTES.PROFILE}>
|
|
<Button variant="outline" size="sm">
|
|
👤 {user?.firstName}
|
|
</Button>
|
|
</Link>
|
|
{user?.role === 'CLIENT' && (
|
|
<Link href={ROUTES.HISTORY}>
|
|
<Button variant="outline" size="sm">
|
|
🏆 Mes gains
|
|
</Button>
|
|
</Link>
|
|
)}
|
|
<Button variant="outline" size="sm" onClick={logout}>
|
|
Déconnexion
|
|
</Button>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* Mobile Menu Button */}
|
|
<button
|
|
onClick={toggleMobileMenu}
|
|
className="md:hidden p-2 text-gray-600 hover:text-gray-900 focus:outline-none"
|
|
aria-label="Toggle menu"
|
|
>
|
|
{isMobileMenuOpen ? (
|
|
<svg
|
|
className="w-6 h-6"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M6 18L18 6M6 6l12 12"
|
|
/>
|
|
</svg>
|
|
) : (
|
|
<svg
|
|
className="w-6 h-6"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M4 6h16M4 12h16M4 18h16"
|
|
/>
|
|
</svg>
|
|
)}
|
|
</button>
|
|
</div>
|
|
|
|
{/* Mobile Menu */}
|
|
{isMobileMenuOpen && (
|
|
<div className="md:hidden py-4 border-t border-gray-200 animate-fadeIn">
|
|
<nav className="flex flex-col gap-3">
|
|
<Link
|
|
href={ROUTES.HOME}
|
|
className="text-gray-700 hover:text-primary-600 font-medium py-2 transition-colors"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
>
|
|
Accueil
|
|
</Link>
|
|
<Link
|
|
href={ROUTES.GAME}
|
|
className="text-gray-700 hover:text-primary-600 font-medium py-2 transition-colors"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
>
|
|
Jeu
|
|
</Link>
|
|
<Link
|
|
href={ROUTES.LOTS}
|
|
className="text-gray-700 hover:text-primary-600 font-medium py-2 transition-colors"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
>
|
|
Gains
|
|
</Link>
|
|
<Link
|
|
href="/about"
|
|
className="text-gray-700 hover:text-primary-600 font-medium py-2 transition-colors"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
>
|
|
À propos
|
|
</Link>
|
|
<Link
|
|
href="/contact"
|
|
className="text-gray-700 hover:text-primary-600 font-medium py-2 transition-colors"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
>
|
|
Contact
|
|
</Link>
|
|
|
|
{/* Participer Mobile - Green Button */}
|
|
{isAuthenticated ? (
|
|
<Link
|
|
href={ROUTES.GAME}
|
|
className="bg-green-600 hover:bg-green-700 text-white font-semibold px-4 py-3 rounded-lg transition-all hover:shadow-lg text-center block"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
>
|
|
🎯 Participer
|
|
</Link>
|
|
) : (
|
|
<div>
|
|
<button
|
|
onClick={() => setIsParticiperDropdownOpen(!isParticiperDropdownOpen)}
|
|
className="bg-green-600 hover:bg-green-700 text-white font-semibold px-4 py-3 rounded-lg transition-all hover:shadow-lg flex items-center justify-center gap-2 w-full"
|
|
>
|
|
🎯 Participer
|
|
<svg
|
|
className={`w-4 h-4 transition-transform ${isParticiperDropdownOpen ? 'rotate-180' : ''}`}
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
</svg>
|
|
</button>
|
|
|
|
{isParticiperDropdownOpen && (
|
|
<div className="mt-2 space-y-2 animate-fadeIn bg-green-50 rounded-lg p-3">
|
|
<Link
|
|
href={ROUTES.LOGIN}
|
|
onClick={() => {
|
|
setIsMobileMenuOpen(false);
|
|
setIsParticiperDropdownOpen(false);
|
|
}}
|
|
className="block text-green-800 hover:text-green-900 font-medium py-2 px-3 bg-white rounded-md hover:bg-green-100 transition-colors"
|
|
>
|
|
→ Connexion
|
|
</Link>
|
|
<Link
|
|
href={ROUTES.REGISTER}
|
|
onClick={() => {
|
|
setIsMobileMenuOpen(false);
|
|
setIsParticiperDropdownOpen(false);
|
|
}}
|
|
className="block text-green-800 hover:text-green-900 font-medium py-2 px-3 bg-white rounded-md hover:bg-green-100 transition-colors"
|
|
>
|
|
→ Inscription
|
|
</Link>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{isAuthenticated && (
|
|
<div className="border-t border-gray-200 pt-3 mt-3 space-y-2">
|
|
<Link
|
|
href={ROUTES.PROFILE}
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
>
|
|
<Button variant="outline" size="sm" fullWidth>
|
|
👤 {user?.firstName}
|
|
</Button>
|
|
</Link>
|
|
{user?.role === 'CLIENT' && (
|
|
<Link
|
|
href={ROUTES.HISTORY}
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
>
|
|
<Button variant="outline" size="sm" fullWidth>
|
|
🏆 Mes gains
|
|
</Button>
|
|
</Link>
|
|
)}
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
fullWidth
|
|
onClick={() => {
|
|
logout();
|
|
setIsMobileMenuOpen(false);
|
|
}}
|
|
>
|
|
Déconnexion
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</nav>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|