This commit is contained in:
118
src/components/Navbar.jsx
Normal file
118
src/components/Navbar.jsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import { Menu, Search, 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?.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>
|
||||
|
||||
{/* Search */}
|
||||
<div className="hidden md:flex items-center gap-2 bg-th-bg-s border border-th-border rounded-lg px-3 py-2 w-64 lg:w-80">
|
||||
<Search size={16} className="text-th-text-s flex-shrink-0" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t('common.search')}
|
||||
className="bg-transparent border-none outline-none text-sm text-th-text placeholder-th-text-s w-full"
|
||||
/>
|
||||
</div>
|
||||
</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?.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?.name}</p>
|
||||
<p className="text-xs text-th-text-s">{user?.email}</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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user