Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/luisumit/LaPreviaRestobar/llms.txt

Use this file to discover all available pages before exploring further.

The public menu is a zero-dependency web page served directly from Firebase Hosting. Customers can open it on any device — phone, tablet, or desktop — by visiting the restaurant’s URL. The page connects to the same Firebase Realtime Database used by the Android app, so any product added or deactivated by an admin appears (or disappears) on the menu within seconds, without any redeployment.

What It Is

The public-menu/ directory contains three files:
FilePurpose
index.htmlStructural shell: header with restaurant name, category filter section, status banner, and the product grid
styles.cssVisual styling: topbar, product cards, category filter buttons, price display
app.jsAll logic: Firebase initialization, real-time data listener, category filters, and card rendering
The page is entirely static HTML/CSS/JS — there is no build step, no Node.js server, and no framework. Firebase CDN scripts are loaded from https://www.gstatic.com/firebasejs/10.12.4/.

index.html Structure

<!doctype html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>La Previa Restobar - Carta</title>
  <link rel="stylesheet" href="./styles.css">
</head>
<body>
  <header class="topbar">
    <div>
      <p class="eyebrow">La Previa Restobar</p>
      <h1>Carta digital</h1>
    </div>
    <div id="tableBadge" class="table-badge">Mesa</div>
  </header>

  <main>
    <section class="filters" id="categoryFilters"></section>
    <section class="status" id="status">Cargando carta...</section>
    <section class="menu-grid" id="menuGrid"></section>
  </main>

  <script src="https://www.gstatic.com/firebasejs/10.12.4/firebase-app-compat.js"></script>
  <script src="https://www.gstatic.com/firebasejs/10.12.4/firebase-database-compat.js"></script>
  <script src="./app.js"></script>
</body>
</html>
The #tableBadge element is updated by JavaScript to show which table is viewing the menu. The #categoryFilters, #status, and #menuGrid elements are all populated dynamically by app.js at runtime.

Firebase Initialization and Real-Time Product Loading

app.js initializes the Firebase compat SDK and opens a persistent listener on the products/ node. The listener fires immediately on load with all current data and again whenever any product changes.
const firebaseConfig = {
  apiKey: "AIzaSyD_nXUvuPfTeEmUYk6n_FhucVfuYhAntx0",
  databaseURL: "https://laprevia-restobar-default-rtdb.firebaseio.com",
  projectId: "laprevia-restobar",
  storageBucket: "laprevia-restobar.firebasestorage.app",
};

firebase.initializeApp(firebaseConfig);

const db = firebase.database();

db.ref("products").on(
  "value",
  (snapshot) => {
    const data = snapshot.val() || {};
    allProducts = Object.entries(data)
      .map(([id, product]) => ({ id, ...product }))
      .filter((product) => product.isActive !== false)
      .sort((a, b) => String(a.name || "").localeCompare(String(b.name || "")));

    renderFilters();
    renderMenu();
  },
  (error) => {
    statusEl.textContent = `No se pudo cargar la carta: ${error.message}`;
  }
);
1

Initialize Firebase

firebase.initializeApp(firebaseConfig) connects to the laprevia-restobar project using the compat SDK. No authentication is required because the products/ node uses public read rules.
2

Attach real-time listener

db.ref("products").on("value", ...) subscribes to all changes under the products/ node. This is a persistent subscription — the callback fires every time any product is created, updated, or deleted.
3

Filter active products

Only products where isActive !== false are included. Products deactivated by the admin (e.g. out-of-season items) are excluded automatically without requiring a page reload.
4

Sort alphabetically

Products are sorted by name using localeCompare so the menu always appears in a consistent alphabetical order regardless of insertion order in the database.
5

Render filters and cards

renderFilters() builds the category button row. renderMenu() populates the product grid. Both are called every time new data arrives.

Table Badge

The page reads the mesa query parameter from the URL to identify which table is viewing the menu:
const params = new URLSearchParams(window.location.search);
const tableNumber = params.get("mesa");

tableBadge.textContent = tableNumber ? `Mesa ${tableNumber}` : "Carta";
A QR code placed on each physical table encodes a URL like:
https://laprevia-restobar.web.app/?mesa=3
When the customer scans the code, the badge in the top-right corner shows Mesa 3, giving the page a personalized feel. If no mesa parameter is present (e.g. a link shared on social media), the badge shows Carta as a neutral fallback.

Dynamic Category Filters

Categories are derived from the live product data rather than hardcoded:
function renderFilters() {
  const categories = ["Todas", ...new Set(allProducts.map((p) => p.category || "General"))]
    .sort((a, b) => {
      if (a === "Todas") return -1;
      if (b === "Todas") return 1;
      return a.localeCompare(b);
    });

  filtersEl.innerHTML = "";
  categories.forEach((category) => {
    const button = document.createElement("button");
    button.className = `filter-button${selectedCategory === category ? " active" : ""}`;
    button.textContent = category;
    button.addEventListener("click", () => {
      selectedCategory = category;
      renderFilters();
      renderMenu();
    });
    filtersEl.appendChild(button);
  });
}
Adding a new product category in the Android admin panel automatically creates a new filter button on the public menu — no code changes needed.

Firebase Hosting Configuration

{
  "hosting": {
    "public": "public-menu",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  },
  "database": {
    "rules": "database.rules.json"
  }
}
The public field points to the public-menu/ directory, which is the root served by Firebase Hosting. The catch-all rewrite rule ("**" → "/index.html") ensures that direct URL navigation always loads the single-page shell, preventing 404 errors.

Deploying

firebase deploy --only hosting
This command uploads the contents of public-menu/ to Firebase Hosting’s CDN. The live URL is:
https://laprevia-restobar.web.app
Only the public-menu/ directory is deployed with --only hosting. The Firebase Realtime Database rules are deployed separately with firebase deploy --only database.
To preview changes before going live, run firebase hosting:channel:deploy preview to create a temporary staging URL that does not affect the production menu.

Build docs developers (and LLMs) love