lokesh341's picture
Update templates/menu.html
56e8c68 verified
raw
history blame
87.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Menu</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
<!-- Preload Critical Resources -->
<link rel="preload" href="/static/placeholder.jpg" as="image">
{% for section, items in ordered_menu.items() %}
{% for item in items[:1] %}
<link rel="preload" href="{{ item.Image1__c }}" as="image" fetchpriority="high">
{% endfor %}
{% endfor %}
<style>
body {
font-family: Arial, sans-serif;
background-color: #fdf4e3;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
}
.container {
max-width: 900px;
}
.menu-card {
max-width: 350px;
border-radius: 15px;
overflow: hidden;
background-color: #fff;
margin: auto;
display: flex;
flex-direction: column;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.menu-card.visible {
opacity: 1;
}
/* Video Container Styles */
.video-container {
position: relative;
width: 100%;
height: 200px;
overflow: hidden;
border-radius: 15px 15px 0 0;
background-color: #000;
}
.video-container video {
width: 100%;
height: 100%;
object-fit: cover;
transition: opacity 0.5s ease;
}
.video-container .video-placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: #f0f0f0;
color: #666;
font-size: 14px;
}
.video-container .play-button {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50px;
height: 50px;
background-color: rgba(0, 0, 0, 0.7);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 10;
opacity: 0;
transition: opacity 0.3s ease;
}
.video-container:hover .play-button {
opacity: 1;
}
.video-container .play-button i {
color: white;
font-size: 20px;
margin-left: 3px;
}
.card-title {
font-size: 1.2rem;
font-weight: bold;
margin: 10px 0;
}
.card-text {
font-size: 1rem;
color: #6c757d;
}
.addbutton .btn {
background-color: #28a745;
color: white;
padding: 10px 20px;
font-size: 16px;
font-weight: bold;
border-radius: 5px;
border: none;
transition: background-color 0.3s ease;
margin-left: 13px;
}
.addbutton .btn:hover {
background-color: #218838;
}
.button-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
}
.customisable-text {
color: #0FAA39;
font-size: 10px;
font-weight: 500;
margin: 0;
text-align: center;
line-height: 1;
}
.btn-primary {
font-size: 12px;
font-weight: bold;
border-radius: 8px;
width: 70px;
height: 35px;
background-color: #0FAA39;
border-color: #0FAA39;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
transition: background-color 0.3s ease, transform 0.1s ease;
}
.btn-primary:hover {
background-color: #0D9232;
border-color: #0D9232;
transform: scale(1.05);
}
.btn-primary:active,
.btn-primary:focus {
background-color: #0B7A29;
border-color: #0B7A29;
box-shadow: none;
transform: scale(0.98);
}
.view-cart-container {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 999;
display: flex;
align-items: center;
}
.view-cart-button {
background-color: #0FAA39;
color: #fff;
padding: 10px 20px;
border-radius: 30px;
font-size: 1rem;
font-weight: bold;
text-decoration: none;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
transition: background-color 0.3s ease, transform 0.2s ease;
}
.view-cart-button:hover {
background-color: #109835;
text-decoration: none;
color: #fff;
transform: scale(1.05);
}
.cart-icon-badge {
background-color: #fff;
color: #0FAA39;
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
margin-left: 5px;
transition: background-color 0.3s ease, color 0.3s ease;
}
.cart-icon-badge.active {
background-color: #ffcc00;
color: #0FAA39;
}
.avatar-dropdown-container {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: right;
justify-content: center;
}
.avatar-icon {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #5bbfc1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
font-weight: bold;
}
.dropdown-menu {
position: absolute;
right: 0;
top: 100%;
background-color: #fff;
border-radius: 5px;
width: 220px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
display: none;
}
.dropdown-menu .dropdown-item {
padding: 12px 16px;
text-decoration: none;
color: #333;
border-bottom: 1px solid #ddd;
display: block;
font-size: 15px;
}
.dropdown-menu .dropdown-item:last-child {
border-bottom: none;
}
.dropdown-menu .dropdown-item:hover {
background-color: #f1f1f1;
}
.fixed-top-bar {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 54px;
background: linear-gradient(45deg, #FFA07A, #FFB347);
color: white;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 1000;
}
.search-bar-container {
position: absolute;
left: 20px;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: center;
width: 300px;
max-width: 90%;
}
.search-bar-container input {
width: 100%;
padding: 8px 15px 8px 40px;
font-size: 16px;
border-radius: 25px;
border: none;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
outline: none;
}
.search-bar-container input::placeholder {
color: #888;
}
.search-icon {
position: absolute;
left: 15px;
font-size: 18px;
color: #888;
}
.autocomplete-suggestions {
position: absolute;
top: 100%;
left: 0;
width: 100%;
max-height: 200px;
overflow-y: auto;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
z-index: 1000;
display: none;
}
.autocomplete-suggestions .suggestion-item {
padding: 8px 15px;
cursor: pointer;
font-size: 14px;
color: #333;
}
.autocomplete-suggestions .suggestion-item:hover {
background-color: #f1f1f1;
}
.addon-section {
background-color: #fff;
border: 2px solid #6c757d;
border-radius: 8px;
padding: 12px;
margin-bottom: 10px;
}
.addon-section h6 {
margin-bottom: 10px;
font-size: 1.1rem;
font-weight: bold;
color: #343a40;
}
.addon-section .form-check {
display: inline-flex;
align-items: center;
margin-left: 10px;
color: #343a40;
}
.addon-section .form-check-input {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border: 2px solid #343a40;
border-radius: 5px;
background-color: #f0f0f0;
position: relative;
margin-right: 10px;
}
.addon-section .form-check-input:checked {
background-color: #006400;
border-color: #006400;
}
.addon-section .form-check-input:checked::before {
content: '\2713';
font-size: 14px;
position: absolute;
top: 3px;
left: 4px;
color: white;
}
.addon-section .form-check-label {
font-size: 16px;
margin-left: 5px;
margin-right: 15px;
cursor: pointer;
display: inline-block;
vertical-align: middle;
}
form.text-center.mb-4 {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 5px;
}
.modal-header {
padding: 10px 15px;
}
.modal-title {
font-size: 16px;
font-weight: bold;
}
.modal-body {
max-height: 60vh;
overflow-y: auto;
padding: 15px;
}
.modal-body #modal-img {
max-height: 200px;
width: 100%;
object-fit: cover;
border-radius: 8px;
margin-bottom: 10px;
}
.modal-body #modal-name {
font-size: 20px;
font-weight: bold;
text-align: center;
margin-bottom: 5px;
}
.modal-body #modal-price {
font-size: 16px;
font-weight: bold;
color: #6c757d;
text-align: center;
margin-bottom: 10px;
}
.modal-body #modal-description {
font-size: 14px;
color: #6c757d;
margin-bottom: 10px;
}
.modal-body .nutritional-info {
font-size: 12px;
color: #6c757d;
margin-bottom: 10px;
}
.modal-body #modal-addons h6,
.modal-body #first-row h6 {
font-size: 14px;
font-weight: bold;
margin-bottom: 10px;
}
.modal-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
}
.modal-footer .d-flex {
display: flex;
align-items: center;
gap: 10px;
}
.modal-footer .btn {
height: 40px;
padding: 0 15px;
}
.modal-footer .form-control {
width: 50px;
height: 40px;
text-align: center;
}
.modal-footer .btn-primary {
background-color: #0FAA39;
border-color: #0FAA39;
font-weight: bold;
padding: 10px 20px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
width: auto;
}
.modal-footer .btn-outline-secondary {
height: 40px;
width: 40px;
}
.item-details {
background-color: #f8f9fa;
border-radius: 8px;
padding: 10px;
margin: 10px 15px;
display: none;
}
.item-details.show {
display: block;
}
.item-details h6 {
font-size: 0.9rem;
font-weight: bold;
margin-bottom: 5px;
}
.item-details p {
font-size: 0.85rem;
margin-bottom: 5px;
color: #333;
}
.item-details .nutritional-info {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
background-color: #e9ecef;
padding: 10px;
border-radius: 5px;
font-size: 0.85rem;
line-height: 1.5;
}
.toggle-details {
cursor: pointer;
color: #0FAA39;
font-size: 0.9rem;
margin-left: 15px;
margin-bottom: 10px;
display: inline-block;
}
.toggle-details:hover {
text-decoration: underline;
}
.category-buttons {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
margin-top: 10px;
}
.category-button {
background-color: #fff;
border: 2px solid #0FAA39;
color: #0FAA39;
padding: 5px 15px;
border-radius: 20px;
font-size: 0.9rem;
cursor: pointer;
transition: background-color 0.3s, color 0.3s;
}
.category-button.selected {
background-color: #0FAA39;
color: #fff;
border-color: #0FAA39;
}
.category-button:hover {
background-color: #e6f4ea;
}
.quantity-selector {
display: flex;
align-items: center;
gap: 5px;
}
.quantity-selector .btn {
width: 25px;
height: 25px;
padding: 0;
font-size: 12px;
line-height: 25px;
text-align: center;
}
.quantity-selector .quantity-display {
width: 25px;
text-align: center;
font-size: 12px;
font-weight: bold;
line-height: 25px;
}
.quantity-selector .quantity-to-add,
.quantity-selector .quantity-to-remove {
width: 45px;
height: 25px;
font-size: 12px;
padding: 0 5px;
}
.modal-dialog {
max-height: 90vh;
}
.modal-body::-webkit-scrollbar {
width: 8px;
}
.modal-body::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.modal-body::-webkit-scrollbar-thumb {
background: #0FAA39;
border-radius: 10px;
}
.modal-body::-webkit-scrollbar-thumb:hover {
background: #0D9232;
}
@media (max-width: 576px) {
.fixed-top-bar {
height: 60px;
padding: 10px;
}
.search-bar-container {
width: 80%;
max-width: 100%;
left: 10px;
top: 50%;
transform: translateY(-50%);
}
.search-bar-container input {
padding: 6px 12px 6px 35px;
font-size: 14px;
border-radius: 20px;
}
.search-icon {
left: 12px;
font-size: 16px;
}
.avatar-dropdown-container {
right: 10px;
}
.avatar-icon {
width: 40px;
height: 40px;
font-size: 20px;
}
.dropdown-menu {
width: 220px;
}
.dropdown-menu .dropdown-item {
padding: 12px 16px;
font-size: 15px;
}
.category-buttons {
gap: 8px;
}
.category-button {
padding: 4px 12px;
font-size: 0.85rem;
}
.modal-dialog {
max-width: 96%;
margin: 5px auto;
}
.modal-header {
padding: 5px 10px;
}
.modal-title {
font-size: 14px;
}
.modal-body {
max-height: 50vh;
padding: 8px;
}
.modal-body #modal-img {
max-height: 150px;
width: 100%;
max-width: 150px;
margin: 0 auto 5px;
display: block;
}
.modal-body #modal-name {
font-size: 18px;
margin-bottom: 3px;
}
.modal-body #modal-price {
font-size: 14px;
margin-bottom: 5px;
}
.modal-body #modal-description {
font-size: 12px;
margin-bottom: 5px;
}
.modal-body .nutritional-info {
font-size: 10px;
margin-bottom: 5px;
}
.modal-body #modal-addons h6,
.modal-body #first-row h6 {
font-size: 12px;
margin-bottom: 5px;
}
.modal-footer {
padding: 5px;
}
.modal-footer .btn {
height: 30px;
padding: 0 10px;
}
.modal-footer .form-control {
width: 30px;
height: 30px;
font-size: 12px;
font-weight: bold;
}
.modal-footer .btn-outline-secondary {
width: 25px;
height: 25px;
font-size: 12px;
line-height: 25px;
}
.modal-footer .btn-primary {
font-size: 12px;
height: 30px;
padding: 0 15px;
border-radius: 5px;
}
.btn-primary {
font-size: 10px;
width: 50px;
height: 25px;
}
.customisable-text {
font-size: 8px;
}
.button-container {
gap: 3px;
}
.quantity-selector .btn {
width: 18px;
height: 18px;
font-size: 9px;
line-height: 18px;
}
.quantity-selector .quantity-display {
width: 18px;
font-size: 9px;
line-height: 18px;
}
.quantity-selector .quantity-to-add,
.quantity-selector .quantity-to-remove {
width: 35px;
height: 18px;
font-size: 9px;
}
.view-cart-button {
padding: 8px 16px;
font-size: 14px;
}
.cart-icon-badge {
width: 20px;
height: 20px;
font-size: 10px;
}
/* Mobile video adjustments */
.video-container {
height: 150px;
}
}
</style>
</head>
<body>
<div class="fixed-top-bar">
<div class="avatar-dropdown-container">
<div class="avatar-icon">
<span>{{ first_letter }}</span>
</div>
<div class="dropdown-menu">
<a href="{{ url_for('user_details.customer_details') }}" class="dropdown-item">View Profile</a>
<a href="{{ url_for('orderhistory.order_history') }}" class="dropdown-item">Order History</a>
<a href="{{ url_for('logout') }}" class="dropdown-item">Logout</a>
</div>
</div>
<div class="search-bar-container">
<input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off">
<i class="bi bi-search search-icon"></i>
<div id="autocompleteSuggestions" class="autocomplete-suggestions"></div>
</div>
</div>
<form method="get" action="/menu" class="text-center mb-4" id="categoryForm">
<label class="form-label fw-bold">Select a Category:</label>
<div class="category-buttons">
{% for category in categories %}
<button type="button" class="category-button {% if selected_category == category %}selected{% endif %}" data-category="{{ category }}">{{ category }}</button>
{% endfor %}
<button type="button" class="category-button {% if selected_category == 'Customized Dish' %}selected{% endif %}" data-category="Customized Dish">Customized Dish</button>
</div>
<input type="hidden" name="category" id="selectedCategoryInput" value="{{ selected_category }}">
</form>
<div class="container mt-4">
{% if selected_category == "Customized Dish" %}
<div id="custom-dish-form" class="mt-4">
<h3>Create Your Custom Dish</h3>
<form method="POST" action="/customdish/generate_custom_dish">
<div class="mb-3">
<label for="custom-dish-name" class="form-label">Dish Name</label>
<input type="text" class="form-control" id="custom-dish-name" name="name" required>
</div>
<div class="mb-3 position-relative">
<label for="custom-dish-description" class="form-label">Dish Description</label>
<textarea class="form-control" id="custom-dish-description" name="description" required></textarea>
<div id="descriptionSuggestions" class="autocomplete-suggestions"></div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
{% else %}
{% for section, items in ordered_menu.items() %}
<h3>{{ section }}</h3>
<div class="row">
{% for item in items %}
<div class="col-md-6 mb-4">
<div class="card menu-card">
<div class="video-container">
<video
id="video-{{ loop.index }}"
preload="metadata"
poster="{{ item.Image1__c if item.Image1__c else '/static/placeholder.jpg' }}"
data-src="{{ item.Video1__c }}"
muted
loop
>
<source src="{{ item.Video1__c }}" type="video/mp4">
Your browser does not support the video tag.
</video>
{% if not item.Video1__c %}
<div class="video-placeholder">
No video available
</div>
{% endif %}
<div class="play-button" onclick="togglePlay(this)">
<i class="bi bi-play-fill"></i>
</div>
</div>
<div class="addbutton">
<div class="card-body d-flex align-items-center justify-content-between">
<div>
<h5 class="card-title">{{ item.Name }}</h5>
<p class="card-text">${{ item.Price__c }}</p>
</div>
<div class="d-flex flex-column align-item-center justify-content-center">
<div class="button-container" data-item-name="{{ item.Name }}" data-item-price="{{ item.Price__c }}" data-item-image="{{ item.Image1__c }}" data-item-section="{{ item.Section__c }}" data-item-category="{{ selected_category }}">
{% if item.Section__c == 'Soft Drinks' %}
<button class="btn btn-primary add-to-cart-btn" onclick="handleSoftDrinkAdd(this)">ADD</button>
<div class="quantity-selector" style="display: none;">
<button class="btn btn-outline-secondary decrease-btn" onclick="decreaseQuantity(this)">-</button>
<select class="quantity-to-remove">
{% for i in range(1, 21) %}
<option value="{{ i }}">{{ i }}</option>
{% endfor %}
</select>
<span class="quantity-display">0</span>
<button class="btn btn-outline-secondary increase-btn" onclick="increaseQuantity(this)">+</button>
<select class="quantity-to-add">
{% for i in range(1, 21) %}
<option value="{{ i }}">{{ i }}</option>
{% endfor %}
</select>
</div>
{% else %}
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#itemModal"
onclick="showItemDetails('{{ item.Name }}', '{{ item.Price__c }}', '{{ item.Image2__c }}', '{{ item.Description__c }}', '{{ item.Section__c }}','{{ selected_category }}')">
ADD
</button>
{% endif %}
{% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' and item.Section__c !='Soft Drinks' %}
<span class="customisable-text">Customisable</span>
{% endif %}
</div>
</div>
</div>
</div>
<div class="toggle-details" data-item-name="{{ item.Name }}">Show Details</div>
<div class="item-details" id="details-{{ item.Name | replace(' ', '-') }}"></div>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
{% endif %}
</div>
<div class="view-cart-container">
<a href="{{ url_for('cart.cart') }}" class="view-cart-button">
<i class="bi bi-cart"></i>
view Cart
<span id="cart-item-count" class="cart-icon-badge {% if cart_item_count > 0 %}active{% endif %}">
{{ cart_item_count if cart_item_count > 0 else '' }}
</span>
</a>
</div>
<div class="modal fade" id="itemModal" tabindex="-1" aria-labelledby="itemModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="itemModalLabel">Item Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<img id="modal-img" class="img-fluid rounded mb-3 d-block mx-auto" alt="Item Image">
<h5 id="modal-name" class="fw-bold text-center"></h5>
<p id="modal-price" class="text-muted text-center"></p>
<p id="modal-description" class="text-secondary"></p>
<p class="nutritional-info" id="modal-nutritional-info"></p>
<div id="first-row">
<h6 id="first-row-title" style="display: none;">Customization Options</h6>
<div class="addon-section">
<h6>Choose Preparation Style</h6>
<div id="prep-style-options"></div>
</div>
<div class="addon-section">
<h6>Type</h6>
<div id="type-options"></div>
</div>
<div class="addon-section">
<h6>Spice Level</h6>
<div id="spice-level-options"></div>
</div>
</div>
<div id="modal-addons" class="modal-addons mt-4">
<h6 id="addons-title">Customization Options</h6>
<div id="addons-list" class="addons-container">Loading customization options...</div>
</div>
<div class="mt-4">
<h6>Custom Request</h6>
<textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
</div>
<span id="modal-section" data-section="" data-category="" style="display: none;"></span>
</div>
<div class="modal-footer d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center gap-2">
<button type="button" class="btn btn-outline-secondary" id="decreaseQuantity">-</button>
<input type="text" class="form-control text-center" id="quantityInput" value="1" readonly style="width: 50px;"/>
<button type="button" class="btn btn-outline-secondary" id="increaseQuantity">+</button>
</div>
<button type="button" class="btn btn-primary" onclick="addToCartFromModal()">Add to Cart</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Video Handling Functions
function togglePlay(button) {
const videoContainer = button.closest('.video-container');
const video = videoContainer.querySelector('video');
if (video.paused) {
// Load video source if not already loaded
if (!video.src && video.dataset.src) {
video.src = video.dataset.src;
}
video.play()
.then(() => {
button.innerHTML = '<i class="bi bi-pause-fill"></i>';
})
.catch(e => {
console.log('Video play error:', e);
// Show error to user if needed
});
} else {
video.pause();
button.innerHTML = '<i class="bi bi-play-fill"></i>';
}
}
// Dynamically populate menuItems from ordered_menu
const menuItems = [
{% for section, items in ordered_menu.items() %}
{% for item in items %}
"{{ item.Name }}",
{% endfor %}
{% endfor %}
];
const ingredientsList = [
"Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
"Chickpea Flour (Besan)", "Chickpea Flour (for batter)", "Chickpeas (Channa)", "Chili Powder",
"Chili Sauce", "Coconut Milk", "Coriander Powder", "Cornflour", "Cream", "Cumin Powder",
"Cumin Seeds", "Curd (Yogurt)", "Curry Leaves", "Fish (e.g., King Fish or Salmon)",
"Fresh Coriander Leaves", "Garam Masala", "Garlic", "Ghee (Clarified Butter)", "Ginger",
"Ginger-Garlic Paste", "Goat Meat (Mutton)", "Green Chilies", "Honey",
"Kasuri Methi (dried fenugreek leaves)", "Lemon Juice", "Mango Puree", "Mint Leaves",
"Mixed Vegetables (Carrot, Peas, Potato, Cauliflower)", "Mixed Vegetables (Carrot, Peas, Potato)",
"Mustard Seeds", "Mutton (Goat Meat)", "Oil", "Oil (for frying)", "Onion",
"Paneer (Indian Cottage Cheese)", "Peas", "Potatoes", "Prawns", "Red Chili Powder",
"Rice Flour", "Saffron", "Salt", "Soy Sauce", "Spring Onion", "Tamarind (for sourness)",
"Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
"Whole Wheat Flour", "Yogurt (Curd)"
];
const menuItemDetails = {
"Veg Manchurian": {
ingredients: "Cauliflower, Onion, Ginger, Garlic, Soy Sauce, Cornflour, Green Chilies, Capsicum, Spring Onion",
nutritionalInfo: { calories: 250, protein: 5, carbs: 35, fats: 12, fiber: 3, sugar: 2 },
allergens: "Soy, Gluten"
},
"Veg Biryani": {
ingredients: "Basmati Rice, Mixed Vegetables (Carrot, Peas, Potato, Cauliflower), Ginger, Garlic, Biryani Masala, Mint Leaves, Curd, Onion, Ghee",
nutritionalInfo: { calories: 300, protein: 6, carbs: 50, fats: 12, fiber: 5, sugar: 3 },
allergens: "Dairy"
},
"Sukka Gosht (Goat)": {
ingredients: "Goat Meat, Ginger-Garlic Paste, Green Chilies, Onion, Tomatoes, Garam Masala, Coriander Powder, Cumin Powder, Fresh Coriander",
nutritionalInfo: { calories: 450, protein: 35, carbs: 10, fats: 30, fiber: 2, sugar: 1 },
allergens: "None"
},
"Samosa": {
ingredients: "Potatoes, Peas, Onion, Ginger, Cumin Seeds, Garam Masala, Wheat Flour (for dough), Oil (for frying)",
nutritionalInfo: { calories: 150, protein: 3, carbs: 25, fats: 7, fiber: 2, sugar: 1 },
allergens: "Gluten"
},
"Roti": {
ingredients: "Whole Wheat Flour, Water, Salt",
nutritionalInfo: { calories: 150, protein: 4, carbs: 30, fats: 1, fiber: 3, sugar: 0 },
allergens: "Gluten"
},
"Prawn Fry": {
ingredients: "Prawns, Garlic, Ginger, Chili Powder, Coriander Powder, Cumin Powder, Lemon Juice, Oil",
nutritionalInfo: { calories: 350, protein: 25, carbs: 10, fats: 20, fiber: 1, sugar: 1 },
allergens: "Shellfish"
},
"Paneer Butter Masala": {
ingredients: "Paneer, Butter, Cream, Tomato Puree, Onion, Ginger, Garlic, Garam Masala",
nutritionalInfo: { calories: 400, protein: 15, carbs: 20, fats: 25, fiber: 2, sugar: 3 },
allergens: "Dairy"
},
"Paneer Biryani": {
ingredients: "Paneer, Basmati Rice, Mixed Vegetables (Carrot, Peas, Potato), Onion, Tomatoes, Biryani Masala, Mint Leaves, Curd",
nutritionalInfo: { calories: 350, protein: 12, carbs: 55, fats: 15, fiber: 4, sugar: 3 },
allergens: "Dairy"
},
"Onion Pakoda": {
ingredients: "Onion, Chickpea Flour (Besan), Rice Flour, Green Chilies, Cumin Seeds, Ginger, Turmeric Powder, Oil (for frying)",
nutritionalInfo: { calories: 200, protein: 5, carbs: 30, fats: 8, fiber: 3, sugar: 2 },
allergens: "Gluten (if cross-contamination)"
},
"Mutton Biryani": {
ingredients: "Mutton, Basmati Rice, Onion, Tomatoes, Ginger-Garlic Paste, Biryani Masala, Mint Leaves, Yogurt, Ghee",
nutritionalInfo: { calories: 500, protein: 30, carbs: 50, fats: 25, fiber: 4, sugar: 3 },
allergens: "Dairy"
},
"Fish Curry": {
ingredients: "Fish (any firm fish like Salmon or King Fish), Onion, Tomato, Ginger-Garlic Paste, Curry Leaves, Coconut Milk, Tamarind, Mustard Seeds",
nutritionalInfo: { calories: 300, protein: 25, carbs: 10, fats: 20, fiber: 2, sugar: 1 },
allergens: "Fish"
},
"Fiery Mango Glaze Chicken": {
ingredients: "Chicken, Mango Puree, Chili Sauce, Soy Sauce, Honey, Garlic, Ginger, Lemon Juice",
nutritionalInfo: { calories: 350, protein: 30, carbs: 15, fats: 18, fiber: 1, sugar: 5 },
allergens: "Soy"
},
"Chilli Gobi": {
ingredients: "Cauliflower, Onion, Green Chilies, Soy Sauce, Cornflour, Garlic, Ginger, Cumin Powder",
nutritionalInfo: { calories: 250, protein: 6, carbs: 35, fats: 12, fiber: 3, sugar: 2 },
allergens: "Soy, Gluten"
},
"Chilli Chicken": {
ingredients: "Chicken, Bell Pepper, Onion, Green Chilies, Soy Sauce, Cornflour, Garlic, Ginger",
nutritionalInfo: { calories: 400, protein: 35, carbs: 20, fats: 18, fiber: 2, sugar: 2 },
allergens: "Soy, Gluten"
},
"Chicken Manchurian": {
ingredients: "Chicken, Onion, Garlic, Ginger, Soy Sauce, Cornflour, Green Chilies, Capsicum",
nutritionalInfo: { calories: 350, protein: 25, carbs: 20, fats: 18, fiber: 2, sugar: 2 },
allergens: "Soy, Gluten"
},
"Chicken Curry": {
ingredients: "Chicken, Onion, Tomatoes, Ginger-Garlic Paste, Garam Masala, Coconut Milk, Coriander Leaves",
nutritionalInfo: { calories: 350, protein: 28, carbs: 15, fats: 12, fiber: 4, sugar: 2 },
allergens: "None"
},
"Chicken Biryani": {
ingredients: "Chicken, Basmati Rice, Onion, Tomatoes, Ginger-Garlic Paste, Biryani Masala, Mint Leaves, Curd",
nutritionalInfo: { calories: 500, protein: 35, carbs: 60, fats: 20, fiber: 5, sugar: 3 },
allergens: "Dairy"
},
"Channa Masala": {
ingredients: "Chickpeas, Onion, Tomatoes, Ginger-Garlic Paste, Garam Masala, Coriander Powder, Cumin Seeds, Lemon Juice",
nutritionalInfo: { calories: 250, protein: 10, carbs: 45, fats: 5, fiber: 6, sugar: 2 },
allergens: "None"
}
};
function addToCartLocalStorage(payload) {
let cart = JSON.parse(localStorage.getItem('cart')) || [];
const existingItem = cart.find(item =>
item.itemName === payload.itemName &&
item.instructions === payload.instructions &&
JSON.stringify(item.addons) === JSON.stringify(payload.addons)
);
if (existingItem) {
existingItem.quantity += payload.quantity;
} else {
cart.push(payload);
}
localStorage.setItem('cart', JSON.stringify(cart));
return cart;
}
function removeFromCartLocalStorage(itemName, quantityToRemove, instructions, addons) {
let cart = JSON.parse(localStorage.getItem('cart')) || [];
const itemIndex = cart.findIndex(item =>
item.itemName === itemName &&
item.instructions === instructions &&
JSON.stringify(item.addons) === JSON.stringify(addons)
);
if (itemIndex !== -1) {
if (quantityToRemove >= cart[itemIndex].quantity) {
cart.splice(itemIndex, 1);
} else {
cart[itemIndex].quantity -= quantityToRemove;
}
}
localStorage.setItem('cart', JSON.stringify(cart));
return cart;
}
function getCartLocalStorage() {
return JSON.parse(localStorage.getItem('cart')) || [];
}
document.addEventListener('DOMContentLoaded', function () {
// Initialize video handling
const videoContainers = document.querySelectorAll('.video-container');
videoContainers.forEach(container => {
const video = container.querySelector('video');
// Only load video when container is in viewport
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && video.dataset.src && !video.src) {
video.src = video.dataset.src;
observer.unobserve(entry.target);
}
});
}, {
rootMargin: '200px',
threshold: 0.1
});
observer.observe(container);
// Handle hover play/pause
container.addEventListener('mouseenter', () => {
if (video.src) {
video.play().catch(e => console.log('Autoplay prevented:', e));
}
});
container.addEventListener('mouseleave', () => {
if (!video.paused) {
video.pause();
const playButton = container.querySelector('.play-button');
if (playButton) {
playButton.innerHTML = '<i class="bi bi-play-fill"></i>';
}
}
});
});
const avatarContainer = document.querySelector('.avatar-dropdown-container');
const dropdownMenu = document.querySelector('.dropdown-menu');
avatarContainer.addEventListener('click', function (event) {
event.stopPropagation();
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
});
document.addEventListener('click', function (event) {
if (!avatarContainer.contains(event.target)) {
dropdownMenu.style.display = 'none';
}
});
const dropdownItems = document.querySelectorAll('.dropdown-item');
dropdownItems.forEach(item => {
item.addEventListener('click', function () {
dropdownMenu.style.display = 'none';
});
});
const menuCards = document.querySelectorAll('.menu-card');
menuCards.forEach(card => {
const itemName = card.querySelector('.card-title').innerText;
const detailsDiv = card.querySelector('.item-details');
const detailsData = menuItemDetails[itemName];
if (detailsData) {
detailsDiv.innerHTML = `
<h6>Ingredients</h6>
<p>${detailsData.ingredients}</p>
<h6>Nutritional Info</h6>
<div class="nutritional-info">
<span>Calories: ${detailsData.nutritionalInfo.calories} kcal</span>
<span>Carbs: ${detailsData.nutritionalInfo.carbs}g</span>
<span>Protein: ${detailsData.nutritionalInfo.protein}g</span>
<span>Fats: ${detailsData.nutritionalInfo.fats}g</span>
</div>
<h6>Allergens</h6>
<p>${detailsData.allergens}</p>
`;
} else {
detailsDiv.innerHTML = '<p>No details available for this item.</p>';
}
});
const cardObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, {
root: null,
rootMargin: '0px',
threshold: 0.1
});
menuCards.forEach(card => cardObserver.observe(card));
const toggleLinks = document.querySelectorAll('.toggle-details');
toggleLinks.forEach(link => {
link.addEventListener('click', function () {
const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
const detailsDiv = document.getElementById(`details-${itemName}`);
detailsDiv.classList.toggle('show');
this.innerText = detailsDiv.classList.contains('show') ? 'Hide Details' : 'Show Details';
});
});
const categoryButtons = document.querySelectorAll('.category-button');
const categoryForm = document.getElementById('categoryForm');
const selectedCategoryInput = document.getElementById('selectedCategoryInput');
if (!selectedCategoryInput.value) {
selectedCategoryInput.value = "All";
document.querySelector('.category-button[data-category="All"]').classList.add('selected');
}
categoryButtons.forEach(button => {
button.addEventListener('click', function () {
categoryButtons.forEach(btn => btn.classList.remove('selected'));
this.classList.add('selected');
selectedCategoryInput.value = this.getAttribute('data-category');
categoryForm.submit();
});
});
const searchBar = document.getElementById('searchBar');
const suggestionsContainer = document.getElementById('autocompleteSuggestions');
searchBar.addEventListener('input', function () {
const input = this.value.trim().toLowerCase();
suggestionsContainer.innerHTML = '';
suggestionsContainer.style.display = 'none';
if (input) {
const filteredItems = menuItems.filter(item =>
item.toLowerCase().includes(input)
);
if (filteredItems.length > 0) {
filteredItems.forEach(item => {
const suggestionDiv = document.createElement('div');
suggestionDiv.classList.add('suggestion-item');
suggestionDiv.innerText = item;
suggestionDiv.addEventListener('click', function () {
searchBar.value = item;
suggestionsContainer.style.display = 'none';
filterMenu();
});
suggestionsContainer.appendChild(suggestionDiv);
});
suggestionsContainer.style.display = 'block';
}
}
filterMenu();
});
document.addEventListener('click', function (event) {
if (!searchBar.contains(event.target) && !suggestionsContainer.contains(event.target)) {
suggestionsContainer.style.display = 'none';
}
});
const descriptionTextarea = document.getElementById('custom-dish-description');
const descriptionSuggestions = document.getElementById('descriptionSuggestions');
if (descriptionTextarea && descriptionSuggestions) {
let usedIngredients = new Set();
function updateUsedIngredients() {
const inputText = descriptionTextarea.value.trim();
usedIngredients.clear();
if (inputText) {
const words = inputText.split(/,\s*/).map(word => word.trim());
words.forEach(word => {
if (word && ingredientsList.includes(word)) {
usedIngredients.add(word);
}
});
}
}
descriptionTextarea.addEventListener('input', function () {
const inputText = this.value.trim();
const words = inputText.split(/,\s*/);
const lastWord = words[words.length - 1].trim().toLowerCase();
descriptionSuggestions.innerHTML = '';
descriptionSuggestions.style.display = 'none';
updateUsedIngredients();
if (lastWord) {
const filteredIngredients = ingredientsList.filter(ingredient =>
ingredient.toLowerCase().includes(lastWord) && !usedIngredients.has(ingredient)
);
if (filteredIngredients.length > 0) {
filteredIngredients.forEach(ingredient => {
const suggestionDiv = document.createElement('div');
suggestionDiv.classList.add('suggestion-item');
suggestionDiv.innerText = ingredient;
suggestionDiv.addEventListener('click', function () {
const currentValue = descriptionTextarea.value;
const lastCommaIndex = currentValue.lastIndexOf(',');
const baseText = lastCommaIndex !== -1 ? currentValue.substring(0, lastCommaIndex + 1) : '';
descriptionTextarea.value = baseText + (baseText ? ' ' : '') + ingredient + ', ';
descriptionSuggestions.style.display = 'none';
descriptionTextarea.focus();
updateUsedIngredients();
});
descriptionSuggestions.appendChild(suggestionDiv);
});
descriptionSuggestions.style.display = 'block';
}
}
});
document.addEventListener('click', function (event) {
if (!descriptionTextarea.contains(event.target) && !descriptionSuggestions.contains(event.target)) {
descriptionSuggestions.style.display = 'none';
}
});
}
fetch('/cart/get')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
updateCartUI(data.cart);
} else {
console.error('Failed to fetch cart:', data.error);
const cart = getCartLocalStorage();
updateCartUI(cart);
}
})
.catch(err => {
console.error('Error fetching cart:', err);
const cart = getCartLocalStorage();
updateCartUI(cart);
});
const preloadedImages = document.querySelectorAll('link[rel="preload"]');
preloadedImages.forEach(link => {
const img = new Image();
img.src = link.href;
});
const decreaseBtn = document.getElementById('decreaseQuantity');
const increaseBtn = document.getElementById('increaseQuantity');
const quantityInput = document.getElementById('quantityInput');
decreaseBtn.addEventListener('click', function () {
let currentQuantity = parseInt(quantityInput.value);
if (currentQuantity > 1) {
currentQuantity--;
quantityInput.value = currentQuantity;
}
});
increaseBtn.addEventListener('click', function () {
let currentQuantity = parseInt(quantityInput.value);
currentQuantity++;
quantityInput.value = currentQuantity;
});
});
function debounce(func, wait) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
function filterMenu() {
const input = document.getElementById('searchBar').value.trim().toLowerCase();
const sections = document.querySelectorAll('h3');
const items = document.querySelectorAll('.menu-card');
let matchedSections = new Set();
items.forEach(item => {
const itemName = item.querySelector('.card-title').innerText.toLowerCase();
const itemSection = item.closest('.row').previousElementSibling.innerText.toLowerCase();
if (itemName.includes(input) || (itemSection && itemSection.includes(input))) {
item.style.display = 'block';
item.classList.add('visible');
matchedSections.add(item.closest('.row'));
} else {
item.style.display = 'none';
}
});
sections.forEach(section => {
const sectionRow = section.nextElementSibling;
if (matchedSections.has(sectionRow)) {
section.style.display = 'block';
sectionRow.style.display = 'flex';
} else {
section.style.display = 'none';
sectionRow.style.display = 'none';
}
});
if (!input) {
sections.forEach(section => {
section.style.display = 'block';
section.nextElementSibling.style.display = 'flex';
});
items.forEach(item => {
item.style.display = 'block';
item.classList.add('visible');
});
}
}
function showItemDetails(name, price, image, description, section, selectedCategory) {
document.getElementById('modal-name').innerText = name;
document.getElementById('modal-price').innerText = `$${price}`;
const modalImg = document.getElementById('modal-img');
if (section.toLowerCase() === 'soft drinks') {
modalImg.style.display = 'none';
} else {
modalImg.style.display = 'block';
modalImg.src = image || '/static/placeholder.jpg';
}
document.getElementById('modal-description').innerText = description || 'No description available.';
const nutritionalInfoEl = document.getElementById('modal-nutritional-info');
const itemDetails = menuItemDetails[name];
if (itemDetails && itemDetails.nutritionalInfo) {
const { calories, protein, carbs, fats, fiber, sugar } = itemDetails.nutritionalInfo;
nutritionalInfoEl.innerText = `[Energy: ${calories} kcal, Protein: ${protein}g, Carbohydrates: ${carbs}g, Fiber: ${fiber}g, Fat: ${fats}g, Sugar: ${sugar}g]`;
} else {
nutritionalInfoEl.innerText = '[No nutritional info available.]';
}
document.getElementById('addons-list').innerHTML = 'Loading customization options...';
document.getElementById('modal-instructions').value = '';
const modalSectionEl = document.getElementById('modal-section');
modalSectionEl.setAttribute('data-section', section);
modalSectionEl.setAttribute('data-category', selectedCategory);
document.getElementById('quantityInput').value = 1;
const prepStyleOptions = document.getElementById('prep-style-options');
const typeOptions = document.getElementById('type-options');
const spiceLevelOptions = document.getElementById('spice-level-options');
const firstRow = document.getElementById('first-row');
const firstRowTitle = document.getElementById('first-row-title');
const addonsTitle = document.getElementById('addons-title');
prepStyleOptions.innerHTML = '';
typeOptions.innerHTML = '';
spiceLevelOptions.innerHTML = '';
if (section.toLowerCase() === 'starters') {
firstRow.style.display = 'block';
firstRowTitle.style.display = 'block';
addonsTitle.style.display = 'none';
} else {
firstRow.style.display = 'none';
firstRowTitle.style.display = 'none';
addonsTitle.style.display = 'block';
}
const addonsList = document.getElementById('addons-list');
addonsList.innerHTML = '';
const dummySections = [
{ name: "Beverages", options: ["Sprite ($3)", "Thums Up ($3)", "Virgin Mojito ($3)", "Lemonade ($3)", "Blue Lagoon Mocktail ($3)"] },
{ name: "Sauces", options: ["Mint Chutney", "Tomato Sauce"] },
{ name: "Extra Toppings", options: ["Cheese ($2)", "Olives ($1)", "Jalapenos ($1)", "Mushrooms ($2)", "Peppers ($1)"] },
{ name: "Sides", options: ["Fries ($3)", "Salad ($2)", "Garlic Bread ($3)", "Onion Rings ($2)", "Coleslaw ($2)"] },
{ name: "Desserts", options: ["Ice Cream ($3)", "Brownie ($3)", "Cheesecake ($4)", "Gulab Jamun ($3)", "Rasmalai ($4)"] }
];
dummySections.forEach(addon => {
const sectionDiv = document.createElement('div');
sectionDiv.classList.add('addon-section');
sectionDiv.setAttribute('data-addon-name', addon.name);
const title = document.createElement('h6');
title.innerText = addon.name;
sectionDiv.appendChild(title);
const optionsContainer = document.createElement('div');
addon.options.forEach((option, index) => {
const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
const listItem = document.createElement('div');
listItem.classList.add('form-check');
listItem.innerHTML = `
<input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
data-name="${option}" data-group="${addon.name}" data-price="0">
<label class="form-check-label" for="${optionId}">
${option}
</label>
`;
optionsContainer.appendChild(listItem);
});
sectionDiv.appendChild(optionsContainer);
addonsList.appendChild(sectionDiv);
});
fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
.then(response => response.json())
.then(data => {
const addonsList = document.getElementById('addons-list');
addonsList.innerHTML = '';
if (!data.success || !data.addons || data.addons.length === 0) {
addonsList.innerHTML = '<p>No customization options available.</p>';
addonsTitle.style.display = 'none';
return;
}
if (section.toLowerCase() === 'starters') {
data.addons.forEach(addon => {
if (addon.name.toLowerCase() === "choose preparation style") {
addon.options.forEach(option => {
const optionId = `addon-prep-style-${option}`;
const optionHTML = `
<div class="form-check">
<input type="checkbox" class="form-check-input" id="${optionId}" value="${option}" data-name="${option}" data-group="Choose Preparation Style">
<label class="form-check-label" for="${optionId}">
${option}
</label>
</div>
`;
prepStyleOptions.innerHTML += optionHTML;
});
}
if (addon.name.toLowerCase() === "type") {
addon.options.forEach(option => {
const optionId = `addon-type-${option}`;
const optionHTML = `
<div class="form-check">
<input type="checkbox" class="form-check-input" id="${optionId}" value="${option}" data-name="${option}" data-group="Type">
<label class="form-check-label" for="${optionId}">
${option}
</label>
</div>
`;
typeOptions.innerHTML += optionHTML;
});
}
if (addon.name.toLowerCase() === "spice level") {
addon.options.forEach(option => {
const optionId = `addon-spice-level-${option}`;
const optionHTML = `
<div class="form-check">
<input type="checkbox" class="form-check-input spice-level-option" id="${optionId}" value="${option}" data-name="${option}" data-group="Spice Level">
<label class="form-check-label" for="${optionId}">
${option}
</label>
</div>
`;
spiceLevelOptions.innerHTML += optionHTML;
});
}
});
}
data.addons.forEach(addon => {
if (section.toLowerCase() === 'starters' &&
(addon.name.toLowerCase() === "type" ||
addon.name.toLowerCase() === "spice level" ||
addon.name.toLowerCase() === "choose preparation style")) {
return;
}
const sectionDiv = document.createElement('div');
sectionDiv.classList.add('addon-section');
sectionDiv.setAttribute('data-addon-name', addon.name);
const title = document.createElement('h6');
title.innerText = addon.name;
sectionDiv.appendChild(title);
const optionsContainer = document.createElement('div');
addon.options.forEach((option, index) => {
const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
const listItem = document.createElement('div');
listItem.classList.add('form-check');
listItem.innerHTML = `
<input type="checkbox" class="form-check-input ${addon.name.toLowerCase() === 'spice level' ? 'spice-level-option' : 'addon-option'}" id="${optionId}" value="${option}"
data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}">
<label class="form-check-label" for="${optionId}">
${option} ${addon.extra_charge ? `($${addon.extra_charge_amount})` : ''}
</label>
`;
optionsContainer.appendChild(listItem);
});
sectionDiv.appendChild(optionsContainer);
addonsList.appendChild(sectionDiv);
});
const startersOrder = [
"Select Dip/Sauce",
"Extra Add-ons",
"Make it a Combo"
];
const desiredOrder = [
"Spice Level",
"Choose Preparation Style",
"Select Dip/Sauce",
"Extra Add-ons",
"Make it a Combo",
"Type"
];
const orderToUse = section.toLowerCase() === 'starters' ? startersOrder : desiredOrder;
const sections = Array.from(addonsList.children);
addonsList.innerHTML = '';
orderToUse.forEach(sectionName => {
const section = sections.find(s => s.getAttribute('data-addon-name') === sectionName);
if (section) {
addonsList.appendChild(section);
}
});
sections.forEach(section => {
if (!orderToUse.includes(section.getAttribute('data-addon-name'))) {
addonsList.appendChild(section);
}
});
})
.catch(err => {
console.error('Error fetching add-ons:', err);
document.getElementById('addons-list').innerHTML = '<p>Error loading customization options.</p>';
addonsTitle.style.display = 'none';
});
}
document.addEventListener('click', function(event) {
if (event.target.classList.contains('spice-level-option') || event.target.classList.contains('addon-option')) {
handleAddonClick(event.target);
}
});
function handleAddonClick(checkbox) {
const groupName = checkbox.getAttribute('data-group');
const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo", "Beverages", "Sauces"].includes(groupName);
if (groupName.toLowerCase() === "spice level") {
const allSpiceLevelCheckboxes = document.querySelectorAll('.spice-level-option');
allSpiceLevelCheckboxes.forEach(otherCheckbox => {
if (otherCheckbox !== checkbox) {
otherCheckbox.checked = false;
}
});
}
else if (!isMultiSelectGroup) {
const checkboxes = document.querySelectorAll(`.addon-option[data-group="${groupName}"]`);
checkboxes.forEach(otherCheckbox => {
if (otherCheckbox !== checkbox) {
otherCheckbox.checked = false;
}
});
}
}
function addToCartFromModal() {
const itemName = document.getElementById('modal-name').innerText;
let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
if (isNaN(itemPrice)) {
alert('Invalid price for the item. Please check the item details.');
return;
}
const itemImage = document.getElementById('modal-img').src;
const modalSectionEl = document.getElementById('modal-section');
const section = modalSectionEl.getAttribute('data-section');
const selectedCategory = modalSectionEl.getAttribute('data-category');
if (!itemName || !itemPrice || !section || !itemImage) {
console.error('Missing data for cart item:', { itemName, itemPrice, section, itemImage});
return;
}
let selectedAddOns = [];
const addonsListOptions = document.querySelectorAll('#addons-list .addon-option');
addonsListOptions.forEach(option => {
if (option.checked) {
selectedAddOns.push({
name: option.getAttribute('data-name') || 'Default Name',
price: parseFloat(option.getAttribute('data-price') || 0)
});
}
});
if (section.toLowerCase() === 'starters') {
const prepStyleOptions = Array.from(
document.querySelectorAll('#prep-style-options input[type="checkbox"]:checked')
).map(option => ({
name: option.getAttribute('data-name') || 'Default Prep Style',
price: 0
}));
const typeOptions = Array.from(
document.querySelectorAll('#type-options input[type="checkbox"]:checked')
).map(option => ({
name: option.getAttribute('data-name') || 'Default Type',
price: 0
}));
const spiceLevelOption = document.querySelector('#spice-level-options input[type="checkbox"].spice-level-option:checked');
const spiceLevelOptions = spiceLevelOption ? [{
name: spiceLevelOption.getAttribute('data-name') || 'Default Spice Level',
price: 0
}] : [];
selectedAddOns = [...selectedAddOns, ...prepStyleOptions, ...typeOptions, ...spiceLevelOptions];
}
const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
const instructions = document.getElementById('modal-instructions').value;
const cartPayload = {
itemName: itemName,
itemPrice: itemPrice,
itemImage: itemImage,
section: section,
category: selectedCategory,
addons: selectedAddOns,
instructions: instructions,
quantity: quantity
};
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(cartPayload)
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
alert('Item added to cart successfully!');
updateCartUI(data.cart);
const modal = document.getElementById('itemModal');
const modalInstance = bootstrap.Modal.getInstance(modal);
modalInstance.hide();
} else {
console.error('Failed to add item to cart:', data.error);
alert(data.error || 'Failed to add item to cart.');
}
})
.catch(err => {
console.error('Error adding item to cart:', err);
alert('An error occurred while adding the item to the cart: ' + err.message);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
const modal = document.getElementById('itemModal');
const modalInstance = bootstrap.Modal.getInstance(modal);
modalInstance.hide();
});
}
function handleSoftDrinkAdd(button) {
const buttonContainer = button.closest('.button-container');
const quantitySelector = buttonContainer.querySelector('.quantity-selector');
const addButton = buttonContainer.querySelector('.add-to-cart-btn');
const quantityDisplay = quantitySelector.querySelector('.quantity-display');
const quantityToAddSelect = quantitySelector.querySelector('.quantity-to-add');
const quantityToAdd = parseInt(quantityToAddSelect.value);
const itemName = buttonContainer.getAttribute('data-item-name');
const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
const itemImage = buttonContainer.getAttribute('data-item-image');
const section = buttonContainer.getAttribute('data-item-section');
const selectedCategory = buttonContainer.getAttribute('data-item-category');
addButton.style.display = 'none';
quantitySelector.style.display = 'flex';
let currentQuantity = parseInt(quantityDisplay.innerText) || 0;
currentQuantity += quantityToAdd;
quantityDisplay.innerText = currentQuantity;
const cartPayload = {
itemName: itemName,
itemPrice: itemPrice,
itemImage: itemImage,
section: section,
category: selectedCategory,
addons: [],
instructions: '',
quantity: quantityToAdd
};
button.disabled = true;
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(cartPayload)
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
alert(`Added ${quantityToAdd} item(s) to cart successfully!`);
updateCartUI(data.cart);
} else {
console.error('Failed to add item to cart:', data.error);
alert(data.error || 'Failed to add item to cart.');
currentQuantity -= quantityToAdd;
quantityDisplay.innerText = currentQuantity;
}
})
.catch(err => {
console.error('Error adding item to cart:', err);
alert('An error occurred while adding the item to the cart: ' + err.message);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
})
.finally(() => {
button.disabled = false;
});
}
function increaseQuantity(button) {
const buttonContainer = button.closest('.button-container');
const quantityDisplay = buttonContainer.querySelector('.quantity-display');
const quantityToAddSelect = buttonContainer.querySelector('.quantity-to-add');
const quantityToAdd = parseInt(quantityToAddSelect.value);
const itemName = buttonContainer.getAttribute('data-item-name');
const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
const itemImage = buttonContainer.getAttribute('data-item-image');
const section = buttonContainer.getAttribute('data-item-section');
const selectedCategory = buttonContainer.getAttribute('data-item-category');
let currentQuantity = parseInt(quantityDisplay.innerText) || 0;
currentQuantity += quantityToAdd;
quantityDisplay.innerText = currentQuantity;
const cartPayload = {
itemName: itemName,
itemPrice: itemPrice,
itemImage: itemImage,
section: section,
category: selectedCategory,
addons: [],
instructions: '',
quantity: quantityToAdd
};
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(cartPayload)
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
alert(`Added ${quantityToAdd} item(s) to cart successfully!`);
updateCartUI(data.cart);
} else {
console.error('Failed to add item to cart:', data.error);
alert(data.error || 'Failed to add item to cart.');
currentQuantity -= quantityToAdd;
quantityDisplay.innerText = currentQuantity;
}
})
.catch(err => {
console.error('Error adding item to cart:', err);
alert('An error occurred while adding the item to the cart: ' + err.message);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
});
}
function decreaseQuantity(button) {
const buttonContainer = button.closest('.button-container');
const quantityDisplay = buttonContainer.querySelector('.quantity-display');
const quantityToRemoveSelect = buttonContainer.querySelector('.quantity-to-remove');
const quantityToRemove = parseInt(quantityToRemoveSelect.value);
const addButton = buttonContainer.querySelector('.add-to-cart-btn');
const quantitySelector = buttonContainer.querySelector('.quantity-selector');
let currentQuantity = parseInt(quantityDisplay.innerText);
if (currentQuantity <= quantityToRemove) {
const itemName = buttonContainer.getAttribute('data-item-name');
fetch(`/cart/remove?item_name=${encodeURIComponent(itemName)}&quantity=${currentQuantity}&instructions=&addons=[]`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
updateCartUI(data.cart);
addButton.style.display = 'block';
quantitySelector.style.display = 'none';
quantityDisplay.innerText = 0;
} else {
console.error('Failed to remove item from cart:', data.error);
alert(data.error || 'Failed to remove item from cart.');
}
})
.catch(err => {
console.error('Error removing item from cart:', err);
alert('An error occurred while removing the item from the cart: ' + err.message);
const cart = removeFromCartLocalStorage(itemName, currentQuantity, '', []);
updateCartUI(cart);
addButton.style.display = 'block';
quantitySelector.style.display = 'none';
quantityDisplay.innerText = 0;
});
} else {
currentQuantity -= quantityToRemove;
quantityDisplay.innerText = currentQuantity;
const itemName = buttonContainer.getAttribute('data-item-name');
fetch(`/cart/remove?item_name=${encodeURIComponent(itemName)}&quantity=${quantityToRemove}&instructions=&addons=[]`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
alert(`Removed ${quantityToRemove} item(s) from cart successfully!`);
updateCartUI(data.cart);
} else {
console.error('Failed to remove item from cart:', data.error);
alert(data.error || 'Failed to remove item from cart.');
currentQuantity += quantityToRemove;
quantityDisplay.innerText = currentQuantity;
}
})
.catch(err => {
console.error('Error removing item from cart:', err);
alert('An error occurred while removing the item from the cart: ' + err.message);
const cart = removeFromCartLocalStorage(itemName, quantityToRemove, '', []);
updateCartUI(cart);
});
}
}
function updateCartUI(cart) {
if (!Array.isArray(cart)) {
console.error('Invalid cart data:', cart);
return;
}
// Calculate total quantity of items in cart
let totalQuantity = 0;
cart.forEach(item => {
totalQuantity += item.quantity;
});
// Update cart item count badge
const cartItemCount = document.getElementById('cart-item-count');
if (cartItemCount) {
cartItemCount.innerText = totalQuantity;
if (totalQuantity > 0) {
cartItemCount.classList.add('active');
} else {
cartItemCount.classList.remove('active');
}
}
// Update quantity displays for soft drinks
const buttonContainers = document.querySelectorAll('.button-container');
buttonContainers.forEach(container => {
const itemName = container.getAttribute('data-item-name');
const quantityDisplay = container.querySelector('.quantity-display');
const addButton = container.querySelector('.add-to-cart-btn');
const quantitySelector = container.querySelector('.quantity-selector');
const cartItem = cart.find(item =>
item.itemName === itemName &&
item.instructions === '' &&
JSON.stringify(item.addons) === JSON.stringify([])
);
if (cartItem && cartItem.quantity > 0) {
quantityDisplay.innerText = cartItem.quantity;
addButton.style.display = 'none';
quantitySelector.style.display = 'flex';
} else {
quantityDisplay.innerText = 0;
addButton.style.display = 'block';
quantitySelector.style.display = 'none';
}
});
}
</script>
</body>
</html>