dressed_for_succes_store/frontend old/components/Header.tsx
2025-03-11 22:42:30 +07:00

287 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Link from "next/link";
import { Search, Heart, User, ShoppingCart, ChevronLeft, LogOut, Menu, X } from "lucide-react";
import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import Image from "next/image";
import { useRouter } from "next/router";
import authService from "../services/auth";
import cartService from "../services/cart";
export default function Header() {
const router = useRouter();
// Состояние для отслеживания прокрутки страницы
const [scrolled, setScrolled] = useState(false);
// Состояние для отслеживания аутентификации пользователя
const [isAuthenticated, setIsAuthenticated] = useState(false);
// Состояние для отображения выпадающего меню пользователя
const [showUserMenu, setShowUserMenu] = useState(false);
// Состояние для отображения мобильного меню
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
// Состояние для хранения количества товаров в корзине
const [cartItemsCount, setCartItemsCount] = useState(0);
// Эффект для проверки аутентификации при загрузке компонента
useEffect(() => {
setIsAuthenticated(authService.isAuthenticated());
}, []);
// Эффект для загрузки количества товаров в корзине
useEffect(() => {
const fetchCartItemsCount = async () => {
if (authService.isAuthenticated()) {
try {
const cart = await cartService.getCart();
setCartItemsCount(cart.items_count);
} catch (error) {
console.error('Ошибка при загрузке корзины:', error);
setCartItemsCount(0);
}
} else {
setCartItemsCount(0);
}
};
fetchCartItemsCount();
// Обновляем количество товаров в корзине при изменении маршрута
const handleRouteChange = () => {
fetchCartItemsCount();
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}, [isAuthenticated, router.events]);
// Эффект для отслеживания прокрутки
useEffect(() => {
const handleScroll = () => {
const isScrolled = window.scrollY > 50;
if (isScrolled !== scrolled) {
setScrolled(isScrolled);
}
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, [scrolled]);
// Функция для выхода из системы
const handleLogout = () => {
authService.logout();
setIsAuthenticated(false);
setShowUserMenu(false);
setCartItemsCount(0);
router.push('/');
};
// Функция для возврата на предыдущую страницу
const goBack = () => {
router.back();
};
// Проверяем, находимся ли мы на главной странице
const isHomePage = router.pathname === "/";
// Проверяем, находимся ли мы на странице категорий или коллекций
const isDetailPage = router.pathname.includes("[slug]");
// Функция для переключения отображения меню пользователя
const toggleUserMenu = () => {
setShowUserMenu(!showUserMenu);
};
// Функция для переключения мобильного меню
const toggleMobileMenu = () => {
setMobileMenuOpen(!mobileMenuOpen);
};
// Закрыть мобильное меню при переходе на другую страницу
useEffect(() => {
setMobileMenuOpen(false);
}, [router.pathname]);
// Закрыть меню пользователя при клике вне его
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
const target = event.target as HTMLElement;
if (showUserMenu && !target.closest('.user-menu-container')) {
setShowUserMenu(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [showUserMenu]);
return (
<header className={`fixed w-full z-50 transition-all duration-300 bg-white ${scrolled ? 'shadow-md' : 'shadow-sm'}`}>
<nav className="py-4 transition-all duration-300 text-black">
<div className="container mx-auto px-4 flex items-center justify-between">
{/* Мобильная кнопка меню */}
<button
className="lg:hidden flex items-center justify-center"
onClick={toggleMobileMenu}
aria-label="Меню"
>
{mobileMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
</button>
{/* Десктопное меню */}
<div className="hidden lg:flex items-center space-x-6">
<Link href="/category" className="text-sm font-medium hover:opacity-70 transition-opacity">
Каталог
</Link>
<Link href="/all-products" className="text-sm font-medium hover:opacity-70 transition-opacity">
Все товары
</Link>
<Link href="/collections" className="text-sm font-medium hover:opacity-70 transition-opacity">
Коллекции
</Link>
<Link href="/new-arrivals" className="text-sm font-medium hover:opacity-70 transition-opacity">
Новинки
</Link>
<Link href="/order-tracking" className="text-sm font-medium hover:opacity-70 transition-opacity">
Отследить заказ
</Link>
</div>
{/* Логотип - центрирован на десктопе, слева на мобильных */}
<Link href="/" className="lg:absolute lg:left-1/2 lg:transform lg:-translate-x-1/2">
<div className="relative h-8 w-24 md:h-10 md:w-32">
<Image
src="/logo.png"
alt="Brand Logo"
fill
className="object-contain"
priority
/>
</div>
</Link>
{/* Иконки справа */}
<div className="flex items-center space-x-3 md:space-x-5">
<Link href="/favorites" className="relative hover:opacity-70 transition-opacity">
<Heart className="w-5 h-5" />
<span className="absolute -top-2 -right-2 bg-black text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">
0
</span>
</Link>
<div className="relative user-menu-container">
<button
onClick={toggleUserMenu}
className="hover:opacity-70 transition-opacity focus:outline-none"
>
<User className="w-5 h-5" />
</button>
{showUserMenu && (
<div className="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-50">
{isAuthenticated ? (
<>
<Link href="/account" className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Мой профиль
</Link>
<Link href="/account/orders" className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Мои заказы
</Link>
{/* Ссылка на админ-панель, если пользователь админ */}
<Link href="/admin" className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Админ-панель
</Link>
<button
onClick={handleLogout}
className="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
>
<div className="flex items-center">
<LogOut className="w-4 h-4 mr-2" />
Выйти
</div>
</button>
</>
) : (
<>
<Link href="/login" className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Войти
</Link>
<Link href="/register" className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
Регистрация
</Link>
</>
)}
</div>
)}
</div>
<Link href="/cart" className="relative hover:opacity-70 transition-opacity">
<ShoppingCart className="w-5 h-5" />
<span className="absolute -top-2 -right-2 bg-black text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">
{cartItemsCount}
</span>
</Link>
</div>
</div>
</nav>
{/* Мобильное меню */}
<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 bg-white border-t border-gray-100 shadow-md"
>
<div className="container mx-auto px-4 py-4">
<div className="flex flex-col space-y-4">
<Link
href="/category"
className="text-sm font-medium py-2 hover:opacity-70 transition-opacity border-b border-gray-100"
>
Каталог
</Link>
<Link
href="/all-products"
className="text-sm font-medium py-2 hover:opacity-70 transition-opacity border-b border-gray-100"
>
Все товары
</Link>
<Link
href="/collections"
className="text-sm font-medium py-2 hover:opacity-70 transition-opacity border-b border-gray-100"
>
Коллекции
</Link>
<Link
href="/new-arrivals"
className="text-sm font-medium py-2 hover:opacity-70 transition-opacity border-b border-gray-100"
>
Новинки
</Link>
<Link
href="/order-tracking"
className="text-sm font-medium py-2 hover:opacity-70 transition-opacity border-b border-gray-100"
>
Отследить заказ
</Link>
<Link
href="/search"
className="text-sm font-medium py-2 hover:opacity-70 transition-opacity border-b border-gray-100 flex items-center"
>
<Search className="w-4 h-4 mr-2" />
Поиск
</Link>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
</header>
);
}