• JohniO34's avatar
    Add takeaway ordering and full menu/coupon CRUD in admin · 67d34ab1
    JohniO34 authored
    Two gaps: the menu only offered an outbound "Order on Toast" link, and
    the dashboard could only read. Both sides are now dynamic.
    
    Ordering
    - The 281-item menu board now comes from the database (new menu_sections
      and menu_products tables) instead of a static file, so anything edited
      in admin shows up on the public menu.
    - Basket (React Context + localStorage), keyed by product + size so a
      large and a small of the same pizza are separate lines. Header button
      carries a live count.
    - Checkout collects name, phone, address, delivery-vs-pickup and
      payment, with "rather just call?" kept as an option throughout.
    - Card payment is SIMULATED: no provider is connected, only the last
      four digits and a fake authorisation reference are stored, and the
      form says so. A test asserts the full number never reaches the row.
    - Delivery fee follows the advertised rule (free over $6).
    - Range-priced items can't be ordered online — there's no single price
      to charge — so they stay phone-only rather than the server guessing.
    
    Admin
    - Tabs: Overview, Takeaway orders, Catering bookings, Menu, Coupons.
    - Full CRUD over all 281 menu products and over the coupons, with
      server-side validation on both.
    - Deleting a product that has already been ordered archives it instead:
      gone from the menu, still attached to past orders, still counted in
      revenue. Hard delete only for items never sold.
    - Takeaway orders get their own table with line items, address, payment
      state and a kitchen workflow (new -> cooking -> out -> done).
    - Overview now splits takeaway from catering, including cash vs card.
    
    Orders are priced server-side here too: the browser sends only
    {productId, sizeLabel, qty}.
    
    Fixed a real bug found while testing: the basket and dish modal stayed
    mounted after navigating to another route, so three dialogs could be
    open at once. They now close on a route change, adjusted during render
    rather than in an effect so it lands in the same commit as the route.
    
    23 new tests (123 total). `npm run seed:demo` now also loads takeaway
    orders so both halves of the dashboard have data to show.
    67d34ab1