133 lines
5 KiB
TypeScript
133 lines
5 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
import Link from 'next/link';
|
|
import { Heart, ShoppingCart, Menu, Search, X, GitCompare } from 'lucide-react';
|
|
import { LiveSearch } from '../components/store/LiveSearch';
|
|
import { useCartStore } from '@/store/cartStore';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import { AccountMenu } from '@/components/AccountMenu';
|
|
|
|
export const HeaderActions: React.FC = () => {
|
|
const [mobileSearchOpen, setMobileSearchOpen] = useState(false);
|
|
const setCartDrawerOpen = useCartStore((state) => state.setCartDrawerOpen);
|
|
|
|
const cartItems = useCartStore((state) => state.cart) || [];
|
|
const cartCount = cartItems.reduce(
|
|
(acc, item) => acc + (item.quantity || 1),
|
|
0
|
|
);
|
|
const wishlistCount = useCartStore((state) => state.wishlist.length);
|
|
const compareCount = useCartStore((state) => (state.compareList || []).length);
|
|
|
|
useEffect(() => {
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if (e.key === 'Escape') setMobileSearchOpen(false);
|
|
};
|
|
document.addEventListener('keydown', handleKeyDown);
|
|
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
}, []);
|
|
|
|
const triggerMobileDrawer = () => {
|
|
window.dispatchEvent(new Event('openMobileDrawer'));
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className="flex items-center gap-2 md:gap-5 flex-shrink-0">
|
|
<button
|
|
onClick={() => setMobileSearchOpen(!mobileSearchOpen)}
|
|
className="lg:hidden p-2 text-gray-650 hover:text-primary transition-colors hover:bg-gray-50 rounded-lg cursor-pointer"
|
|
aria-label="Toggle Search"
|
|
>
|
|
<Search size={22} className="stroke-[2.5]" />
|
|
</button>
|
|
|
|
<button
|
|
onClick={triggerMobileDrawer}
|
|
className="lg:hidden p-2 text-gray-650 hover:text-primary transition-colors hover:bg-gray-50 rounded-lg cursor-pointer"
|
|
aria-label="Open Menu"
|
|
>
|
|
<Menu size={24} className="stroke-[2.5]" />
|
|
</button>
|
|
|
|
<Link
|
|
href="/compare"
|
|
className="relative p-2 text-gray-650 hover:text-primary transition-colors hover:bg-gray-50 rounded-lg group focus:outline-none"
|
|
aria-label="Compare products"
|
|
>
|
|
<GitCompare
|
|
size={22}
|
|
className="group-hover:scale-105 transition-transform"
|
|
/>
|
|
{compareCount > 0 && (
|
|
<span className="absolute top-0 right-0 w-5 h-5 bg-[#0073EC] text-white text-[10px] font-bold rounded-full flex items-center justify-center border-2 border-white shadow-xs">
|
|
{compareCount}
|
|
</span>
|
|
)}
|
|
</Link>
|
|
|
|
<Link
|
|
href="/wishlist"
|
|
className="relative p-2 text-gray-650 hover:text-primary transition-colors hover:bg-gray-50 rounded-lg group focus:outline-none"
|
|
aria-label="Open Wishlist"
|
|
>
|
|
<Heart
|
|
size={24}
|
|
className="group-hover:scale-105 transition-transform"
|
|
/>
|
|
{wishlistCount > 0 && (
|
|
<span className="absolute top-0 right-0 w-5 h-5 bg-[#0073EC] text-white text-[10px] font-bold rounded-full flex items-center justify-center border-2 border-white shadow-xs">
|
|
{wishlistCount}
|
|
</span>
|
|
)}
|
|
</Link>
|
|
|
|
<AccountMenu />
|
|
|
|
<button
|
|
type="button"
|
|
onClick={() => setCartDrawerOpen(true)}
|
|
className="flex items-center gap-2.5 p-2 text-gray-650 hover:text-primary transition-colors hover:bg-gray-50 rounded-lg group relative cursor-pointer"
|
|
>
|
|
<div className="relative">
|
|
<ShoppingCart
|
|
size={24}
|
|
className="group-hover:scale-105 transition-transform"
|
|
/>
|
|
{cartCount > 0 && (
|
|
<span className="absolute -top-1.5 -right-1.5 w-5 h-5 bg-[#0073EC] text-white text-[10px] font-bold rounded-full flex items-center justify-center border-2 border-white shadow-xs">
|
|
{cartCount}
|
|
</span>
|
|
)}
|
|
</div>
|
|
<div className="text-left hidden md:block text-[11.5px] leading-tight font-medium">
|
|
<span className="text-gray-400 block font-normal">My Cart</span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
<AnimatePresence>
|
|
{mobileSearchOpen && (
|
|
<motion.div
|
|
initial={{ opacity: 0, height: 0 }}
|
|
animate={{ opacity: 1, height: 'auto' }}
|
|
exit={{ opacity: 0, height: 0 }}
|
|
className="lg:hidden border-t border-gray-100 px-4 pt-3 pb-2 bg-white w-full absolute left-0 right-0 top-full z-[120] shadow-md"
|
|
>
|
|
<div className="flex gap-2 items-center relative z-55">
|
|
<LiveSearch />
|
|
<button
|
|
onClick={() => setMobileSearchOpen(false)}
|
|
className="p-2 text-gray-400 hover:text-gray-650 cursor-pointer"
|
|
aria-label="Close Search"
|
|
>
|
|
<X size={20} />
|
|
</button>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</>
|
|
);
|
|
};
|