feat(restaurant): customer-friendly order status labels
Order status came through to the customer as raw operational
strings — 'paid', 'accepted', 'ready'. These are fine for the
operator's KDS but unfriendly for the customer waiting on their
food.
types/restaurant.ts:
+ FRIENDLY_ORDER_STATUS map (status → label)
pending → 'Awaiting payment'
paid → 'Order received'
accepted → 'Cooking'
ready → 'Ready for pickup'
completed → 'Served'
canceled → 'Canceled'
refunded → 'Refunded'
+ friendlyOrderStatus(status) helper. Unknown statuses (future
kitchen-workflow values from aiolabs/restaurant#4 — e.g.
'preparing', 'plating', 'in_service') fall through to a
titlecased version of the raw key so the build stays green
and the surface stays readable.
views/OrderStatusPage.vue:
- Status Badge uses friendlyOrderStatus().
- Alert sections now have one per status with appropriate copy:
paid → 'Order received / Payment confirmed — the
kitchen will start preparing it shortly.'
accepted → 'Cooking / Your food is being made.'
ready → 'Ready for pickup / Pick up at the counter.'
completed → 'Served / Enjoy! Thanks for ordering.'
views/CheckoutPage.vue: Phase 2 status badge uses
friendlyOrderStatus() so the checkout's live per-restaurant
status pill matches the language on the order page.
Deeper kitchen workflow (prep stations, courses, ETA, per-station
status) stays on aiolabs/restaurant#4 — this commit is the cheap
win that ships with the existing data model unchanged.
This commit is contained in:
parent
1d815652c4
commit
15545c9b5e
3 changed files with 57 additions and 6 deletions
|
|
@ -233,6 +233,34 @@ export const KNOWN_ORDER_STATUSES = [
|
|||
export type KnownOrderStatus = (typeof KNOWN_ORDER_STATUSES)[number]
|
||||
export type OrderStatus = string
|
||||
|
||||
/**
|
||||
* Customer-facing labels for order statuses. The extension's raw
|
||||
* status names are operational ('paid' / 'accepted' / 'ready') but
|
||||
* customers prefer human-friendly framing ('Order received' /
|
||||
* 'Cooking' / 'Ready for pickup').
|
||||
*
|
||||
* Future statuses from aiolabs/restaurant#4 (kitchen workflow) —
|
||||
* 'preparing', 'plating', 'at_pass', 'in_service', etc — can land
|
||||
* here as they arrive. Unknown values fall through to the raw
|
||||
* status string titlecased.
|
||||
*/
|
||||
export const FRIENDLY_ORDER_STATUS: Record<string, string> = {
|
||||
pending: 'Awaiting payment',
|
||||
paid: 'Order received',
|
||||
accepted: 'Cooking',
|
||||
ready: 'Ready for pickup',
|
||||
completed: 'Served',
|
||||
canceled: 'Canceled',
|
||||
refunded: 'Refunded',
|
||||
}
|
||||
|
||||
export function friendlyOrderStatus(status: OrderStatus): string {
|
||||
if (status in FRIENDLY_ORDER_STATUS) return FRIENDLY_ORDER_STATUS[status]
|
||||
// Unknown status — titlecase the raw key as a graceful fallback.
|
||||
if (!status) return ''
|
||||
return status.charAt(0).toUpperCase() + status.slice(1).replace(/_/g, ' ')
|
||||
}
|
||||
|
||||
export interface Order {
|
||||
id: string
|
||||
restaurant_id: string
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import { Separator } from '@/components/ui/separator'
|
|||
import OrderInvoiceCard from '../components/OrderInvoiceCard.vue'
|
||||
import { useCartStore } from '../stores/cart'
|
||||
import { useCheckout, type PlacedOrder } from '../composables/useCheckout'
|
||||
import { friendlyOrderStatus } from '../types/restaurant'
|
||||
import {
|
||||
injectService,
|
||||
tryInjectService,
|
||||
|
|
@ -383,7 +384,7 @@ function buildOrderInvoice(p: PlacedOrder) {
|
|||
:variant="isPaid(placed.order.id) ? 'default' : 'outline'"
|
||||
class="text-xs"
|
||||
>
|
||||
{{ statusOf(placed.order.id) }}
|
||||
{{ friendlyOrderStatus(statusOf(placed.order.id)) }}
|
||||
</Badge>
|
||||
</div>
|
||||
<OrderInvoiceCard
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import OrderInvoiceCard from '../components/OrderInvoiceCard.vue'
|
|||
import { useOrder } from '../composables/useOrder'
|
||||
import {
|
||||
KNOWN_ORDER_STATUSES,
|
||||
friendlyOrderStatus,
|
||||
type OrderInvoice,
|
||||
} from '../types/restaurant'
|
||||
|
||||
|
|
@ -150,7 +151,7 @@ const timeline = computed(() => {
|
|||
</p>
|
||||
</div>
|
||||
<Badge :variant="statusStyle" class="text-sm">
|
||||
{{ order.status }}
|
||||
{{ friendlyOrderStatus(order.status) }}
|
||||
</Badge>
|
||||
</header>
|
||||
|
||||
|
|
@ -161,13 +162,25 @@ const timeline = computed(() => {
|
|||
/>
|
||||
|
||||
<Alert
|
||||
v-else-if="['paid', 'accepted'].includes(order.status)"
|
||||
v-else-if="order.status === 'paid'"
|
||||
class="mb-4 border-emerald-500/40"
|
||||
>
|
||||
<CheckCircle2 class="h-4 w-4 text-emerald-500" />
|
||||
<AlertTitle>Payment received</AlertTitle>
|
||||
<AlertTitle>Order received</AlertTitle>
|
||||
<AlertDescription>
|
||||
The kitchen is on it.
|
||||
Payment confirmed — the kitchen will start preparing it
|
||||
shortly.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Alert
|
||||
v-else-if="order.status === 'accepted'"
|
||||
class="mb-4 border-emerald-500/40"
|
||||
>
|
||||
<CheckCircle2 class="h-4 w-4 text-emerald-500" />
|
||||
<AlertTitle>Cooking</AlertTitle>
|
||||
<AlertDescription>
|
||||
Your food is being made.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
|
|
@ -176,12 +189,21 @@ const timeline = computed(() => {
|
|||
class="mb-4 border-amber-500/40"
|
||||
>
|
||||
<Clock class="h-4 w-4 text-amber-500" />
|
||||
<AlertTitle>Ready</AlertTitle>
|
||||
<AlertTitle>Ready for pickup</AlertTitle>
|
||||
<AlertDescription>
|
||||
Pick up at the counter.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Alert
|
||||
v-else-if="order.status === 'completed'"
|
||||
class="mb-4 border-emerald-500/40"
|
||||
>
|
||||
<CheckCircle2 class="h-4 w-4 text-emerald-500" />
|
||||
<AlertTitle>Served</AlertTitle>
|
||||
<AlertDescription>Enjoy! Thanks for ordering.</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Card class="mb-4">
|
||||
<CardHeader>
|
||||
<CardTitle class="text-base">Items</CardTitle>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue