Stream linining

This commit is contained in:
Zeeshaun
2026-05-05 18:41:34 +00:00
parent 36a484bc3e
commit 4c95327d94
2 changed files with 74 additions and 38 deletions
+44 -38
View File
@@ -12,6 +12,11 @@ import logo from "../../assets/ranaze-logo.png";
const queueStatuses = ["new", "making", "ready"];
const orderIdleTimeoutMs = 90_000;
const tabLabels = {
order: "Order",
queue: "Order Status",
menu: "Menu Admin"
};
const initialBuilder = (settings) => ({
size: settings.sizeOptions[0]?.name ?? "Regular",
@@ -132,22 +137,22 @@ export default function App() {
const selectedDrink = menu.find((item) => item._id === selectedDrinkId) || null;
const modeDetails = {
premade: {
stepLabel: "Quick pick",
title: "Pick a house favorite",
description: "Choose a ready-to-go drink and add it to the ticket in one tap.",
buttonLabel: "Add this drink"
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 a drink",
description: "Make a few easy choices and keep the line moving.",
buttonLabel: "Add customized drink"
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: "Full customize",
title: selectedDrink?.name || "Choose a drink",
description: "Adjust every detail, including toppings and special instructions.",
buttonLabel: "Add fully customized drink"
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;
@@ -161,9 +166,9 @@ export default function App() {
</div>
<div className="brand-copy">
<p className="eyebrow">Ranaze Bubble Tea & Slush</p>
<h1>Tablet POS</h1>
<h1>Choose your drink</h1>
<p className="muted">
Fast ordering for house favorites, easy edits, and detailed custom drinks.
Fresh bubble tea, fruit slushes, and easy customizations made just the way you like them.
</p>
</div>
</div>
@@ -174,7 +179,7 @@ export default function App() {
className={`tab ${view === tab ? "is-active" : ""}`}
onClick={() => setView(tab)}
>
{titleCase(tab)}
{tabLabels[tab]}
</button>
))}
</nav>
@@ -185,10 +190,10 @@ export default function App() {
{orderMode && (
<div className="order-toolbar">
<button className="text-btn" onClick={() => setOrderMode(null)}>
Back to order options
Back to drink options
</button>
<p className="muted order-toolbar-note">
This screen returns to the start menu after 90 seconds of inactivity.
This screen returns to the drink menu after 90 seconds of inactivity.
</p>
</div>
)}
@@ -196,27 +201,27 @@ export default function App() {
{!orderMode && (
<section className="panel mode-launcher">
<div className="mode-launcher-copy">
<p className="eyebrow">Start a new order</p>
<h2>How would you like to order today?</h2>
<p className="eyebrow">Welcome to Ranaze</p>
<h2>How would you like to choose your drink?</h2>
<p className="muted">
Pick the path that feels easiest for your guest. You can switch anytime during the order.
Start with a signature favorite, make a few quick changes, or fully customize your drink.
</p>
</div>
<div className="mode-grid">
<button className="mode-card" onClick={() => setOrderMode("premade")}>
<p className="eyebrow">Fastest</p>
<h3>Pre-Made Recipes</h3>
<p className="muted">Best for guests who want a house favorite with no extra decisions.</p>
<h3>House Favorites</h3>
<p className="muted">Perfect if you want one of our signature drinks with no extra steps.</p>
</button>
<button className="mode-card" onClick={() => setOrderMode("simple")}>
<p className="eyebrow">Easy</p>
<h3>Simple Customization</h3>
<p className="muted">Choose a drink, pick a size and sweetness level, and place it quickly.</p>
<h3>Quick Customization</h3>
<p className="muted">Choose your drink, then adjust size and sweetness in just a few taps.</p>
</button>
<button className="mode-card" onClick={() => setOrderMode("detailed")}>
<p className="eyebrow">Flexible</p>
<h3>Detailed Customization</h3>
<p className="muted">Fine-tune ice, toppings, and special instructions for exact orders.</p>
<h3>Build It Your Way</h3>
<p className="muted">Fine-tune ice, toppings, and special instructions for the exact drink you want.</p>
</button>
</div>
</section>
@@ -267,7 +272,7 @@ export default function App() {
<div className="inline-builder">
<div className="inline-builder-header">
<div>
<p className="eyebrow">Selected drink</p>
<p className="eyebrow">Your drink</p>
<h3>{activeMode.title}</h3>
</div>
<div className="line-price">
@@ -341,7 +346,7 @@ export default function App() {
)}
{orderMode === "premade" && (
<div className="empty-state mode-note">
This version uses the house recipe exactly as listed on the menu.
This option keeps the drink exactly as our signature recipe.
</div>
)}
<div className="builder-actions">
@@ -375,14 +380,14 @@ export default function App() {
<section className="ticket">
<div className="ticket-header">
<div>
<p className="eyebrow">Current order</p>
<h3>Current ticket</h3>
<p className="eyebrow">Your order</p>
<h3>Review your drinks</h3>
</div>
<button className="text-btn" onClick={() => setTicket([])}>Clear</button>
<button className="text-btn" onClick={() => setTicket([])}>Clear all</button>
</div>
<div className="ticket-lines">
{ticket.length === 0 && <div className="empty-state">No items in the ticket.</div>}
{ticket.length === 0 && <div className="empty-state">Your order is empty.</div>}
{ticket.map((line, index) => (
<article key={`${line.menuItemId}-${index}`} className="ticket-line">
<header>
@@ -397,10 +402,10 @@ export default function App() {
</button>
</header>
<p>{line.size} • {line.sweetness} • {line.ice}</p>
<p className="muted">{line.toppings.length ? line.toppings.join(", ") : "No toppings"}</p>
{line.notes && <p className="muted">Note: {line.notes}</p>}
<p className="muted">{line.toppings.length ? line.toppings.join(", ") : "No extra toppings"}</p>
{line.notes && <p className="muted">Special request: {line.notes}</p>}
<div className="line-meta">
<span>Line total</span>
<span>Drink total</span>
<strong>{formatCurrency(lineTotal({ basePrice: line.basePrice }, line, settings))}</strong>
</div>
</article>
@@ -409,21 +414,22 @@ export default function App() {
<div className="checkout-form">
<label className="field">
<span className="field-label">Customer name</span>
<span className="field-label">Name for the order</span>
<input
placeholder="Optional"
value={customerName}
maxLength="40"
onChange={(event) => setCustomerName(event.target.value)}
/>
</label>
<label className="field">
<span className="field-label">Payment</span>
<span className="field-label">How would you like to pay?</span>
<select
value={paymentMethod}
onChange={(event) => setPaymentMethod(event.target.value)}
>
<option value="cash">Cash</option>
<option value="tab">House Tab</option>
<option value="tab">Store Tab</option>
<option value="unpaid">Pay Later</option>
</select>
</label>
@@ -447,7 +453,7 @@ export default function App() {
}
}}
>
Place order
Place my order
</button>
</div>
</section>
+30
View File
@@ -95,6 +95,11 @@ button {
gap: 0.2rem;
}
.brand-copy h1 {
font-size: clamp(2rem, 3vw, 3rem);
line-height: 0.98;
}
.brand-copy p:last-child {
margin: 0;
max-width: 30rem;
@@ -123,6 +128,13 @@ button {
flex-wrap: wrap;
}
.tabs {
padding: 0.4rem;
border-radius: 999px;
background: rgba(255, 255, 255, 0.55);
border: 1px solid rgba(16, 16, 16, 0.06);
}
.screen {
display: grid;
grid-template-columns: 1.15fr 0.85fr;
@@ -140,6 +152,7 @@ button {
.order-toolbar-note {
margin: 0;
font-size: 0.92rem;
}
.queue-screen,
@@ -170,6 +183,13 @@ button {
.mode-launcher-copy {
max-width: 48rem;
display: grid;
gap: 0.45rem;
}
.mode-launcher-copy h2 {
font-size: clamp(2rem, 3.4vw, 3.3rem);
line-height: 0.96;
}
.mode-grid {
@@ -181,7 +201,9 @@ button {
.mode-card {
display: grid;
gap: 0.65rem;
align-content: start;
padding: 1.25rem;
min-height: 200px;
border: 1px solid rgba(16, 16, 16, 0.08);
border-radius: 24px;
background: rgba(255, 255, 255, 0.9);
@@ -240,6 +262,7 @@ button {
background: var(--accent);
color: #fff6e8;
border-color: var(--accent);
box-shadow: 0 8px 18px rgba(16, 16, 16, 0.18);
}
.text-btn {
@@ -286,6 +309,12 @@ button {
text-align: left;
}
.drink-card h3,
.ticket-line strong,
.queue-card h3 {
line-height: 1.05;
}
.drink-card.is-selected {
border-color: rgba(246, 179, 62, 0.7);
box-shadow:
@@ -350,6 +379,7 @@ select {
.builder-intro {
max-width: 28rem;
margin-top: 0.35rem;
}
.inline-builder {