119 lines
4.9 KiB
TypeScript
119 lines
4.9 KiB
TypeScript
/**
|
|
* @component StoreHeader
|
|
* @purpose Storefront header matching TechShop reference UI with logo, category search bar, blue search button, wishlist counter, account login, and shopping cart counter.
|
|
* @dependencies cartStore, LiveSearch, lucide-react
|
|
*/
|
|
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import Link from 'next/link';
|
|
import { ShoppingBag, Heart, User, ShoppingCart } from 'lucide-react';
|
|
import { useCartStore } from '@/store/cartStore';
|
|
import { LiveSearch } from './LiveSearch';
|
|
import { formatCurrency } from '@/lib/utils';
|
|
import { storefrontService, StorefrontSettings } from '@/services/api/storefrontService';
|
|
import { getMediaUrl } from '@/services/api/client';
|
|
|
|
export function StoreHeader() {
|
|
const itemCount = useCartStore((state) => state.getItemCount());
|
|
const cartTotal = useCartStore((state) => state.getCartTotal());
|
|
const wishlistCount = useCartStore((state) => state.wishlist.length);
|
|
const setCartDrawerOpen = useCartStore((state) => state.setCartDrawerOpen);
|
|
|
|
const [settings, setSettings] = useState<StorefrontSettings | null>(null);
|
|
|
|
useEffect(() => {
|
|
storefrontService.getSettings().then((s) => {
|
|
setSettings(s);
|
|
if (s?.favicon_url && typeof window !== 'undefined') {
|
|
let link = document.querySelector("link[rel*='icon']") as HTMLLinkElement;
|
|
if (!link) {
|
|
link = document.createElement('link');
|
|
link.rel = 'shortcut icon';
|
|
document.head.appendChild(link);
|
|
}
|
|
link.href = getMediaUrl(s.favicon_url);
|
|
}
|
|
}).catch(() => {});
|
|
}, []);
|
|
|
|
const logoUrl = settings?.logo_url || settings?.primary_wordmark_url;
|
|
const storeName = settings?.store_name || 'iFixKart';
|
|
const logoMediaUrl = getMediaUrl(logoUrl);
|
|
|
|
return (
|
|
<header className="w-full bg-white border-b border-gray-100 py-4 px-4 sticky top-0 z-40 shadow-xs">
|
|
<div className="max-w-7xl mx-auto flex items-center justify-between gap-4 md:gap-8">
|
|
{/* Dynamic Store Logo */}
|
|
<Link href="/" className="flex items-center gap-1.5 shrink-0 group">
|
|
{logoMediaUrl ? (
|
|
/* eslint-disable-next-line @next/next/no-img-element */
|
|
<img
|
|
src={logoMediaUrl}
|
|
alt={storeName}
|
|
className="h-9 md:h-10 object-contain max-w-[220px]"
|
|
onError={(e) => {
|
|
// If logo image fails to load, fall back to text
|
|
(e.target as HTMLElement).style.display = 'none';
|
|
}}
|
|
/>
|
|
) : (
|
|
<span className="font-extrabold text-2xl md:text-3xl text-gray-900 tracking-tight">
|
|
iFix<span className="text-[#1877f2]">Kart</span>
|
|
</span>
|
|
)}
|
|
</Link>
|
|
|
|
{/* Live Catalog Search Component */}
|
|
<LiveSearch />
|
|
|
|
{/* Action Counters */}
|
|
<div className="flex items-center gap-4 sm:gap-6 shrink-0">
|
|
{/* Wishlist */}
|
|
<Link
|
|
href="/wishlist"
|
|
className="flex items-center gap-1.5 text-gray-700 hover:text-[#1877f2] transition-colors relative"
|
|
>
|
|
<div className="relative">
|
|
<Heart className="w-6 h-6 stroke-1.5 text-gray-700" />
|
|
{wishlistCount > 0 && (
|
|
<span className="absolute -top-1.5 -right-2 bg-[#1877f2] text-white text-[10px] font-bold w-4 h-4 rounded-full flex items-center justify-center">
|
|
{wishlistCount}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</Link>
|
|
|
|
{/* Account */}
|
|
<Link
|
|
href="/login"
|
|
className="hidden sm:flex items-center gap-2 text-gray-700 hover:text-[#1877f2] transition-colors"
|
|
>
|
|
<User className="w-6 h-6 stroke-1.5 text-gray-700" />
|
|
<div className="flex flex-col leading-tight text-left">
|
|
<span className="text-[10px] text-gray-400 font-medium">My Account</span>
|
|
<span className="text-xs font-bold text-gray-900">Login</span>
|
|
</div>
|
|
</Link>
|
|
|
|
{/* Shopping Cart Drawer Trigger */}
|
|
<button
|
|
onClick={() => setCartDrawerOpen(true)}
|
|
className="flex items-center gap-2 text-gray-700 hover:text-[#1877f2] transition-colors cursor-pointer"
|
|
>
|
|
<div className="relative">
|
|
<ShoppingCart className="w-6 h-6 stroke-1.5 text-gray-700" />
|
|
<span className="absolute -top-1.5 -right-2 bg-[#1877f2] text-white text-[10px] font-bold w-4 h-4 rounded-full flex items-center justify-center">
|
|
{itemCount}
|
|
</span>
|
|
</div>
|
|
<div className="hidden sm:flex flex-col leading-tight text-left">
|
|
<span className="text-[10px] text-gray-400 font-medium">My Cart</span>
|
|
<span className="text-xs font-bold text-gray-900">{formatCurrency(cartTotal)}</span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|