Retour au catalogue

Cart Summary

Resume du panier avec liste d'articles, quantites et total.

ecommercemedium Both Responsive a11y
minimalecommerceuniversalstacked
Theme
"use client";

import { motion } from "framer-motion";
import { Minus, Plus, Trash2, ArrowRight } from "lucide-react";

interface CartItem { name: string; price: number; quantity: number; }
interface EcommerceCartSummaryProps { title?: string; items?: CartItem[]; shipping?: number; ctaLabel?: string; }
const ease: [number, number, number, number] = [0.16, 1, 0.3, 1];

export default function EcommerceCartSummary({ title = "Votre panier", items = [], shipping = 0, ctaLabel = "Commander" }: EcommerceCartSummaryProps) {
  const subtotal = items.reduce((s, i) => s + i.price * i.quantity, 0);
  const total = subtotal + shipping;

  return (
    <section className="py-20 lg:py-28" style={{ background: "var(--color-background)" }}>
      <div className="mx-auto max-w-2xl px-6">
        <motion.h2 initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} transition={{ duration: 0.6, ease }} viewport={{ once: true }} className="text-2xl md:text-3xl font-bold mb-8" style={{ color: "var(--color-foreground)" }}>{title}</motion.h2>

        <div className="flex flex-col gap-0">
          {items.map((item, i) => (
            <motion.div key={item.name} initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} transition={{ duration: 0.4, delay: i * 0.05 }} viewport={{ once: true }} className="flex items-center gap-4 py-5" style={{ borderBottom: "1px solid var(--color-border)" }}>
              <div className="w-16 h-16 rounded-lg flex-shrink-0" style={{ background: "var(--color-background-alt)" }} />
              <div className="flex-1 min-w-0">
                <h4 className="text-sm font-semibold truncate" style={{ color: "var(--color-foreground)" }}>{item.name}</h4>
                <p className="text-sm mt-0.5" style={{ color: "var(--color-foreground-muted)" }}>{item.price.toFixed(2)}\u20ac</p>
              </div>
              <div className="flex items-center gap-2">
                <button className="w-7 h-7 rounded flex items-center justify-center" style={{ border: "1px solid var(--color-border)" }}><Minus size={12} style={{ color: "var(--color-foreground-muted)" }} /></button>
                <span className="w-6 text-center text-sm font-medium" style={{ color: "var(--color-foreground)" }}>{item.quantity}</span>
                <button className="w-7 h-7 rounded flex items-center justify-center" style={{ border: "1px solid var(--color-border)" }}><Plus size={12} style={{ color: "var(--color-foreground-muted)" }} /></button>
              </div>
              <p className="text-sm font-semibold w-20 text-right" style={{ color: "var(--color-foreground)" }}>{(item.price * item.quantity).toFixed(2)}\u20ac</p>
              <button className="text-sm hover:opacity-60 transition-opacity"><Trash2 size={14} style={{ color: "var(--color-foreground-light)" }} /></button>
            </motion.div>
          ))}
        </div>

        <div className="mt-6 flex flex-col gap-2 py-4" style={{ borderTop: "2px solid var(--color-border)" }}>
          <div className="flex justify-between text-sm"><span style={{ color: "var(--color-foreground-muted)" }}>Sous-total</span><span style={{ color: "var(--color-foreground)" }}>{subtotal.toFixed(2)}\u20ac</span></div>
          <div className="flex justify-between text-sm"><span style={{ color: "var(--color-foreground-muted)" }}>Livraison</span><span style={{ color: "var(--color-foreground)" }}>{shipping > 0 ? `${shipping.toFixed(2)}\u20ac` : "Gratuit"}</span></div>
          <div className="flex justify-between text-base font-bold mt-2 pt-2" style={{ borderTop: "1px solid var(--color-border)" }}><span style={{ color: "var(--color-foreground)" }}>Total</span><span style={{ color: "var(--color-foreground)" }}>{total.toFixed(2)}\u20ac</span></div>
        </div>

        <button className="w-full flex items-center justify-center gap-2 py-3.5 rounded-lg text-sm font-semibold mt-4 transition-opacity hover:opacity-90" style={{ background: "var(--color-accent)", color: "var(--color-background)" }}>
          {ctaLabel} <ArrowRight size={15} />
        </button>
      </div>
    </section>
  );
}

Avis

Cart Summary — React Ecommerce Section — Incubator