145 lines
4.5 KiB
TypeScript
145 lines
4.5 KiB
TypeScript
import * as React from 'react';
|
|
import { useRef, useEffect, useState } from 'react';
|
|
|
|
interface UserMenuProps {
|
|
userEmail: string;
|
|
userRole?: 'admin' | 'moderator';
|
|
editProfilePath: string;
|
|
signOutPath: string;
|
|
csrfToken: string;
|
|
globalStatesPath: string;
|
|
goodJobPath: string;
|
|
grafanaPath: string;
|
|
prometheusPath: string;
|
|
}
|
|
|
|
export const UserMenu: React.FC<UserMenuProps> = ({
|
|
userEmail,
|
|
userRole,
|
|
editProfilePath,
|
|
signOutPath,
|
|
csrfToken,
|
|
globalStatesPath,
|
|
goodJobPath,
|
|
grafanaPath,
|
|
prometheusPath,
|
|
}) => {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const menuRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
|
setIsOpen(false);
|
|
}
|
|
};
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
}, []);
|
|
|
|
const handleSignOut = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
const form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = signOutPath;
|
|
form.style.display = 'none';
|
|
|
|
const methodInput = document.createElement('input');
|
|
methodInput.type = 'hidden';
|
|
methodInput.name = '_method';
|
|
methodInput.value = 'delete';
|
|
|
|
const csrfInput = document.createElement('input');
|
|
csrfInput.type = 'hidden';
|
|
csrfInput.name = 'authenticity_token';
|
|
csrfInput.value = csrfToken;
|
|
|
|
form.appendChild(methodInput);
|
|
form.appendChild(csrfInput);
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
};
|
|
|
|
return (
|
|
<div className="relative" ref={menuRef}>
|
|
<button
|
|
className="flex items-center space-x-2 text-slate-600 hover:text-slate-900 focus:outline-none"
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
>
|
|
<i className="fas fa-user-circle text-2xl" />
|
|
<i className="fas fa-chevron-down text-xs" />
|
|
</button>
|
|
|
|
<div
|
|
className={`absolute right-0 z-50 mt-2 w-48 rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 transition-all duration-200 ${
|
|
isOpen ? 'visible opacity-100' : 'invisible opacity-0'
|
|
}`}
|
|
>
|
|
<div className="border-b border-slate-200 px-4 py-2 text-sm text-slate-700">
|
|
<div className="font-medium">{userEmail}</div>
|
|
{userRole === 'admin' && (
|
|
<span className="inline-flex items-center rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-800">
|
|
Admin
|
|
</span>
|
|
)}
|
|
{userRole === 'moderator' && (
|
|
<span className="inline-flex items-center rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-800">
|
|
Mod
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
{userRole === 'admin' && (
|
|
<>
|
|
<a
|
|
href={globalStatesPath}
|
|
className="flex w-full items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-100"
|
|
>
|
|
<i className="fas fa-cogs mr-2 w-5" />
|
|
<span>Global State</span>
|
|
</a>
|
|
<a
|
|
href={goodJobPath}
|
|
className="flex w-full items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-100"
|
|
>
|
|
<i className="fas fa-tasks mr-2 w-5" />
|
|
<span>Jobs Queue</span>
|
|
</a>
|
|
<a
|
|
href={grafanaPath}
|
|
className="flex w-full items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-100"
|
|
>
|
|
<i className="fas fa-chart-line mr-2 w-5" />
|
|
<span>Grafana</span>
|
|
</a>
|
|
<a
|
|
href={prometheusPath}
|
|
className="flex w-full items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-100"
|
|
>
|
|
<i className="fas fa-chart-bar mr-2 w-5" />
|
|
<span>Prometheus</span>
|
|
</a>
|
|
</>
|
|
)}
|
|
|
|
<a
|
|
href={editProfilePath}
|
|
className="flex w-full items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-100"
|
|
>
|
|
<i className="fas fa-cog mr-2 w-5" />
|
|
<span>Edit Profile</span>
|
|
</a>
|
|
|
|
<button
|
|
onClick={handleSignOut}
|
|
className="flex w-full items-center px-4 py-2 text-left text-sm text-slate-700 hover:bg-slate-100"
|
|
>
|
|
<i className="fas fa-sign-out-alt mr-2 w-5" />
|
|
<span>Sign Out</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|