130 lines
4.7 KiB
JavaScript
130 lines
4.7 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { Menu, Sun, Moon, User, LogOut, ChevronDown } from 'lucide-react';
|
|
import { signOut } from '../services/api';
|
|
import { useAuthStore } from '../store/authStore';
|
|
import { useAuth } from '../context/AuthContext';
|
|
|
|
const Navbar = ({ onSidebarToggle }) => {
|
|
let user = null;
|
|
try {
|
|
const authContext = useAuth();
|
|
user = authContext?.user || null;
|
|
} catch (e) {
|
|
// useAuth not available, will use localStorage
|
|
}
|
|
const userData = user || JSON.parse(localStorage.getItem('user') || '{}') || {};
|
|
const userName = userData.name && userData.name !== '...' ? userData.name : (userData.email || '...');
|
|
const userEmail = userData.email || '';
|
|
const isLoggedIn = useAuthStore((s) => s.isLoggedIn);
|
|
const [isDarkMode, setIsDarkMode] = useState(() => {
|
|
return localStorage.getItem('theme') === 'dark' ||
|
|
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
});
|
|
const [isUserMenuOpen, setIsUserMenuOpen] = useState(false);
|
|
|
|
// Apply theme to document
|
|
React.useEffect(() => {
|
|
if (isDarkMode) {
|
|
document.documentElement.classList.add('dark');
|
|
localStorage.setItem('theme', 'dark');
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
localStorage.setItem('theme', 'light');
|
|
}
|
|
}, [isDarkMode]);
|
|
|
|
const toggleTheme = () => {
|
|
setIsDarkMode(!isDarkMode);
|
|
};
|
|
|
|
const handleLogout = async () => {
|
|
try {
|
|
await signOut();
|
|
} catch (e) {
|
|
// no-op; interceptor handles redirect and state
|
|
} finally {
|
|
setIsUserMenuOpen(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<header className="bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700 h-16 flex items-center justify-between px-4 lg:px-6 relative z-20">
|
|
{/* Left side */}
|
|
<div className="flex items-center space-x-4">
|
|
<button
|
|
onClick={onSidebarToggle}
|
|
className="lg:hidden p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800"
|
|
>
|
|
<Menu className="h-5 w-5" />
|
|
</button>
|
|
|
|
<h1 className="text-lg font-semibold text-gray-900 dark:text-white lg:hidden">
|
|
KHalij Payment
|
|
</h1>
|
|
</div>
|
|
|
|
{/* Right side */}
|
|
<div className="flex items-center space-x-4">
|
|
{/* Theme toggle */}
|
|
<button
|
|
onClick={toggleTheme}
|
|
className="p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-200"
|
|
aria-label="Toggle theme"
|
|
>
|
|
{isDarkMode ? (
|
|
<Sun className="h-5 w-5" />
|
|
) : (
|
|
<Moon className="h-5 w-5" />
|
|
)}
|
|
</button>
|
|
|
|
{/* User menu */}
|
|
<div className="relative">
|
|
<button
|
|
onClick={() => setIsUserMenuOpen(!isUserMenuOpen)}
|
|
className="flex items-center space-x-2 p-2 rounded-md text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800 transition-colors duration-200"
|
|
>
|
|
<div className="w-8 h-8 bg-blue-100 dark:bg-blue-900 rounded-full flex items-center justify-center">
|
|
<User className="h-4 w-4 text-blue-600 dark:text-blue-400" />
|
|
</div>
|
|
<span className="hidden sm:block text-sm font-medium">
|
|
{isLoggedIn ? userName : 'Guest'}
|
|
</span>
|
|
<ChevronDown className="h-4 w-4" />
|
|
</button>
|
|
|
|
{/* Dropdown menu */}
|
|
{isUserMenuOpen && (
|
|
<div className="absolute right-0 mt-2 w-48 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 py-1 z-50">
|
|
<div className="px-4 py-2 border-b border-gray-200 dark:border-gray-700">
|
|
<p className="text-sm font-medium text-gray-900 dark:text-white">
|
|
{isLoggedIn ? userName : 'Guest'}
|
|
</p>
|
|
<p className="text-xs text-gray-500 dark:text-gray-400">
|
|
{isLoggedIn ? userEmail : ''}
|
|
</p>
|
|
</div>
|
|
<button
|
|
onClick={handleLogout}
|
|
className="w-full flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 transition-colors duration-200"
|
|
>
|
|
<LogOut className="mr-2 h-4 w-4" />
|
|
Sign out
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Click outside to close user menu */}
|
|
{isUserMenuOpen && (
|
|
<div
|
|
className="fixed inset-0 z-40"
|
|
onClick={() => setIsUserMenuOpen(false)}
|
|
/>
|
|
)}
|
|
</header>
|
|
);
|
|
};
|
|
|
|
export default Navbar; |