2026-03-13 10:08:46 +05:30

102 lines
5.6 KiB
JavaScript

import React, { useState, useRef, useEffect } from 'react';
import { Search, Bell, ChevronDown, LogOut, User, Settings, Shield } from 'lucide-react';
export default function Header({ profile }) {
const [isProfileOpen, setIsProfileOpen] = useState(false);
const dropdownRef = useRef(null);
// Close dropdown on click outside
useEffect(() => {
function handleClickOutside(event) {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsProfileOpen(false);
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
const handleLogout = async () => {
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
try {
const response = await fetch('/logout', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrfToken
}
});
if (response.ok || response.status === 419) {
window.location.href = '/';
}
} catch (error) {
console.error('Logout failed:', error);
// Fallback for SPA
window.location.href = '/';
}
};
return (
<header className="h-16 bg-white border-b border-gray-100 flex items-center justify-between px-8 sticky top-0 z-50">
{/* Logo */}
<div className="flex items-center gap-2">
<div className="bg-red-500 p-1.5 rounded-lg">
<svg className="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 2v2m0 16v2m-8-8h2m12 0h2M5.6 5.6l1.4 1.4m10 10l1.4 1.4M5.6 18.4l1.4-1.4m10-10l1.4-1.4M12 6a6 6 0 100 12 6 6 0 000-12z" />
</svg>
</div>
<h1 className="text-xl font-extrabold tracking-tight text-gray-900 leading-none">GymPro</h1>
</div>
{/* User Actions */}
<div className="flex items-center gap-6 ml-auto">
<button className="relative p-2 text-gray-400 hover:text-gray-900 hover:bg-gray-100 rounded-full transition-all text-xs font-bold uppercase tracking-widest">
<Bell size={22} />
<span className="absolute top-2 right-2 w-2.5 h-2.5 bg-red-500 border-2 border-white rounded-full"></span>
</button>
<div className="relative" ref={dropdownRef}>
<div
onClick={() => setIsProfileOpen(!isProfileOpen)}
className="flex items-center gap-3 pl-6 border-l border-gray-100 cursor-pointer group select-none"
>
<div className="flex flex-col items-end">
<span className="text-sm font-bold text-gray-900">{profile?.user?.name || 'Loading...'}</span>
<span className="text-[10px] text-gray-400 font-bold uppercase tracking-wider">{profile?.role ? profile.role.charAt(0).toUpperCase() + profile.role.slice(1) : 'User'}</span>
</div>
<div className="w-10 h-10 bg-gray-100 rounded-xl overflow-hidden border-2 border-transparent group-hover:border-red-500/20 transition-all flex items-center justify-center relative">
<div className="w-8 h-8 bg-gray-300 rounded-full flex items-center justify-center text-white text-xs font-bold">
{profile?.user?.name?.split(' ').map(n => n[0]).join('').toUpperCase() || 'U'}
</div>
</div>
<ChevronDown size={14} className={`text-gray-400 transition-transform duration-200 ${isProfileOpen ? 'rotate-180' : ''}`} />
</div>
{/* Profile Dropdown */}
{isProfileOpen && (
<div className="absolute right-0 mt-4 w-64 bg-white rounded-[2rem] shadow-2xl border border-gray-50 overflow-hidden animate-in fade-in slide-in-from-top-4 duration-200 py-3 z-50">
<div className="px-6 py-4 border-b border-gray-50 mb-2">
<p className="text-xs font-black text-gray-400 uppercase tracking-widest">Active Account</p>
<p className="text-sm font-bold text-gray-900 mt-1">{profile?.user?.email || '...'}</p>
</div>
<div className="px-2 space-y-1 text-xs font-bold">
<div className="h-px bg-gray-50 mx-4 my-2" />
<button
onClick={handleLogout}
className="w-full flex items-center gap-3 px-4 py-3 text-red-500 hover:bg-red-50 rounded-2xl transition-all group"
>
<div className="w-8 h-8 rounded-xl bg-red-50 flex items-center justify-center group-hover:bg-red-100 transition-all">
<LogOut size={16} />
</div>
<span>Sign Out</span>
</button>
</div>
</div>
)}
</div>
</div>
</header>
);
}