diff --git a/cloud_backend/main.py b/cloud_backend/main.py index 8cf5b12..0df0459 100644 --- a/cloud_backend/main.py +++ b/cloud_backend/main.py @@ -45,9 +45,13 @@ def _run_migrations(): "ALTER TABLE sites ADD COLUMN menu_mode VARCHAR NOT NULL DEFAULT 'order'", "ALTER TABLE sites ADD COLUMN menu_tagline_en VARCHAR", "ALTER TABLE sites ADD COLUMN menu_tagline_gr VARCHAR", - "ALTER TABLE sites ADD COLUMN menu_hours_en VARCHAR", - "ALTER TABLE sites ADD COLUMN menu_hours_gr VARCHAR", + "ALTER TABLE sites ADD COLUMN menu_hours_en VARCHAR", # superseded by menu_hours, kept for history + "ALTER TABLE sites ADD COLUMN menu_hours_gr VARCHAR", # superseded by menu_hours, kept for history "ALTER TABLE sites ADD COLUMN menu_header_image_url VARCHAR", + "ALTER TABLE sites ADD COLUMN menu_display_name VARCHAR", + "ALTER TABLE sites ADD COLUMN menu_blurb_en VARCHAR", + "ALTER TABLE sites ADD COLUMN menu_blurb_gr VARCHAR", + "ALTER TABLE sites ADD COLUMN menu_hours VARCHAR", ] for sql in migrations: try: diff --git a/cloud_backend/models/site.py b/cloud_backend/models/site.py index 8459be0..25969ca 100644 --- a/cloud_backend/models/site.py +++ b/cloud_backend/models/site.py @@ -26,8 +26,10 @@ class Site(Base): # QR menu branding/config menu_mode = Column(String, nullable=False, default="order") # "order" | "view_only" + menu_display_name = Column(String, nullable=True) menu_tagline_en = Column(String, nullable=True) menu_tagline_gr = Column(String, nullable=True) - menu_hours_en = Column(String, nullable=True) - menu_hours_gr = Column(String, nullable=True) + menu_blurb_en = Column(String, nullable=True) + menu_blurb_gr = Column(String, nullable=True) + menu_hours = Column(String, nullable=True) menu_header_image_url = Column(String, nullable=True) diff --git a/cloud_backend/routers/menu.py b/cloud_backend/routers/menu.py index 1ca5340..3a6cc2e 100644 --- a/cloud_backend/routers/menu.py +++ b/cloud_backend/routers/menu.py @@ -39,9 +39,10 @@ def get_menu(site_slug: str, db: Session = Depends(get_db)): data = json.loads(snapshot.snapshot_json) data["menu_mode"] = site.menu_mode data["restaurant"] = { - "name": site.name, + "name": site.menu_display_name, "tagline": {"en": site.menu_tagline_en, "gr": site.menu_tagline_gr}, - "hours": {"en": site.menu_hours_en, "gr": site.menu_hours_gr}, + "blurb": {"en": site.menu_blurb_en, "gr": site.menu_blurb_gr}, + "hours": site.menu_hours, "headerImageUrl": site.menu_header_image_url, } return data diff --git a/cloud_backend/schemas/site.py b/cloud_backend/schemas/site.py index edfab04..26275ed 100644 --- a/cloud_backend/schemas/site.py +++ b/cloud_backend/schemas/site.py @@ -16,10 +16,12 @@ class SiteUpdate(BaseModel): license_expires_at: datetime | None = None waiter_domain: str | None = None menu_mode: str | None = None + menu_display_name: str | None = None menu_tagline_en: str | None = None menu_tagline_gr: str | None = None - menu_hours_en: str | None = None - menu_hours_gr: str | None = None + menu_blurb_en: str | None = None + menu_blurb_gr: str | None = None + menu_hours: str | None = None class SiteOut(BaseModel): @@ -38,10 +40,12 @@ class SiteOut(BaseModel): last_seen_local_ip: str | None waiter_domain: str | None menu_mode: str + menu_display_name: str | None menu_tagline_en: str | None menu_tagline_gr: str | None - menu_hours_en: str | None - menu_hours_gr: str | None + menu_blurb_en: str | None + menu_blurb_gr: str | None + menu_hours: str | None menu_header_image_url: str | None model_config = {"from_attributes": True} diff --git a/connect_frontend/menu-app/src/api.js b/connect_frontend/menu-app/src/api.js index bbb96b2..7086eff 100644 --- a/connect_frontend/menu-app/src/api.js +++ b/connect_frontend/menu-app/src/api.js @@ -1,8 +1,8 @@ import axios from 'axios' -const BASE = import.meta.env.VITE_CLOUD_URL || '' +export const CLOUD_URL = import.meta.env.VITE_CLOUD_URL || '' -const api = axios.create({ baseURL: BASE }) +const api = axios.create({ baseURL: CLOUD_URL }) export async function fetchMenu(siteSlug) { const { data } = await api.get(`/api/menu/${siteSlug}`) diff --git a/connect_frontend/menu-app/src/pages/MenuPage.jsx b/connect_frontend/menu-app/src/pages/MenuPage.jsx index 6528956..651763c 100644 --- a/connect_frontend/menu-app/src/pages/MenuPage.jsx +++ b/connect_frontend/menu-app/src/pages/MenuPage.jsx @@ -1,25 +1,19 @@ import { useState, useEffect, useRef, useMemo } from 'react' import { useParams, useNavigate } from 'react-router-dom' import { - MapPin, Search, Leaf, X, Plus, ShoppingBag, + Search, Leaf, X, Plus, ShoppingBag, ChevronLeft, ArrowRight, Send, Loader2, Info, Armchair, Check, SearchX, UtensilsCrossed, AlertCircle, Soup, Salad, Wheat, IceCream2, Wine, } from 'lucide-react' -import { fetchMenu, submitOrder } from '../api' +import { fetchMenu, submitOrder, CLOUD_URL } from '../api' import { DishArt, Badge, DietChip, TagIcons, Price, DiscountFlag, Stepper, eur, discountedPrice, discountPct, } from '../components/primitives' -// Used when a site hasn't configured a field yet (API sends nulls until set in sysadmin) -const RESTAURANT_FALLBACK = { - name: 'Our Menu', - tagline: { en: 'Kitchen & Bar', gr: 'Κουζίνα & Μπαρ' }, - blurb: { en: 'Fresh seasonal plates, served with care.', gr: 'Εποχιακά πιάτα, με αγάπη.' }, - hours: { en: 'Open today · 12:00 – 23:30', gr: 'Ανοιχτά σήμερα · 12:00 – 23:30' }, - location: { en: '', gr: '' }, -} +// Shown only when a site has never been configured at all (brand-new site, restaurant === null) +const RESTAURANT_FALLBACK = { name: 'Our Menu' } // Category glyph icons — mapped by category id or index const GLYPH_BY_ID = { starters: Soup, salads: Salad, mains: UtensilsCrossed, sides: Wheat, desserts: IceCream2, drinks: Wine } @@ -121,7 +115,12 @@ function SheetHandle() { // ── Hero ────────────────────────────────────────────────────────────────────── function Hero({ lang, setLang, restaurant }) { - const r = { ...RESTAURANT_FALLBACK, ...restaurant } + const name = restaurant?.name || RESTAURANT_FALLBACK.name + const tagline = restaurant?.tagline?.[lang] + const blurb = restaurant?.blurb?.[lang] + const hours = restaurant?.hours + const headerImageUrl = restaurant?.headerImageUrl ? `${CLOUD_URL}${restaurant.headerImageUrl}` : null + return (
{/* Language toggle */} @@ -141,27 +140,22 @@ function Hero({ lang, setLang, restaurant }) { - {r.location?.[lang] && ( -
- - {r.location[lang]} -
- )} - - {r.headerImageUrl ? ( + {headerImageUrl ? ( {r.name} ) : (

- {r.name} + {name}

)} -
- {r.tagline?.[lang] || RESTAURANT_FALLBACK.tagline[lang] || ''} -
+ {tagline && ( +
+ {tagline} +
+ )} {/* Ornament */}
@@ -170,17 +164,19 @@ function Hero({ lang, setLang, restaurant }) {
-

- {r.blurb?.[lang] || RESTAURANT_FALLBACK.blurb[lang] || ''} -

+ {blurb && ( +

+ {blurb} +

+ )} - {r.hours?.[lang] && ( + {hours && (
- {r.hours[lang]} + {hours}
)}
diff --git a/sysadmin_panel/src/pages/SiteDetailPage.jsx b/sysadmin_panel/src/pages/SiteDetailPage.jsx index 9d2d3c3..bb09529 100644 --- a/sysadmin_panel/src/pages/SiteDetailPage.jsx +++ b/sysadmin_panel/src/pages/SiteDetailPage.jsx @@ -35,10 +35,12 @@ export default function SiteDetailPage() { // Menu settings form state const [menuMode, setMenuMode] = useState('order') + const [displayName, setDisplayName] = useState('') const [taglineEn, setTaglineEn] = useState('') const [taglineGr, setTaglineGr] = useState('') - const [hoursEn, setHoursEn] = useState('') - const [hoursGr, setHoursGr] = useState('') + const [blurbEn, setBlurbEn] = useState('') + const [blurbGr, setBlurbGr] = useState('') + const [hours, setHours] = useState('') const [headerImageFile, setHeaderImageFile] = useState(null) const [uploadingHeaderImage, setUploadingHeaderImage] = useState(false) @@ -177,10 +179,12 @@ export default function SiteDetailPage() { try { const { data } = await client.put(`/api/sites/${siteId}`, { menu_mode: menuMode, - menu_tagline_en: taglineEn.trim() || null, - menu_tagline_gr: taglineGr.trim() || null, - menu_hours_en: hoursEn.trim() || null, - menu_hours_gr: hoursGr.trim() || null, + menu_display_name: displayName.trim(), + menu_tagline_en: taglineEn.trim(), + menu_tagline_gr: taglineGr.trim(), + menu_blurb_en: blurbEn.trim(), + menu_blurb_gr: blurbGr.trim(), + menu_hours: hours.trim(), }) setSite(data) setModal(null) @@ -347,10 +351,12 @@ export default function SiteDetailPage() {