chore: add client/src/pages/cart.tsx
This commit is contained in:
parent
5ad1e8a6df
commit
d1b0b0fd7b
1 changed files with 82 additions and 0 deletions
82
client/src/pages/cart.tsx
Normal file
82
client/src/pages/cart.tsx
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import { Link } from "wouter";
|
||||
import { ShoppingBag, Trash2 } from "lucide-react";
|
||||
import { useCart } from "../hooks/use-cart";
|
||||
|
||||
export default function CartPage() {
|
||||
const { items, updateQuantity, removeItem, subtotal } = useCart();
|
||||
|
||||
if (items.length === 0) {
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto px-4 py-20 text-center" data-testid="cart-empty">
|
||||
<ShoppingBag size={48} className="mx-auto mb-4 text-muted-foreground/30" />
|
||||
<h1 className="text-2xl font-bold mb-3">Your cart is empty</h1>
|
||||
<Link href="/" className="inline-block bg-primary text-primary-foreground px-6 py-3 rounded-md font-medium hover:bg-primary/90 transition-colors">
|
||||
Browse products
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto px-4 py-10" data-testid="cart-page">
|
||||
<h1 className="text-2xl font-bold mb-8">Shopping cart ({items.length})</h1>
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
<div className="md:col-span-2 space-y-4">
|
||||
{items.map((item) => (
|
||||
<div key={item.id} className="flex gap-4 border border-border rounded-xl p-4" data-testid={`cart-row-${item.id}`}>
|
||||
{item.imageUrl && (
|
||||
<img src={item.imageUrl} alt={item.title} className="w-20 h-20 object-cover rounded-md border border-border flex-shrink-0" />
|
||||
)}
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href={`/products/${item.productHandle}`} className="font-medium hover:text-primary transition-colors line-clamp-2">
|
||||
{item.title}
|
||||
</Link>
|
||||
{item.variantTitle && item.variantTitle !== "Default Title" && (
|
||||
<p className="text-sm text-muted-foreground">{item.variantTitle}</p>
|
||||
)}
|
||||
<p className="text-sm font-semibold mt-1">${parseFloat(item.price).toFixed(2)}</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-3">
|
||||
<button onClick={() => removeItem(item.id)} className="text-muted-foreground hover:text-destructive transition-colors" data-testid={`remove-item-${item.id}`}>
|
||||
<Trash2 size={15} />
|
||||
</button>
|
||||
<div className="flex items-center border border-border rounded-md overflow-hidden">
|
||||
<button onClick={() => updateQuantity(item.id, item.quantity - 1)} className="px-3 py-1.5 text-sm hover:bg-muted transition-colors" data-testid={`decrease-${item.id}`}>−</button>
|
||||
<span className="px-3 py-1.5 text-sm border-x border-border min-w-[2.5rem] text-center" data-testid={`qty-${item.id}`}>{item.quantity}</span>
|
||||
<button onClick={() => updateQuantity(item.id, item.quantity + 1)} className="px-3 py-1.5 text-sm hover:bg-muted transition-colors" data-testid={`increase-${item.id}`}>+</button>
|
||||
</div>
|
||||
<span className="text-sm font-semibold">${(parseFloat(item.price) * item.quantity).toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="border border-border rounded-xl p-5 sticky top-24">
|
||||
<h2 className="font-semibold mb-4">Order summary</h2>
|
||||
<div className="space-y-2 mb-4 text-sm">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Subtotal</span>
|
||||
<span>${subtotal.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Shipping</span>
|
||||
<span className="text-muted-foreground">Calculated at checkout</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between font-semibold border-t border-border pt-4 mb-4">
|
||||
<span>Total</span>
|
||||
<span data-testid="cart-page-total">${subtotal.toFixed(2)}</span>
|
||||
</div>
|
||||
<Link href="/checkout" className="w-full bg-primary text-primary-foreground py-3 rounded-md font-semibold block text-center hover:bg-primary/90 transition-colors" data-testid="link-to-checkout">
|
||||
Proceed to checkout
|
||||
</Link>
|
||||
<Link href="/" className="w-full text-sm text-muted-foreground hover:text-foreground block text-center mt-3 transition-colors">
|
||||
← Continue shopping
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue