freshyo/apps/web-ui/src/routes/home.cart.tsx
2026-08-18 23:12:55 +05:30

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>
)
}