diff --git a/client/src/App.jsx b/client/src/App.jsx index 18d17a9..530a443 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -8,24 +8,16 @@ import { resetMenu, updateOrderStatus } from "./api.js"; -import logo from "../../assets/ranaze-logo-transparent.png"; -import heroCup from "../../assets/ranaze-bubble-tea-single-cup-transparent.png"; - -const queueStatuses = ["new", "making", "ready"]; -const orderIdleTimeoutMs = 90_000; -const adminUnlockPressMs = 3_000; -const adminPassword = "admin"; -const tabLabels = { - queue: "Order Status", - menu: "Menu Admin" -}; -const initialBuilder = (settings) => ({ - size: settings.sizeOptions[0]?.name ?? "Regular", - sweetness: settings.sweetnessOptions[3] ?? settings.sweetnessOptions[0] ?? "100%", - ice: settings.iceOptions[2] ?? settings.iceOptions[0] ?? "Regular Ice", - toppings: [], - notes: "" -}); +import AppHeader from "./components/AppHeader.jsx"; +import MenuPage from "./pages/MenuPage.jsx"; +import OrderPage from "./pages/OrderPage.jsx"; +import QueuePage from "./pages/QueuePage.jsx"; +import { + ADMIN_PASSWORD, + ADMIN_UNLOCK_PRESS_MS, + initialBuilder, + ORDER_IDLE_TIMEOUT_MS +} from "./lib/order.js"; export default function App() { const adminPressTimerRef = useRef(null); @@ -73,13 +65,13 @@ export default function App() { let timeoutId = window.setTimeout(() => { setOrderMode(null); - }, orderIdleTimeoutMs); + }, ORDER_IDLE_TIMEOUT_MS); function resetIdleTimer() { window.clearTimeout(timeoutId); timeoutId = window.setTimeout(() => { setOrderMode(null); - }, orderIdleTimeoutMs); + }, ORDER_IDLE_TIMEOUT_MS); } const events = ["pointerdown", "keydown", "touchstart"]; @@ -138,6 +130,30 @@ export default function App() { } } + function startAdminPress() { + window.clearTimeout(adminPressTimerRef.current); + setLogoPressing(true); + adminPressTimerRef.current = window.setTimeout(() => { + if (adminUnlocked) { + setAdminUnlocked(false); + setView("order"); + } else { + const password = window.prompt("Enter admin password"); + if (password === ADMIN_PASSWORD) { + setAdminUnlocked(true); + } else if (password !== null && password !== "") { + window.alert("Incorrect password"); + } + } + setLogoPressing(false); + }, ADMIN_UNLOCK_PRESS_MS); + } + + function cancelAdminPress() { + window.clearTimeout(adminPressTimerRef.current); + setLogoPressing(false); + } + if (loading) { return
Loading POS...
; } @@ -151,698 +167,74 @@ export default function App() { ); } - const categories = ["All", ...new Set(menu.map((item) => item.category))]; - const visibleMenu = menu.filter((item) => { - return selectedCategory === "All" || item.category === selectedCategory; - }); - const selectedDrink = menu.find((item) => item._id === selectedDrinkId) || null; - const visibleTabs = adminUnlocked ? ["queue", "menu"] : []; - const modeDetails = { - premade: { - stepLabel: "House favorite", - title: selectedDrink?.name || "Pick a house favorite", - description: "Choose one of our ready-to-enjoy drinks and add it in one tap.", - buttonLabel: "Add to my order" - }, - simple: { - stepLabel: "Quick customize", - title: selectedDrink?.name || "Choose your drink", - description: "Pick your drink, then make a few simple choices like size and sweetness.", - buttonLabel: "Add to my order" - }, - detailed: { - stepLabel: "Build it your way", - title: selectedDrink?.name || "Build your drink", - description: "Customize every detail, including ice, toppings, and special requests.", - buttonLabel: "Add to my order" - } - }; - const activeMode = orderMode ? modeDetails[orderMode] : null; - - function startAdminPress() { - window.clearTimeout(adminPressTimerRef.current); - setLogoPressing(true); - adminPressTimerRef.current = window.setTimeout(() => { - if (adminUnlocked) { - setAdminUnlocked(false); - setView("order"); - } else { - const password = window.prompt("Enter admin password"); - if (password === adminPassword) { - setAdminUnlocked(true); - } else if (password !== null && password !== "") { - window.alert("Incorrect password"); - } - } - setLogoPressing(false); - }, adminUnlockPressMs); - } - - function cancelAdminPress() { - window.clearTimeout(adminPressTimerRef.current); - setLogoPressing(false); - } - - function addLineToTicket(drink, lineBuilder) { - setTicket((current) => [ - ...current, - { - menuItemId: drink._id, - name: drink.name, - basePrice: drink.basePrice, - ...lineBuilder - } - ]); - } - return (
-
-
- -
-

Ranaze Bubble Tea & Slush

-

Choose your drink

-

- Fresh bubble tea, fruit slushes, and easy customizations made just the way you like them. -

-
-
- {adminUnlocked && ( - - )} -
+ { + setAdminUnlocked(false); + setView("order"); + }} + view={view} + setView={setView} + /> {view === "order" && ( -
- {orderMode && ( -
- -
- {ticket.length > 0 && ( - - )} -

- This screen returns to the drink menu after 90 seconds of inactivity. -

-
-
- )} - - {!orderMode && ( -
-
-

Welcome to Ranaze

-

How would you like to choose your drink?

-

- Start with a signature favorite, make a few quick changes, or fully customize your drink. -

-
-
-
-

Freshly made for you

-

Bubble tea, fruit tea, and slushes with easy customization.

-
- Ranaze signature bubble tea -
-
- - - -
-
- )} - - {orderMode && !showCart && ( -
-
-
-

{activeMode.stepLabel}

-

Choose a drink

-

{activeMode.description}

-
-
- - {ticket.length > 0 && ( - - )} -
-
-
- {categories.map((category) => ( - - ))} -
-
- {visibleMenu.map((drink) => ( - - ))} -
- {orderMode === "premade" && ( -
- Tap any drink to add it to your order. Use the order button whenever you are ready to review. -
- )} -
- )} - - {orderMode && !showCart && orderMode !== "premade" && ( -
- {selectedDrink && builder ? ( -
-
-
-

Your drink

-

{activeMode.title}

-
-
- {formatCurrency(lineTotal(selectedDrink, builder, settings))} -
-
- - {orderMode !== "premade" && ( - option.name)} - value={builder.size} - onChange={(size) => setBuilder((current) => ({ ...current, size }))} - /> - )} - {orderMode !== "premade" && ( - setBuilder((current) => ({ ...current, sweetness }))} - /> - )} - {orderMode === "detailed" && ( - setBuilder((current) => ({ ...current, ice }))} - /> - )} - {orderMode === "detailed" && ( -
- Toppings -
- {settings.toppings.map((topping) => { - const checked = builder.toppings.includes(topping.name); - return ( - - ); - })} -
-
- )} - {orderMode === "detailed" && ( -