143 lines
5.9 KiB
TypeScript
143 lines
5.9 KiB
TypeScript
"use client";
|
|
|
|
import { useCartStore } from "@/store/cart-store";
|
|
import { X, Minus, Plus, Trash2, ArrowRight } from "lucide-react";
|
|
import { useEffect, useState } from "react";
|
|
import Image from "next/image";
|
|
import { getProductImageUrl } from "@/lib/supabase";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export default function CartDrawer() {
|
|
const {
|
|
items,
|
|
isOpen,
|
|
closeCart,
|
|
removeItem,
|
|
updateQuantity,
|
|
getTotalPrice
|
|
} = useCartStore();
|
|
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
// Evitar problemas de hidratación (SSR vs Client)
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
if (!mounted) return null;
|
|
|
|
return (
|
|
<>
|
|
{/* Overlay Oscuro (Backdrop) */}
|
|
<div
|
|
className={cn(
|
|
"fixed inset-0 bg-black/20 backdrop-blur-sm z-[60] transition-opacity duration-300",
|
|
isOpen ? "opacity-100 visible" : "opacity-0 invisible pointer-events-none"
|
|
)}
|
|
onClick={closeCart}
|
|
/>
|
|
|
|
{/* Panel Deslizante */}
|
|
<div
|
|
className={cn(
|
|
"fixed top-0 right-0 h-full w-full md:w-[450px] bg-white z-[70] shadow-2xl transform transition-transform duration-500 cubic-bezier(0.32, 0.72, 0, 1)",
|
|
// Borde redondeado a la izquierda estilo boutique
|
|
"md:rounded-l-[2.5rem]",
|
|
isOpen ? "translate-x-0" : "translate-x-full"
|
|
)}
|
|
>
|
|
<div className="flex flex-col h-full p-8">
|
|
|
|
{/* Header */}
|
|
<div className="flex justify-between items-center mb-8">
|
|
<h2 className="text-2xl font-light tracking-tight">
|
|
Tu Pedido <span className="text-accent text-sm font-medium ml-2">({items.length})</span>
|
|
</h2>
|
|
<button onClick={closeCart} className="p-2 hover:bg-gray-100 rounded-full transition">
|
|
<X className="w-6 h-6 text-gray-400" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Lista de Items */}
|
|
<div className="flex-1 overflow-y-auto pr-2 -mr-2 no-scrollbar">
|
|
{items.length === 0 ? (
|
|
<div className="h-full flex flex-col items-center justify-center text-center opacity-50">
|
|
<span className="text-6xl mb-4">🥑</span>
|
|
<p className="font-light">Tu cesta está vacía.</p>
|
|
<button onClick={closeCart} className="mt-4 text-sm underline hover:text-accent">
|
|
Volver a la tienda
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-8">
|
|
{items.map((item) => (
|
|
<div key={item.id} className="flex gap-4">
|
|
{/* Imagen Miniatura */}
|
|
<div className="w-20 h-24 bg-[#f8f8f8] rounded-xl flex items-center justify-center shrink-0">
|
|
<img
|
|
src={getProductImageUrl(item.image_url)}
|
|
alt={item.name}
|
|
className="w-16 h-16 object-contain"
|
|
/>
|
|
</div>
|
|
|
|
{/* Info */}
|
|
<div className="flex-1 flex flex-col justify-between">
|
|
<div className="flex justify-between items-start">
|
|
<div>
|
|
<h4 className="font-medium text-dark line-clamp-1">{item.name}</h4>
|
|
<p className="text-xs text-gray-400">{item.category}</p>
|
|
</div>
|
|
<button onClick={() => removeItem(item.id)} className="text-gray-300 hover:text-red-400 transition">
|
|
<Trash2 className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="flex justify-between items-end">
|
|
{/* Control Cantidad Mini */}
|
|
<div className="flex items-center gap-3 bg-gray-50 rounded-full px-2 py-1">
|
|
<button onClick={() => updateQuantity(item.id, item.quantity - 1)} className="p-1 hover:text-accent">
|
|
<Minus className="w-3 h-3" />
|
|
</button>
|
|
<span className="text-xs font-medium w-3 text-center">{item.quantity}</span>
|
|
<button onClick={() => updateQuantity(item.id, item.quantity + 1)} className="p-1 hover:text-accent">
|
|
<Plus className="w-3 h-3" />
|
|
</button>
|
|
</div>
|
|
|
|
<span className="font-medium text-dark">
|
|
{new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'EUR' }).format(item.price * item.quantity)}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Footer / Checkout */}
|
|
{items.length > 0 && (
|
|
<div className="mt-8 pt-6 border-t border-gray-100">
|
|
<div className="flex justify-between items-center mb-6 text-lg font-medium">
|
|
<span>Subtotal</span>
|
|
<span>
|
|
{new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'EUR' }).format(getTotalPrice())}
|
|
</span>
|
|
</div>
|
|
|
|
<button className="w-full bg-dark text-white py-4 rounded-full font-medium flex justify-center items-center gap-2 hover:bg-accent hover:shadow-lg hover:shadow-green-100 transition-all duration-300 group">
|
|
Tramitar Pedido
|
|
<ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
|
|
</button>
|
|
|
|
<p className="text-center text-[10px] text-gray-400 mt-4 uppercase tracking-widest">
|
|
Envío calculado en el siguiente paso
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
} |