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>
This commit is contained in:
2026-09-09 20:31:32 +02:00
co-authored by Claude Sonnet 5
parent b7fdbd4779
commit ea459e72b3
19 changed files with 1118 additions and 24 deletions
@@ -0,0 +1,91 @@
@use '../../styles/variables' as *;
.page {
max-width: 720px;
margin: 0 auto;
padding: $space-5 $space-3;
}
.heading {
margin: 0 0 $space-1;
}
.orderStatus {
margin: 0 0 $space-4;
color: $color-text-muted;
text-transform: capitalize;
}
.error {
color: $color-danger;
}
.items {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: $space-3;
}
.item {
padding: $space-3;
border: 1px solid $color-border;
border-radius: $radius;
background: $color-surface;
}
.itemHeader {
display: flex;
justify-content: space-between;
font-weight: 600;
margin-bottom: $space-2;
}
.itemStatus {
text-transform: capitalize;
color: $color-text-muted;
}
.steps {
margin: 0 0 $space-2;
padding-left: $space-4;
font-size: 0.85rem;
color: $color-text-muted;
}
.step {
&[data-status='done'] {
text-decoration: line-through;
}
&[data-status='in_progress'] {
color: $color-primary;
font-weight: 600;
}
}
.eta {
margin: 0 0 $space-2;
font-size: 0.9rem;
color: $color-success;
}
.actions {
display: flex;
gap: $space-2;
button {
padding: $space-1 $space-3;
border: 1px solid $color-border;
border-radius: $radius;
background: $color-background;
cursor: pointer;
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
}