Add src/app/cart/page.tsx
This commit is contained in:
162
src/app/cart/page.tsx
Normal file
162
src/app/cart/page.tsx
Normal file
@@ -0,0 +1,162 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { ThemeProvider } from '@/components/theme-provider';
|
||||
import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen';
|
||||
import ButtonHoverBubble from '@/components/button/ButtonHoverBubble';
|
||||
import { Trash2, Plus, Minus } from 'lucide-react';
|
||||
|
||||
const navItems = [
|
||||
{ name: 'Home', id: '/' },
|
||||
{ name: 'Shop', id: '/shop' },
|
||||
{ name: 'Cart', id: '/cart' },
|
||||
{ name: 'Checkout', id: '/checkout' },
|
||||
];
|
||||
|
||||
interface CartItem {
|
||||
id: string;
|
||||
name: string;
|
||||
price: number;
|
||||
quantity: number;
|
||||
image: string;
|
||||
}
|
||||
|
||||
export default function CartPage() {
|
||||
const [cartItems, setCartItems] = useState<CartItem[]>([
|
||||
{ id: '1', name: 'Premium Headphones', price: 199.99, quantity: 1, image: '/product1.jpg' },
|
||||
{ id: '2', name: 'Wireless Mouse', price: 49.99, quantity: 2, image: '/product2.jpg' },
|
||||
]);
|
||||
|
||||
const updateQuantity = (id: string, newQuantity: number) => {
|
||||
if (newQuantity <= 0) {
|
||||
removeItem(id);
|
||||
return;
|
||||
}
|
||||
setCartItems(cartItems.map(item =>
|
||||
item.id === id ? { ...item, quantity: newQuantity } : item
|
||||
));
|
||||
};
|
||||
|
||||
const removeItem = (id: string) => {
|
||||
setCartItems(cartItems.filter(item => item.id !== id));
|
||||
};
|
||||
|
||||
const subtotal = cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0);
|
||||
const tax = subtotal * 0.1;
|
||||
const total = subtotal + tax;
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="hover-magnetic"
|
||||
defaultTextAnimation="entrance-slide"
|
||||
borderRadius="rounded"
|
||||
contentWidth="medium"
|
||||
sizing="medium"
|
||||
background="none"
|
||||
cardStyle="solid"
|
||||
primaryButtonStyle="gradient"
|
||||
secondaryButtonStyle="glass"
|
||||
headingFontWeight="bold"
|
||||
>
|
||||
<NavbarStyleFullscreen
|
||||
navItems={navItems}
|
||||
brandName="Shop"
|
||||
bottomLeftText="Global Community"
|
||||
bottomRightText="hello@example.com"
|
||||
/>
|
||||
<main className="w-full py-12">
|
||||
<div className="max-w-6xl mx-auto px-4">
|
||||
<h1 className="text-4xl font-bold mb-8">Shopping Cart</h1>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Cart Items */}
|
||||
<div className="lg:col-span-2">
|
||||
{cartItems.length === 0 ? (
|
||||
<div className="text-center py-12">
|
||||
<p className="text-lg text-gray-600 mb-4">Your cart is empty</p>
|
||||
<ButtonHoverBubble text="Continue Shopping" href="/shop" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{cartItems.map(item => (
|
||||
<div key={item.id} className="flex gap-4 border rounded-lg p-4">
|
||||
{/* Product Image */}
|
||||
<div className="w-24 h-24 bg-gray-200 rounded-lg flex-shrink-0"></div>
|
||||
|
||||
{/* Product Details */}
|
||||
<div className="flex-1">
|
||||
<h3 className="font-semibold text-lg mb-2">{item.name}</h3>
|
||||
<p className="text-gray-600 mb-4">${item.price.toFixed(2)}</p>
|
||||
|
||||
{/* Quantity Controls */}
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => updateQuantity(item.id, item.quantity - 1)}
|
||||
className="p-1 border rounded hover:bg-gray-100"
|
||||
aria-label="Decrease quantity"
|
||||
>
|
||||
<Minus size={16} />
|
||||
</button>
|
||||
<input
|
||||
type="number"
|
||||
value={item.quantity}
|
||||
onChange={(e) => updateQuantity(item.id, parseInt(e.target.value))}
|
||||
className="w-12 text-center border rounded px-2 py-1"
|
||||
min="1"
|
||||
/>
|
||||
<button
|
||||
onClick={() => updateQuantity(item.id, item.quantity + 1)}
|
||||
className="p-1 border rounded hover:bg-gray-100"
|
||||
aria-label="Increase quantity"
|
||||
>
|
||||
<Plus size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Price and Remove */}
|
||||
<div className="flex flex-col items-end justify-between">
|
||||
<p className="font-semibold">${(item.price * item.quantity).toFixed(2)}</p>
|
||||
<button
|
||||
onClick={() => removeItem(item.id)}
|
||||
className="text-red-600 hover:text-red-800"
|
||||
aria-label="Remove item"
|
||||
>
|
||||
<Trash2 size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Order Summary */}
|
||||
{cartItems.length > 0 && (
|
||||
<div className="lg:col-span-1">
|
||||
<div className="border rounded-lg p-6 sticky top-4">
|
||||
<h2 className="text-2xl font-bold mb-6">Order Summary</h2>
|
||||
<div className="space-y-3 mb-6">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">Subtotal</span>
|
||||
<span>${subtotal.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">Tax (10%)</span>
|
||||
<span>${tax.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="border-t pt-3 flex justify-between font-semibold text-lg">
|
||||
<span>Total</span>
|
||||
<span>${total.toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ButtonHoverBubble text="Proceed to Checkout" href="/checkout" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user