first commit
This commit is contained in:
366
components/layout/header.tsx
Normal file
366
components/layout/header.tsx
Normal file
@@ -0,0 +1,366 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { ChevronDown, Menu, X, Wheat, Leaf, Package, Building2, Settings, ShoppingBag, LogOut, LucideIcon } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
|
||||
import { useSession, signOut } from 'next-auth/react'
|
||||
import CartSidebar from '@/components/shop/CartSidebar'
|
||||
import MegaMenu from '@/components/layout/MegaMenu'
|
||||
import { isFeatureEnabled } from '@/lib/business-config'
|
||||
|
||||
interface MenuItem {
|
||||
name: string
|
||||
href: string
|
||||
description: string
|
||||
}
|
||||
|
||||
interface MenuCategory {
|
||||
name: string
|
||||
icon: LucideIcon
|
||||
items: MenuItem[]
|
||||
}
|
||||
|
||||
interface MegaMenuConfig {
|
||||
title: string
|
||||
type: 'categories'
|
||||
categories: MenuCategory[]
|
||||
}
|
||||
|
||||
export function Header() {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
const [activeDropdown, setActiveDropdown] = useState<string | null>(null)
|
||||
const [isScrolled, setIsScrolled] = useState(false)
|
||||
|
||||
const navItems = [
|
||||
// { name: 'Home', href: '/' },
|
||||
{ name: 'Recipes', href: '/recipes' },
|
||||
// { name: 'About', href: '/about' },
|
||||
{ name: 'Contact', href: '/contact' },
|
||||
]
|
||||
|
||||
const megaMenus: Record<string, MegaMenuConfig> = {
|
||||
products: {
|
||||
title: 'Products',
|
||||
type: 'categories' as const,
|
||||
categories: [] // Will be populated dynamically by MegaMenu component
|
||||
},
|
||||
company: {
|
||||
title: 'Company',
|
||||
type: 'categories' as const,
|
||||
categories: [
|
||||
{
|
||||
name: 'About Us',
|
||||
icon: Building2,
|
||||
items: [
|
||||
{ name: 'Our Story', href: '/about', description: 'Company history and mission' },
|
||||
{ name: 'Our Founder', href: '/about/founder', description: 'Meet our visionary leader' },
|
||||
{ name: 'Certifications', href: '/about/certifications', description: 'Industry recognition' },
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Business',
|
||||
icon: Settings,
|
||||
items: [
|
||||
{ name: 'Partnership', href: '/partnership', description: 'Join our network' },
|
||||
{ name: 'Wholesaler', href: '/wholesaler', description: 'Wholesaler program' },
|
||||
{ name: 'Sustainability', href: '/sustainability', description: 'Environmental commitment' },
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const { data: session } = useSession()
|
||||
|
||||
const adminNavigation = [
|
||||
{ name: 'Admin Dashboard', href: '/admin', icon: Settings },
|
||||
{ name: 'Manage Products', href: '/admin/products', icon: Package },
|
||||
{ name: 'Manage Orders', href: '/admin/orders', icon: ShoppingBag },
|
||||
]
|
||||
|
||||
const memberNavigation = [
|
||||
{ name: 'Dashboard', href: '/dashboard', icon: Settings },
|
||||
{ name: 'My Orders', href: '/dashboard/orders', icon: ShoppingBag },
|
||||
{ name: 'Profile', href: '/dashboard/profile', icon: Settings },
|
||||
]
|
||||
|
||||
// Scroll detection for sticky header
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
const scrollTop = window.scrollY
|
||||
const scrolled = scrollTop > 0
|
||||
setIsScrolled(scrolled)
|
||||
|
||||
// Add/remove class to body for content padding
|
||||
if (scrolled) {
|
||||
document.body.classList.add('header-sticky')
|
||||
} else {
|
||||
document.body.classList.remove('header-sticky')
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', handleScroll)
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
document.body.classList.remove('header-sticky')
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (mobileMenuOpen) {
|
||||
document.body.style.overflow = 'hidden'
|
||||
} else {
|
||||
document.body.style.overflow = 'unset'
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.body.style.overflow = 'unset'
|
||||
}
|
||||
}, [mobileMenuOpen])
|
||||
|
||||
const handleMouseEnter = (dropdown: string) => {
|
||||
setActiveDropdown(dropdown)
|
||||
}
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
setActiveDropdown(null)
|
||||
}
|
||||
|
||||
const handleMobileMenuClick = () => {
|
||||
setMobileMenuOpen(!mobileMenuOpen)
|
||||
}
|
||||
|
||||
const handleMobileLinkClick = () => {
|
||||
setMobileMenuOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<nav className={`transition-all duration-300 ${
|
||||
isScrolled
|
||||
? 'fixed top-0 left-0 right-0 z-50 bg-white/95 backdrop-blur-md border-b border-slate-200 shadow-lg'
|
||||
: 'relative bg-white border-b border-slate-200'
|
||||
}`}>
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className={`flex justify-between items-center transition-all duration-300 ${
|
||||
isScrolled ? 'h-20' : 'h-24'
|
||||
}`}>
|
||||
{/* Logo */}
|
||||
<Link href="/" className="flex-shrink-0 flex items-center z-10">
|
||||
<div className="flex items-center space-x-3">
|
||||
<Image
|
||||
src="/kashmina-logo.png"
|
||||
alt="PADMAAJA RASOOI PVT. LTD."
|
||||
width={150}
|
||||
height={150}
|
||||
className="object-contain"
|
||||
/>
|
||||
{/* <div className="flex flex-col">
|
||||
<span className="text-lg font-bold text-slate-800 transition-colors duration-300 leading-tight">
|
||||
KASHMINA RICE
|
||||
</span>
|
||||
<span className="text-xs uppercase text-slate-600 transition-colors duration-300 leading-tight">
|
||||
"Premium Rice"
|
||||
</span>
|
||||
</div> */}
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<div className="hidden lg:flex items-center space-x-8">
|
||||
{/* Regular Nav Items */}
|
||||
{navItems.map(item => (
|
||||
<Link
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
className="text-base font-medium text-slate-700 hover:text-emerald-600 transition-colors duration-200"
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
))}
|
||||
|
||||
{/* Mega Menu Items */}
|
||||
{Object.entries(megaMenus).map(([key, menu]) => (
|
||||
<div
|
||||
key={key}
|
||||
className="relative"
|
||||
onMouseEnter={() => handleMouseEnter(key)}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<button
|
||||
className={`flex items-center space-x-1 text-base font-medium text-slate-700 hover:text-emerald-600 transition-colors duration-200 ${
|
||||
activeDropdown === key ? 'text-emerald-600' : ''
|
||||
}`}
|
||||
>
|
||||
<span>{menu.title}</span>
|
||||
<ChevronDown className={`w-4 h-4 transition-transform duration-200 ${
|
||||
activeDropdown === key ? 'rotate-180' : ''
|
||||
}`} />
|
||||
</button>
|
||||
|
||||
{/* Mega Menu Dropdown */}
|
||||
<MegaMenu
|
||||
menuKey={key}
|
||||
menu={menu}
|
||||
isActive={activeDropdown === key}
|
||||
onClose={() => setActiveDropdown(null)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
{/* B2C Feature - Cart Sidebar (Disabled for B2B mode) */}
|
||||
{isFeatureEnabled('cart') && <CartSidebar />}
|
||||
|
||||
{session ? (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="relative h-10 w-10 rounded-full">
|
||||
<Avatar className="h-10 w-10">
|
||||
<AvatarImage src={session.user.image || ''} alt={session.user.name || ''} />
|
||||
<AvatarFallback>
|
||||
{session.user.name?.[0] || session.user.email?.[0] || 'U'}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56" align="end" forceMount>
|
||||
<DropdownMenuLabel className="font-normal">
|
||||
<div className="flex flex-col space-y-1">
|
||||
<p className="text-sm font-medium leading-none">{session.user.name}</p>
|
||||
<p className="text-xs leading-none text-muted-foreground">
|
||||
{session.user.email}
|
||||
</p>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
{session.user.role === 'ADMIN' && adminNavigation.map((item) => (
|
||||
<DropdownMenuItem key={item.name} asChild>
|
||||
<Link href={item.href} className="flex items-center">
|
||||
<item.icon className="mr-2 h-4 w-4" />
|
||||
{item.name}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
|
||||
{(session.user.role === 'MEMBER' || session.user.role === 'ADMIN') &&
|
||||
memberNavigation.map((item) => (
|
||||
<DropdownMenuItem key={item.name} asChild>
|
||||
<Link href={item.href} className="flex items-center">
|
||||
<item.icon className="mr-2 h-4 w-4" />
|
||||
{item.name}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => signOut()}>
|
||||
<LogOut className="mr-2 h-4 w-4" />
|
||||
Log out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
) : (
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button variant="ghost" className="h-10 px-4 py-2 text-base font-medium" asChild>
|
||||
<Link href="/auth/signin">Sign In</Link>
|
||||
</Button>
|
||||
<Button className="h-10 px-4 py-2 text-base font-medium" asChild>
|
||||
<Link href="/auth/signup">Sign Up</Link>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<div className="lg:hidden">
|
||||
<button
|
||||
onClick={handleMobileMenuClick}
|
||||
className="p-4 rounded-lg text-slate-700 hover:bg-slate-100 transition-colors duration-200 touch-manipulation min-w-[48px] min-h-[48px] flex items-center justify-center"
|
||||
aria-label="Toggle mobile menu"
|
||||
>
|
||||
{mobileMenuOpen ? <X className="w-7 h-7" /> : <Menu className="w-7 h-7" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
<AnimatePresence>
|
||||
{mobileMenuOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: 'auto' }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="lg:hidden border-t bg-white border-slate-200 shadow-lg relative z-50"
|
||||
>
|
||||
<div className="px-4 py-6 space-y-6 max-h-[80vh] overflow-y-auto">
|
||||
{/* Regular Nav Items */}
|
||||
{navItems.map(item => (
|
||||
<Link
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
className="mobile-nav-item block text-lg font-medium text-slate-700 hover:text-emerald-600 transition-colors duration-200 py-3 px-2 rounded-lg hover:bg-slate-50 touch-manipulation"
|
||||
onClick={handleMobileLinkClick}
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
))}
|
||||
|
||||
{/* Mobile Mega Menu Items */}
|
||||
{Object.entries(megaMenus).map(([key, menu]) => (
|
||||
<div key={key} className="space-y-3">
|
||||
<h3 className="font-semibold text-slate-800 text-lg sm:text-xl">{menu.title}</h3>
|
||||
|
||||
{menu.type === 'categories' ? (
|
||||
// Products with Categories - Mobile Responsive
|
||||
<div className="space-y-4">
|
||||
{menu.categories?.map((category: MenuCategory, idx: number) => {
|
||||
const IconComponent = category.icon
|
||||
return (
|
||||
<div key={idx} className="space-y-2">
|
||||
<div className="flex items-center space-x-2 text-emerald-600 font-medium text-base sm:text-lg">
|
||||
<IconComponent className="w-4 h-4 flex-shrink-0" />
|
||||
<span>{category.name}</span>
|
||||
</div>
|
||||
<div className="pl-6 space-y-1">
|
||||
{category.items.map((item: MenuItem, itemIdx: number) => (
|
||||
<Link
|
||||
key={itemIdx}
|
||||
href={item.href}
|
||||
className="mobile-nav-item block text-base text-slate-600 hover:text-emerald-600 hover:bg-slate-50 transition-colors duration-200 py-2 px-2 rounded-md touch-manipulation"
|
||||
onClick={handleMobileLinkClick}
|
||||
>
|
||||
<div className="font-medium">{item.name}</div>
|
||||
<div className="text-xs text-slate-500 mt-0.5">{item.description}</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Mobile CTA */}
|
||||
<Link href="/contact#quote" onClick={handleMobileLinkClick}>
|
||||
<Button className="w-full bg-emerald-600 text-white hover:bg-emerald-700 rounded-xl px-6 py-4 mt-6 font-medium text-lg touch-manipulation">
|
||||
Get a Quote
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user