All checks were successful
Build & Push Docker Image / build (push) Successful in 6m18s
109 lines
4.0 KiB
JavaScript
109 lines
4.0 KiB
JavaScript
import { Menu, LogOut, User } from 'lucide-react';
|
|
import { useAuth } from '../contexts/AuthContext';
|
|
import { useLanguage } from '../contexts/LanguageContext';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useState, useRef, useEffect } from 'react';
|
|
import api from '../services/api';
|
|
|
|
export default function Navbar({ onMenuClick }) {
|
|
const { user, logout } = useAuth();
|
|
const { t } = useLanguage();
|
|
const navigate = useNavigate();
|
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
const dropdownRef = useRef(null);
|
|
|
|
useEffect(() => {
|
|
function handleClick(e) {
|
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
setDropdownOpen(false);
|
|
}
|
|
}
|
|
document.addEventListener('mousedown', handleClick);
|
|
return () => document.removeEventListener('mousedown', handleClick);
|
|
}, []);
|
|
|
|
const handleLogout = () => {
|
|
logout();
|
|
navigate('/');
|
|
};
|
|
|
|
const initials = (user?.display_name || user?.name)
|
|
? (user.display_name || user.name)
|
|
.split(' ')
|
|
.map(n => n[0])
|
|
.join('')
|
|
.toUpperCase()
|
|
.slice(0, 2)
|
|
: '?';
|
|
|
|
return (
|
|
<header className="sticky top-0 z-20 bg-th-nav border-b border-th-border backdrop-blur-sm">
|
|
<div className="flex items-center justify-between h-16 px-4 md:px-6">
|
|
{/* Left section */}
|
|
<div className="flex items-center gap-3">
|
|
<button
|
|
onClick={onMenuClick}
|
|
className="lg:hidden p-2 rounded-lg hover:bg-th-hover text-th-text-s transition-colors"
|
|
>
|
|
<Menu size={20} />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Right section */}
|
|
<div className="flex items-center gap-2">
|
|
{/* User dropdown */}
|
|
<div className="relative" ref={dropdownRef}>
|
|
<button
|
|
onClick={() => setDropdownOpen(!dropdownOpen)}
|
|
className="flex items-center gap-2 p-1.5 rounded-lg hover:bg-th-hover transition-colors"
|
|
>
|
|
<div
|
|
className="w-8 h-8 rounded-full flex items-center justify-center text-white text-xs font-bold overflow-hidden"
|
|
style={{ backgroundColor: user?.avatar_color || '#6366f1' }}
|
|
>
|
|
{user?.avatar_image ? (
|
|
<img
|
|
src={`${api.defaults.baseURL}/auth/avatar/${user.avatar_image}`}
|
|
alt="Avatar"
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
) : (
|
|
initials
|
|
)}
|
|
</div>
|
|
<span className="hidden md:block text-sm font-medium text-th-text">
|
|
{user?.display_name || user?.name}
|
|
</span>
|
|
</button>
|
|
|
|
{dropdownOpen && (
|
|
<div className="absolute right-0 mt-2 w-56 bg-th-card rounded-xl border border-th-border shadow-th-lg overflow-hidden">
|
|
<div className="px-4 py-3 border-b border-th-border">
|
|
<p className="text-sm font-medium text-th-text">{user?.display_name || user?.name}</p>
|
|
<p className="text-xs text-th-text-s">@{user?.name}</p>
|
|
</div>
|
|
<div className="py-1">
|
|
<button
|
|
onClick={() => { navigate('/settings'); setDropdownOpen(false); }}
|
|
className="w-full flex items-center gap-2 px-4 py-2.5 text-sm text-th-text hover:bg-th-hover transition-colors"
|
|
>
|
|
<User size={16} />
|
|
{t('nav.settings')}
|
|
</button>
|
|
<button
|
|
onClick={handleLogout}
|
|
className="w-full flex items-center gap-2 px-4 py-2.5 text-sm text-th-error hover:bg-th-hover transition-colors"
|
|
>
|
|
<LogOut size={16} />
|
|
{t('auth.logout')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|