137 lines
6.2 KiB
TypeScript
137 lines
6.2 KiB
TypeScript
import { createFileRoute, useNavigate } from '@tanstack/react-router'
|
|
import { useGetCart, useUpdateCartItem, useRemoveFromCart } from '../hooks/cart-query-hooks'
|
|
import { useAllProducts } from '../hooks/prominent-api-hooks'
|
|
import { Quantifier } from 'web-components'
|
|
import { AppLayout } from '../components/AppLayout'
|
|
import { Trash2, ShoppingCart } from 'lucide-react'
|
|
|
|
export const Route = createFileRoute('/home/cart')({ component: CartPage })
|
|
|
|
function CartPage() {
|
|
const navigate = useNavigate()
|
|
const { data: cart } = useGetCart('regular')
|
|
const { data: productsData } = useAllProducts()
|
|
const updateItem = useUpdateCartItem('regular')
|
|
const removeItem = useRemoveFromCart('regular')
|
|
|
|
const products = productsData?.products || []
|
|
const productsById: Record<number, any> = {}
|
|
products.forEach((p: any) => { productsById[p.id] = p })
|
|
|
|
const cartItems = (cart?.items || []).filter((item) => productsById[item.productId])
|
|
|
|
let total = 0
|
|
cartItems.forEach((item) => {
|
|
const product = productsById[item.productId]
|
|
if (product) {
|
|
total += product.price * item.quantity
|
|
}
|
|
})
|
|
|
|
return (
|
|
<AppLayout>
|
|
<div className="mx-auto w-full max-w-7xl px-4 py-6 pb-24 md:px-8 md:pb-12">
|
|
<div className="mb-6">
|
|
<p className="text-[11px] font-black uppercase tracking-[0.22em] text-brand-600">
|
|
Review Before Delivery
|
|
</p>
|
|
<h1 className="display-2 mt-1 text-gray-900">Your Cart</h1>
|
|
</div>
|
|
|
|
{cartItems.length === 0 ? (
|
|
<div className="flex flex-col items-center gap-4 rounded-xl border border-dashed border-gray-300 bg-white py-24">
|
|
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-gray-50">
|
|
<ShoppingCart className="h-7 w-7 text-gray-400" />
|
|
</div>
|
|
<p className="font-bold text-gray-800">Your cart is empty</p>
|
|
<p className="text-sm text-gray-500">Fresh cuts are waiting at the counter</p>
|
|
<button
|
|
onClick={() => navigate({ to: '/home' })}
|
|
className="mt-2 rounded-lg bg-brand-600 px-6 py-2.5 text-sm font-bold text-white transition-colors hover:bg-brand-700"
|
|
>
|
|
Browse Products
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<div className="grid gap-8 lg:grid-cols-[minmax(0,1fr)_360px]">
|
|
{/* Items */}
|
|
<div className="flex flex-col gap-3">
|
|
{cartItems.map((item) => {
|
|
const product = productsById[item.productId]
|
|
const price = product.price
|
|
return (
|
|
<div
|
|
key={item.productId}
|
|
className="flex items-center gap-4 rounded-xl border border-gray-200 bg-white p-4"
|
|
>
|
|
<img
|
|
src={product.images?.[0]}
|
|
alt={product.name}
|
|
className="h-20 w-20 shrink-0 rounded-lg object-cover"
|
|
/>
|
|
<div className="min-w-0 flex-1">
|
|
<p className="text-sm font-bold text-gray-900">{product.name}</p>
|
|
<p className="mt-0.5 text-xs text-gray-500">
|
|
{product.productQuantity || 1}{product.unitNotation || ''} per unit
|
|
</p>
|
|
<div className="mt-2 flex items-center gap-3">
|
|
<Quantifier
|
|
value={item.quantity}
|
|
setValue={(q) => updateItem.mutate({ productId: item.productId, quantity: q })}
|
|
/>
|
|
<p className="text-sm font-bold text-gray-900">₹{price}</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-col items-end gap-2">
|
|
<p className="text-base font-extrabold text-brand-600">₹{price * item.quantity}</p>
|
|
<button
|
|
onClick={() => removeItem.mutate(item.productId)}
|
|
className="flex h-9 w-9 items-center justify-center rounded-lg text-gray-400 transition-colors hover:bg-red-50 hover:text-red-500"
|
|
aria-label={`Remove ${product.name}`}
|
|
>
|
|
<Trash2 className="h-4 w-4" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
|
|
{/* Summary */}
|
|
<div className="lg:sticky lg:top-24 lg:self-start">
|
|
<div className="rounded-xl border border-gray-200 bg-white p-6">
|
|
<p className="font-display text-lg font-extrabold text-gray-900">Bill Summary</p>
|
|
<div className="mt-4 space-y-2 border-b border-gray-100 pb-4">
|
|
<div className="flex items-center justify-between">
|
|
<p className="text-sm text-gray-600">Item Total</p>
|
|
<p className="text-sm font-bold text-gray-900">₹{total}</p>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<p className="text-sm text-gray-600">Delivery Fee</p>
|
|
<p className="text-sm font-semibold text-green-600">Calculated at checkout</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center justify-between py-4">
|
|
<p className="font-bold text-gray-900">Total</p>
|
|
<p className="font-display text-xl font-extrabold text-gray-900">₹{total}</p>
|
|
</div>
|
|
<button
|
|
onClick={() => navigate({ to: '/home/checkout' })}
|
|
className="w-full rounded-lg bg-brand-600 py-3.5 text-sm font-bold text-white transition-colors hover:bg-brand-700"
|
|
>
|
|
Proceed to Checkout
|
|
</button>
|
|
<button
|
|
onClick={() => navigate({ to: '/home' })}
|
|
className="mt-3 w-full rounded-lg border border-gray-200 py-3 text-sm font-bold text-gray-700 transition-colors hover:bg-gray-50"
|
|
>
|
|
Continue Shopping
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</AppLayout>
|
|
)
|
|
}
|