Files
cve-dashboard/frontend/src/components/UserMenu.js

95 lines
3.6 KiB
JavaScript
Raw Normal View History

import React, { useState, useRef, useEffect } from 'react';
import { User, LogOut, ChevronDown, Shield } from 'lucide-react';
import { useAuth } from '../contexts/AuthContext';
export default function UserMenu({ onManageUsers }) {
const { user, logout, isAdmin } = useAuth();
const [isOpen, setIsOpen] = useState(false);
const menuRef = useRef(null);
// Close menu when clicking outside
useEffect(() => {
function handleClickOutside(event) {
if (menuRef.current && !menuRef.current.contains(event.target)) {
setIsOpen(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const getRoleBadgeColor = (role) => {
switch (role) {
case 'admin':
return 'bg-red-100 text-red-800';
case 'editor':
return 'bg-blue-100 text-blue-800';
default:
return 'bg-gray-100 text-gray-800';
}
};
const handleLogout = async () => {
setIsOpen(false);
await logout();
};
const handleManageUsers = () => {
setIsOpen(false);
if (onManageUsers) {
onManageUsers();
}
};
if (!user) return null;
return (
<div className="relative" ref={menuRef}>
<button
onClick={() => setIsOpen(!isOpen)}
className="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-100 transition-colors"
>
<div className="w-8 h-8 bg-[#0476D9] rounded-full flex items-center justify-center">
<User className="w-4 h-4 text-white" />
</div>
<div className="text-left hidden sm:block">
<p className="text-sm font-medium text-gray-900">{user.username}</p>
<p className="text-xs text-gray-500 capitalize">{user.role}</p>
</div>
<ChevronDown className={`w-4 h-4 text-gray-500 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
</button>
{isOpen && (
<div className="absolute right-0 mt-2 w-64 bg-white rounded-lg shadow-lg border border-gray-200 py-2 z-50">
<div className="px-4 py-3 border-b border-gray-100">
<p className="text-sm font-medium text-gray-900">{user.username}</p>
<p className="text-sm text-gray-500">{user.email}</p>
<span className={`inline-block mt-2 px-2 py-1 rounded text-xs font-medium ${getRoleBadgeColor(user.role)}`}>
{user.role.charAt(0).toUpperCase() + user.role.slice(1)}
</span>
</div>
{isAdmin() && (
<button
onClick={handleManageUsers}
className="w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-50 flex items-center gap-3"
>
<Shield className="w-4 h-4" />
Manage Users
</button>
)}
<button
onClick={handleLogout}
className="w-full px-4 py-2 text-left text-sm text-red-600 hover:bg-red-50 flex items-center gap-3"
>
<LogOut className="w-4 h-4" />
Sign Out
</button>
</div>
)}
</div>
);
}