ajinkya-mhetre-mern
Version:
A MERN starter with frontend and backend folders
299 lines (273 loc) • 11.3 kB
JSX
// 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