"use client"; import React, { useState, useEffect, useRef } from 'react'; import { usePathname, useRouter } from 'next/navigation'; import Link from 'next/link'; import Image from 'next/image'; import { ShoppingCart, Trash2, Search, X, ChevronDown, Home, ShoppingBag, Wallet, MapPin, Headphones, IdCard, LogOut } from "lucide-react"; import { useCart } from './context/cartcontext'; import { products } from '@/lib/data'; import '@/public/src/css/header.css'; import { registerUser } from '@/public/src/services/auth/api'; import { loginUser } from '@/public/src/services/auth/api'; import { logoutUser } from '@/public/src/services/auth/api'; import { useCategories } from './context/categoryprovider'; import { getCartApi } from '@/public/src/services/cart/api'; import AuthModal from './Auth'; const topBarLinks = [ { label: "بخش صنعتی", href: "/" }, { label: "بخش خودرویی", href: "/automotive" }, ]; const mainNavLinks = [ { label: "صفحه اصلی", href: "/" }, { label: "محصولات", href: "/products" }, { label: "مقالات", href: "/blog" }, { label: "درباره ما", href: "/about" }, { label: "تماس با ما", href: "/contact" }, ]; type FloatingInputProps = { name?: string; value: string; onChange: (e: React.ChangeEvent) => void; label: string; type?: string; dir?: "rtl" | "ltr"; inputMode?: React.HTMLAttributes["inputMode"]; autoComplete?: string; className?: string; leftSlot?: React.ReactNode; rightSlot?: React.ReactNode; }; function FloatingInput({ name, value, onChange, label, type = "text", dir = "rtl", inputMode, autoComplete, className = "", leftSlot, rightSlot, }: FloatingInputProps) { const hasLeftSlot = Boolean(leftSlot); const hasRightSlot = Boolean(rightSlot); return ( ); } function IranPhoneAdornment() { return (
🇮🇷 +98
); } const dashboardMenuItems = [ { id: "dash", label: "پیشخوان", icon: Home, href: "/dashboard?tab=dash" }, { id: "orders", label: "سفارش‌های من", icon: ShoppingBag, href: "/dashboard?tab=orders" }, { id: "wallet", label: "کیف پول", icon: Wallet, href: "/dashboard?tab=wallet" }, { id: "address", label: "آدرس‌ها", icon: MapPin, href: "/dashboard?tab=address" }, { id: "tickets", label: "تیکت پشتیبانی", icon: Headphones, href: "/dashboard?tab=tickets" }, { id: "profile", label: "مشخصات حساب", icon: IdCard, href: "/dashboard?tab=profile" }, ]; export function Header() { const [menuOpen, setMenuOpen] = useState(false); const [isAuthModalOpen, setIsAuthModalOpen] = useState(false); const pathname = usePathname(); const { cart, removeFromCart } = useCart(); const [searchTerm, setSearchTerm] = useState(''); const [showResults, setShowResults] = useState(false); const [filteredProducts, setFilteredProducts] = useState([]); const searchRef = useRef(null); const router = useRouter(); const [isOpen, setIsOpen] = useState(false); const [formType, setFormType] = useState("mobile"); const [activeTab, setActiveTab] = useState("login"); const [registerError, setRegisterError] = useState(""); const [loginError, setLoginError] = useState(""); const [registerUsernameError, setRegisterUsernameError] = useState(""); const [loginUsernameError, setLoginUsernameError] = useState(""); const { rootCategories } = useCategories(); const [user, setUser] = useState<{ username: string; displayName: string } | null>(null); const [userMenuOpen, setUserMenuOpen] = useState(false); const [showPassword, setShowPassword] = useState(false); const [showLoginPassword, setShowLoginPassword] = useState(false); const [loginMobile, setLoginMobile] = useState(""); const [showRegisterSuccessDialog, setShowRegisterSuccessDialog] = useState(false); const [isOptimistic, setIsOptimistic] = useState(false); useEffect(() => { setIsOptimistic(true); // بعد از ۱.۵ ثانیه (زمانی که قاعدتاً API سرور کارش تمام شده) به حالت عادی برمی‌گردد const timer = setTimeout(() => setIsOptimistic(false), 1500); return () => clearTimeout(timer); }, [cart]); // ۲. افکت دوم: دریافت اطلاعات سرور در پس‌زمینه بدون رفرش صفحه useEffect(() => { const fetchServerData = async () => { const token = localStorage.getItem('accessToken'); if (token) { setIsLoggedIn(true); try { const data = await getCartApi(); if (data) { setServerCartItems(data.items || []); setServerSummary(data.summary || null); } } catch (error) { console.error("خطا در همگام‌سازی سبد خرید سرور:", error); } } }; // گوش دادن به سیگنالی که از ProductCard ارسال می‌شود window.addEventListener('cartUpdated', fetchServerData); // فراخوانی در لود اولیه fetchServerData(); return () => window.removeEventListener('cartUpdated', fetchServerData); }, []); // محاسبه قیمت کل لوکال (برای زمانی که کاربر لاگین نیست یا در حالت Optimistic هستیم) const localTotalPrice = cart.reduce((total, item) => { const price = item.price ? Number(item.price.toString().replace(/,/g, '')) : 0; return total + (price * item.quantity); }, 0); const [loginForm, setLoginForm] = useState({ username: "", password: "", }); const [registerForm, setRegisterForm] = useState({ phone: "", fullName: "", username: "", password: "", }); const usernamePattern = /^[A-Za-z0-9]*$/; const usernameErrorMessage = "نام کاربری فقط باید با حروف انگلیسی و عدد وارد شود"; const handleChange = (e: React.ChangeEvent) => { if (e.target.name === "username") { if (!usernamePattern.test(e.target.value)) { setRegisterUsernameError(usernameErrorMessage); return; } setRegisterUsernameError(""); } setRegisterForm({ ...registerForm, [e.target.name]: e.target.value, }); }; useEffect(() => { const token = localStorage.getItem("accessToken"); const username = localStorage.getItem("username"); const fullName = localStorage.getItem("fullName"); if (token && username) { setUser({ username, displayName: fullName || username }); } }, []); const handleRegister = async () => { setRegisterError(""); const phone = registerForm.phone.trim(); const username = registerForm.username.trim(); const password = registerForm.password.trim(); const fullName = registerForm.fullName.trim(); if (!usernamePattern.test(username)) { setRegisterUsernameError(usernameErrorMessage); return; } // ✅ بررسی خالی بودن فیلدها if (!phone || !username || !password || !fullName) { setRegisterError("لطفاً فیلدها را پر کنید"); return; } try { const payload = { phone, username, password, fullName, }; const res = await registerUser(payload); const role = res.data?.user?.role; const displayName = res.data?.user?.fullName || fullName || username; localStorage.setItem("accessToken", res.data.accessToken); localStorage.setItem("refreshToken", res.data.refreshToken); localStorage.setItem("username", username); localStorage.setItem("fullName", displayName); localStorage.setItem("role", role.toLowerCase()); console.log(res); setUser({ username, displayName }); setIsOpen(false); setShowRegisterSuccessDialog(true); } catch (error: any) { const message = error?.message?.toLowerCase() || ""; const usernameDuplicate = message.includes("username"); const phoneDuplicate = message.includes("phone"); if (usernameDuplicate && phoneDuplicate) { setRegisterError("نام کاربری و شماره موبایل قبلاً ثبت شده‌اند"); } else if (usernameDuplicate) { setRegisterError("این نام کاربری قبلاً ثبت شده است"); } else if (phoneDuplicate) { setRegisterError("این شماره موبایل قبلاً ثبت شده است"); } else { setRegisterError("خطا در ثبت نام"); } } }; const handleLogin = async () => { setLoginError(""); const username = loginForm.username.trim(); const password = loginForm.password.trim(); if (!usernamePattern.test(username)) { setLoginUsernameError(usernameErrorMessage); return; } if (!username || !password) { setLoginError("لطفاً نام کاربری و رمز عبور را وارد کنید"); return; } try { const res = await loginUser({ username, password }); const role = res.data?.user?.role; const displayName = res.data?.user?.fullName || username; localStorage.setItem("role", role.toLowerCase()); localStorage.setItem("accessToken", res.data.accessToken); localStorage.setItem("refreshToken", res.data.refreshToken); localStorage.setItem("username", username); localStorage.setItem("fullName", displayName); console.log(res); setUser({ username, displayName }); setIsOpen(false); router.push("/dashboard?success=login"); } catch (error: any) { const msg = error?.message?.toLowerCase() || ""; console.log("LOGIN ERROR RAW:", msg); // این خیلی مهمه // 1) اول بررسی کنیم که نام کاربری وجود ندارد if ( msg.includes("not found") || msg.includes("user") && msg.includes("not") || msg.includes("username") && msg.includes("not") ) { setLoginError("این نام کاربری وجود ندارد"); return; } // 2) سپس رمز عبور اشتباه if ( msg.includes("password") || msg.includes("invalid") || msg.includes("incorrect") ) { setLoginError("رمز عبور اشتباه است"); return; } // 3) خطای عمومی setLoginError("خطا در ورود. لطفاً دوباره تلاش کنید."); } }; const clearAuthState = () => { localStorage.removeItem("accessToken"); localStorage.removeItem("refreshToken"); localStorage.removeItem("username"); localStorage.removeItem("fullName"); localStorage.removeItem("role"); setUser(null); }; const handleLogout = async () => { const token = localStorage.getItem("accessToken"); try { if (token) { await logoutUser(token); } } catch (error) { console.error("Logout failed:", error); } finally { clearAuthState(); setUserMenuOpen(false); window.location.href = "/"; } }; const parsePrice = (priceStr?: number | null) => { if (!priceStr) return 0; return Number(priceStr.toString().replace(/,/g, '')); }; const totalPrice = cart.reduce((total, item) => total + (parsePrice(item.price) * item.quantity), 0); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (searchRef.current && !searchRef.current.contains(event.target as Node)) { setShowResults(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); useEffect(() => { if (searchTerm.trim().length > 1) { const results = products.filter(p => p.title.toLowerCase().includes(searchTerm.toLowerCase()) || p.brand?.toLowerCase().includes(searchTerm.toLowerCase()) || p.d?.toLowerCase().includes(searchTerm.toLowerCase()) || p.l?.toLowerCase().includes(searchTerm.toLowerCase()) ).slice(0, 6); setFilteredProducts(results); setShowResults(true); } else { setFilteredProducts([]); setShowResults(false); } }, [searchTerm]); const handleSearch = (e: React.FormEvent) => { e.preventDefault(); if (searchTerm.trim()) { setShowResults(false); router.push(`/search?q=${encodeURIComponent(searchTerm)}`); } }; const [isLoggedIn, setIsLoggedIn] = useState(false); const [serverCartItems, setServerCartItems] = useState([]); const [serverSummary, setServerSummary] = useState(null); // دریافت اطلاعات سبد خرید از سرور useEffect(() => { const fetchServerCart = async () => { const token = localStorage.getItem('accessToken'); if (token) { setIsLoggedIn(true); try { const data = await getCartApi(); if (data) { setServerCartItems(data.items || []); setServerSummary(data.summary || null); } } catch (error) { console.error("خطا در دریافت سبد خرید منو:", error); } } else { setIsLoggedIn(false); } }; // --- این تابع جدید را اضافه کنید --- const handleCartClear = () => { setServerCartItems([]); // درجا لیست منو را خالی می‌کند setServerSummary(null); }; // گوش دادن به رویدادها window.addEventListener('cartUpdated', fetchServerCart); window.addEventListener('cartCleared', handleCartClear); // لیسنر جدید fetchServerCart(); return () => { window.removeEventListener('cartUpdated', fetchServerCart); window.removeEventListener('cartCleared', handleCartClear); // کلین‌آپ لیسنر جدید }; // در صورت نیاز به آپدیت شدن دراپ‌داون با هر تغییر، می‌توانید این تابع را به یک Event یا Context متصل کنید }, []); const displayCart = (isLoggedIn && !isOptimistic) ? serverCartItems.map(item => ({ id: item.product?.id || item.productId, title: item.product?.title || "بدون نام", brand: item.product?.brand || "متفرقه", price: item.unitPrice || item.product?.price || 0, quantity: item.quantity || 1, image: item.product?.mainImageUrl || item.product?.image || "/placeholder.png" })) : cart; const displayTotalQuantity = (isLoggedIn && !isOptimistic) && serverSummary ? serverSummary.totalQuantity || serverSummary.itemsCount || 0 : cart.reduce((total, item) => total + item.quantity, 0); const displayTotalPrice = (isLoggedIn && !isOptimistic) && serverSummary ? serverSummary.totalPrice || serverSummary.total || 0 : localTotalPrice; return (
{/* ... کدهای مربوط به mobile slider, top bar, main bar ... */} {/* overlay */} {menuOpen && (
setMenuOpen(false)} /> )} {/* mobile slider */}
{mainNavLinks.map((link) => ( setMenuOpen(false)} > {link.label} ))} {/* mobile contact */}
شیراز، معالی‌آباد
071‑1234‑5678
{/* top bar */}
{/* links */}
{topBarLinks.map((link) => { // --- منطق جدید برای فعال بودن --- let isActive = false; if (link.href === "/automotive") { // بخش خودرویی فقط زمانی فعال است که آدرس با /automotive شروع شود isActive = pathname?.startsWith("/automotive"); } else if (link.href === "/") { // بخش صنعتی در تمام صفحات (جز خودرویی) همیشه فعال می‌ماند isActive = !pathname?.startsWith("/automotive"); } // --------------------------------- const baseClasses = "hover:text-amber-300 transition duration-200 px-3 md:px-6 py-2 text-xs"; const activeClasses = isActive ? "text-amber-400 border-t-2 border-amber-400 ac" : "text-white"; return ( {link.label} ); })}
{/* contact */}
شیراز، معالی‌آباد
{/* main bar */}
{/* logo */}
B
Bearing Site
{/* hamburger */} {/* search */}
setSearchTerm(e.target.value)} onFocus={() => searchTerm.length > 1 && setShowResults(true)} className="w-full p-3 text-gray-800 placeholder-gray-400 focus:outline-none text-xs font-medium" /> {searchTerm && ( )}
{/* دراپ‌داون نتایج لحظه‌ای */} {showResults && filteredProducts.length > 0 && (
{filteredProducts.map((product) => { const productSlug = product.title.replace(/\s+/g, '-'); return ( setShowResults(false)} className="flex items-center gap-3 p-2 hover:bg-gray-50 rounded-xl transition group" >
{product.title}

{product.title}

{product.brand}

{product.price ? `${Number(product.price.toString().replace(/,/g, '')).toLocaleString('fa-IR')} ت` : 'استعلام'}
); })}
)}
{/* User/Cart Actions */}
{/* دراپ‌داون سبد خرید */}
{displayCart.length > 0 && ( {displayTotalQuantity} )}
{displayCart.length === 0 ? (
سبد خرید شما خالی است
) : ( <>
{displayCart.length} کالا مشاهده سبد خرید
{displayCart.slice(0, 3).map((item) => { const itemTotal = item.price ? (Number(item.price.toString().replace(/,/g, '')) * item.quantity).toLocaleString('fa-IR') : null; return (
{item.title}

{item.title}

{itemTotal ? `${itemTotal} تومان` : 'استعلام'} {item.quantity} عدد
) })} {displayCart.length > 3 && (

و {displayCart.length - 3} کالای دیگر...

)}
مبلغ قابل پرداخت: {displayTotalPrice > 0 ? `${displayTotalPrice.toLocaleString('fa-IR')} تومان` : 'استعلام'}
ثبت سفارش
)}
{!user ? ( ) : (
{userMenuOpen && (

{user.displayName}

دسترسی سریع به بخش‌های پیشخوان

{dashboardMenuItems.map((item) => ( ))}
)}
)} {/* فراخوانی مودال احراز هویت */} setIsAuthModalOpen(false)} onLoginSuccess={(userData) => setUser(userData)} onRegisterSuccess={(userData) => { setUser(userData); setShowRegisterSuccessDialog(true); }} /> {/* {isOpen && (
setIsOpen(false)} >
{activeTab === "login" && (

ورود سریع به حساب کاربری

سفارش‌ها، وضعیت خرید و اطلاعات حساب‌تان را یک‌جا و بدون دردسر مدیریت کنید.

{formType === "mobile" && (
setLoginMobile(e.target.value)} type="tel" dir="ltr" inputMode="tel" autoComplete="tel" label="شماره موبایل" className="text-left tracking-[0.18em]" leftSlot={} />
)} {formType === "password" && (

خوش برگشتی. برای ادامه، نام کاربری و رمز عبورت را وارد کن.

{ const username = e.target.value; if (!usernamePattern.test(username)) { setLoginUsernameError(usernameErrorMessage); return; } setLoginUsernameError(""); setLoginForm((prev) => ({ ...prev, username, })); }} type="text" dir="ltr" autoComplete="username" label="نام کاربری" className="text-left" /> {loginUsernameError && (
{loginUsernameError}
)} { const password = e.target.value; setLoginForm((prev) => ({ ...prev, password, })); if (!password) { setShowLoginPassword(false); } }} type={showLoginPassword ? "text" : "password"} dir="ltr" autoComplete="current-password" label="رمز عبور" className="text-left" rightSlot={loginForm.password ? ( ) : undefined} /> {loginError && (
{loginError}
)}
)}
)} {false && activeTab === "login" && (
{formType === "mobile" && (
)} {formType === "password" && (
setLoginForm((prev) => ({ ...prev, username: e.target.value, })) } placeholder="نام کاربری" className="w-full px-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]" />
setLoginForm((prev) => ({ ...prev, password: e.target.value, })) } placeholder="رمز عبور" className="w-full px-4 pl-4 py-3.5 bg-gray-50 border border-gray-200 rounded-2xl text-sm text-right focus:outline-none focus:border-[#ffb900]" />
{loginError && (
{loginError}
)}
)}
)} {activeTab === "register" && (

چند قدم تا شروع خرید هوشمند

با ساخت حساب، پیگیری سفارش‌ها و دسترسی سریع به سبد خرید همیشه همراهت می‌ماند.

} /> {registerUsernameError && (
{registerUsernameError}
)} { handleChange(e); if (!e.target.value) { setShowPassword(false); } }} type={showPassword ? "text" : "password"} dir="ltr" autoComplete="new-password" label="رمز عبور" className="text-left" rightSlot={registerForm.password ? ( ) : undefined} />

با ثبت‌نام، تجربه خرید سریع‌تر و دسترسی راحت‌تر به حساب کاربری برایت فعال می‌شود.

{registerError && (
{registerError}
)}
)} {false && activeTab === "register" && (
{registerError && (
{registerError}
)}
)}
)} */} {showRegisterSuccessDialog && (
setShowRegisterSuccessDialog(false)} >

تشکر از ثبت نام

حساب کاربری شما با موفقیت ساخته شد. حالا می‌توانید وارد پیشخوان کاربری شوید و اطلاعات حساب و سفارش‌ها را مدیریت کنید.

setShowRegisterSuccessDialog(false)} className="flex items-center justify-center rounded-2xl bg-[#ffb900] px-4 py-3 text-sm font-semibold text-[#1A2332] hover:bg-[#e5a600]" > ورود به پیشخوان کاربری
)}
{/* nav -- این بخش تغییر کرده است */}
); }