148 lines
5.9 KiB
TypeScript
148 lines
5.9 KiB
TypeScript
"use client";
|
|
|
|
import React from 'react';
|
|
import { Heart, X, ShoppingCart } from 'lucide-react';
|
|
import Link from 'next/link';
|
|
import { useCartStore } from '@/store/cartStore';
|
|
import { getImageUrl, formatCurrency } from '@/lib/utils';
|
|
|
|
interface WishlistModalProps {
|
|
onClose: () => void;
|
|
}
|
|
|
|
export const WishlistModal: React.FC<WishlistModalProps> = ({ onClose }) => {
|
|
// Read directly from Zustand store — no localStorage mismatch
|
|
const wishlist = useCartStore((state) => state.wishlist);
|
|
const toggleWishlist = useCartStore((state) => state.toggleWishlist);
|
|
const addToCart = useCartStore((state) => state.addToCart);
|
|
|
|
React.useEffect(() => {
|
|
document.body.style.overflow = 'hidden';
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if (e.key === 'Escape') onClose();
|
|
};
|
|
document.addEventListener('keydown', handleKeyDown);
|
|
return () => {
|
|
document.body.style.overflow = '';
|
|
document.removeEventListener('keydown', handleKeyDown);
|
|
};
|
|
}, [onClose]);
|
|
|
|
const handleMoveToCart = (product: any) => {
|
|
const variant = product.variants?.[0];
|
|
if (variant) {
|
|
addToCart(product, variant, 1);
|
|
toggleWishlist(product); // remove from wishlist
|
|
}
|
|
};
|
|
|
|
const getPrice = (product: any): number => {
|
|
return product.variants?.[0]?.price ?? 0;
|
|
};
|
|
|
|
const getImage = (product: any): string => {
|
|
const img = product.variants?.[0]?.images?.[0] ?? product.image ?? '';
|
|
return getImageUrl(img);
|
|
};
|
|
|
|
return (
|
|
<div
|
|
onClick={onClose}
|
|
className="fixed inset-0 bg-black/75 backdrop-blur-xs flex items-center justify-center z-[200] p-4 font-sans animate-in fade-in duration-200"
|
|
>
|
|
<div
|
|
onClick={(e) => e.stopPropagation()}
|
|
className="bg-white w-full max-w-[740px] rounded-2xl shadow-2xl overflow-hidden relative flex flex-col max-h-[85vh] text-left"
|
|
>
|
|
{/* Header */}
|
|
<div className="bg-[#1E1E1E] text-white px-7 py-4 flex items-center justify-between">
|
|
<h2 className="text-[16px] font-bold tracking-wide">
|
|
Wishlist ({wishlist.length})
|
|
</h2>
|
|
<button
|
|
onClick={onClose}
|
|
className="w-9 h-9 rounded-full flex items-center justify-center text-gray-400 hover:text-white transition-colors cursor-pointer -mr-2"
|
|
title="Close"
|
|
>
|
|
<X size={19} className="stroke-[2.5]" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Wishlist Items */}
|
|
{wishlist.length === 0 ? (
|
|
<div className="flex flex-col items-center justify-center py-20 text-gray-500 flex-grow bg-[#F8F9FB]">
|
|
<Heart size={40} className="text-gray-300 mb-3 stroke-[1.5]" />
|
|
<p className="text-[13px] font-semibold">Your wishlist is empty!</p>
|
|
<p className="text-[11px] text-gray-400 mt-1">Add items from the store to see them here.</p>
|
|
</div>
|
|
) : (
|
|
<div className="overflow-y-auto divide-y divide-gray-150 max-h-[495px] bg-white px-7 border-b border-gray-100">
|
|
{wishlist.map((product) => {
|
|
const price = getPrice(product);
|
|
const imgSrc = getImage(product);
|
|
const slug = product.slug ?? product.product_id;
|
|
|
|
return (
|
|
<div key={product.product_id} className="py-5 flex items-center gap-5 justify-between">
|
|
<div className="flex items-center gap-4 flex-grow min-w-0">
|
|
{/* Product Image */}
|
|
{imgSrc ? (
|
|
<img
|
|
src={imgSrc}
|
|
alt={product.name}
|
|
className="w-[72px] h-[72px] object-contain rounded-xl border border-gray-150 bg-white p-2 flex-shrink-0 shadow-xs"
|
|
/>
|
|
) : (
|
|
<div className="w-[72px] h-[72px] bg-gray-100 rounded-xl flex items-center justify-center text-gray-400 text-[10px] font-semibold flex-shrink-0">
|
|
No Image
|
|
</div>
|
|
)}
|
|
|
|
<div className="min-w-0 pr-2">
|
|
{/* Product Name */}
|
|
<Link
|
|
href={`/products/${slug}`}
|
|
onClick={onClose}
|
|
className="text-[15px] font-bold text-[#0073EC] hover:text-black line-clamp-1 block transition-colors leading-snug mb-1"
|
|
>
|
|
{product.name}
|
|
</Link>
|
|
|
|
{/* Price */}
|
|
<p className="text-[14.5px] font-extrabold text-gray-950 mb-1">
|
|
{formatCurrency(price)}
|
|
</p>
|
|
|
|
{/* SKU */}
|
|
<p className="text-xs text-gray-400 font-medium">
|
|
SKU: {product.variants?.[0]?.sku ?? '—'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
<div className="flex items-center gap-3.5 flex-shrink-0">
|
|
<button
|
|
onClick={() => handleMoveToCart(product)}
|
|
className="bg-[#0073EC] hover:bg-black text-white text-[12.5px] font-bold px-5 py-3 rounded-xl transition-colors cursor-pointer select-none shadow-xs whitespace-nowrap flex items-center gap-2"
|
|
>
|
|
<ShoppingCart size={13} />
|
|
Move to Cart
|
|
</button>
|
|
<button
|
|
onClick={() => toggleWishlist(product)}
|
|
className="w-9 h-9 rounded-full flex items-center justify-center text-gray-400 hover:text-red-500 transition-colors cursor-pointer -mr-2"
|
|
title="Remove from Wishlist"
|
|
>
|
|
<X size={18} className="stroke-[2.5]" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|