veza/apps/web/src/components/commerce/WishlistView.tsx

104 lines
5.6 KiB
TypeScript
Raw Normal View History

import React, { useState } from 'react';
import { Card } from '../ui/card';
import { Button } from '../ui/button';
import { Product } from '../../types';
import { useCart } from '../../context/CartContext';
import { Heart, ShoppingCart, Trash2, Play, Pause, Zap } from 'lucide-react';
import { useToast } from '../../context/ToastContext';
// Mock Wishlist Data
const MOCK_WISHLIST: Product[] = [
{ id: 'w1', title: 'Analog Dreams Vol. 2', type: 'sample_pack', price: 24.99, currency: 'USD', rating: 4.8, coverUrl: 'https://picsum.photos/id/40/300/300', author: 'Vintage Synths', description: 'Warm analog pads and leads.', features: [], licenses: [] },
{ id: 'w2', title: 'Tech House Essentials', type: 'preset', price: 19.99, currency: 'USD', rating: 4.5, coverUrl: 'https://picsum.photos/id/45/300/300', author: 'Club Ready', description: 'Floor filling serum presets.', features: [], licenses: [] },
{ id: 'w3', title: 'Cinematic FX', type: 'sample_pack', price: 34.50, currency: 'USD', rating: 5.0, coverUrl: 'https://picsum.photos/id/50/300/300', author: 'Sound Design Co', isHot: true, description: 'Impacts, risers, and drops.', features: [], licenses: [] },
];
export const WishlistView: React.FC = () => {
const { addToCart } = useCart();
const { addToast } = useToast();
const [wishlist, setWishlist] = useState<Product[]>(MOCK_WISHLIST);
const [playingPreview, setPlayingPreview] = useState<string | null>(null);
const handleRemove = (id: string) => {
setWishlist(prev => prev.filter(p => p.id !== id));
addToast("Removed from wishlist", "info");
};
const handleAddToCart = (product: Product) => {
addToCart(product);
handleRemove(product.id);
};
const handleAddAll = () => {
wishlist.forEach(p => addToCart(p));
setWishlist([]);
addToast("All items moved to cart", "success");
};
if (wishlist.length === 0) {
return (
<div className="flex flex-col items-center justify-center min-h-[50vh] text-center animate-fadeIn">
<div className="w-24 h-24 bg-kodo-ink rounded-full flex items-center justify-center mb-6 border-2 border-dashed border-kodo-steel">
<Heart className="w-10 h-10 text-gray-600" />
</div>
<h2 className="text-2xl font-bold text-white mb-2">Your wishlist is empty</h2>
<p className="text-gray-400 max-w-sm">Save items you want to listen to later or purchase in the future.</p>
</div>
);
}
return (
<div className="animate-fadeIn max-w-6xl mx-auto pb-20">
<div className="flex flex-col md:flex-row justify-between items-end border-b border-kodo-steel/50 pb-6 gap-4 mb-8">
<div>
<h1 className="text-3xl font-display font-bold text-white mb-2">WISHLIST</h1>
<p className="text-gray-400 font-mono text-sm">{wishlist.length} saved items</p>
</div>
<Button variant="primary" icon={<ShoppingCart className="w-4 h-4" />} onClick={handleAddAll}>
ADD ALL TO CART
</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{wishlist.map(product => (
<Card key={product.id} variant="default" className="p-4 group hover:border-kodo-cyan/50 transition-all">
<div className="flex gap-4">
<div className="relative w-24 h-24 bg-gray-800 rounded-lg overflow-hidden flex-shrink-0">
<img src={product.coverUrl} className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500" />
<div
className="absolute inset-0 bg-black/40 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer"
onClick={() => setPlayingPreview(playingPreview === product.id ? null : product.id)}
>
{playingPreview === product.id ? <Pause className="w-8 h-8 text-white" /> : <Play className="w-8 h-8 text-white fill-current" />}
</div>
{product.isHot && <div className="absolute top-1 left-1 bg-kodo-gold text-black text-[9px] font-bold px-1.5 py-0.5 rounded"><Zap className="w-2 h-2 inline" /> HOT</div>}
</div>
<div className="flex-1 min-w-0 flex flex-col justify-between">
<div>
<h3 className="font-bold text-white truncate">{product.title}</h3>
<p className="text-xs text-gray-400 truncate">{product.author}</p>
<p className="text-xs text-gray-500 mt-1 capitalize">{product.type}</p>
</div>
<div className="text-lg font-mono font-bold text-kodo-cyan">
${product.price}
</div>
</div>
</div>
<div className="flex gap-2 mt-4 pt-4 border-t border-kodo-steel/30">
<Button variant="secondary" size="sm" className="flex-1" onClick={() => handleAddToCart(product)}>
Add to Cart
</Button>
<Button variant="ghost" size="icon" className="text-gray-500 hover:text-kodo-red" onClick={() => handleRemove(product.id)}>
<Trash2 className="w-4 h-4" />
</Button>
</div>
</Card>
))}
</div>
</div>
);
};