Add an admin panel: orders dashboard, menu management, kitchen status
Introduces a role-gated /admin section (sidebar layout, requireAdmin checked both in route loaders and independently in every admin server function) with three sections: - Orders: every order across all customers, and an admin-only order detail view nested under /admin so the sidebar persists and admin access bypasses the guest-token check. - Menu: create/edit/delete menu items, their options, and their preparation steps; deleting an item with past orders is refused (protected by the orderItems FK) instead of crashing. - Kitchen: read-only live view of every machine's busy/idle status and per-tag queue depth, with a manual refresh. Also: - Adds a `role` field to the user table (Better Auth additionalFields, input:false so it can't be self-assigned) and a db:seed-admin script to create/promote an admin account. - Fixes a real bug found while building this: src/server/auth.ts's shared session helpers were plain exported functions using a server-only import, which the framework couldn't tree-shake out of the client bundle once shared across multiple server/*.ts modules — this silently broke hydration app-wide. Fixed with createServerOnlyFn. - Removes the now-fully-unused @tanstack/devtools-vite plugin. - Disables view transitions for in-admin navigation so the persistent sidebar doesn't cross-fade/shift on every click. - Gives the "your orders" empty state the same visual treatment as the basket page's. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,22 @@ type OrdersListViewProps = {
|
||||
orders: Array<CustomerOrderSummary>
|
||||
}
|
||||
|
||||
const OrdersIcon = () => (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M9 3h6l1 3H8l1-3Z" />
|
||||
<path d="M4 6h16l-1.2 13.2A2 2 0 0 1 16.81 21H7.19a2 2 0 0 1-2-1.8L4 6Z" />
|
||||
<path d="M9 11h6" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
const formatItems = (items: CustomerOrderSummary['items']) =>
|
||||
items
|
||||
.map(({ menuItemName, quantity }) =>
|
||||
@@ -20,10 +36,16 @@ export const OrdersListView = ({ orders }: OrdersListViewProps) => (
|
||||
<section className={styles.page}>
|
||||
<h1 className={styles.heading}>Your orders</h1>
|
||||
{orders.length === 0 ? (
|
||||
<p className={styles.empty}>
|
||||
You haven't placed an order yet — <Link to="/">browse the menu</Link>{' '}
|
||||
to get started.
|
||||
</p>
|
||||
<div className={styles.empty}>
|
||||
<OrdersIcon />
|
||||
<p className={styles.emptyTitle}>No orders yet</p>
|
||||
<p className={styles.emptyText}>
|
||||
Your placed orders will show up here.
|
||||
</p>
|
||||
<Link to="/" className={styles.emptyCta}>
|
||||
Browse the menu
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<ul className={styles.orders}>
|
||||
{orders.map((order) => (
|
||||
|
||||
Reference in New Issue
Block a user