Skip to content
Snippets Groups Projects
Commit 102807de authored by ALMAZROUEI Shamma (2021) WKIS203's avatar ALMAZROUEI Shamma (2021) WKIS203
Browse files

Build the cart page

parent 1051751e
Branches
No related tags found
No related merge requests found
...@@ -16,6 +16,7 @@ import Register from './pages/Register'; ...@@ -16,6 +16,7 @@ import Register from './pages/Register';
import Menu from './pages/Menu'; import Menu from './pages/Menu';
import MenuItem from './pages/MenuItem'; import MenuItem from './pages/MenuItem';
import ErrorPage from './pages/Error'; import ErrorPage from './pages/Error';
import Cart from './pages/Cart';
const router = createBrowserRouter([ const router = createBrowserRouter([
{ {
...@@ -43,6 +44,10 @@ const router = createBrowserRouter([ ...@@ -43,6 +44,10 @@ const router = createBrowserRouter([
path: '/register', path: '/register',
element: <Register />, element: <Register />,
}, },
{
path: '/cart',
element: <Cart />,
},
{ {
path: '/menu', path: '/menu',
element: <Menu />, element: <Menu />,
......
...@@ -66,7 +66,7 @@ export default function About() { ...@@ -66,7 +66,7 @@ export default function About() {
Get in Touch <ArrowRight className='ml-2 h-4 w-4' /> Get in Touch <ArrowRight className='ml-2 h-4 w-4' />
</Button> </Button>
</div> </div>
<div className='relative h-[300px] md:h-[400px] rounded-2xl overflow-hidden shadow-xl order-1 md:order-2'> <div className='relative h-[300px] md:h-[400px] rounded-2xl overflow-hidden shadow-md order-1 md:order-2'>
<img <img
src='https://images.unsplash.com/photo-1572054466274-25b4ed6d6899?q=80&w=2940&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D' src='https://images.unsplash.com/photo-1572054466274-25b4ed6d6899?q=80&w=2940&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'
alt='Our bakery team' alt='Our bakery team'
......
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { toast } from 'sonner';
import { Minus, Plus, ShoppingCart, Trash2 } from 'lucide-react';
import { useCartStore } from '@/lib/store';
import { useAuthStore } from '@/lib/authStore';
import { Button } from '@/components/ui/button';
export default function Cart() {
const navigate = useNavigate();
const { cart, removeFromCart, updateQuantity, clearCart, initializeCart } =
useCartStore();
const { isAuthenticated } = useAuthStore();
useEffect(() => {
initializeCart();
// Redirect to login if not authenticated
if (!isAuthenticated) {
toast.error('Authentication required!', {
description: 'Please sign in to view your cart.',
});
navigate('/login');
}
}, [initializeCart, isAuthenticated, navigate]);
// If not authenticated, don't render the cart content
if (!isAuthenticated) {
return null;
}
const totalItems = cart.reduce((total, item) => total + item.quantity, 0);
const subtotal = cart.reduce(
(total, item) => total + item.price * item.quantity,
0
);
const tax = subtotal * 0.08; // 8% tax
const total = subtotal + tax;
const handleQuantityChange = (id, newQuantity) => {
if (newQuantity < 1) return;
updateQuantity(id, newQuantity);
};
const handleRemoveItem = (id, name) => {
removeFromCart(id);
toast.success('Item removed', {
description: `${name} has been removed from your cart.`,
});
};
const handleCheckout = () => {
if (cart.length === 0) {
toast.error('Cart is empty!', {
description: 'Please add items to your cart before checking out.',
});
return;
}
navigate('/checkout');
};
return (
<div className='container mx-auto px-4 py-8 md:py-12'>
<div className='text-center mb-8'>
<h1 className='text-4xl font-bold text-gray-800 mb-4'>
Your Shopping Cart
</h1>
<p className='text-gray-600'>
{totalItems > 0
? `You have ${totalItems} item${
totalItems !== 1 ? 's' : ''
} in your cart`
: 'Your cart is empty'}
</p>
</div>
{cart.length > 0 ? (
<div className='grid grid-cols-1 lg:grid-cols-3 gap-8'>
<div className='lg:col-span-2'>
<div className='bg-white rounded-xl shadow-sm border overflow-hidden'>
<div className='p-6'>
<div className='flow-root'>
<ul className='divide-y divide-gray-200'>
{cart.map((item) => (
<li key={item.id} className='py-6 flex'>
<div className='relative h-24 w-24 rounded-md overflow-hidden'>
<img
src={item.image}
alt={item.name}
className='object-cover h-full w-full'
/>
</div>
<div className='ml-4 flex-1 flex flex-col'>
<div>
<div className='flex justify-between text-base font-medium text-gray-900'>
<h3>{item.name}</h3>
<p className='ml-4'>
${(item.price * item.quantity).toFixed(2)}
</p>
</div>
<p className='mt-1 text-sm text-gray-500 line-clamp-2'>
{item.description}
</p>
</div>
<div className='flex-1 flex items-end justify-between text-sm'>
<div className='flex items-center space-x-2'>
<Button
variant='outline'
size='icon'
className='h-8 w-8 rounded-full'
onClick={() =>
handleQuantityChange(
item.id,
item.quantity - 1
)
}
>
<Minus className='h-4 w-4' />
</Button>
<span className='text-gray-700 w-8 text-center'>
{item.quantity}
</span>
<Button
variant='outline'
size='icon'
className='h-8 w-8 rounded-full'
onClick={() =>
handleQuantityChange(
item.id,
item.quantity + 1
)
}
>
<Plus className='h-4 w-4' />
</Button>
</div>
<Button
variant='ghost'
className='text-red-500 hover:text-red-700 hover:bg-red-50'
onClick={() =>
handleRemoveItem(item.id, item.name)
}
>
<Trash2 className='h-5 w-5' />
</Button>
</div>
</div>
</li>
))}
</ul>
</div>
</div>
</div>
</div>
<div className='lg:col-span-1'>
<div className='bg-white rounded-xl shadow-sm border overflow-hidden'>
<div className='p-6'>
<h2 className='text-lg font-semibold text-gray-900 mb-4'>
Order Summary
</h2>
<div className='flow-root'>
<div className='border-t border-gray-200 pt-4'>
<div className='flex justify-between py-2'>
<dt className='text-sm text-gray-600'>Subtotal</dt>
<dd className='text-sm font-medium text-gray-900'>
${subtotal.toFixed(2)}
</dd>
</div>
<div className='flex justify-between py-2'>
<dt className='text-sm text-gray-600'>Tax (8%)</dt>
<dd className='text-sm font-medium text-gray-900'>
${tax.toFixed(2)}
</dd>
</div>
<div className='flex justify-between py-2 border-t border-gray-200'>
<dt className='text-base font-medium text-gray-900'>
Total
</dt>
<dd className='text-base font-medium text-pink-600'>
${total.toFixed(2)}
</dd>
</div>
</div>
</div>
<div className='mt-6'>
<Button
onClick={handleCheckout}
className='w-full bg-pink-500 hover:bg-pink-600 text-white rounded-full py-6'
>
Proceed to Checkout
</Button>
<Button
variant='outline'
onClick={() => navigate('/menu')}
className='w-full mt-4 border-pink-300 text-pink-600 hover:bg-pink-50 rounded-full'
>
Continue Shopping
</Button>
{cart.length > 0 && (
<Button
variant='ghost'
onClick={() => {
clearCart();
toast.success('Cart cleared!', {
description:
'All items have been removed from your cart.',
});
}}
className='w-full mt-2 text-gray-500 hover:text-gray-700 hover:bg-gray-50 rounded-full'
>
Clear Cart
</Button>
)}
</div>
</div>
</div>
</div>
</div>
) : (
<div className='text-center py-12'>
<div className='mx-auto w-24 h-24 bg-pink-100 rounded-full flex items-center justify-center mb-6'>
<ShoppingCart className='h-12 w-12 text-pink-500' />
</div>
<h2 className='text-2xl font-semibold text-gray-800 mb-4'>
Your cart is empty
</h2>
<p className='text-gray-600 mb-8'>
Looks like you haven't added any cakes to your cart yet.
</p>
<Button
onClick={() => navigate('/menu')}
className='bg-pink-500 hover:bg-pink-600 text-white rounded-full px-8 py-6 text-lg'
>
Browse Our Menu
</Button>
</div>
)}
</div>
);
}
...@@ -95,7 +95,7 @@ export default function Landing() { ...@@ -95,7 +95,7 @@ export default function Landing() {
</Button> </Button>
</div> </div>
</div> </div>
<div className='relative h-[300px] md:h-[400px] rounded-2xl overflow-hidden shadow-xl'> <div className='relative h-[300px] md:h-[400px] rounded-2xl overflow-hidden'>
<img <img
src='https://images.pexels.com/photos/2536967/pexels-photo-2536967.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2' src='https://images.pexels.com/photos/2536967/pexels-photo-2536967.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
alt='Delicious cake showcase' alt='Delicious cake showcase'
......
...@@ -92,7 +92,7 @@ export default function MenuItem() { ...@@ -92,7 +92,7 @@ export default function MenuItem() {
</Button> </Button>
<div className='grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-16 mb-12'> <div className='grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-16 mb-12'>
<div className='relative h-[300px] md:h-[500px] rounded-2xl overflow-hidden shadow-xl'> <div className='relative h-[300px] md:h-[500px] rounded-2xl overflow-hidden'>
<img <img
src={cake.image} src={cake.image}
alt={cake.name} alt={cake.name}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment