All files / components/cart CartDrawer.tsx

100% Statements 7/7
100% Branches 9/9
100% Functions 2/2
100% Lines 7/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 1011x                                                             8x     8x 8x 8x       8x                                                                     2x                                                  
"use client";
 
import Link from "next/link";
import type { ReactNode } from "react";
 
import { CartLineItem } from "@/components/cart/CartLineItem";
import { Button } from "@/components/ui/Button";
import { Drawer } from "@/components/ui/Drawer";
import { Price } from "@/components/ui/Price";
import { useCart } from "@/lib/cart/cart-store";
 
/**
 * Public props for the cart drawer shell rendered from the app layout.
 */
export interface CartDrawerProps {
  readonly title?: string;
}
 
/**
 * Accessible cart drawer bound to the global cart context.
 */
export function CartDrawer({ title = "Carrello" }: CartDrawerProps): ReactNode {
  const {
    clearCart,
    closeCart,
    decrementItem,
    incrementItem,
    isOpen,
    itemCount,
    items,
    removeItem,
    subtotalCents,
  } = useCart();
 
  const hasItems = items.length > 0;
  const itemLabel = itemCount === 1 ? "1 articolo" : `${itemCount} articoli`;
  const statusMessage = hasItems
    ? `${itemLabel} nel carrello, subtotale aggiornato.`
    : "Il carrello è vuoto.";
 
  return (
    <Drawer
      footer={
        hasItems ? (
          <div className="space-y-4">
            <div className="flex items-center justify-between text-base font-semibold text-stone-950 dark:text-white">
              <span>Subtotale</span>
              <Price amountCents={subtotalCents} />
            </div>
            <p className="text-sm text-stone-500 dark:text-stone-400">
              Checkout Stripe simulato: nessuna carta reale e nessuna chiamata server.
            </p>
            <Link
              className="inline-flex min-h-11 w-full items-center justify-center rounded-md bg-stone-950 px-5 text-sm font-semibold text-white transition hover:bg-emerald-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-700 dark:bg-emerald-400 dark:text-stone-950 dark:hover:bg-emerald-300"
              href="/checkout"
              onClick={closeCart}
            >
              Vai al checkout
            </Link>
            <Button className="w-full" onClick={clearCart} variant="ghost">
              Svuota carrello
            </Button>
          </div>
        ) : null
      }
      isOpen={isOpen}
      onClose={closeCart}
      title={`${title} (${itemCount})`}
    >
      <p aria-live="polite" className="sr-only">
        {statusMessage}
      </p>
      {hasItems ? (
        <div aria-live="polite">
          {items.map((item) => (
            <CartLineItem
              item={item}
              key={item.product.slug}
              onDecrement={decrementItem}
              onIncrement={incrementItem}
              onRemove={removeItem}
            />
          ))}
        </div>
      ) : (
        <div className="flex min-h-64 flex-col items-center justify-center text-center">
          <h3 className="text-lg font-semibold text-stone-950 dark:text-white">
            Il carrello è vuoto
          </h3>
          <p className="mt-2 max-w-xs text-sm text-stone-500 dark:text-stone-400">
            Salva qui gli articoli che vuoi confrontare e completa il checkout nella demo Stripe.
          </p>
          <Button className="mt-5" onClick={closeCart} variant="secondary">
            Continua lo shopping
          </Button>
        </div>
      )}
    </Drawer>
  );
}