Files
tai-test-hotsauce/src/pages/Cart.tsx
T
2026-05-21 11:30:45 +01:00

178 lines
8.4 KiB
TypeScript

import { useState } from "react";
import { toast } from "sonner";
import { Link } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import { Minus, Plus, X, ShoppingBag, ArrowRight, ArrowLeft, Tag } from "lucide-react";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import { useCart } from "@/lib/cart-context";
export default function CartPage() {
const { items, removeItem, updateQuantity, total, itemCount, clearCart } = useCart();
const [coupon, setCoupon] = useState("");
const [couponApplied, setCouponApplied] = useState(false);
const shipping = total >= 100 ? 0 : 12.99;
const tax = total * 0.08;
const discount = couponApplied ? total * 0.1 : 0;
const grandTotal = total + shipping + tax - discount;
const applyCoupon = () => {
if (coupon.trim().length > 0) {
setCouponApplied(true);
toast.success("Coupon applied!");
}
};
if (items.length === 0) {
return (
<div className="min-h-screen bg-white text-stone-900 antialiased">
<Header />
<div className="flex flex-col items-center justify-center py-40 px-6">
<div className="h-20 w-20 rounded-full bg-stone-100 flex items-center justify-center mb-6">
<ShoppingBag className="h-10 w-10 text-stone-400" />
</div>
<h1 className="text-2xl font-bold mb-2">Your cart is empty</h1>
<p className="text-stone-500 mb-8">Looks like you haven't added anything to your cart yet.</p>
<Button asChild className="bg-stone-900 hover:bg-stone-800 rounded-full px-8">
<Link to="/products">Continue Shopping</Link>
</Button>
</div>
<Footer />
</div>
);
}
return (
<div className="min-h-screen bg-white text-stone-900 antialiased">
<Header />
<div className="mx-auto max-w-7xl px-6 pt-28 pb-20">
<h1 className="text-3xl font-bold tracking-tight mb-2 animate-fade-up">Shopping Cart</h1>
<p className="text-stone-500 mb-10">{itemCount} {itemCount === 1 ? "item" : "items"} in your cart</p>
<div className="grid lg:grid-cols-3 gap-10">
{/* Cart Items */}
<div className="lg:col-span-2 space-y-4">
{items.map((item) => (
<Card key={item.id + item.size + item.color} className="border-stone-100">
<CardContent className="p-4 sm:p-6">
<div className="flex gap-4">
<div className="h-24 w-20 sm:h-28 sm:w-24 rounded-lg bg-gradient-to-br from-rose-100 to-stone-200 flex items-center justify-center text-stone-400 text-xs shrink-0 relative overflow-hidden">
<div className="absolute inset-0" style={{ backgroundImage: "radial-gradient(circle, rgba(0,0,0,0.06) 1px, transparent 1px)", backgroundSize: "12px 12px" }} />
<div className="absolute top-1/4 -left-4 h-12 w-12 rounded-full bg-white/30 blur-xl" />
<span className="relative">Image</span>
</div>
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between">
<div>
<h3 className="font-semibold text-sm sm:text-base">{item.name}</h3>
<div className="flex items-center gap-2 mt-1">
{item.color && <Badge variant="secondary" className="text-xs">{item.color}</Badge>}
{item.size && <Badge variant="secondary" className="text-xs">Size: {item.size}</Badge>}
</div>
</div>
<button onClick={() => removeItem(item.id)} className="text-stone-400 hover:text-stone-600 transition-colors">
<X className="h-4 w-4" />
</button>
</div>
<div className="flex items-center justify-between mt-4">
<div className="flex items-center border rounded-full">
<Button variant="ghost" size="icon" className="h-8 w-8 rounded-full active:scale-90 transition-transform" onClick={() => updateQuantity(item.id, Math.max(1, item.quantity - 1))}>
<Minus className="h-3 w-3" />
</Button>
<span className="w-8 text-center text-sm font-medium">{item.quantity}</span>
<Button variant="ghost" size="icon" className="h-8 w-8 rounded-full active:scale-90 transition-transform" onClick={() => updateQuantity(item.id, item.quantity + 1)}>
<Plus className="h-3 w-3" />
</Button>
</div>
<span className="font-semibold">\${(item.price * item.quantity).toFixed(2)}</span>
</div>
</div>
</div>
</CardContent>
</Card>
))}
</div>
{/* Order Summary */}
<div>
<Card className="border-stone-200 sticky top-28 backdrop-blur-xl bg-white/80 dark:bg-slate-900/80 border-white/20">
<CardContent className="p-6">
<h2 className="text-lg font-bold mb-6">Order Summary</h2>
<div className="space-y-3 text-sm">
<div className="flex justify-between">
<span className="text-stone-500">Subtotal</span>
<span className="font-medium">\${total.toFixed(2)}</span>
</div>
<div className="flex justify-between">
<span className="text-stone-500">Shipping</span>
<span className={\`font-medium \${shipping === 0 ? "text-green-600" : ""}\`}>
{shipping === 0 ? "Free" : \`\$\${shipping.toFixed(2)}\`}
</span>
</div>
<div className="flex justify-between">
<span className="text-stone-500">Tax</span>
<span className="font-medium">\${tax.toFixed(2)}</span>
</div>
{couponApplied && (
<div className="flex justify-between text-green-600">
<span>Discount (10%)</span>
<span>-\${discount.toFixed(2)}</span>
</div>
)}
</div>
<Separator className="my-4" />
<div className="flex justify-between text-lg font-bold">
<span>Total</span>
<span>\${grandTotal.toFixed(2)}</span>
</div>
{/* Coupon */}
<div className="mt-6 flex gap-2">
<div className="relative flex-1">
<Tag className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-stone-400" />
<Input
placeholder="Coupon code"
value={coupon}
onChange={(e) => setCoupon(e.target.value)}
className="pl-9 rounded-full text-sm"
/>
</div>
<Button variant="outline" size="sm" className="rounded-full" onClick={applyCoupon}>
Apply
</Button>
</div>
{shipping > 0 && (
<p className="text-xs text-stone-400 mt-4 text-center">
Add \${(100 - total).toFixed(2)} more for free shipping
</p>
)}
<div className="mt-6 space-y-3">
<Button asChild size="lg" className="w-full bg-stone-900 hover:bg-stone-800 rounded-full active:scale-[0.98] transition-all">
<Link to="/checkout">Checkout <ArrowRight className="ml-2 h-4 w-4" /></Link>
</Button>
<Button asChild variant="outline" size="lg" className="w-full rounded-full active:scale-[0.98] transition-all">
<Link to="/products"><ArrowLeft className="mr-2 h-4 w-4" /> Continue Shopping</Link>
</Button>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
<Footer />
</div>
);
}