270 lines
13 KiB
TypeScript
270 lines
13 KiB
TypeScript
'use client';
|
||
|
||
import React from 'react';
|
||
import Link from 'next/link';
|
||
import { X, Trash2, ShoppingBag, ArrowRight, Zap, Truck, MessageCircle } from 'lucide-react';
|
||
import { CartItem, City } from '@/types';
|
||
import { formatCOP, calculateSeparationBreakdown } from '@/lib/pricing-engine';
|
||
import { useBrand } from '@/context/BrandContext';
|
||
import { renderClientTemplate } from '@/lib/templates-client';
|
||
import { OptimizedImage } from '@/components/ui/OptimizedImage';
|
||
|
||
|
||
interface CartDrawerProps {
|
||
isOpen: boolean;
|
||
onClose: () => void;
|
||
cartItems: CartItem[];
|
||
onRemoveItem: (productId: string, size: string) => void;
|
||
onUpdateQuantity: (productId: string, size: string, delta: number) => void;
|
||
selectedCity: City;
|
||
onOpenCitySelector: () => void;
|
||
}
|
||
|
||
export const CartDrawer: React.FC<CartDrawerProps> = ({
|
||
isOpen,
|
||
onClose,
|
||
cartItems,
|
||
onRemoveItem,
|
||
onUpdateQuantity,
|
||
selectedCity,
|
||
onOpenCitySelector,
|
||
}) => {
|
||
const { currentBrand } = useBrand();
|
||
const [officialPhone, setOfficialPhone] = React.useState('573106390296');
|
||
|
||
React.useEffect(() => {
|
||
fetch('/api/settings')
|
||
.then((r) => r.json())
|
||
.then((d) => {
|
||
if (d.success && d.settings?.whatsappNumber) {
|
||
setOfficialPhone(d.settings.whatsappNumber);
|
||
}
|
||
})
|
||
.catch(() => {});
|
||
}, []);
|
||
|
||
if (!isOpen) return null;
|
||
|
||
const totalQuantity = cartItems.reduce((acc, item) => acc + item.quantity, 0);
|
||
const subtotal = cartItems.reduce((acc, item) => acc + item.product.retailPrice * item.quantity, 0);
|
||
const shippingCost = selectedCity.shippingCost;
|
||
const totalAmount = subtotal + shippingCost;
|
||
const separation = calculateSeparationBreakdown(totalAmount);
|
||
|
||
const handleWhatsAppCheckout = () => {
|
||
const itemsList = cartItems
|
||
.map((item) => `👟 *${item.product.name}* (Talla: *${item.selectedSize}*, Cant: ${item.quantity}) - ${formatCOP(item.product.retailPrice * item.quantity)}`)
|
||
.join('\n');
|
||
|
||
const paymentCondition = `⚡ *Condición de Pago:* Pago Contraentrega (Separo con $10.000 COP y cancelo saldo de ${formatCOP(separation.balanceDue)} al recibir).`;
|
||
|
||
const rawText = renderClientTemplate('order_checkout_wa', {
|
||
tienda_nombre: currentBrand.name,
|
||
orden_id: `WEB-${Date.now().toString().slice(-4)}`,
|
||
cliente_nombre: 'Cliente',
|
||
cliente_telefono: '',
|
||
cliente_direccion: '',
|
||
cliente_ciudad: selectedCity.name,
|
||
articulos_resumen: itemsList,
|
||
total: `${formatCOP(totalAmount)} COP`,
|
||
condicion_pago_resumen: paymentCondition,
|
||
metodo_pago: 'Pago Contraentrega',
|
||
saldo_contraentrega: formatCOP(separation.balanceDue),
|
||
});
|
||
|
||
window.open(`https://wa.me/${officialPhone}?text=${encodeURIComponent(rawText)}`, '_blank');
|
||
};
|
||
|
||
|
||
return (
|
||
<div className="fixed inset-0 z-50 overflow-hidden animate-in fade-in duration-200">
|
||
{/* Backdrop */}
|
||
<div onClick={onClose} className="absolute inset-0 bg-black/80 backdrop-blur-xs transition-opacity" />
|
||
|
||
<div className="fixed inset-y-0 right-0 max-w-full flex pl-10">
|
||
<div className={`w-screen max-w-md bg-slate-900 border-l ${currentBrand.colors.border} text-white shadow-2xl flex flex-col justify-between`}>
|
||
{/* Header */}
|
||
<div className="p-4 border-b border-slate-800 flex items-center justify-between bg-slate-950">
|
||
<div className="flex items-center space-x-2">
|
||
<div className={`w-8 h-8 rounded-full bg-gradient-to-r ${currentBrand.colors.primaryGradient} flex items-center justify-center text-white font-bold shadow-sm`}>
|
||
<ShoppingBag className="w-4 h-4" />
|
||
</div>
|
||
<div>
|
||
<h2 className="font-black text-white text-base">Tu Carrito • {currentBrand.shortName}</h2>
|
||
<p className="text-xs text-slate-400">{cartItems.length} {cartItems.length === 1 ? 'artículo' : 'artículos'}</p>
|
||
</div>
|
||
</div>
|
||
<button
|
||
onClick={onClose}
|
||
className="w-8 h-8 rounded-full bg-slate-800 hover:bg-slate-700 text-slate-300 flex items-center justify-center transition-all cursor-pointer"
|
||
>
|
||
<X className="w-4 h-4" />
|
||
</button>
|
||
</div>
|
||
|
||
{/* Items List */}
|
||
<div className="flex-1 overflow-y-auto p-4 space-y-3">
|
||
{cartItems.length === 0 ? (
|
||
<div className="h-full flex flex-col items-center justify-center text-center p-6 space-y-3">
|
||
<div className="w-16 h-16 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-slate-400">
|
||
<ShoppingBag className="w-8 h-8" />
|
||
</div>
|
||
<h3 className="font-bold text-white text-base">Tu carrito está vacío</h3>
|
||
<p className="text-xs text-slate-400 max-w-xs">
|
||
Aprovecha las ofertas de calzado con pago contraentrega en Cali y despachos nacionales.
|
||
</p>
|
||
<button
|
||
onClick={onClose}
|
||
className={`bg-gradient-to-r ${currentBrand.colors.primaryGradient} text-white text-xs font-bold px-4 py-2 rounded-full mt-2 cursor-pointer shadow-md`}
|
||
>
|
||
Explorar Zapatillas
|
||
</button>
|
||
</div>
|
||
) : (
|
||
cartItems.map((item, idx) => (
|
||
<div
|
||
key={`${item.product.id}-${item.selectedSize}-${idx}`}
|
||
className="flex gap-3 bg-slate-950 p-3 rounded-2xl border border-slate-800 relative group"
|
||
>
|
||
<OptimizedImage
|
||
src={item.product.images[0]}
|
||
alt={item.product.name}
|
||
width={160}
|
||
height={160}
|
||
quality={80}
|
||
className="w-20 h-20 rounded-xl object-cover bg-slate-900 shrink-0 border border-slate-700"
|
||
containerClassName="w-20 h-20 rounded-xl shrink-0"
|
||
/>
|
||
<div className="flex-1 flex flex-col justify-between">
|
||
<div>
|
||
<div className="flex items-start justify-between gap-1">
|
||
<h4 className="font-bold text-white text-xs line-clamp-2 leading-snug">
|
||
{item.product.name}
|
||
</h4>
|
||
<button
|
||
onClick={() => onRemoveItem(item.product.id, item.selectedSize)}
|
||
className="text-slate-500 hover:text-rose-400 transition-colors p-1 cursor-pointer"
|
||
>
|
||
<Trash2 className="w-3.5 h-3.5" />
|
||
</button>
|
||
</div>
|
||
<div className="flex items-center gap-2 mt-1">
|
||
<span className="text-[11px] font-bold bg-slate-900 text-white px-2 py-0.5 rounded border border-slate-700">
|
||
Talla {item.selectedSize}
|
||
</span>
|
||
<span className="text-[11px] font-semibold text-slate-400">
|
||
{item.product.brand}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex items-center justify-between pt-2">
|
||
<span className={`font-black text-sm text-transparent bg-clip-text bg-gradient-to-r ${currentBrand.colors.primaryGradient}`}>
|
||
{formatCOP(item.product.retailPrice * item.quantity)}
|
||
</span>
|
||
<div className="flex items-center border border-slate-700 rounded-lg bg-slate-900 overflow-hidden">
|
||
<button
|
||
onClick={() => onUpdateQuantity(item.product.id, item.selectedSize, -1)}
|
||
className="px-2 py-0.5 text-xs text-slate-300 hover:bg-slate-800 cursor-pointer font-bold"
|
||
>
|
||
-
|
||
</button>
|
||
<span className="px-2 py-0.5 text-xs font-bold text-white">{item.quantity}</span>
|
||
<button
|
||
onClick={() => onUpdateQuantity(item.product.id, item.selectedSize, 1)}
|
||
className="px-2 py-0.5 text-xs text-slate-300 hover:bg-slate-800 cursor-pointer font-bold"
|
||
>
|
||
+
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))
|
||
)}
|
||
</div>
|
||
|
||
{/* Footer & Checkout Breakdown */}
|
||
{cartItems.length > 0 && (
|
||
<div className="p-4 border-t border-slate-800 bg-slate-950 space-y-3">
|
||
{/* City Delivery selector pill */}
|
||
<div className="bg-slate-900 p-2.5 rounded-xl border border-slate-800 flex items-center justify-between text-xs">
|
||
<div className="flex items-center space-x-1.5">
|
||
<Truck className="w-4 h-4 text-white" />
|
||
<span>Destino: <strong className="text-white">{selectedCity.name}</strong></span>
|
||
</div>
|
||
<button
|
||
onClick={onOpenCitySelector}
|
||
className="text-white hover:underline font-bold text-[11px] cursor-pointer"
|
||
>
|
||
Cambiar
|
||
</button>
|
||
</div>
|
||
|
||
{/* Price Calculations */}
|
||
<div className="space-y-1.5 text-xs text-slate-400">
|
||
<div className="flex justify-between">
|
||
<span>Subtotal:</span>
|
||
<span className="font-bold text-white">{formatCOP(subtotal)}</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span>Costo de Envío:</span>
|
||
<span className="font-bold text-white">
|
||
{shippingCost === 0 ? <span className="text-emerald-400 uppercase font-black">Gratis</span> : formatCOP(shippingCost)}
|
||
</span>
|
||
</div>
|
||
<div className="flex justify-between text-sm font-bold text-white pt-1 border-t border-slate-800">
|
||
<span>Total de la Orden:</span>
|
||
<span className="font-bold text-white">
|
||
{formatCOP(totalAmount)}
|
||
</span>
|
||
</div>
|
||
<div className="flex justify-between text-xs text-purple-300 font-semibold pt-1">
|
||
<span>⚡ Separación (1er Pedido):</span>
|
||
<span className="font-bold font-mono">$10.000 COP</span>
|
||
</div>
|
||
<div className="flex justify-between text-xs text-emerald-400 font-black pt-1 border-t border-white/5">
|
||
<span>🤝 Saldo Restante Contraentrega:</span>
|
||
<span className="font-mono">{formatCOP(Math.max(0, totalAmount - 10000))}</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Separation Highlight Banner */}
|
||
<div className="bg-white/5 border border-white/10 rounded-xl p-2.5 text-xs space-y-1">
|
||
<p className="font-bold text-white flex items-center gap-1">
|
||
<Zap className="w-3.5 h-3.5 fill-white" />
|
||
Separación fija de $10.000 COP (1er Pedido)
|
||
</p>
|
||
<p className="text-slate-300 text-[11px]">
|
||
Separas tu pedido completo ({totalQuantity} {totalQuantity > 1 ? 'productos' : 'producto'}) con una tarifa única de <strong>$10.000 COP</strong> y cancelas el saldo restante (<strong>{formatCOP(Math.max(0, totalAmount - 10000))}</strong>) contraentrega al recibir en tu puerta.
|
||
</p>
|
||
<p className="text-[10px] text-emerald-400 font-semibold pt-0.5 border-t border-white/5">
|
||
🛡️ {selectedCity.firstExchangeFree
|
||
? `1er Cambio de Talla 100% GRATIS en ${selectedCity.name}`
|
||
: `Garantía de cambio en ${selectedCity.name} (flete asumido por cliente)`}
|
||
</p>
|
||
</div>
|
||
|
||
{/* Action Button */}
|
||
<div className="pt-1 space-y-2">
|
||
<div className="flex items-center justify-center gap-1.5 text-[11px] text-purple-300 font-semibold bg-purple-950/40 border border-purple-500/20 py-1.5 px-3 rounded-xl">
|
||
<span>🎟️ ¿Tienes cupón de descuento? Podrás aplicarlo al pagar</span>
|
||
</div>
|
||
|
||
<Link
|
||
href="/checkout"
|
||
onClick={onClose}
|
||
className={`w-full bg-gradient-to-r ${currentBrand.colors.primaryGradient} text-white font-black text-sm py-3.5 px-4 rounded-xl flex items-center justify-center space-x-2 shadow-lg active:scale-95 transition-all text-center`}
|
||
>
|
||
<span>Continuar al Pago Contraentrega</span>
|
||
<ArrowRight className="w-4 h-4" />
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|