5 Commits

Author SHA1 Message Date
a6f759bf49 fix(menu-app): 6 UI adjustments
1. Font consistency: add Noto Sans as fallback for both display and body
   fonts so Greek characters render in the same visual weight as Latin
2. Category panel gradients: reduce top opacity 0.85 → 0.65 (20% less)
3. Mobile full-width: remove max-w cap on mobile; sm:max-w-[960px] on
   desktop (2× wider than before); shadow only on sm+ breakpoint
4. Smaller Add button (h-9→h-8, text-13→12) and price (22px→18px)
5. More spacing between description and footer hairline (pt-3 mt-3)
6. Square hero image in product detail sheet (aspect-square instead of h-44)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 16:23:40 +03:00
ffaeab136d feat(menu-app): full redesign to Olive & Thyme design spec
Rebuild the public-facing digital menu from the design handoff bundle.
Matches high-fidelity spec: Bricolage Grotesque + Hanken Grotesk fonts,
cream/green/gold palette, per-category tinted panels, product cards with
gradient art, tag icon badges, bottom-sheet product detail, search overlay,
cart → checkout bottom-sheet flow posting to real API, floating cart button
with bump animation, and restyled order-confirm page.

- New: src/components/primitives.jsx (DishArt, Badge, DietChip, TagIcons,
  Price, DiscountFlag, Stepper, price helpers)
- Rewrite: MenuPage.jsx — all screens in one component tree, API-driven,
  lang toggle (EN/GR) persisted to localStorage, scroll-spy category bar
- Rewrite: OrderConfirm.jsx — design-system styling, brand colors
- Update: App.jsx — remove /order route (cart flow is now a bottom sheet)
- Update: tailwind.config.js — font families, brand tokens, animations
- Update: index.html — Google Fonts for Bricolage Grotesque + Hanken Grotesk
- Delete: CartPage, ProductModal, ProductCard, CategoryNav, CartButton

Cart checkout POSTs to real submitOrder API and redirects to /confirm/:ref
for live order status polling. Restaurant info falls back to hardcoded
placeholder until backend includes it in the fetchMenu response (see
REWORK_REVISIT.md).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 15:55:52 +03:00
70c7b9564b feat(manager-app): Part 5 — show snapshot_taken_at freshness in DashboardPage
Adds a "Site data: X min ago" line derived from snapshot.snapshot_taken_at
so managers can see how fresh the stats snapshot is.

All other Part 5 items (menu-app api.js, OrderConfirm polling, manager-app
api.js, IncomingOrdersPage 15s poll + OrderCard actions) were already fully
implemented in the existing scaffolding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 10:10:08 +03:00
b45a93a559 feat(connect): Phase 7 — Docker & nginx for connect_frontend
connect_frontend/Dockerfile
  Multi-stage build: node:20-alpine builds both menu-app and
  manager-app in parallel stages, then nginx:alpine serves both
  dist folders under /menu and /manage respectively.
  VITE_CLOUD_URL passed as build arg so the API URL is baked
  in at build time (standard Vite pattern).

connect_frontend/nginx-connect.conf
  Single nginx server block:
    /menu/   → /usr/share/nginx/html/menu  (SPA fallback)
    /manage/ → /usr/share/nginx/html/manage (SPA fallback)
    /health  → 200 ok

nginx-connect.conf
  Kept at cloud-service root for reference / standalone use.

docker-compose.yml
  connect_frontend service added:
    - build context: ./connect_frontend
    - VITE_CLOUD_URL passed from root .env
    - port 3100:80
    - depends_on cloud_backend

Individual Dockerfiles also added to menu-app/ and manager-app/
for standalone builds if needed.

To deploy:
  docker compose build connect_frontend
  docker compose up -d connect_frontend

  Public menu:    http://<host>:3100/menu/<site_slug>
  Manager app:    http://<host>:3100/manage/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 01:00:56 +03:00
12bd589bb7 feat(connect): Phase 6 — menu-app and manager-app frontend SPAs
Two Vite + React 18 + Tailwind apps under connect_frontend/.
Both use React Router v6, Axios, react-hot-toast, and Lucide icons.
Neither uses localStorage — tokens live in sessionStorage (manager-app)
or component state (menu-app cart).

── menu-app (public menu + ordering) ──────────────────────────────

Routing (basename /menu):
  /:siteSlug              → MenuPage
  /:siteSlug/order        → CartPage
  /:siteSlug/confirm/:ref → OrderConfirm

Pages:
  MenuPage      — fetches menu snapshot, category nav tabs, product
                  cards; floating CartButton; opens ProductModal
  ProductModal  — quantity picker, quick-option toggles, price/discount
                  display, "Add to order" with line total
  CartPage      — order type selector (dine_in/delivery), customer
                  details form, cart summary, submits to cloud API
  OrderConfirm  — polls GET /api/orders/status/:ref every 10s;
                  renders status icon + label; stops polling on
                  terminal states (delivered/rejected)

Components:
  CategoryNav   — horizontal scrollable pill tabs
  ProductCard   — image, name, description, price with discount badge;
                  greyed + "Out of stock" badge when unavailable
  CartButton    — fixed bottom bar with item count + total

── manager-app (remote dashboard) ─────────────────────────────────

Routing (basename /manage):
  /login              → LoginPage
  /                   → SiteSelectorPage (auto-navigates if one site)
  /:siteId            → DashboardPage
  /:siteId/orders     → IncomingOrdersPage
  /:siteId/orders/history → OrderHistoryPage
  /:siteId/orders/:id → OrderDetailPage
  RequireAuth wrapper redirects to /login if no sessionStorage token

Pages:
  LoginPage          — email/password → POST /api/manager/login;
                       stores JWT in sessionStorage
  SiteSelectorPage   — lists accessible venues; auto-selects if one
  DashboardPage      — polls snapshot + pending orders every 15s;
                       2×2 stat grid + pending order list
  IncomingOrdersPage — polls pending orders every 15s; order cards
  OrderDetailPage    — full order detail; Accept/Reject with optional
                       rejection reason; lifecycle progression buttons
                       (Preparing → Ready → Delivered etc.)
  OrderHistoryPage   — all orders with status filter tabs

Components:
  RequireAuth   — route guard using sessionStorage token
  StatCard      — labelled metric tile
  StatusBadge   — colour-coded status pill
  OrderCard     — summary card linking to OrderDetailPage
  (no OrderCard uses useParams to get siteId for nav — wired correctly)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 00:25:28 +03:00