almeira-web/dripzone-app/src/components/store/ProductCard.tsx

180 lines
8.2 KiB
TypeScript

'use client';
import React, { useState } from 'react';
import { Star, Zap, Truck, ShoppingBag, Layers, Palette, Sparkles } from 'lucide-react';
import { Product } from '@/types';
import { formatCOP, calculateSeparationBreakdown, getProductPriceRange } from '@/lib/pricing-engine';
import { useBrand } from '@/context/BrandContext';
import { getProductSocialProof } from '@/lib/social-proof';
interface ProductCardProps {
product: Product;
onOpenDetail: (product: Product) => void;
onQuickAdd: (product: Product, size: string) => void;
}
export const ProductCard: React.FC<ProductCardProps> = ({
product,
onOpenDetail,
}) => {
const { currentBrand } = useBrand();
const [activeImage, setActiveImage] = useState<string>(product.images[0]);
const [activeColorName, setActiveColorName] = useState<string>(product.colorName || '');
const socialProof = getProductSocialProof(product);
const priceRange = getProductPriceRange(product);
const discountPercent = product.originalPrice
? Math.round(((product.originalPrice - product.retailPrice) / product.originalPrice) * 100)
: 28;
const separation = calculateSeparationBreakdown(product.retailPrice);
const colorCount = product.colors?.length || 1;
return (
<div
onClick={() => onOpenDetail(product)}
className={`group rounded-3xl border transition-all duration-300 flex flex-col cursor-pointer overflow-hidden ${currentBrand.colors.cardBg} hover:shadow-2xl hover:border-purple-500/40`}
>
{/* Image Container */}
<div className="relative aspect-square w-full bg-slate-950 overflow-hidden">
<img
src={activeImage || product.images[0]}
alt={product.name}
className="w-full h-full object-cover group-hover:scale-108 transition-transform duration-500"
/>
{/* Badges */}
<div className="absolute top-2.5 left-2.5 flex flex-col gap-1 z-10">
<span className={`bg-gradient-to-r ${currentBrand.colors.primaryGradient} text-white text-[10px] sm:text-xs font-black px-2.5 py-0.5 rounded-lg shadow-md uppercase tracking-wider`}>
-{discountPercent}% OFF
</span>
{product.isFlashDeal && (
<span className="bg-white/95 text-slate-950 text-[10px] font-black px-2 py-0.5 rounded-lg shadow-md flex items-center gap-0.5">
<Zap className="w-3 h-3 fill-slate-950" /> FLASH
</span>
)}
</div>
{/* Colors count indicator badge */}
{colorCount > 1 && (
<div className="absolute top-2.5 right-2.5 z-10">
<span className="bg-slate-950/90 backdrop-blur-md text-purple-300 border border-purple-500/40 text-[10px] font-black px-2 py-0.5 rounded-full flex items-center gap-1 shadow-lg">
<Palette className="w-3 h-3 text-purple-400" />
<span>{colorCount} Colores</span>
</span>
</div>
)}
<div className="absolute bottom-2 left-2 right-2 flex items-center justify-between pointer-events-none">
<span className="bg-slate-950/80 backdrop-blur-xs text-white border border-white/10 text-[10px] font-semibold px-2 py-0.5 rounded-full flex items-center gap-1">
<Truck className="w-3 h-3 text-white" /> Contraentrega
</span>
<span className={`bg-gradient-to-r ${currentBrand.colors.primaryGradient} text-white text-[10px] font-bold px-2 py-0.5 rounded-full shadow-xs`}>
{product.brand}
</span>
</div>
</div>
{/* Product Info */}
<div className="p-3.5 sm:p-4 flex-1 flex flex-col justify-between space-y-2.5">
<div>
{/* Variable Realistic Social Proof & Reviews */}
<div className="flex items-center justify-between text-xs text-slate-400 mb-1">
<div className="flex items-center text-amber-400 font-bold">
<Star className="w-3.5 h-3.5 fill-amber-400 mr-1" />
<span>{socialProof.rating}</span>
<span className="text-slate-500 font-normal ml-1">({socialProof.reviewsCount})</span>
</div>
<span className="text-[11px] font-medium text-slate-400">
+{socialProof.salesCount} pedidos
</span>
</div>
{/* Product Title */}
<h3 className="font-bold text-white text-sm sm:text-base line-clamp-2 transition-colors leading-snug">
{product.modelName || product.name}
</h3>
{/* Color Thumbnails Preview Swatches if multi-color */}
{product.colors && product.colors.length > 1 && (
<div className="flex items-center gap-1.5 mt-2 overflow-x-auto pb-1" onClick={(e) => e.stopPropagation()}>
<span className="text-[10px] text-slate-500 font-semibold uppercase shrink-0">Colores:</span>
<div className="flex items-center gap-1">
{product.colors.slice(0, 4).map((c) => (
<button
key={c.id}
onClick={(e) => {
e.stopPropagation();
setActiveImage(c.image);
setActiveColorName(c.colorName);
}}
title={c.colorName}
className={`w-6 h-6 rounded-full overflow-hidden border transition-all cursor-pointer ${
activeImage === c.image ? 'border-purple-400 scale-110 shadow-md ring-1 ring-purple-400' : 'border-slate-700 opacity-70 hover:opacity-100'
}`}
>
<img src={c.image} alt={c.colorName} className="w-full h-full object-cover" />
</button>
))}
{product.colors.length > 4 && (
<span className="text-[10px] font-bold text-purple-400 bg-purple-500/10 border border-purple-500/30 rounded-full px-1.5 py-0.5">
+{product.colors.length - 4}
</span>
)}
</div>
</div>
)}
{/* Available Sizes Pills */}
<div className="flex items-center gap-1 flex-wrap mt-2">
<span className="text-[10px] text-slate-500 font-semibold uppercase">Tallas:</span>
{product.sizes.slice(0, 5).map((size) => (
<span
key={size}
className="text-[10px] font-bold bg-slate-950 text-slate-300 px-1.5 py-0.5 rounded border border-slate-800"
>
{size}
</span>
))}
{product.sizes.length > 5 && (
<span className="text-[10px] font-semibold text-slate-500">+{product.sizes.length - 5}</span>
)}
</div>
</div>
{/* Pricing & Separation terms */}
<div className="pt-2 border-t border-slate-800">
<div className="flex items-baseline space-x-2">
<span className={`text-lg sm:text-xl font-black text-transparent bg-clip-text bg-gradient-to-r ${currentBrand.colors.primaryGradient}`}>
{priceRange.hasVariation ? `Desde ${formatCOP(priceRange.minPrice)}` : formatCOP(product.retailPrice)}
</span>
{product.originalPrice && (
<span className="text-xs text-slate-500 line-through font-semibold">
{formatCOP(product.originalPrice)}
</span>
)}
</div>
<p className="text-[11px] font-semibold bg-white/5 px-2 py-1 rounded-md mt-1.5 border border-white/10 text-slate-300">
⚡ Separa con <strong className="text-white">{formatCOP(separation.depositAmount)}</strong> y cancelas al recibir.
</p>
{/* Quick Action Button */}
<div className="mt-3">
<button
onClick={(e) => {
e.stopPropagation();
onOpenDetail(product);
}}
className={`w-full bg-gradient-to-r ${currentBrand.colors.primaryGradient} text-white font-bold text-xs sm:text-sm py-2.5 px-3 rounded-2xl flex items-center justify-center space-x-1.5 shadow-md active:scale-95 transition-all cursor-pointer`}
>
<ShoppingBag className="w-3.5 h-3.5" />
<span>{colorCount > 1 ? `Ver ${colorCount} Colores & Tallas` : 'Ver Tallas & Pedir'}</span>
</button>
</div>
</div>
</div>
</div>
);
};