138 lines
4.9 KiB
TypeScript
138 lines
4.9 KiB
TypeScript
import { createFileRoute, useNavigate } from '@tanstack/react-router'
|
|
import { useState } from 'react'
|
|
import { useAuth } from '../lib/auth-context'
|
|
import { useGetCart } from '../hooks/cart-query-hooks'
|
|
import { useAllProducts } from '../hooks/prominent-api-hooks'
|
|
import { ProtectedRoute } from '../components/ProtectedRoute'
|
|
import { CheckoutAddressSelector } from '../components/CheckoutAddressSelector'
|
|
import { PaymentAndOrderComponent } from '../components/PaymentAndOrderComponent'
|
|
import { AddressForm } from '../components/AddressForm'
|
|
import { Dialog } from '../components/Dialog'
|
|
import { useAddressStore } from '../lib/stores/address-store'
|
|
import { useQueryClient } from '@tanstack/react-query'
|
|
import { ShoppingCart, ChevronLeft, MapPin } from 'lucide-react'
|
|
|
|
export const Route = createFileRoute('/checkout')({ component: CheckoutPage })
|
|
|
|
function CheckoutPage() {
|
|
return (
|
|
<ProtectedRoute>
|
|
<CheckoutContent />
|
|
</ProtectedRoute>
|
|
)
|
|
}
|
|
|
|
function CheckoutContent() {
|
|
const navigate = useNavigate()
|
|
const queryClient = useQueryClient()
|
|
const { isAuthenticated } = useAuth()
|
|
const { selectedAddressId, setSelectedAddressId } = useAddressStore()
|
|
const [showAddAddress, setShowAddAddress] = useState(false)
|
|
const [editingAddress, setEditingAddress] = useState<any>(null)
|
|
|
|
const cartType: 'regular' | 'flash' = 'regular'
|
|
const { data: cartData } = useGetCart(cartType)
|
|
const { data: productsData } = useAllProducts()
|
|
|
|
const products = productsData?.products || []
|
|
const productsById: Record<number, any> = {}
|
|
products.forEach((p: any) => { productsById[p.id] = p })
|
|
|
|
const cartItems = (cartData?.items || []).filter((item) => productsById[item.productId])
|
|
|
|
// Handle empty cart case
|
|
if (cartItems.length === 0) {
|
|
return (
|
|
<div className="flex min-h-screen flex-col items-center justify-center bg-gray-50 p-6">
|
|
<div className="flex h-20 w-20 items-center justify-center rounded-2xl bg-white">
|
|
<ShoppingCart className="h-9 w-9 text-gray-400" />
|
|
</div>
|
|
<p className="mt-6 text-xl font-bold text-gray-900">
|
|
Your cart is empty
|
|
</p>
|
|
<p className="mb-6 mt-1 text-gray-500">
|
|
Add some delicious items to your cart before checking out
|
|
</p>
|
|
<button
|
|
onClick={() => navigate({ to: '/home' })}
|
|
className="rounded-lg bg-brand-600 px-6 py-3 text-sm font-bold text-white transition-colors hover:bg-brand-700"
|
|
>
|
|
Back to Shopping
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50">
|
|
{/* Checkout Header */}
|
|
<div className="sticky top-0 z-20 border-b border-gray-200 bg-white">
|
|
<div className="mx-auto flex h-16 w-full max-w-7xl items-center gap-3 px-4 md:px-8">
|
|
<button
|
|
onClick={() => navigate({ to: '/cart' })}
|
|
className="flex h-9 w-9 items-center justify-center rounded-lg text-gray-600 transition-colors hover:bg-gray-50"
|
|
aria-label="Back to cart"
|
|
>
|
|
<ChevronLeft className="h-5 w-5" />
|
|
</button>
|
|
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-brand-25">
|
|
<MapPin className="h-4 w-4 text-brand-600" />
|
|
</div>
|
|
<p className="font-display text-lg font-extrabold text-gray-900">
|
|
Checkout
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mx-auto grid w-full max-w-7xl gap-8 px-4 py-6 md:px-8 lg:grid-cols-[minmax(0,1fr)_420px]">
|
|
{/* Left: Address Selection + Payment */}
|
|
<div>
|
|
<CheckoutAddressSelector
|
|
onAddressSelect={setSelectedAddressId}
|
|
onAddAddress={() => {
|
|
setEditingAddress(null)
|
|
setShowAddAddress(true)
|
|
}}
|
|
onEditAddress={(address) => {
|
|
setEditingAddress(address)
|
|
setShowAddAddress(true)
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
{/* Right: Order summary + payment */}
|
|
<div className="lg:sticky lg:top-24 lg:self-start">
|
|
<PaymentAndOrderComponent
|
|
selectedAddress={selectedAddressId}
|
|
cartItems={cartItems}
|
|
isFlashDelivery={false}
|
|
onBack={() => navigate({ to: '/cart' })}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Add/Edit Address Dialog */}
|
|
<Dialog
|
|
open={showAddAddress}
|
|
onClose={() => {
|
|
setShowAddAddress(false)
|
|
setEditingAddress(null)
|
|
}}
|
|
title={editingAddress ? 'Edit Address' : 'Add Address'}
|
|
>
|
|
<AddressForm
|
|
onSuccess={(addressId) => {
|
|
setShowAddAddress(false)
|
|
setEditingAddress(null)
|
|
if (addressId) {
|
|
setSelectedAddressId(addressId)
|
|
}
|
|
queryClient.invalidateQueries({ queryKey: ['user.address.getUserAddresses'] })
|
|
}}
|
|
initialValues={editingAddress || undefined}
|
|
isEdit={!!editingAddress}
|
|
/>
|
|
</Dialog>
|
|
</div>
|
|
)
|
|
}
|