Spaces:
Sleeping
Sleeping
| {% extends "base.html" %} | |
| {% block title %}Menu - Table {{ table_number }} - Tabble-v3{% endblock %} | |
| {% block extra_css %} | |
| <style> | |
| .menu-header { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 2rem 0; | |
| } | |
| .dish-card { | |
| transition: transform 0.2s; | |
| height: 100%; | |
| } | |
| .dish-card:hover { | |
| transform: translateY(-2px); | |
| } | |
| .dish-image { | |
| height: 200px; | |
| object-fit: cover; | |
| } | |
| .category-tab { | |
| border-radius: 25px; | |
| margin: 0 5px; | |
| } | |
| .cart-fab { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| width: 60px; | |
| height: 60px; | |
| border-radius: 50%; | |
| z-index: 1000; | |
| } | |
| .cart-count { | |
| position: absolute; | |
| top: -5px; | |
| right: -5px; | |
| background: #dc3545; | |
| color: white; | |
| border-radius: 50%; | |
| width: 25px; | |
| height: 25px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 12px; | |
| font-weight: bold; | |
| } | |
| </style> | |
| {% endblock %} | |
| {% block content %} | |
| <!-- Menu Header --> | |
| <div class="menu-header"> | |
| <div class="container text-center"> | |
| <h2> | |
| <i class="fas fa-utensils me-2"></i> | |
| Restaurant Menu | |
| </h2> | |
| <p class="mb-0">Table {{ table_number }} | Order ID: {{ unique_id }}</p> | |
| </div> | |
| </div> | |
| <div class="container mt-4"> | |
| <!-- Table Info & Quick Actions --> | |
| <div class="row mb-4"> | |
| <div class="col-md-8"> | |
| <div class="card"> | |
| <div class="card-body py-2"> | |
| <div class="row align-items-center"> | |
| <div class="col-sm-6"> | |
| <small class="text-muted">Dining at:</small> | |
| <strong class="d-block">Demo Restaurant</strong> | |
| </div> | |
| <div class="col-sm-6 text-sm-end"> | |
| <small class="text-muted">Table {{ table_number }}</small> | |
| <div class="badge bg-success ms-2"> | |
| <i class="fas fa-wifi me-1"></i>Connected | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="col-md-4"> | |
| <div class="d-flex gap-2"> | |
| <button class="btn btn-outline-primary flex-fill" onclick="viewOrders()"> | |
| <i class="fas fa-history me-1"></i>Orders | |
| </button> | |
| <button class="btn btn-outline-success flex-fill" onclick="callWaiter()"> | |
| <i class="fas fa-bell me-1"></i>Call Waiter | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Category Tabs --> | |
| <div class="row mb-4"> | |
| <div class="col-12"> | |
| <div class="d-flex flex-wrap justify-content-center"> | |
| <button class="btn btn-primary category-tab active" onclick="filterCategory('all')"> | |
| All Items | |
| </button> | |
| <button class="btn btn-outline-primary category-tab" onclick="filterCategory('starters')"> | |
| Starters | |
| </button> | |
| <button class="btn btn-outline-primary category-tab" onclick="filterCategory('main-course')"> | |
| Main Course | |
| </button> | |
| <button class="btn btn-outline-primary category-tab" onclick="filterCategory('beverages')"> | |
| Beverages | |
| </button> | |
| <button class="btn btn-outline-primary category-tab" onclick="filterCategory('desserts')"> | |
| Desserts | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Menu Items --> | |
| <div class="row" id="menu-items"> | |
| <!-- Sample Dish 1 --> | |
| <div class="col-md-4 col-sm-6 mb-4 menu-item" data-category="main-course"> | |
| <div class="card dish-card"> | |
| <img src="https://images.unsplash.com/photo-1563379091339-03246963d96c?w=400&h=200&fit=crop" | |
| class="card-img-top dish-image" alt="Chicken Biryani"> | |
| <div class="card-body"> | |
| <div class="d-flex justify-content-between align-items-start mb-2"> | |
| <h6 class="card-title mb-0">Chicken Biryani</h6> | |
| <span class="badge bg-warning"> | |
| <i class="fas fa-pepper-hot"></i> | |
| </span> | |
| </div> | |
| <p class="card-text text-muted small"> | |
| Aromatic basmati rice cooked with tender chicken and traditional spices | |
| </p> | |
| <div class="d-flex justify-content-between align-items-center"> | |
| <strong class="text-success">₹250</strong> | |
| <div class="btn-group btn-group-sm"> | |
| <button class="btn btn-outline-secondary" onclick="updateQuantity('biryani', -1)">-</button> | |
| <span class="btn btn-outline-secondary" id="qty-biryani">0</span> | |
| <button class="btn btn-outline-secondary" onclick="updateQuantity('biryani', 1)">+</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Sample Dish 2 --> | |
| <div class="col-md-4 col-sm-6 mb-4 menu-item" data-category="starters"> | |
| <div class="card dish-card"> | |
| <img src="https://images.unsplash.com/photo-1599487488170-d11ec9c172f0?w=400&h=200&fit=crop" | |
| class="card-img-top dish-image" alt="Paneer Tikka"> | |
| <div class="card-body"> | |
| <div class="d-flex justify-content-between align-items-start mb-2"> | |
| <h6 class="card-title mb-0">Paneer Tikka</h6> | |
| <span class="badge bg-success"> | |
| <i class="fas fa-leaf"></i> | |
| </span> | |
| </div> | |
| <p class="card-text text-muted small"> | |
| Marinated cottage cheese cubes grilled to perfection | |
| </p> | |
| <div class="d-flex justify-content-between align-items-center"> | |
| <strong class="text-success">₹180</strong> | |
| <div class="btn-group btn-group-sm"> | |
| <button class="btn btn-outline-secondary" onclick="updateQuantity('paneer', -1)">-</button> | |
| <span class="btn btn-outline-secondary" id="qty-paneer">0</span> | |
| <button class="btn btn-outline-secondary" onclick="updateQuantity('paneer', 1)">+</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Sample Dish 3 --> | |
| <div class="col-md-4 col-sm-6 mb-4 menu-item" data-category="beverages"> | |
| <div class="card dish-card"> | |
| <img src="https://images.unsplash.com/photo-1571091718767-18b5b1457add?w=400&h=200&fit=crop" | |
| class="card-img-top dish-image" alt="Mango Lassi"> | |
| <div class="card-body"> | |
| <div class="d-flex justify-content-between align-items-start mb-2"> | |
| <h6 class="card-title mb-0">Mango Lassi</h6> | |
| <span class="badge bg-info"> | |
| <i class="fas fa-snowflake"></i> | |
| </span> | |
| </div> | |
| <p class="card-text text-muted small"> | |
| Refreshing yogurt-based drink with fresh mango pulp | |
| </p> | |
| <div class="d-flex justify-content-between align-items-center"> | |
| <strong class="text-success">₹80</strong> | |
| <div class="btn-group btn-group-sm"> | |
| <button class="btn btn-outline-secondary" onclick="updateQuantity('lassi', -1)">-</button> | |
| <span class="btn btn-outline-secondary" id="qty-lassi">0</span> | |
| <button class="btn btn-outline-secondary" onclick="updateQuantity('lassi', 1)">+</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Empty Menu State --> | |
| <div id="no-items" class="text-center py-5" style="display: none;"> | |
| <i class="fas fa-search fa-3x text-muted mb-3"></i> | |
| <p class="text-muted">No items found in this category</p> | |
| </div> | |
| </div> | |
| <!-- Floating Cart Button --> | |
| <button class="btn btn-success cart-fab" onclick="openCart()" id="cart-btn" style="display: none;"> | |
| <i class="fas fa-shopping-cart"></i> | |
| <span class="cart-count" id="cart-count">0</span> | |
| </button> | |
| <!-- Cart Modal --> | |
| <div class="modal fade" id="cartModal" tabindex="-1"> | |
| <div class="modal-dialog modal-lg"> | |
| <div class="modal-content"> | |
| <div class="modal-header"> | |
| <h5 class="modal-title"> | |
| <i class="fas fa-shopping-cart me-2"></i>Your Order | |
| </h5> | |
| <button type="button" class="btn-close" data-bs-dismiss="modal"></button> | |
| </div> | |
| <div class="modal-body"> | |
| <div id="cart-items"> | |
| <!-- Cart items will be populated here --> | |
| </div> | |
| <hr> | |
| <div class="d-flex justify-content-between"> | |
| <strong>Total: ₹<span id="cart-total">0</span></strong> | |
| </div> | |
| </div> | |
| <div class="modal-footer"> | |
| <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"> | |
| Continue Shopping | |
| </button> | |
| <button type="button" class="btn btn-success" onclick="placeOrder()"> | |
| <i class="fas fa-check me-2"></i>Place Order | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {% endblock %} | |
| {% block extra_js %} | |
| <script> | |
| let cart = {}; | |
| let dishes = { | |
| 'biryani': { name: 'Chicken Biryani', price: 250 }, | |
| 'paneer': { name: 'Paneer Tikka', price: 180 }, | |
| 'lassi': { name: 'Mango Lassi', price: 80 } | |
| }; | |
| function filterCategory(category) { | |
| // Update active tab | |
| document.querySelectorAll('.category-tab').forEach(tab => { | |
| tab.classList.remove('active', 'btn-primary'); | |
| tab.classList.add('btn-outline-primary'); | |
| }); | |
| event.target.classList.remove('btn-outline-primary'); | |
| event.target.classList.add('active', 'btn-primary'); | |
| // Filter items | |
| const items = document.querySelectorAll('.menu-item'); | |
| let visibleCount = 0; | |
| items.forEach(item => { | |
| const itemCategory = item.dataset.category; | |
| const show = category === 'all' || itemCategory === category; | |
| item.style.display = show ? 'block' : 'none'; | |
| if (show) visibleCount++; | |
| }); | |
| document.getElementById('no-items').style.display = visibleCount === 0 ? 'block' : 'none'; | |
| } | |
| function updateQuantity(dishId, change) { | |
| if (!cart[dishId]) cart[dishId] = 0; | |
| cart[dishId] += change; | |
| if (cart[dishId] < 0) cart[dishId] = 0; | |
| if (cart[dishId] === 0) delete cart[dishId]; | |
| document.getElementById(`qty-${dishId}`).textContent = cart[dishId] || 0; | |
| updateCartDisplay(); | |
| } | |
| function updateCartDisplay() { | |
| const totalItems = Object.values(cart).reduce((sum, qty) => sum + qty, 0); | |
| const cartBtn = document.getElementById('cart-btn'); | |
| const cartCount = document.getElementById('cart-count'); | |
| if (totalItems > 0) { | |
| cartBtn.style.display = 'block'; | |
| cartCount.textContent = totalItems; | |
| } else { | |
| cartBtn.style.display = 'none'; | |
| } | |
| } | |
| function openCart() { | |
| const cartItems = document.getElementById('cart-items'); | |
| const cartTotal = document.getElementById('cart-total'); | |
| let html = ''; | |
| let total = 0; | |
| for (let dishId in cart) { | |
| const dish = dishes[dishId]; | |
| const qty = cart[dishId]; | |
| const subtotal = dish.price * qty; | |
| total += subtotal; | |
| html += ` | |
| <div class="d-flex justify-content-between align-items-center mb-2"> | |
| <div> | |
| <strong>${dish.name}</strong> | |
| <small class="text-muted d-block">₹${dish.price} each</small> | |
| </div> | |
| <div class="d-flex align-items-center"> | |
| <span class="me-3">Qty: ${qty}</span> | |
| <strong>₹${subtotal}</strong> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| if (html === '') { | |
| html = '<p class="text-muted text-center">Your cart is empty</p>'; | |
| } | |
| cartItems.innerHTML = html; | |
| cartTotal.textContent = total; | |
| new bootstrap.Modal(document.getElementById('cartModal')).show(); | |
| } | |
| function placeOrder() { | |
| if (Object.keys(cart).length === 0) { | |
| alert('Your cart is empty!'); | |
| return; | |
| } | |
| const total = Object.keys(cart).reduce((sum, dishId) => { | |
| return sum + (dishes[dishId].price * cart[dishId]); | |
| }, 0); | |
| const orderSummary = Object.keys(cart).map(dishId => { | |
| return `${cart[dishId]}x ${dishes[dishId].name}`; | |
| }).join(', '); | |
| if (confirm(`Place order for ₹${total}?\n\nItems: ${orderSummary}`)) { | |
| alert('Order placed successfully! You will receive updates on the status.'); | |
| cart = {}; | |
| updateCartDisplay(); | |
| // Reset all quantities | |
| Object.keys(dishes).forEach(dishId => { | |
| document.getElementById(`qty-${dishId}`).textContent = '0'; | |
| }); | |
| bootstrap.Modal.getInstance(document.getElementById('cartModal')).hide(); | |
| } | |
| } | |
| function viewOrders() { | |
| alert('Order history feature will show your past orders'); | |
| } | |
| function callWaiter() { | |
| if (confirm('Call waiter to your table?')) { | |
| alert('Waiter has been notified and will be at your table shortly!'); | |
| } | |
| } | |
| </script> | |
| {% endblock %} |