UNPKG

ajinkya-mhetre-mern

Version:

A MERN starter with frontend and backend folders

299 lines (273 loc) 11.3 kB
// components/layout/Header.jsx import React from 'react' import { Link, useLocation, useNavigate } from 'react-router-dom' import { useAuth } from '../../contexts/AuthContext' import { User, LogOut, Home, Users, UserCheck, Plus, Package, ShoppingBag, ShoppingCart, Menu, X,ChevronDown, Settings } from 'lucide-react' const baseUrl = import.meta.env.VITE_API_URL; const Header = () => { const { user, logout, token } = useAuth() const location = useLocation() const navigate = useNavigate() const [profile, setProfile] = React.useState(false) const [profileData, setProfileData] = React.useState(null) const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false) const [dropdownOpen, setDropdownOpen] = React.useState(false) const getInfo = async () => { if (!user || !token) { console.error('User or token not found') return } try { const response = await fetch(`${baseUrl}/auth/profile`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, }) const data = await response.json() if (data.success) { setProfileData(data.user) setProfile(true) } else { console.error('Failed to fetch profile:', data.message) } } catch (error) { console.error('Error fetching profile:', error.message) } } const handleLogout = () => { // Clear all local storage data localStorage.clear() // Clear session storage as well (if you're using it) sessionStorage.clear() // Close mobile menu and profile popup setMobileMenuOpen(false) setProfile(false) setProfileData(null) // Call the logout function from context logout() // Navigate to home page navigate('/') } const getNavigationItems = () => { if (!user || !user.role) { return [] } switch (user.role.toLowerCase()) { case 'farmer': return [ { icon: Package, label: 'My Products', path: '/dashboard/farmer/my-products' }, { icon: ShoppingBag, label: 'My Orders', path: '/dashboard/farmer/my-orders' }, ] case 'customer': return [ { icon: ShoppingCart, label: 'My Orders', path: '/dashboard/customer/order' }, ] case 'admin': return [ { icon: UserCheck, label: 'Farmers', path: '/dashboard/admin/farmers' }, { icon: Users, label: 'Users', path: '/dashboard/admin/users' }, { icon: Plus, label: 'Add Farmer', path: '/dashboard/admin/addframer' }, ] default: return [] } } const navigationItems = getNavigationItems() // If user is not logged in, show a simple header if (!user || !token) { return ( <header className="bg-white border-b shadow-sm"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="flex items-center justify-between h-16"> {/* Logo */} <div className="flex items-center"> <h1 className="text-xl font-bold text-green-600">FarmFresh</h1> </div> {/* Navigation for non-logged in users */} <nav className="flex items-center space-x-4"> <Link to="/" className="flex items-center space-x-1 text-gray-600 hover:text-gray-900 px-3 py-2 rounded-md transition-colors" > <Home className="h-4 w-4" /> <span>Home</span> </Link> <Link to="/login" className="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 transition-colors" > Login </Link> <Link to="/register" className="border border-green-600 text-green-600 px-4 py-2 rounded-md hover:bg-green-50 transition-colors" > Register </Link> </nav> </div> </div> </header> ) } return ( <header className="bg-white border-b shadow-sm relative z-50"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="flex items-center justify-between h-16"> {/* Left: Logo & Title */} <div className="flex items-center space-x-2"> <h1 className="text-xl font-bold text-green-600">FarmFresh</h1> <span className="text-sm text-gray-500 capitalize hidden sm:inline"> - {user.role} Dashboard </span> </div> {/* Center: Desktop Navigation */} <div className="flex"> <nav className="hidden md:flex items-center space-x-1"> <Link to="/home" className="flex items-center space-x-1 text-gray-600 hover:text-gray-900 px-3 py-2 rounded-md transition-colors" > <Home className="h-4 w-4" /> <span>Home</span> </Link> {navigationItems.map((item) => { const Icon = item.icon const isActive = location.pathname === item.path return ( <Link key={item.path} to={item.path} className={`flex items-center space-x-1 px-3 py-2 rounded-md transition-colors ${ isActive ? 'bg-blue-100 text-blue-600' : 'text-gray-600 hover:text-gray-900' }`} > <Icon className="h-4 w-4" /> <span>{item.label}</span> </Link> ) })} </nav> {/* Right: User Actions */} <div className="flex items-center space-x-2"> {/* Mobile Menu Button */} <button onClick={() => setMobileMenuOpen(!mobileMenuOpen)} className="md:hidden p-2 rounded-md hover:bg-gray-100" > {mobileMenuOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />} </button> {/* Desktop User Actions */} <div className="hidden md:flex items-center space-x-2"> <button onClick={getInfo} className="flex items-center space-x-1 text-gray-700 hover:text-gray-900 px-3 py-2 rounded-md" > <User className="h-4 w-4" /> <span className="hidden lg:inline">{user.name || user.email || 'User'}</span> </button> <button onClick={handleLogout} className="flex items-center space-x-1 text-red-600 hover:text-red-800 px-3 py-2 rounded-md" > <LogOut className="h-4 w-4" /> <span className="hidden lg:inline">Logout</span> </button> </div> </div> </div> </div> {/* Mobile Navigation Menu */} {mobileMenuOpen && ( <div className="md:hidden border-t bg-white"> <div className="px-2 pt-2 pb-3 space-y-1"> <Link to="/home" className="flex items-center space-x-2 text-gray-600 hover:text-gray-900 block px-3 py-2 rounded-md" onClick={() => setMobileMenuOpen(false)} > <Home className="h-4 w-4" /> <span>Home</span> </Link> {navigationItems.map((item) => { const Icon = item.icon const isActive = location.pathname === item.path return ( <Link key={item.path} to={item.path} className={`flex items-center space-x-2 block px-3 py-2 rounded-md ${ isActive ? 'bg-blue-100 text-blue-600' : 'text-gray-600 hover:text-gray-900' }`} onClick={() => setMobileMenuOpen(false)} > <Icon className="h-4 w-4" /> <span>{item.label}</span> </Link> ) })} {/* Mobile User Actions */} <div className="border-t pt-2 mt-2"> <button onClick={() => { getInfo() setMobileMenuOpen(false) }} className="flex items-center space-x-2 text-gray-700 hover:text-gray-900 w-full px-3 py-2 rounded-md" > <User className="h-4 w-4" /> <span>{user.name || user.email || 'User'}</span> </button> <button onClick={handleLogout} className="flex items-center space-x-2 text-red-600 hover:text-red-800 w-full px-3 py-2 rounded-md" > <LogOut className="h-4 w-4" /> <span>Logout</span> </button> </div> </div> </div> )} </div> {/* Profile Popup */} {profile && profileData && ( <div className="absolute right-4 top-[4.2rem] w-72 bg-white border border-gray-200 rounded-xl shadow-xl z-50"> <div className="p-4"> <h3 className="text-base font-semibold text-green-600 mb-2">User Profile</h3> <div className="space-y-1 text-sm text-gray-700"> <p><span className="font-medium">Name:</span> {profileData.name}</p> <p><span className="font-medium">Email:</span> {profileData.email}</p> <p><span className="font-medium">Phone:</span> {profileData.phone}</p> <p><span className="font-medium">Role:</span> {profileData.role}</p> <p><span className="font-medium">Verified:</span> {profileData.isVerified ? 'Yes' : 'No'}</p> {profileData.address && ( <> <p className="font-medium mt-2">Address:</p> <ul className="pl-4 list-disc text-gray-600"> <li>{profileData.address.street}</li> <li>{profileData.address.city}, {profileData.address.state}</li> <li>{profileData.address.zipCode}</li> </ul> </> )} </div> <button onClick={() => setProfile(false)} className="mt-3 text-sm text-blue-600 hover:text-blue-800" > Close </button> </div> </div> )} </header> ) } export default Header