'use client'; import { useEffect, useRef, useState } from 'react'; import { Loader2, Plus, Search } from 'lucide-react'; import { toast } from 'sonner'; import { storefrontService } from '@/services/api/storefrontService'; import { ProductResponse } from '@/services/api/catalogService'; import { mapProductCardToProductResponse } from '@/utils/productMapper'; import { getCatalogPriceInfo, getImageUrl } from '@/lib/utils'; import { isSameCompareProduct, notifyCompareResult } from '@/lib/compare'; import { compareKindLabel, detectProductKind, formatComparePrice, lockedCompareKind, } from '@/lib/compareSpecs'; import { useCartStore } from '@/store/cartStore'; interface CompareProductPickerProps { variant?: 'hero' | 'icon' | 'button'; replaceProductId?: string; defaultOpen?: boolean; onAdded?: () => void; } export function CompareProductPicker({ variant = 'icon', replaceProductId, defaultOpen = false, onAdded, }: CompareProductPickerProps) { const compareList = useCartStore((s) => s.compareList); const addToCompare = useCartStore((s) => s.addToCompare); const replaceCompareProduct = useCartStore((s) => s.replaceCompareProduct); const [query, setQuery] = useState(''); const [results, setResults] = useState([]); const [loading, setLoading] = useState(false); const [open, setOpen] = useState(variant === 'hero' || defaultOpen); useEffect(() => { if (defaultOpen) setOpen(true); }, [defaultOpen, replaceProductId]); const rootRef = useRef(null); const inputRef = useRef(null); const lockedKind = lockedCompareKind(compareList, replaceProductId); const kindLabel = lockedKind ? compareKindLabel(lockedKind) : 'products'; useEffect(() => { if (open) inputRef.current?.focus(); }, [open]); useEffect(() => { const q = query.trim(); if (q.length < 2) { setResults([]); setLoading(false); return; } setLoading(true); const timer = window.setTimeout(async () => { try { const data = await storefrontService.getLiveSearch(q); const products = (data.products || []) .map((p) => mapProductCardToProductResponse(p as unknown as Record)) .filter((p) => { if (!p.product_id) return false; const alreadyListed = compareList.some( (c) => isSameCompareProduct(c, p) && (!replaceProductId || !isSameCompareProduct(c, replaceProductId)) ); if (alreadyListed) return false; if (lockedKind && detectProductKind(p) !== lockedKind) return false; return true; }) .slice(0, 8); setResults(products); } catch { setResults([]); } finally { setLoading(false); } }, 280); return () => window.clearTimeout(timer); }, [query, compareList, replaceProductId, lockedKind]); useEffect(() => { if (variant === 'hero') return; const onPointer = (event: MouseEvent) => { if (!rootRef.current?.contains(event.target as Node)) setOpen(false); }; document.addEventListener('mousedown', onPointer); return () => document.removeEventListener('mousedown', onPointer); }, [variant]); const handleSelect = (product: ProductResponse) => { const result = replaceProductId ? replaceCompareProduct(replaceProductId, product) : addToCompare(product); if (!notifyCompareResult(result)) return; if (result.ok && !result.already) { toast.success(replaceProductId ? 'Product replaced' : 'Added to comparison'); } setQuery(''); setResults([]); if (variant === 'icon') setOpen(false); onAdded?.(); }; const searchField = (
setQuery(e.target.value)} placeholder={lockedKind ? `Search ${kindLabel}` : 'Search product name'} className="w-full h-10 pl-9 pr-9 rounded-lg border border-gray-200 bg-white text-[13px] text-gray-800 placeholder:text-gray-400 focus:outline-none focus:border-primary" /> {loading ? ( ) : null}
); const resultList = query.trim().length >= 2 ? (
    {loading && results.length === 0 ? (
  • Searching…
  • ) : results.length === 0 ? (
  • {lockedKind ? `No matching ${kindLabel}` : 'No matching products'}
  • ) : ( results.map((product) => { const img = getImageUrl(product.images?.[0]?.image_url); const price = getCatalogPriceInfo(product).price; return (
  • ); }) )}
) : null; if (variant === 'hero') { return (
{searchField} {resultList}
); } return (
{open ? (

{replaceProductId ? 'Replace product' : 'Add a product'}

{searchField} {resultList}
) : null}
); }