Shyamnath's picture
feat(core): implement unified database with multi-hotel support and session management
90537f3
{% extends "base.html" %}
{% block title %}Dishes Management - Admin Dashboard{% endblock %}
{% block content %}
<div class="container mt-4">
<div class="row">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>
<i class="fas fa-utensils me-2"></i>
Dishes Management
</h2>
<div class="d-flex gap-2">
<a href="/admin" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-1"></i>Back to Dashboard
</a>
<button class="btn btn-success" onclick="addNewDish()">
<i class="fas fa-plus me-1"></i>Add New Dish
</button>
</div>
</div>
</div>
</div>
<!-- Filters and Search -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="row align-items-center">
<div class="col-md-3">
<label class="form-label">Search Dishes:</label>
<input type="text" class="form-control" id="searchInput"
placeholder="Search by name..." onkeyup="filterDishes()">
</div>
<div class="col-md-2">
<label class="form-label">Category:</label>
<select class="form-select" id="categoryFilter" onchange="filterDishes()">
<option value="">All Categories</option>
<option value="starters">Starters</option>
<option value="main-course">Main Course</option>
<option value="beverages">Beverages</option>
<option value="desserts">Desserts</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">Availability:</label>
<select class="form-select" id="availabilityFilter" onchange="filterDishes()">
<option value="">All</option>
<option value="available">Available</option>
<option value="unavailable">Unavailable</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">Price Range:</label>
<select class="form-select" id="priceFilter" onchange="filterDishes()">
<option value="">All Prices</option>
<option value="0-100">₹0 - ₹100</option>
<option value="100-300">₹100 - ₹300</option>
<option value="300+">₹300+</option>
</select>
</div>
<div class="col-md-3 d-flex align-items-end gap-2">
<button class="btn btn-outline-secondary flex-fill" onclick="clearFilters()">
<i class="fas fa-times me-1"></i>Clear
</button>
<button class="btn btn-outline-primary flex-fill" onclick="exportDishes()">
<i class="fas fa-download me-1"></i>Export
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Dishes Grid -->
<div class="row" id="dishes-container">
<!-- Sample Dish 1 -->
<div class="col-md-4 col-sm-6 mb-4 dish-item" data-category="main-course" data-price="250" data-available="true">
<div class="card h-100">
<img src="https://images.unsplash.com/photo-1563379091339-03246963d96c?w=400&h=200&fit=crop"
class="card-img-top" style="height: 200px; object-fit: cover;" 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>
<div class="d-flex gap-1">
<span class="badge bg-warning">Main Course</span>
<span class="badge bg-success">Available</span>
</div>
</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 mb-3">
<strong class="text-success fs-5">₹250</strong>
<div class="d-flex gap-1">
<i class="fas fa-star text-warning"></i>
<span class="small">4.5 (24 reviews)</span>
</div>
</div>
<div class="d-flex gap-2">
<button class="btn btn-primary btn-sm flex-fill" onclick="editDish(1)">
<i class="fas fa-edit me-1"></i>Edit
</button>
<button class="btn btn-warning btn-sm" onclick="toggleAvailability(1)">
<i class="fas fa-eye-slash me-1"></i>
</button>
<button class="btn btn-danger btn-sm" onclick="deleteDish(1)">
<i class="fas fa-trash me-1"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Sample Dish 2 -->
<div class="col-md-4 col-sm-6 mb-4 dish-item" data-category="starters" data-price="180" data-available="true">
<div class="card h-100">
<img src="https://images.unsplash.com/photo-1599487488170-d11ec9c172f0?w=400&h=200&fit=crop"
class="card-img-top" style="height: 200px; object-fit: cover;" 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>
<div class="d-flex gap-1">
<span class="badge bg-primary">Starters</span>
<span class="badge bg-success">Available</span>
</div>
</div>
<p class="card-text text-muted small">
Marinated cottage cheese cubes grilled to perfection with Indian spices
</p>
<div class="d-flex justify-content-between align-items-center mb-3">
<strong class="text-success fs-5">₹180</strong>
<div class="d-flex gap-1">
<i class="fas fa-star text-warning"></i>
<span class="small">4.2 (18 reviews)</span>
</div>
</div>
<div class="d-flex gap-2">
<button class="btn btn-primary btn-sm flex-fill" onclick="editDish(2)">
<i class="fas fa-edit me-1"></i>Edit
</button>
<button class="btn btn-warning btn-sm" onclick="toggleAvailability(2)">
<i class="fas fa-eye-slash me-1"></i>
</button>
<button class="btn btn-danger btn-sm" onclick="deleteDish(2)">
<i class="fas fa-trash me-1"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Sample Dish 3 -->
<div class="col-md-4 col-sm-6 mb-4 dish-item" data-category="beverages" data-price="80" data-available="false">
<div class="card h-100">
<img src="https://images.unsplash.com/photo-1571091718767-18b5b1457add?w=400&h=200&fit=crop"
class="card-img-top" style="height: 200px; object-fit: cover;" 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>
<div class="d-flex gap-1">
<span class="badge bg-info">Beverages</span>
<span class="badge bg-danger">Unavailable</span>
</div>
</div>
<p class="card-text text-muted small">
Refreshing yogurt-based drink with fresh mango pulp and a hint of cardamom
</p>
<div class="d-flex justify-content-between align-items-center mb-3">
<strong class="text-success fs-5">₹80</strong>
<div class="d-flex gap-1">
<i class="fas fa-star text-warning"></i>
<span class="small">4.7 (35 reviews)</span>
</div>
</div>
<div class="d-flex gap-2">
<button class="btn btn-primary btn-sm flex-fill" onclick="editDish(3)">
<i class="fas fa-edit me-1"></i>Edit
</button>
<button class="btn btn-success btn-sm" onclick="toggleAvailability(3)">
<i class="fas fa-eye me-1"></i>
</button>
<button class="btn btn-danger btn-sm" onclick="deleteDish(3)">
<i class="fas fa-trash me-1"></i>
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Empty State -->
<div id="no-dishes" 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 dishes match your filters</p>
<button class="btn btn-primary" onclick="clearFilters()">
Clear Filters
</button>
</div>
</div>
<!-- Add/Edit Dish Modal -->
<div class="modal fade" id="dishModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="dishModalTitle">
<i class="fas fa-plus me-2"></i>Add New Dish
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="dishForm">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Dish Name *</label>
<input type="text" class="form-control" id="dishName" required>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Category *</label>
<select class="form-select" id="dishCategory" required>
<option value="">Select Category</option>
<option value="starters">Starters</option>
<option value="main-course">Main Course</option>
<option value="beverages">Beverages</option>
<option value="desserts">Desserts</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Price (₹) *</label>
<input type="number" class="form-control" id="dishPrice" min="0" step="0.01" required>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Cooking Time (minutes)</label>
<input type="number" class="form-control" id="cookingTime" min="0">
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea class="form-control" id="dishDescription" rows="3"
placeholder="Describe the dish..."></textarea>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Image Upload</label>
<input type="file" class="form-control" id="dishImage" accept="image/*">
<small class="text-muted">Upload dish image (JPG, PNG)</small>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="isAvailable" checked>
<label class="form-check-label" for="isAvailable">
Available for orders
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="isSpecial">
<label class="form-check-label" for="isSpecial">
Today's special
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="isVegetarian">
<label class="form-check-label" for="isVegetarian">
Vegetarian
</label>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
Cancel
</button>
<button type="button" class="btn btn-success" onclick="saveDish()">
<i class="fas fa-save me-2"></i>Save Dish
</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
let editingDishId = null;
function filterDishes() {
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
const categoryFilter = document.getElementById('categoryFilter').value;
const availabilityFilter = document.getElementById('availabilityFilter').value;
const priceFilter = document.getElementById('priceFilter').value;
const dishes = document.querySelectorAll('.dish-item');
let visibleCount = 0;
dishes.forEach(dish => {
let show = true;
// Search filter
if (searchTerm && !dish.textContent.toLowerCase().includes(searchTerm)) {
show = false;
}
// Category filter
if (categoryFilter && dish.dataset.category !== categoryFilter) {
show = false;
}
// Availability filter
if (availabilityFilter) {
const isAvailable = dish.dataset.available === 'true';
if ((availabilityFilter === 'available' && !isAvailable) ||
(availabilityFilter === 'unavailable' && isAvailable)) {
show = false;
}
}
// Price filter
if (priceFilter) {
const price = parseInt(dish.dataset.price);
if (priceFilter === '0-100' && (price < 0 || price > 100)) show = false;
if (priceFilter === '100-300' && (price < 100 || price > 300)) show = false;
if (priceFilter === '300+' && price < 300) show = false;
}
dish.style.display = show ? 'block' : 'none';
if (show) visibleCount++;
});
document.getElementById('no-dishes').style.display = visibleCount === 0 ? 'block' : 'none';
}
function clearFilters() {
document.getElementById('searchInput').value = '';
document.getElementById('categoryFilter').value = '';
document.getElementById('availabilityFilter').value = '';
document.getElementById('priceFilter').value = '';
filterDishes();
}
function addNewDish() {
editingDishId = null;
document.getElementById('dishModalTitle').innerHTML = '<i class="fas fa-plus me-2"></i>Add New Dish';
document.getElementById('dishForm').reset();
document.getElementById('isAvailable').checked = true;
new bootstrap.Modal(document.getElementById('dishModal')).show();
}
function editDish(dishId) {
editingDishId = dishId;
document.getElementById('dishModalTitle').innerHTML = '<i class="fas fa-edit me-2"></i>Edit Dish';
// In production, this would fetch dish data from API
// For demo, populating with sample data
document.getElementById('dishName').value = 'Chicken Biryani';
document.getElementById('dishCategory').value = 'main-course';
document.getElementById('dishPrice').value = '250';
document.getElementById('cookingTime').value = '30';
document.getElementById('dishDescription').value = 'Aromatic basmati rice cooked with tender chicken and traditional spices';
document.getElementById('isAvailable').checked = true;
new bootstrap.Modal(document.getElementById('dishModal')).show();
}
function saveDish() {
const name = document.getElementById('dishName').value;
const category = document.getElementById('dishCategory').value;
const price = document.getElementById('dishPrice').value;
if (!name || !category || !price) {
alert('Please fill in all required fields');
return;
}
const action = editingDishId ? 'updated' : 'added';
alert(`Dish ${action} successfully! (In production, this would save to the database)`);
bootstrap.Modal.getInstance(document.getElementById('dishModal')).hide();
// In production, refresh the dishes list
}
function toggleAvailability(dishId) {
if (confirm('Toggle dish availability?')) {
alert(`Dish availability toggled! (In production, this would update the database)`);
// In production, update the UI to reflect the change
}
}
function deleteDish(dishId) {
if (confirm('Are you sure you want to delete this dish? This action cannot be undone.')) {
alert(`Dish deleted! (In production, this would remove from database)`);
// In production, remove the dish element from the DOM
}
}
function exportDishes() {
alert('Export dishes feature - would generate CSV/Excel file with all dish data');
}
// File upload preview
document.getElementById('dishImage').addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
console.log('Image selected:', file.name);
// In production, show image preview
}
});
</script>
{% endblock %}