668 lines
32 KiB
TypeScript
668 lines
32 KiB
TypeScript
"use client";
|
||
|
||
import React, { useState, useRef, useEffect } from "react";
|
||
import { Search, ChevronDown, Menu, X, Pill, ShieldCheck, HeartPulse, Sparkles, ShoppingBag, User, Check, Building2, LogIn, LogOut, FileHeart, Dog, BookOpen, FileText, Video, Award, PhoneCall, Activity } from "lucide-react";
|
||
import { motion, AnimatePresence } from "motion/react";
|
||
import Link from "next/link";
|
||
import { useCartStore } from "../lib/store/cartStore";
|
||
import { usePetStore } from "../lib/store/usePetStore";
|
||
import { useUserStore } from "../lib/store/userStore";
|
||
import { useSettingsStore } from "../lib/store/settingsStore";
|
||
import { toast } from "sonner";
|
||
import AuthModal from "./AuthModal";
|
||
import PrescriptionUploadModal from "./PrescriptionUploadModal";
|
||
import TickerBanner from "./TickerBanner";
|
||
import BrandLogo from "./BrandLogo";
|
||
import { cn } from "../lib/utils";
|
||
import { productService } from "../lib/services/productService";
|
||
|
||
const MENU_ICONS: Record<string, React.ReactNode> = {
|
||
joints: <Pill className="w-5 h-5" />,
|
||
immune: <ShieldCheck className="w-5 h-5" />,
|
||
energy: <HeartPulse className="w-5 h-5" />,
|
||
"special-care": <Sparkles className="w-5 h-5" />,
|
||
};
|
||
|
||
import { NavigationTarget } from "../lib/types";
|
||
|
||
export default function Header({
|
||
onCartOpen = () => {},
|
||
onSearch = () => {},
|
||
onB2BOpen = () => {}
|
||
}: {
|
||
onNavigate?: (v: NavigationTarget) => void;
|
||
onShopNavigate?: (c?: string, s?: string) => void;
|
||
currentView?: string;
|
||
onCartOpen?: () => void;
|
||
onSearch?: (q: string) => void;
|
||
onB2BOpen?: () => void;
|
||
}) {
|
||
const [isMegaMenuOpen, setIsMegaMenuOpen] = useState(false);
|
||
const [activeDropdown, setActiveDropdown] = useState<string | null>(null);
|
||
const [isAuthModalOpen, setIsAuthModalOpen] = useState(false);
|
||
const [isPrescriptionModalOpen, setIsPrescriptionModalOpen] = useState(false);
|
||
const [isProfileMenuOpen, setIsProfileMenuOpen] = useState(false);
|
||
const userProfileRef = useRef<HTMLDivElement>(null);
|
||
const navBarRef = useRef<HTMLDivElement>(null);
|
||
const [searchQuery, setSearchQuery] = useState("");
|
||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||
const isB2BEnabled = useSettingsStore((s) => s.getBoolean('b2bRegistrationOpen', true) && s.getBoolean('b2b_enabled', true));
|
||
const isPrescriptionEnabled = useSettingsStore((s) => s.getText('PRESCRIPTION_UPLOAD_ENABLED', 'true') !== 'false');
|
||
|
||
const [menuItems, setMenuItems] = useState<{
|
||
id: string;
|
||
title: string;
|
||
icon: React.ReactNode;
|
||
solutions: string[];
|
||
}[]>([
|
||
{
|
||
id: "joints",
|
||
title: "مفاصل و استخوان",
|
||
icon: MENU_ICONS["joints"],
|
||
solutions: ["لنگیدن", "سختی در بلند شدن", "درد مفاصل", "رشد سریع تولهسگ", "پاهای پرانتزی", "ضعف تاندون"]
|
||
},
|
||
{
|
||
id: "immune",
|
||
title: "تقویت سیستم ایمنی و گوارش",
|
||
icon: MENU_ICONS["immune"],
|
||
solutions: ["ضعف بعد از بیماری", "بیاشتهایی", "بعد از زایمان", "اسهال", "مشکلات گوارشی"]
|
||
},
|
||
{
|
||
id: "energy",
|
||
title: "ویتامینها و انرژیبخشها",
|
||
icon: MENU_ICONS["energy"],
|
||
solutions: ["نفسنفس زدن", "خستگی", "سن بالا", "بیحالی"]
|
||
},
|
||
{
|
||
id: "special-care",
|
||
title: "مراقبتهای ویژه (پوست، دندان و چشم)",
|
||
icon: MENU_ICONS["special-care"],
|
||
solutions: ["ریزش مو", "خشکی پوست", "خارش", "جرم دندان", "سوزش چشم"]
|
||
}
|
||
]);
|
||
|
||
interface HeaderMenuItem {
|
||
id: string;
|
||
label: string;
|
||
href: string;
|
||
icon?: string | null;
|
||
badge?: string | null;
|
||
children?: { id: string; label: string; href: string; icon?: string | null }[];
|
||
}
|
||
|
||
const [headerNavItems, setHeaderNavItems] = useState<HeaderMenuItem[]>([
|
||
{
|
||
id: 'symptoms',
|
||
label: 'راهکارهای درمانی',
|
||
href: '/shop?view=symptoms',
|
||
icon: 'Pill',
|
||
},
|
||
{
|
||
id: 'products',
|
||
label: 'محصولات تخصصی',
|
||
href: '/shop',
|
||
icon: 'ShoppingBag',
|
||
children: [
|
||
{ id: 'shop-all', label: 'فروشگاه تخصصی محصولات کنینا', href: '/shop' },
|
||
{ id: 'catalog', label: 'کاتالوگ دیجیتال و راهنمای بالینی', href: '/catalog' },
|
||
],
|
||
},
|
||
{
|
||
id: 'science',
|
||
label: 'دانشنامه علمی',
|
||
href: '/wiki',
|
||
icon: 'BookOpen',
|
||
children: [
|
||
{ id: 'wiki', label: 'دانشنامه علمی ترکیبات', href: '/wiki' },
|
||
{ id: 'blog', label: 'مجله سلامت پت (وبلاگ)', href: '/blog' },
|
||
],
|
||
},
|
||
{
|
||
id: 'blog-mag',
|
||
label: 'مجله سلامت پت',
|
||
href: '/blog',
|
||
icon: 'FileText',
|
||
},
|
||
{
|
||
id: 'pets',
|
||
label: 'شناسنامه پتها',
|
||
href: '/dashboard/pets',
|
||
icon: 'Dog',
|
||
},
|
||
{
|
||
id: 'videos',
|
||
label: 'ویدیوها',
|
||
href: '/videos',
|
||
icon: 'Video',
|
||
},
|
||
]);
|
||
|
||
const [isMounted, setIsMounted] = useState(false);
|
||
useEffect(() => {
|
||
Promise.resolve().then(() => setIsMounted(true));
|
||
}, []);
|
||
const { getTotalItems } = useCartStore();
|
||
const { pets, activePetId, setActivePet } = usePetStore();
|
||
const { isLoggedIn, logout, profile } = useUserStore();
|
||
const getText = useSettingsStore(state => state.getText);
|
||
const isCatalogMode = getText('catalog_mode', 'false') === 'true';
|
||
const isCatalogDisableCart = getText('catalog_disable_cart', 'false') === 'true';
|
||
const isCartDisabled = isCatalogMode || isCatalogDisableCart;
|
||
|
||
useEffect(() => {
|
||
const loadDynamicNav = async () => {
|
||
try {
|
||
const [filtersRes, menuRes] = await Promise.allSettled([
|
||
productService.getNavigationFilters(),
|
||
fetch(`${process.env.NEXT_PUBLIC_API_URL || '/api'}/menu/type/HEADER`).then((r) => r.json()),
|
||
]);
|
||
|
||
if (filtersRes.status === 'fulfilled' && filtersRes.value && filtersRes.value.length > 0) {
|
||
setMenuItems(
|
||
filtersRes.value.map((item) => ({
|
||
id: item.slug,
|
||
title: item.name,
|
||
icon: MENU_ICONS[item.slug] || <Pill className="w-5 h-5" />,
|
||
solutions: item.symptoms || [],
|
||
}))
|
||
);
|
||
}
|
||
|
||
if (menuRes.status === 'fulfilled' && Array.isArray(menuRes.value) && menuRes.value.length > 0) {
|
||
setHeaderNavItems(menuRes.value);
|
||
}
|
||
} catch (err) {
|
||
console.error('Failed to load navigation data:', err);
|
||
}
|
||
};
|
||
loadDynamicNav();
|
||
}, []);
|
||
|
||
|
||
useEffect(() => {
|
||
function handleClickOutside(event: MouseEvent) {
|
||
if (userProfileRef.current && !userProfileRef.current.contains(event.target as Node)) {
|
||
setIsProfileMenuOpen(false);
|
||
}
|
||
if (navBarRef.current && !navBarRef.current.contains(event.target as Node)) {
|
||
setIsMegaMenuOpen(false);
|
||
setActiveDropdown(null);
|
||
}
|
||
}
|
||
document.addEventListener("mousedown", handleClickOutside);
|
||
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||
}, []);
|
||
|
||
const handleSearch = (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
if (searchQuery.trim()) {
|
||
onSearch(searchQuery);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<AuthModal isOpen={isAuthModalOpen} onClose={() => setIsAuthModalOpen(false)} />
|
||
<PrescriptionUploadModal isOpen={isPrescriptionModalOpen} onClose={() => setIsPrescriptionModalOpen(false)} />
|
||
|
||
<div className="sticky top-0 z-50 w-full shadow-md font-vazir" dir="rtl">
|
||
{/* Sliding Announcement Ticker Banner */}
|
||
<TickerBanner />
|
||
|
||
<header className="bg-white border-b border-medical-gray-200">
|
||
{/* TOP ROW: Logo + Search + Primary Actions */}
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-3 flex items-center justify-between gap-4">
|
||
|
||
{/* Mobile Menu Toggle & Logo */}
|
||
<div className="flex items-center gap-3">
|
||
<button
|
||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||
className="lg:hidden p-2 rounded-xl text-medical-gray-600 hover:bg-medical-gray-100 transition-all"
|
||
aria-label="منو"
|
||
>
|
||
{isMobileMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
|
||
</button>
|
||
|
||
<BrandLogo />
|
||
</div>
|
||
|
||
{/* Center Search Input (Desktop) */}
|
||
<div className="hidden md:flex flex-1 max-w-md mx-4">
|
||
<form onSubmit={handleSearch} className="w-full relative">
|
||
<input
|
||
type="text"
|
||
placeholder="جستجوی محصول، ترکیب دارویی یا بیماری پت..."
|
||
value={searchQuery}
|
||
onChange={(e) => setSearchQuery(e.target.value)}
|
||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-2.5 pr-10 pl-4 text-xs font-bold text-medical-gray-900 focus:outline-none focus:ring-2 focus:ring-canina-blue/20 focus:bg-white transition-all"
|
||
/>
|
||
<button type="submit" className="absolute right-3 top-1/2 -translate-y-1/2 text-medical-gray-400 hover:text-canina-blue">
|
||
<Search className="w-4 h-4" />
|
||
</button>
|
||
</form>
|
||
</div>
|
||
|
||
{/* Left Action Buttons */}
|
||
<div className="flex items-center gap-1.5 sm:gap-3 shrink-0">
|
||
{/* Prescription Upload Button (Desktop & Mobile) */}
|
||
{isPrescriptionEnabled && (
|
||
<button
|
||
onClick={() => setIsPrescriptionModalOpen(true)}
|
||
className="flex items-center gap-1.5 px-2.5 sm:px-3 py-2 bg-emerald-50 text-emerald-700 border border-emerald-200 hover:bg-emerald-100 rounded-xl text-[11px] sm:text-xs font-black transition-all shadow-xs cursor-pointer"
|
||
title="ثبت نسخه دامپزشک"
|
||
>
|
||
<FileHeart className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-emerald-600 shrink-0" />
|
||
<span className="hidden xs:inline sm:inline">ثبت نسخه دامپزشک</span>
|
||
<span className="inline xs:hidden sm:hidden">ثبت نسخه</span>
|
||
</button>
|
||
)}
|
||
|
||
{/* User Account Button with Dropdown & Pets List */}
|
||
{isLoggedIn ? (
|
||
<div className="relative" ref={userProfileRef}>
|
||
<button
|
||
onClick={() => setIsProfileMenuOpen(!isProfileMenuOpen)}
|
||
className="flex items-center gap-1.5 p-2 sm:px-3 sm:py-2 bg-medical-gray-50 hover:bg-medical-gray-100 border border-medical-gray-200 rounded-xl text-xs font-black text-medical-gray-900 transition-all cursor-pointer"
|
||
>
|
||
<User className="w-4 h-4 text-canina-blue" />
|
||
<span className="hidden sm:inline">{profile.firstName || 'حساب کاربری'}</span>
|
||
<ChevronDown className={cn("w-3.5 h-3.5 text-medical-gray-500 transition-transform duration-200", isProfileMenuOpen && "rotate-180")} />
|
||
</button>
|
||
|
||
<AnimatePresence>
|
||
{isProfileMenuOpen && (
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 8, scale: 0.96 }}
|
||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||
exit={{ opacity: 0, y: 8, scale: 0.96 }}
|
||
className="absolute left-0 mt-2 w-64 bg-white rounded-2xl shadow-xl border border-medical-gray-100 overflow-hidden z-50 p-2 text-xs font-vazir"
|
||
>
|
||
{/* User info header */}
|
||
<div className="px-3 py-2.5 bg-medical-gray-50 rounded-xl mb-1">
|
||
<p className="font-black text-medical-gray-900 truncate">
|
||
{profile.firstName ? `${profile.firstName} ${profile.lastName || ''}` : 'کاربر عزیز'}
|
||
</p>
|
||
<p className="text-[10px] text-medical-gray-500 font-mono mt-0.5 truncate">{profile.mobile || profile.email}</p>
|
||
</div>
|
||
|
||
{/* Pets List Section */}
|
||
<div className="py-1">
|
||
<div className="flex items-center justify-between px-3 py-1.5 text-[11px] font-black text-medical-gray-500">
|
||
<span className="flex items-center gap-1">
|
||
<HeartPulse className="w-3.5 h-3.5 text-canina-blue" />
|
||
پتهای من ({pets.length})
|
||
</span>
|
||
<Link href="/dashboard?tab=pets" onClick={() => setIsProfileMenuOpen(false)} className="text-canina-blue hover:underline text-[10px]">
|
||
مدیریت
|
||
</Link>
|
||
</div>
|
||
{pets.length > 0 ? (
|
||
<div className="space-y-1 max-h-32 overflow-y-auto">
|
||
{pets.map((p) => (
|
||
<button
|
||
key={p.id}
|
||
onClick={() => {
|
||
setActivePet(p.id);
|
||
setIsProfileMenuOpen(false);
|
||
toast.success(`پت فعال به ${p.name} تغییر یافت`);
|
||
}}
|
||
className={cn(
|
||
"w-full flex items-center justify-between px-3 py-1.5 rounded-lg text-right transition-colors",
|
||
p.id === activePetId ? "bg-canina-blue/10 text-canina-blue font-bold" : "hover:bg-medical-gray-50 text-medical-gray-700"
|
||
)}
|
||
>
|
||
<div className="flex items-center gap-2 truncate">
|
||
<span className="text-sm">{(p.type === 'سگ' || (p.type as string) === 'dog') ? '🐶' : '🐱'}</span>
|
||
<span className="truncate">{p.name}</span>
|
||
</div>
|
||
{p.id === activePetId && <Check className="w-3.5 h-3.5 shrink-0" />}
|
||
</button>
|
||
))}
|
||
</div>
|
||
) : (
|
||
<p className="px-3 py-2 text-[10px] text-medical-gray-400 text-center">پتی ثبت نشده است</p>
|
||
)}
|
||
</div>
|
||
|
||
<div className="border-t border-medical-gray-100 my-1" />
|
||
|
||
{/* Direct Navigation Links */}
|
||
<Link
|
||
href="/dashboard"
|
||
onClick={() => setIsProfileMenuOpen(false)}
|
||
className="flex items-center gap-2 px-3 py-2 hover:bg-medical-gray-50 text-medical-gray-700 rounded-xl font-bold transition-colors"
|
||
>
|
||
<User className="w-4 h-4 text-canina-blue" />
|
||
<span>داشبورد کاربری</span>
|
||
</Link>
|
||
|
||
<button
|
||
onClick={() => {
|
||
logout();
|
||
setIsProfileMenuOpen(false);
|
||
toast.success('از حساب کاربری خارج شدید');
|
||
}}
|
||
className="w-full flex items-center gap-2 px-3 py-2 hover:bg-rose-50 text-rose-600 rounded-xl font-bold transition-colors text-right"
|
||
>
|
||
<LogOut className="w-4 h-4" />
|
||
<span>خروج از حساب</span>
|
||
</button>
|
||
</motion.div>
|
||
)}
|
||
</AnimatePresence>
|
||
</div>
|
||
) : (
|
||
<button
|
||
data-testid="header-login-btn"
|
||
onClick={() => setIsAuthModalOpen(true)}
|
||
className="flex items-center gap-1.5 px-2.5 py-2 sm:px-3.5 sm:py-2 bg-medical-gray-900 text-white hover:bg-canina-blue rounded-xl text-[11px] sm:text-xs font-black transition-all shadow-xs whitespace-nowrap"
|
||
>
|
||
<LogIn className="w-4 h-4 shrink-0" />
|
||
<span className="hidden xs:inline sm:inline">ورود / ثبتنام</span>
|
||
<span className="xs:hidden sm:hidden">ورود</span>
|
||
</button>
|
||
)}
|
||
|
||
{/* Shopping Cart Button */}
|
||
{!isCartDisabled && (
|
||
<button
|
||
data-testid="cart-header-btn"
|
||
onClick={onCartOpen}
|
||
className="relative px-3.5 py-2 bg-canina-blue text-white rounded-xl text-xs font-black hover:bg-medical-gray-900 transition-all flex items-center gap-2 shadow-sm"
|
||
>
|
||
<ShoppingBag className="w-4 h-4" />
|
||
<span className="hidden sm:inline">سبد خرید</span>
|
||
{isMounted && getTotalItems() > 0 && (
|
||
<span className="w-5 h-5 bg-canina-gold text-canina-dark rounded-full text-[10px] font-black flex items-center justify-center">
|
||
{getTotalItems()}
|
||
</span>
|
||
)}
|
||
</button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{/* BOTTOM ROW: Clean Organized Dropdown Navigation Bar (Desktop) */}
|
||
<div ref={navBarRef} className="hidden lg:block border-t border-medical-gray-100 bg-medical-gray-50/50">
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center gap-1 py-1 text-xs font-black">
|
||
|
||
<div className="flex items-center gap-1 xl:gap-2 text-xs font-bold font-vazir">
|
||
{headerNavItems.map((navItem) => {
|
||
const hasChildren = Array.isArray(navItem.children) && navItem.children.length > 0;
|
||
const isMega = navItem.href?.includes('view=symptoms') || navItem.id === 'category-mega' || navItem.id === 'symptoms';
|
||
|
||
if (isMega) {
|
||
return (
|
||
<div
|
||
key={navItem.id}
|
||
className="relative group py-2"
|
||
onMouseEnter={() => setIsMegaMenuOpen(true)}
|
||
onMouseLeave={() => setIsMegaMenuOpen(false)}
|
||
>
|
||
<Link
|
||
href={navItem.href || '/shop?view=symptoms'}
|
||
className={`flex items-center gap-1.5 px-3 py-2 rounded-xl transition-all ${
|
||
isMegaMenuOpen
|
||
? 'bg-canina-blue text-white'
|
||
: 'text-medical-gray-700 hover:bg-medical-gray-100 hover:text-canina-blue'
|
||
}`}
|
||
>
|
||
<Pill className="w-4 h-4" />
|
||
<span>{navItem.label}</span>
|
||
<ChevronDown className={`w-3.5 h-3.5 transition-transform ${isMegaMenuOpen ? 'rotate-180' : ''}`} />
|
||
</Link>
|
||
|
||
<AnimatePresence>
|
||
{isMegaMenuOpen && (
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 10 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
exit={{ opacity: 0, y: 10 }}
|
||
className="absolute top-full right-0 w-[640px] bg-white border border-medical-gray-200 shadow-2xl rounded-2xl p-6 grid grid-cols-2 gap-6 z-50"
|
||
>
|
||
{menuItems.map((item, idx) => (
|
||
<div key={idx} className="group/item">
|
||
<Link
|
||
href={`/shop?category=${item.id}`}
|
||
onClick={() => setIsMegaMenuOpen(false)}
|
||
className="flex items-center gap-3 mb-3 cursor-pointer"
|
||
>
|
||
<div className="p-2 bg-canina-blue/10 rounded-xl text-canina-blue group-hover/item:bg-canina-blue group-hover/item:text-white transition-all">
|
||
{item.icon}
|
||
</div>
|
||
<h4 className="font-black text-medical-gray-900 text-sm">{item.title}</h4>
|
||
</Link>
|
||
<div className="flex flex-wrap gap-1 border-r-2 border-medical-gray-100 pr-2">
|
||
{item.solutions.slice(0, 6).map((sol, sIdx) => (
|
||
<Link
|
||
key={sIdx}
|
||
href={`/shop?category=${item.id}&symptom=${encodeURIComponent(sol)}`}
|
||
className="inline-block px-2 py-0.5 rounded-md text-[10px] font-bold bg-medical-gray-50 hover:bg-canina-blue hover:text-white transition-all text-medical-gray-600"
|
||
onClick={() => setIsMegaMenuOpen(false)}
|
||
>
|
||
{sol}
|
||
</Link>
|
||
))}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</motion.div>
|
||
)}
|
||
</AnimatePresence>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
if (hasChildren) {
|
||
return (
|
||
<div
|
||
key={navItem.id}
|
||
className="relative group py-2"
|
||
onMouseEnter={() => setActiveDropdown(navItem.id)}
|
||
onMouseLeave={() => setActiveDropdown(null)}
|
||
>
|
||
<Link
|
||
href={navItem.href || '#'}
|
||
className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-medical-gray-700 hover:bg-medical-gray-100 hover:text-canina-blue transition-all"
|
||
>
|
||
<span>{navItem.label}</span>
|
||
<ChevronDown className="w-3.5 h-3.5" />
|
||
</Link>
|
||
{activeDropdown === navItem.id && (
|
||
<div className="absolute top-full right-0 w-60 bg-white border border-medical-gray-200 shadow-xl rounded-xl p-2 z-50 space-y-1 text-xs">
|
||
{navItem.children!.map((child) => (
|
||
<Link
|
||
key={child.id || child.href}
|
||
href={child.href}
|
||
className="block px-3 py-2 hover:bg-canina-blue/5 hover:text-canina-blue rounded-lg font-bold transition-colors"
|
||
>
|
||
{child.label}
|
||
</Link>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<Link
|
||
key={navItem.id}
|
||
href={navItem.href}
|
||
className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-medical-gray-700 hover:bg-medical-gray-100 hover:text-canina-blue transition-all"
|
||
>
|
||
<span>{navItem.label}</span>
|
||
{navItem.badge && (
|
||
<span className="bg-rose-500 text-white text-[9px] font-black px-1.5 py-0.2 rounded-full font-mono">
|
||
{navItem.badge}
|
||
</span>
|
||
)}
|
||
</Link>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
{/* Mobile Navigation Drawer & Backdrop */}
|
||
<AnimatePresence>
|
||
{isMobileMenuOpen && (
|
||
<>
|
||
<motion.div
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
exit={{ opacity: 0 }}
|
||
onClick={() => setIsMobileMenuOpen(false)}
|
||
className="lg:hidden fixed inset-0 bg-black/50 z-40 backdrop-blur-xs"
|
||
/>
|
||
<motion.div
|
||
initial={{ opacity: 0, height: 0 }}
|
||
animate={{ opacity: 1, height: "auto" }}
|
||
exit={{ opacity: 0, height: 0 }}
|
||
className="lg:hidden relative z-50 bg-white border-b border-medical-gray-200 px-4 py-5 space-y-4 shadow-xl max-h-[85vh] overflow-y-auto font-vazir text-right"
|
||
dir="rtl"
|
||
>
|
||
<form onSubmit={handleSearch} className="relative mb-3">
|
||
<input
|
||
type="text"
|
||
placeholder="جستجو در محصولات..."
|
||
value={searchQuery}
|
||
onChange={(e) => setSearchQuery(e.target.value)}
|
||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2.5 pr-10 pl-4 text-xs font-bold focus:ring-2 focus:ring-canina-blue/20 outline-none font-vazir placeholder:font-vazir"
|
||
/>
|
||
<Search className="w-4 h-4 text-medical-gray-400 absolute right-3 top-1/2 -translate-y-1/2" />
|
||
</form>
|
||
|
||
{/* Direct Prescription CTA in Mobile Drawer */}
|
||
{isPrescriptionEnabled && (
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
setIsMobileMenuOpen(false);
|
||
setIsPrescriptionModalOpen(true);
|
||
}}
|
||
className="w-full flex items-center justify-between p-3.5 bg-gradient-to-r from-emerald-500 to-teal-600 text-white rounded-2xl font-black text-xs shadow-md shadow-emerald-500/20 hover:brightness-105 transition-all cursor-pointer font-vazir"
|
||
>
|
||
<div className="flex items-center gap-2.5">
|
||
<div className="p-1.5 bg-white/20 rounded-xl">
|
||
<FileHeart className="w-4 h-4 text-white" />
|
||
</div>
|
||
<div className="text-right">
|
||
<div className="text-xs font-black">ثبت و استعلام نسخه دامپزشک</div>
|
||
<div className="text-[10px] text-emerald-100 font-medium">تامین فوری دارو و مکملهای اورجینال</div>
|
||
</div>
|
||
</div>
|
||
<span className="text-lg">←</span>
|
||
</button>
|
||
)}
|
||
|
||
{/* Dynamic Menu Groups in Mobile Drawer */}
|
||
{headerNavItems.map((navGroup) => {
|
||
const hasChildren = Array.isArray(navGroup.children) && navGroup.children.length > 0;
|
||
const isMega = navGroup.href?.includes('view=symptoms') || navGroup.id === 'category-mega' || navGroup.id === 'symptoms';
|
||
|
||
if (isMega) {
|
||
return (
|
||
<div key={navGroup.id} className="space-y-1 border-t border-medical-gray-100 pt-3">
|
||
<div className="text-[11px] font-black text-medical-gray-400 px-2 py-1 uppercase tracking-wider">
|
||
{navGroup.label}
|
||
</div>
|
||
<div className="grid grid-cols-2 gap-2">
|
||
{menuItems.map((item, idx) => (
|
||
<Link
|
||
key={idx}
|
||
href={`/shop?category=${item.id}`}
|
||
onClick={() => setIsMobileMenuOpen(false)}
|
||
className="flex items-center gap-2 p-2.5 rounded-xl border border-medical-gray-100 bg-white hover:border-canina-blue/30 text-medical-gray-800 text-[11px] font-bold"
|
||
>
|
||
<span className="text-canina-blue">{item.icon}</span>
|
||
<span className="truncate">{item.title}</span>
|
||
</Link>
|
||
))}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
if (hasChildren) {
|
||
return (
|
||
<div key={navGroup.id} className="space-y-1 border-t border-medical-gray-100 pt-3">
|
||
<div className="text-[11px] font-black text-medical-gray-400 px-2 py-1 uppercase tracking-wider">
|
||
{navGroup.label}
|
||
</div>
|
||
{navGroup.children!.map((child) => (
|
||
<Link
|
||
key={child.id || child.href}
|
||
href={child.href}
|
||
onClick={() => setIsMobileMenuOpen(false)}
|
||
className="flex items-center gap-3 p-2.5 rounded-xl hover:bg-medical-gray-50 text-medical-gray-800 font-bold text-xs transition-all"
|
||
>
|
||
<span className="w-1.5 h-1.5 rounded-full bg-canina-blue" />
|
||
<span>{child.label}</span>
|
||
</Link>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div key={navGroup.id} className="border-t border-medical-gray-100 pt-2">
|
||
<Link
|
||
href={navGroup.href}
|
||
onClick={() => setIsMobileMenuOpen(false)}
|
||
className="flex items-center justify-between p-3 rounded-xl bg-medical-gray-50/70 hover:bg-canina-blue/10 hover:text-canina-blue text-medical-gray-900 font-black text-xs transition-all"
|
||
>
|
||
<span>{navGroup.label}</span>
|
||
{navGroup.badge && (
|
||
<span className="bg-rose-500 text-white text-[9px] font-bold px-2 py-0.5 rounded-full">
|
||
{navGroup.badge}
|
||
</span>
|
||
)}
|
||
</Link>
|
||
</div>
|
||
);
|
||
})}
|
||
|
||
{/* Additional Company & Support links if needed */}
|
||
<div className="space-y-1 border-t border-medical-gray-100 pt-3">
|
||
<div className="text-[11px] font-black text-medical-gray-400 px-2 py-1 uppercase tracking-wider">
|
||
پشتیبانی و اطلاعات
|
||
</div>
|
||
<Link
|
||
href="/trust-seals"
|
||
onClick={() => setIsMobileMenuOpen(false)}
|
||
className="flex items-center gap-3 p-2.5 rounded-xl hover:bg-medical-gray-50 text-emerald-600 font-bold text-xs transition-all"
|
||
>
|
||
<ShieldCheck className="w-4 h-4 text-emerald-600" />
|
||
<span>نمادهای اعتماد و مجوزهای رسمی</span>
|
||
</Link>
|
||
{isB2BEnabled && (
|
||
<Link
|
||
href="/b2b"
|
||
onClick={() => setIsMobileMenuOpen(false)}
|
||
className="flex items-center gap-3 p-2.5 rounded-xl hover:bg-medical-gray-50 text-medical-gray-800 font-bold text-xs transition-all"
|
||
>
|
||
<Building2 className="w-4 h-4 text-canina-blue" />
|
||
<span>درخواست نمایندگی و خرید عمده (B2B)</span>
|
||
</Link>
|
||
)}
|
||
<Link
|
||
href="/contact"
|
||
onClick={() => setIsMobileMenuOpen(false)}
|
||
className="flex items-center gap-3 p-2.5 rounded-xl hover:bg-medical-gray-50 text-medical-gray-800 font-bold text-xs transition-all"
|
||
>
|
||
<PhoneCall className="w-4 h-4 text-canina-blue" />
|
||
<span>تماس با مرکز پشتیبانی</span>
|
||
</Link>
|
||
</div>
|
||
</motion.div>
|
||
</>
|
||
)}
|
||
</AnimatePresence>
|
||
</div>
|
||
</>
|
||
);
|
||
}
|