Files
Ghost_Kitchen/src/routes/index.tsx
T
lukasandClaude Sonnet 5 ea459e72b3 Add the customer ordering page
Builds the main customer-facing flow: browse the Brand's menu, add
items to a cart, and check out either as a guest (name + contact) or,
if signed in, as the account customer — both call the existing
placeOrder server function, which already distinguishes the two. On
success, navigates to a new /orders/$orderId status page showing each
Order Item's Preparation Steps, queue position, ETA, and (per the
domain rules already established) a Cancel button while cancellable
and a pickup-confirmation button once ready.

Styled with SCSS Modules per CLAUDE.md; added the sass dependency and
the src/styles/ structure it describes (globals.scss imported once in
__root.tsx, alongside the existing Tailwind stylesheet the not-yet-
mounted header-user.tsx component depends on).

Verified end-to-end against a throwaway local Postgres: menu renders
with seeded items, cart quantities update, guest checkout places a
real order, and the status page reflects a real cancellation.

Also fixes CLAUDE.md's Commands section, which documented pnpm even
though this repo only has npm (package-lock.json, no pnpm installed).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 20:31:32 +02:00

79 lines
2.3 KiB
TypeScript

import { createFileRoute, useNavigate } from '@tanstack/react-router'
import { useState } from 'react'
import { CheckoutSection } from '#/components/ordering/CheckoutSection.tsx'
import { MenuList } from '#/components/ordering/MenuList.tsx'
import { OrderSummary } from '#/components/ordering/OrderSummary.tsx'
import { getBrand } from '#/server/brand.ts'
import { getMenu } from '#/server/menu.ts'
import styles from './index.module.scss'
export const Route = createFileRoute('/')({
loader: async () => {
const brand = await getBrand()
const menu = await getMenu({ data: { brandId: brand.id } })
return { brand, menu }
},
component: OrderingPage,
})
function OrderingPage() {
const { brand, menu } = Route.useLoaderData()
const navigate = useNavigate()
const [quantities, setQuantities] = useState<Record<number, number>>({})
const add = (menuItemId: number) =>
setQuantities((prev) => ({
...prev,
[menuItemId]: (prev[menuItemId] ?? 0) + 1,
}))
const remove = (menuItemId: number) =>
setQuantities((prev) => {
const current = prev[menuItemId] ?? 0
if (current <= 1) {
const next = { ...prev }
delete next[menuItemId]
return next
}
return { ...prev, [menuItemId]: current - 1 }
})
const items = Object.entries(quantities).flatMap(([menuItemId, quantity]) =>
Array.from({ length: quantity }, () => ({
menuItemId: Number(menuItemId),
})),
)
return (
<main className={styles.page}>
<h1 className={styles.heading}>{brand.name}</h1>
<div className={styles.layout}>
<MenuList
menu={menu}
quantities={quantities}
onAdd={add}
onRemove={remove}
/>
<aside className={styles.sidebar}>
<OrderSummary menu={menu} quantities={quantities} />
<CheckoutSection
items={items}
disabled={items.length === 0}
onPlaced={(order) =>
navigate({
to: '/orders/$orderId',
params: { orderId: String(order.id) },
search: order.guestAccessToken
? { token: order.guestAccessToken }
: {},
})
}
/>
</aside>
</div>
</main>
)
}