lokesh341 commited on
Commit
3927896
·
verified ·
1 Parent(s): 6ec77cb

Update templates/menu.html

Browse files
Files changed (1) hide show
  1. templates/menu.html +367 -610
templates/menu.html CHANGED
@@ -15,7 +15,6 @@
15
  {% endfor %}
16
  {% endfor %}
17
  <style>
18
- /* Same styles as previous response */
19
  body {
20
  font-family: Arial, sans-serif;
21
  background-color: #fdf4e3;
@@ -42,7 +41,6 @@
42
  }
43
  .menu-card.visible {
44
  opacity: 1;
45
- animation: fadeIn 0.3s ease-in-out;
46
  }
47
  .menu-card.highlighted {
48
  border: 3px solid #0FAA39;
@@ -496,100 +494,59 @@
496
  #softDrinkModal .modal-footer .quantity-controls-footer .btn:active {
497
  transform: scale(0.95);
498
  }
499
- /* Toggle Styling */
 
 
 
 
 
 
 
 
 
 
 
 
 
500
  .toggle-container {
501
- display: inline-flex;
502
  align-items: center;
503
- margin: 0 15px;
504
- gap: 8px;
505
  }
506
  .custom-toggle {
507
- -webkit-appearance: none;
508
- -moz-appearance: none;
509
  appearance: none;
510
- width: 40px;
511
- height: 20px;
512
- background: #e9ecef;
513
- border-radius: 20px;
514
  position: relative;
515
  cursor: pointer;
516
- outline: none;
517
- transition: background-color 0.2s ease;
518
  }
519
  .custom-toggle:checked {
520
- background: #0FAA39;
521
  }
522
  .custom-toggle::before {
523
  content: '';
524
  position: absolute;
525
- width: 16px;
526
- height: 16px;
527
- border-radius: 50%;
528
- background: #fff;
529
  top: 2px;
530
  left: 2px;
531
- transition: transform 0.2s ease;
 
 
 
 
 
532
  }
533
  .custom-toggle:checked::before {
534
- transform: translateX(20px);
535
  }
536
  .toggle-container label {
537
  font-size: 1rem;
538
- font-weight: 500;
539
  color: #333;
540
  cursor: pointer;
541
  }
542
- #filter-form {
543
- display: flex;
544
- flex-direction: column;
545
- align-items: center;
546
- gap: 10px;
547
- margin-bottom: 20px;
548
- }
549
- #filter-form .form-label {
550
- font-size: 1.2rem;
551
- color: #333;
552
- }
553
- .toast-container {
554
- position: fixed;
555
- top: 20px;
556
- right: 20px;
557
- z-index: 2000;
558
- }
559
- .toast {
560
- background-color: #dc3545;
561
- color: white;
562
- padding: 15px;
563
- border-radius: 5px;
564
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
565
- opacity: 0;
566
- transition: opacity 0.3s ease;
567
- }
568
- .toast.show {
569
- opacity: 1;
570
- }
571
- .search-suggestions {
572
- position: absolute;
573
- top: 100%;
574
- left: 0;
575
- right: 0;
576
- background-color: #fff;
577
- border-radius: 5px;
578
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
579
- max-height: 200px;
580
- overflow-y: auto;
581
- display: none;
582
- z-index: 1000;
583
- }
584
- .search-suggestions .suggestion-item {
585
- padding: 10px;
586
- cursor: pointer;
587
- font-size: 14px;
588
- color: #333;
589
- }
590
- .search-suggestions .suggestion-item:hover {
591
- background-color: #e6f4ea;
592
- }
593
  @keyframes checkmark {
594
  from { transform: scale(0); }
595
  to { transform: scale(1); }
@@ -606,13 +563,6 @@
606
  from { opacity: 0; transform: translateY(-20px); }
607
  to { opacity: 1; transform: translateY(0); }
608
  }
609
- form.text-center.mb-4 {
610
- display: flex;
611
- flex-direction: column;
612
- align-items: center;
613
- justify-content: center;
614
- margin-bottom: 5px;
615
- }
616
  .modal-header {
617
  padding: 10px 15px;
618
  }
@@ -859,6 +809,7 @@
859
  font-size: 12px;
860
  margin-left: 8px;
861
  }
 
862
  @media (max-width: 576px) {
863
  .fixed-top-bar {
864
  height: 60px;
@@ -1012,6 +963,7 @@
1012
  font-size: 10px;
1013
  margin-left: 5px;
1014
  }
 
1015
  .addon-section {
1016
  margin-bottom: 10px;
1017
  }
@@ -1040,6 +992,7 @@
1040
  margin-left: 6px;
1041
  font-size: 0.8rem;
1042
  }
 
1043
  #softDrinkModal .modal-dialog {
1044
  max-width: 90%;
1045
  }
@@ -1091,38 +1044,39 @@
1091
  font-size: 1rem;
1092
  line-height: 28px;
1093
  }
 
 
 
 
 
 
 
1094
  .toggle-container {
1095
- margin: 0 10px;
1096
- gap: 6px;
1097
  }
1098
  .custom-toggle {
1099
- width: 36px;
1100
- height: 18px;
1101
  }
1102
  .custom-toggle::before {
1103
- width: 14px;
1104
- height: 14px;
1105
  top: 2px;
1106
  left: 2px;
1107
  }
1108
  .custom-toggle:checked::before {
1109
- transform: translateX(18px);
1110
  }
1111
  .toggle-container label {
1112
  font-size: 0.9rem;
1113
  }
1114
- #filter-form .form-label {
1115
- font-size: 1.1rem;
1116
- }
1117
  }
1118
  </style>
1119
  </head>
1120
  <body>
1121
- <div class="toast-container" id="toastContainer"></div>
1122
-
1123
  <div class="fixed-top-bar">
1124
  <div class="avatar-dropdown-container">
1125
- <div class="avatar-icon" role="button" aria-label="Open user menu">
1126
  <span>{{ first_letter }}</span>
1127
  </div>
1128
  <div class="dropdown-menu">
@@ -1132,59 +1086,59 @@
1132
  </div>
1133
  </div>
1134
  <div class="search-bar-container">
1135
- <input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off" aria-label="Search menu items">
1136
  <i class="bi bi-search search-icon"></i>
1137
- <i class="bi bi-mic mic-icon" id="micIcon" aria-label="Voice search"></i>
1138
- <div class="search-suggestions" id="searchSuggestions"></div>
1139
  </div>
1140
  </div>
1141
 
1142
- <!-- NEW: Updated Filter Form -->
1143
  <form method="get" action="/menu" class="text-center mb-4" id="filter-form">
1144
  <label class="form-label fw-bold">Filters:</label>
1145
  <div class="toggle-container">
 
1146
  <input type="checkbox" id="veg-toggle" name="veg"
1147
- {% if veg_filter %}checked{% endif %}
1148
- class="custom-toggle" onchange="handleToggle('veg')" aria-label="Filter vegetarian items">
 
1149
  <label for="veg-toggle">Veg</label>
1150
  </div>
1151
  <div class="toggle-container">
1152
- <input type="checkbox" id="category-CustomizedDish" name="custom"
1153
- {% if custom_filter %}checked{% endif %}
1154
- class="custom-toggle" onchange="handleToggle('custom')" aria-label="Filter customized dishes">
 
 
1155
  <label for="category-CustomizedDish">Customized Dish</label>
1156
  </div>
1157
  </form>
1158
 
1159
  <div class="container mt-4">
1160
- {% if custom_filter %}
1161
  <div id="custom-dish-form" class="mt-4">
1162
  <h3>Create Your Custom Dish</h3>
1163
  <form method="POST" action="/customdish/generate_custom_dish">
1164
  <div class="mb-3">
1165
  <label for="custom-dish-name" class="form-label">Dish Name</label>
1166
- <input type="text" class="form-control" id="custom-dish-name" name="name" required aria-required="true">
1167
  </div>
1168
  <div class="mb-3 position-relative">
1169
  <label for="custom-dish-description" class="form-label">Dish Description</label>
1170
- <textarea class="form-control" id="custom-dish-description" name="description" required aria-required="true"></textarea>
1171
  <div id="descriptionSuggestions" class="autocomplete-suggestions"></div>
1172
  </div>
1173
- <button type="submit" class="btn btn-primary" aria-label="Submit custom dish">Submit Custom Dish</button>
1174
  </form>
1175
  </div>
1176
  {% else %}
1177
- <!-- NEW: Enhanced Empty State Handling -->
1178
  {% if ordered_menu.items()|length == 0 %}
1179
- <p id="no-items-message">No menu items available for this filter. Please try adjusting the filters or contact support.</p>
1180
- <div id="client-side-menu" class="row"></div>
1181
  {% else %}
1182
  {% for section, items in ordered_menu.items() %}
1183
  <h3>{{ section }}</h3>
1184
  <div class="row">
1185
  {% for item in items %}
1186
  <div class="col-md-6 mb-4">
1187
- <div class="card menu-card" data-item-name="{{ item.Name | default('Unnamed Item') }}" data-item-section="{{ item.Section__c | default(section) }}" data-is-veg="{{ item.IsVeg__c | default('false') | lower }}">
1188
  <video
1189
  class="card-img-top menu-video"
1190
  muted
@@ -1214,16 +1168,14 @@
1214
  data-item-section="{{ item.Section__c | default(section) }}"
1215
  data-item-category="{{ selected_category }}"
1216
  data-item-description="{{ item.Description__c | default('No description') }}"
1217
- data-item-image2="{{ item.Image2__c | default(item.Image1__c) }}"
1218
- data-is-veg="{{ item.IsVeg__c | default('false') | lower }}">
1219
  {% if item.Section__c == 'Soft Drinks' %}
1220
- <button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)" aria-label="Add {{ item.Name | default('Unnamed Item') }} to cart">ADD</button>
1221
  {% else %}
1222
  <button class="btn btn-primary"
1223
  data-bs-toggle="modal"
1224
  data-bs-target="#itemModal"
1225
- onclick="showItemDetails('{{ item.Name | default('Unnamed Item') }}', '{{ item.Price__c | default('0.00') }}', '{{ item.Image2__c | default(item.Image1__c) }}', '{{ item.Description__c | default('No description') }}', '{{ item.Section__c | default(section) }}', '{{ selected_category }}')"
1226
- aria-label="Customize {{ item.Name | default('Unnamed Item') }}">
1227
  ADD
1228
  </button>
1229
  {% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' %}
@@ -1235,12 +1187,12 @@
1235
  </div>
1236
  </div>
1237
  {% if item.Section__c != 'Soft Drinks' %}
1238
- <div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}" role="button" aria-label="Toggle details for {{ item.Name | default('Unnamed Item') }}">Show Details</div>
1239
  <div class="item-details" id="details-{{ item.Name | default('unnamed-item') | replace(' ', '-') }}">
1240
  <h6>Description</h6>
1241
  <p>{{ item.Description__c | default('No description available') }}</p>
1242
  <h6>Ingredients</h6>
1243
- <p>{{ item.Ingredientsinfo__c | default('Not specified') }}</p>
1244
  <h6>Nutritional Info</h6>
1245
  <p class="nutritional-info">{{ item.NutritionalInfo__c | default('Not available') }}</p>
1246
  <h6>Allergens</h6>
@@ -1257,10 +1209,10 @@
1257
  </div>
1258
 
1259
  <div class="bottom-action-bar">
1260
- <a href="{{ url_for('orderhistory.order_history') }}" class="btn btn-order-history" aria-label="View order history">
1261
  <i class="bi bi-clock-history"></i> Order History
1262
  </a>
1263
- <a href="{{ url_for('cart.cart') }}" class="btn btn-view-cart" aria-label="View cart">
1264
  <i class="bi bi-cart"></i> View Cart
1265
  <span id="cart-item-count" class="cart-icon-badge" style="display: none;">0</span>
1266
  </a>
@@ -1285,17 +1237,17 @@
1285
  </div>
1286
  <div class="mt-4">
1287
  <h6>Special Instructions</h6>
1288
- <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..." aria-label="Special instructions"></textarea>
1289
  </div>
1290
  <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
1291
  </div>
1292
  <div class="modal-footer d-flex align-items-center justify-content-between">
1293
  <div class="d-flex align-items-center gap-2">
1294
- <button type="button" class="btn btn-outline-secondary" id="decreaseQuantity" aria-label="Decrease quantity">-</button>
1295
- <input type="text" class="form-control text-center" id="quantityInput" value="1" readonly style="width: 50px;" aria-label="Selected quantity"/>
1296
- <button type="button" class="btn btn-outline-secondary" id="increaseQuantity" aria-label="Increase quantity">+</button>
1297
  </div>
1298
- <button type="button" class="btn btn-primary" onclick="addToCartFromModal()" aria-label="Add to cart">Add to Cart</button>
1299
  </div>
1300
  </div>
1301
  </div>
@@ -1334,30 +1286,19 @@
1334
 
1335
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
1336
  <script>
1337
- // === Global State ===
1338
  let isProcessingRequest = false;
1339
  let currentSoftDrinkButton = null;
1340
  let baseItemPrice = 0;
1341
-
1342
- // === Menu Data ===
1343
  const menuItems = [
1344
  {% for section, items in ordered_menu.items() %}
1345
  {% for item in items %}
1346
  {
1347
  name: "{{ item.Name | default('Unnamed Item') }}",
1348
- section: "{{ item.Section__c | default(section) }}",
1349
- isVeg: {{ item.IsVeg__c | default('false') | lower }},
1350
- price: "{{ item.Price__c | default('0.00') }}",
1351
- image: "{{ item.Image1__c | default('/static/placeholder.jpg') }}",
1352
- image2: "{{ item.Image2__c | default(item.Image1__c) }}",
1353
- description: "{{ item.Description__c | default('No description') }}",
1354
- video: "{{ item.Video1__c | default('/static/placeholder.mp4') }}"
1355
  },
1356
  {% endfor %}
1357
  {% endfor %}
1358
  ];
1359
-
1360
- // === Ingredients for Custom Dish ===
1361
  const ingredientsList = [
1362
  "Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
1363
  "Chickpea Flour (Besan)", "Chickpea Flour (for batter)", "Chickpeas (Channa)", "Chili Powder",
@@ -1373,30 +1314,6 @@
1373
  "Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
1374
  "Whole Wheat Flour", "Yogurt (Curd)"
1375
  ];
1376
-
1377
- // === Utility Functions ===
1378
- function debounce(func, wait) {
1379
- let timeout;
1380
- return function (...args) {
1381
- clearTimeout(timeout);
1382
- timeout = setTimeout(() => func.apply(this, args), wait);
1383
- };
1384
- }
1385
-
1386
- function showToast(message) {
1387
- const toastContainer = document.getElementById('toastContainer');
1388
- const toast = document.createElement('div');
1389
- toast.classList.add('toast');
1390
- toast.innerText = message;
1391
- toastContainer.appendChild(toast);
1392
- setTimeout(() => toast.classList.add('show'), 100);
1393
- setTimeout(() => {
1394
- toast.classList.remove('show');
1395
- setTimeout(() => toast.remove(), 300);
1396
- }, 3000);
1397
- }
1398
-
1399
- // === Cart Functions ===
1400
  function addToCartLocalStorage(payload) {
1401
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
1402
  const existingItem = cart.find(item =>
@@ -1412,7 +1329,6 @@
1412
  localStorage.setItem('cart', JSON.stringify(cart));
1413
  return cart;
1414
  }
1415
-
1416
  function removeFromCartLocalStorage(itemName, quantityToRemove, instructions, addons) {
1417
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
1418
  const itemIndex = cart.findIndex(item =>
@@ -1430,29 +1346,16 @@
1430
  localStorage.setItem('cart', JSON.stringify(cart));
1431
  return cart;
1432
  }
1433
-
1434
  function getCartLocalStorage() {
1435
  return JSON.parse(localStorage.getItem('cart')) || [];
1436
  }
1437
-
1438
- function updateCartUI(cart) {
1439
- if (!Array.isArray(cart)) {
1440
- console.error('Invalid cart data:', cart);
1441
- showToast('Error updating cart');
1442
- return;
1443
- }
1444
- let totalQuantity = 0;
1445
- cart.forEach(item => {
1446
- totalQuantity += item.quantity;
1447
- });
1448
- const cartItemCount = document.getElementById('cart-item-count');
1449
- if (cartItemCount) {
1450
- cartItemCount.innerText = totalQuantity;
1451
- cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
1452
- }
1453
  }
1454
-
1455
- // === Modal Functions ===
1456
  function updateModalPrice() {
1457
  const selectedAddOns = Array.from(
1458
  document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
@@ -1461,14 +1364,12 @@
1461
  const totalPrice = baseItemPrice + totalAddOnPrice;
1462
  document.getElementById('modal-price').innerText = `$${totalPrice.toFixed(2)}`;
1463
  }
1464
-
1465
  function updateSoftDrinkQuantity(delta) {
1466
  const quantityInput = document.getElementById('soft-drink-quantity');
1467
  let currentQuantity = parseInt(quantityInput.value) || 1;
1468
  currentQuantity = Math.max(1, currentQuantity + delta);
1469
  quantityInput.value = currentQuantity;
1470
  }
1471
-
1472
  function showSoftDrinkModal(button) {
1473
  currentSoftDrinkButton = button;
1474
  const buttonContainer = button.closest('.button-container');
@@ -1477,14 +1378,13 @@
1477
  const itemImage = buttonContainer.getAttribute('data-item-image');
1478
 
1479
  document.getElementById('soft-drink-name').textContent = itemName;
1480
- document.getElementById('soft-drink-price').textContent = `$${itemPrice}`;
1481
  document.getElementById('soft-drink-quantity').value = '1';
1482
  document.getElementById('soft-drink-image').src = itemImage || '/static/placeholder.jpg';
1483
 
1484
  const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
1485
  modal.show();
1486
  }
1487
-
1488
  function addSoftDrinkToCart() {
1489
  if (!currentSoftDrinkButton) return;
1490
 
@@ -1523,7 +1423,6 @@
1523
  modal.hide();
1524
  } else {
1525
  console.error('Failed to add item to cart:', data.error);
1526
- showToast('Failed to add item to cart');
1527
  const cart = addToCartLocalStorage(cartPayload);
1528
  updateCartUI(cart);
1529
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
@@ -1532,14 +1431,27 @@
1532
  })
1533
  .catch(err => {
1534
  console.error('Error adding item to cart:', err);
1535
- showToast('Error adding item to cart');
1536
  const cart = addToCartLocalStorage(cartPayload);
1537
  updateCartUI(cart);
1538
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1539
  modal.hide();
1540
  });
1541
  }
1542
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1543
  function showItemDetails(name, price, image, description, section, selectedCategory) {
1544
  document.getElementById('modal-name').innerText = name;
1545
  baseItemPrice = parseFloat(price) || 0;
@@ -1555,91 +1467,79 @@
1555
  modalSectionEl.setAttribute('data-category', selectedCategory);
1556
  document.getElementById('quantityInput').value = 1;
1557
 
1558
- let retryCount = 0;
1559
- const maxRetries = 2;
1560
- function fetchAddons() {
1561
- fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
1562
- .then(response => response.json())
1563
- .then(data => {
1564
- const addonsList = document.getElementById('addons-list');
1565
- addonsList.classList.remove('addon-loading');
1566
- addonsList.innerHTML = '';
1567
- if (!data.success || !data.addons || data.addons.length === 0) {
1568
- addonsList.innerHTML = '<p>No customization options available.</p>';
1569
- return;
1570
- }
1571
-
1572
- data.addons.forEach(addon => {
1573
- const sectionDiv = document.createElement('div');
1574
- sectionDiv.classList.add('addon-section');
1575
- const title = document.createElement('h6');
1576
- title.innerText = addon.name;
1577
- sectionDiv.appendChild(title);
1578
- const optionsContainer = document.createElement('div');
1579
- optionsContainer.classList.add('addon-options');
1580
 
1581
- addon.options.forEach((option, index) => {
1582
- const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
1583
- const listItem = document.createElement('div');
1584
- listItem.classList.add('form-check');
1585
- listItem.innerHTML = `
1586
- <input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
1587
- data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}"
1588
- aria-label="Select ${option} for ${addon.name}">
1589
- <label class="form-check-label" for="${optionId}">
1590
- ${option} ${addon.extra_charge ? `<span class="extra-charge">($${addon.extra_charge_amount.toFixed(2)})</span>` : ''}
1591
- </label>
1592
- `;
1593
- optionsContainer.appendChild(listItem);
1594
- });
1595
 
1596
- sectionDiv.appendChild(optionsContainer);
1597
- addonsList.appendChild(sectionDiv);
 
 
 
 
 
 
 
 
 
 
 
1598
  });
1599
 
1600
- const addonSections = addonsList.querySelectorAll('.addon-section');
1601
- addonSections.forEach(section => {
1602
- const title = section.querySelector('h6');
1603
- const options = section.querySelector('.addon-options');
1604
- title.addEventListener('click', () => {
1605
- section.classList.toggle('collapsed');
1606
- options.classList.toggle('collapsed');
1607
- });
1608
- });
1609
 
1610
- document.querySelectorAll('.addon-option').forEach(checkbox => {
1611
- checkbox.addEventListener('change', updateModalPrice);
 
 
 
 
 
1612
  });
 
1613
 
1614
- document.querySelectorAll('.addon-option').forEach(checkbox => {
1615
- checkbox.addEventListener('change', function () {
1616
- const groupName = this.getAttribute('data-group');
1617
- const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo", "Beverages", "Sauces"].includes(groupName);
1618
- if (!isMultiSelectGroup && this.checked) {
1619
- document.querySelectorAll(`.addon-option[data-group="${groupName}"]`).forEach(otherCheckbox => {
1620
- if (otherCheckbox !== this) {
1621
- otherCheckbox.checked = false;
1622
- }
1623
- });
1624
- }
1625
- });
 
 
 
1626
  });
1627
- })
1628
- .catch(err => {
1629
- console.error('Error fetching add-ons:', err);
1630
- if (retryCount < maxRetries) {
1631
- retryCount++;
1632
- setTimeout(fetchAddons, 1000);
1633
- } else {
1634
- document.getElementById('addons-list').classList.remove('addon-loading');
1635
- document.getElementById('addons-list').innerHTML = '<p>Failed to load customization options. Please try again later.</p>';
1636
- showToast('Error loading customization options');
1637
- }
1638
  });
1639
- }
1640
- fetchAddons();
 
 
 
 
1641
  }
1642
-
1643
  function addToCartFromModal() {
1644
  if (isProcessingRequest) return;
1645
  isProcessingRequest = true;
@@ -1659,7 +1559,7 @@
1659
  }));
1660
  if (!itemName || isNaN(itemPrice) || !section || !itemImage || quantity < 1) {
1661
  console.error('Invalid cart item data:', { itemName, itemPrice, section, itemImage, quantity });
1662
- showToast('Invalid item data. Please try again.');
1663
  isProcessingRequest = false;
1664
  return;
1665
  }
@@ -1688,7 +1588,6 @@
1688
  modal.hide();
1689
  } else {
1690
  console.error('Failed to add item to cart:', data.error);
1691
- showToast('Failed to add item to cart');
1692
  const cart = addToCartLocalStorage(cartPayload);
1693
  updateCartUI(cart);
1694
  const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
@@ -1697,7 +1596,6 @@
1697
  })
1698
  .catch(err => {
1699
  console.error('Error adding item to cart:', err);
1700
- showToast('Error adding item to cart');
1701
  const cart = addToCartLocalStorage(cartPayload);
1702
  updateCartUI(cart);
1703
  const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
@@ -1707,19 +1605,10 @@
1707
  isProcessingRequest = false;
1708
  });
1709
  }
1710
-
1711
- // NEW: Updated Filter Form Logic
1712
  function handleToggle(source) {
1713
  const form = document.getElementById("filter-form");
1714
  const veg = document.getElementById("veg-toggle");
1715
  const custom = document.getElementById("category-CustomizedDish");
1716
-
1717
- if (!form || !veg || !custom) {
1718
- console.error("Form or toggle elements not found");
1719
- showToast("Error applying filter");
1720
- return;
1721
- }
1722
-
1723
  if (source === 'veg') {
1724
  if (veg.checked) {
1725
  custom.checked = false;
@@ -1729,365 +1618,233 @@
1729
  veg.checked = false;
1730
  }
1731
  }
1732
-
1733
- // NEW: Log query parameters for debugging
1734
- const params = new URLSearchParams();
1735
- if (veg.checked) params.set('veg', 'on');
1736
- if (custom.checked) params.set('custom', 'on');
1737
- console.log('Filter form submitting with:', params.toString());
1738
-
1739
  form.submit();
1740
  }
1741
-
1742
- // NEW: Client-Side Filtering for Veg
1743
- function applyClientSideVegFilter() {
1744
- const noItemsMessage = document.getElementById('no-items-message');
1745
- const clientSideMenu = document.getElementById('client-side-menu');
1746
- if (!noItemsMessage || !clientSideMenu) return;
1747
-
1748
- const vegItems = menuItems.filter(item => item.isVeg === true);
1749
- if (vegItems.length > 0) {
1750
- noItemsMessage.innerText = 'Showing vegetarian items (client-side)';
1751
- clientSideMenu.innerHTML = '';
1752
-
1753
- const sections = [...new Set(vegItems.map(item => item.section))];
1754
- sections.forEach(section => {
1755
- const sectionItems = vegItems.filter(item => item.section === section);
1756
- const sectionDiv = document.createElement('div');
1757
- sectionDiv.innerHTML = `<h3>${section}</h3>`;
1758
- const rowDiv = document.createElement('div');
1759
- rowDiv.classList.add('row');
1760
-
1761
- sectionItems.forEach(item => {
1762
- const itemDiv = document.createElement('div');
1763
- itemDiv.classList.add('col-md-6', 'mb-4');
1764
- itemDiv.innerHTML = `
1765
- <div class="card menu-card" data-item-name="${item.name}" data-item-section="${item.section}" data-is-veg="${item.isVeg}">
1766
- <video
1767
- class="card-img-top menu-video"
1768
- muted
1769
- loop
1770
- preload="auto"
1771
- data-src="${item.video}"
1772
- poster="${item.image}"
1773
- width="350"
1774
- height="200"
1775
- onmouseover="this.play()"
1776
- onmouseout="this.pause(); this.currentTime = 0;"
1777
- onerror="this.poster='/static/placeholder.jpg';">
1778
- <source src="${item.video}" type="video/mp4">
1779
- Your browser does not support the video tag.
1780
- </video>
1781
- <div class="addbutton">
1782
- <div class="card-body d-flex align-items-center justify-content-between">
1783
- <div>
1784
- <h5 class="card-title">${item.name}</h5>
1785
- <p class="card-text price">$${item.price}</p>
1786
- </div>
1787
- <div class="d-flex flex-column align-items-center justify-content-center
1788
- <div class="button-container"
1789
- data-item-name="${item.name}"
1790
- data-item-price="${item.price}"
1791
- data-item-image="${item.image}"
1792
- data-item-section="${item.section}"
1793
- data-item-category="Veg"
1794
- data-item-description="${item.description}"
1795
- data-item-image2="${item.image2}"
1796
- data-is-veg="${item.isVeg}">
1797
- <button class="btn btn-primary"
1798
- data-bs-toggle="modal"
1799
- data-bs-target="#itemModal"
1800
- onclick="showItemDetails('${item.name}', '${item.price}', '${item.image2}', '${item.description}', '${item.section}', 'Veg')"
1801
- aria-label="Customize ${item.name}">
1802
- ADD
1803
- </button>
1804
- ${item.section !== 'Apetizer' && item.section !== 'Customized Dish' ? '<span class="customisable-text">Customisable</span>' : ''}
1805
- </div>
1806
- </div>
1807
- </div>
1808
- <div class="toggle-details" data-item-name="${item.name}" role="button" aria-label="Toggle details for ${item.name}">Show Details</div>
1809
- <div class="item-details" id="details-${item.name.replace(/ /g, '-')}">
1810
- <h6>Description</h6>
1811
- <p>${item.description}</p>
1812
- <!-- NEW: Placeholder for ingredients and nutritional info -->
1813
- <h6>Ingredients</h6>
1814
- <p>Not specified</p>
1815
- <h6>Nutritional Info</h6>
1816
- <p class="nutritional-info">Not available</p>
1817
- <h6>Allergens</h6>
1818
- <p>None listed</p>
1819
- </div>
1820
- </div>
1821
- `;
1822
- rowDiv.appendChild(itemDiv);
1823
- });
1824
- sectionDiv.appendChild(rowDiv);
1825
- clientSideMenu.appendChild(sectionDiv);
1826
  });
1827
-
1828
- // NEW: Re-apply Intersection Observers for client-side rendered cards
1829
- const newMenuCards = clientSideMenu.querySelectorAll('.menu-card');
1830
- const newMenuVideos = clientSideMenu.querySelectorAll('.menu-video');
1831
- newMenuCards.forEach(card => cardObserver.observe(card));
1832
- newMenuVideos.forEach(video => videoObserver.observe(video));
1833
-
1834
- // NEW: Re-apply toggle details listeners
1835
- const newToggleLinks = clientSideMenu.querySelectorAll('.toggle-details');
1836
- newToggleLinks.forEach(link => {
1837
- link.addEventListener('click', function () {
1838
- const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
1839
- const detailsDiv = document.getElementById(`details-${itemName}`);
1840
- const isCurrentlyShown = detailsDiv.classList.contains('show');
1841
- document.querySelectorAll('.item-details.show').forEach(otherDetails => {
1842
- if (otherDetails !== detailsDiv) {
1843
- otherDetails.classList.remove('show');
1844
- const otherLink = document.querySelector(`.toggle-details[data-item-name="${otherDetails.id.replace('details-', '').replace(/-/g, ' ')}"]`);
1845
- if (otherLink) {
1846
- otherLink.innerText = 'Show Details';
1847
- }
 
 
1848
  }
1849
- });
1850
- if (!isCurrentlyShown) {
1851
- detailsDiv.classList.add('show');
1852
- this.innerText = 'Hide Details';
1853
- } else {
1854
- detailsDiv.classList.remove('show');
1855
- this.innerText = 'Show Details';
1856
  }
1857
  });
1858
- });
1859
- } else {
1860
- noItemsMessage.innerText = 'No vegetarian items available. Please try adjusting the filters or contact support.';
1861
- }
1862
- }
1863
-
1864
- // NEW: Apply client-side filter if no items are returned
1865
- if (document.getElementById('no-items-message')) {
1866
- applyClientSideVegFilter();
1867
- }
1868
-
1869
- // === Search Functionality ===
1870
- const searchBar = document.getElementById('searchBar');
1871
- const searchSuggestions = document.getElementById('searchSuggestions');
1872
- const debouncedSearch = debounce(function () {
1873
- const query = searchBar.value.trim().toLowerCase();
1874
- searchSuggestions.innerHTML = '';
1875
- searchSuggestions.style.display = 'none';
1876
- if (query.length >= 2) {
1877
- const filteredItems = menuItems.filter(item =>
1878
- item.name.toLowerCase().includes(query) ||
1879
- item.section.toLowerCase().includes(query) ||
1880
- item.description.toLowerCase().includes(query)
1881
- );
1882
- if (filteredItems.length > 0) {
1883
- filteredItems.forEach(item => {
1884
- const suggestionDiv = document.createElement('div');
1885
- suggestionDiv.classList.add('suggestion-item');
1886
- suggestionDiv.innerText = item.name;
1887
- suggestionDiv.addEventListener('click', () => {
1888
- searchBar.value = item.name;
1889
- searchSuggestions.style.display = 'none';
1890
- window.location.href = '/search';
1891
- });
1892
- searchSuggestions.appendChild(suggestionDiv);
1893
- });
1894
- searchSuggestions.style.display = 'block';
1895
- }
1896
- }
1897
- }, 300);
1898
- searchBar.addEventListener('input', debouncedSearch);
1899
- document.addEventListener('click', function (event) {
1900
- if (!searchBar.contains(event.target) && !searchSuggestions.contains(event.target)) {
1901
- searchSuggestions.style.display = 'none';
1902
- }
1903
- });
1904
-
1905
- // === Dropdown Menu ===
1906
- const avatarIcon = document.querySelector('.avatar-icon');
1907
- const dropdownMenu = document.querySelector('.dropdown-menu');
1908
- avatarIcon.addEventListener('click', function () {
1909
- dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
1910
- });
1911
- document.addEventListener('click', function (event) {
1912
- if (!avatarIcon.contains(event.target) && !dropdownMenu.contains(event.target)) {
1913
- dropdownMenu.style.display = 'none';
1914
- }
1915
- });
1916
-
1917
- // === Intersection Observers ===
1918
- const menuCards = document.querySelectorAll('.menu-card');
1919
- const menuVideos = document.querySelectorAll('.menu-video');
1920
- const cardObserver = new IntersectionObserver((entries, observer) => {
1921
- entries.forEach(entry => {
1922
- if (entry.isIntersecting) {
1923
- entry.target.classList.add('visible');
1924
- observer.unobserve(entry.target);
1925
- }
1926
- });
1927
- }, {
1928
- root: null,
1929
- rootMargin: '0px',
1930
- threshold: 0.1
1931
- });
1932
- const videoObserver = new IntersectionObserver((entries, observer) => {
1933
- entries.forEach(entry => {
1934
- if (entry.isIntersecting) {
1935
- const video = entry.target;
1936
- const src = video.getAttribute('data-src');
1937
- if (src && src !== '/static/placeholder.mp4') {
1938
- const source = video.querySelector('source');
1939
- if (source && !source.src) {
1940
- source.src = src;
1941
- video.load().catch(err => {
1942
- console.error('Error loading video:', err);
1943
- video.poster = '/static/placeholder.jpg';
1944
- });
1945
  }
1946
- } else {
1947
- video.poster = '/static/placeholder.jpg';
1948
  }
1949
- video.classList.add('loaded');
1950
- observer.unobserve(video);
1951
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1952
  });
1953
- }, {
1954
- root: null,
1955
- rootMargin: '200px',
1956
- threshold: 0.01
1957
- });
1958
- menuCards.forEach(card => cardObserver.observe(card));
1959
- menuVideos.forEach(video => videoObserver.observe(video));
1960
-
1961
- // === Toggle Details ===
1962
- const toggleLinks = document.querySelectorAll('.toggle-details');
1963
- toggleLinks.forEach(link => {
1964
- link.addEventListener('click', function () {
1965
- const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
1966
- const detailsDiv = document.getElementById(`details-${itemName}`);
1967
- const isCurrentlyShown = detailsDiv.classList.contains('show');
1968
- document.querySelectorAll('.item-details.show').forEach(otherDetails => {
1969
- if (otherDetails !== detailsDiv) {
1970
- otherDetails.classList.remove('show');
1971
- const otherLink = document.querySelector(`.toggle-details[data-item-name="${otherDetails.id.replace('details-', '').replace(/-/g, ' ')}"]`);
1972
- if (otherLink) {
1973
- otherLink.innerText = 'Show Details';
1974
  }
 
 
1975
  }
1976
  });
1977
- if (!isCurrentlyShown) {
1978
- detailsDiv.classList.add('show');
1979
- this.innerText = 'Hide Details';
1980
- } else {
1981
- detailsDiv.classList.remove('show');
1982
- this.innerText = 'Show Details';
1983
- }
1984
  });
1985
- });
1986
-
1987
- // === Custom Dish Form Suggestions ===
1988
- const descriptionTextarea = document.getElementById('custom-dish-description');
1989
- const descriptionSuggestions = document.getElementById('descriptionSuggestions');
1990
- if (descriptionTextarea && descriptionSuggestions) {
1991
- let usedIngredients = new Set();
1992
- function updateUsedIngredients() {
1993
- const inputText = descriptionTextarea.value.trim();
1994
- usedIngredients.clear();
1995
- if (inputText) {
1996
- const words = inputText.split(/,\s*/).map(word => word.trim());
1997
- words.forEach(word => {
1998
- if (word && ingredientsList.includes(word)) {
1999
- usedIngredients.add(word);
2000
  }
2001
  });
2002
- }
2003
- }
2004
- const debouncedSuggestions = debounce(function () {
2005
- const inputText = descriptionTextarea.value.trim();
2006
- const words = inputText.split(/,\s*/);
2007
- const lastWord = words[words.length - 1].trim().toLowerCase();
2008
- descriptionSuggestions.innerHTML = '';
2009
- descriptionSuggestions.style.display = 'none';
2010
- updateUsedIngredients();
2011
- if (lastWord) {
2012
- const filteredIngredients = ingredientsList.filter(ingredient =>
2013
- ingredient.toLowerCase().includes(lastWord) && !usedIngredients.has(ingredient)
2014
- );
2015
- if (filteredIngredients.length > 0) {
2016
- filteredIngredients.forEach(ingredient => {
2017
- const suggestionDiv = document.createElement('div');
2018
- suggestionDiv.classList.add('suggestion-item');
2019
- suggestionDiv.innerText = ingredient;
2020
- suggestionDiv.addEventListener('click', function () {
2021
- const currentValue = descriptionTextarea.value;
2022
- const lastCommaIndex = currentValue.lastIndexOf(',');
2023
- const baseText = lastCommaIndex !== -1 ? currentValue.substring(0, lastCommaIndex + 1) : '';
2024
- descriptionTextarea.value = baseText + (baseText ? ' ' : '') + ingredient + ', ';
2025
- descriptionSuggestions.style.display = 'none';
2026
- descriptionTextarea.focus();
2027
- updateUsedIngredients();
2028
- });
2029
- descriptionSuggestions.appendChild(suggestionDiv);
2030
  });
2031
- descriptionSuggestions.style.display = 'block';
2032
  }
2033
  }
2034
- }, 300);
2035
- descriptionTextarea.addEventListener('input', debouncedSuggestions);
2036
- document.addEventListener('click', function (event) {
2037
- if (!descriptionTextarea.contains(event.target) && !descriptionSuggestions.contains(event.target)) {
 
2038
  descriptionSuggestions.style.display = 'none';
2039
- }
2040
- });
2041
- }
2042
-
2043
- // === Fetch Initial Cart ===
2044
- fetch('/cart/get')
2045
- .then(response => {
2046
- if (!response.ok) {
2047
- throw new Error(`HTTP error! Status: ${response.status}`);
2048
- }
2049
- return response.json();
2050
- })
2051
- .then(data => {
2052
- if (data.success) {
2053
- updateCartUI(data.cart);
2054
- } else {
2055
- console.error('Failed to fetch cart:', data.error);
2056
- showToast('Failed to load cart');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2057
  const cart = getCartLocalStorage();
2058
  updateCartUI(cart);
2059
- }
2060
- })
2061
- .catch(err => {
2062
- console.error('Error fetching cart:', err);
2063
- showToast('Error loading cart');
2064
- const cart = getCartLocalStorage();
2065
- updateCartUI(cart);
 
 
 
 
 
 
 
 
 
 
 
 
2066
  });
2067
-
2068
- // === Quantity Controls for Item Modal ===
2069
- const decreaseBtn = document.getElementById('decreaseQuantity');
2070
- const increaseBtn = document.getElementById('increaseQuantity');
2071
- const quantityInput = document.getElementById('quantityInput');
2072
- decreaseBtn.addEventListener('click', function () {
2073
- let quantity = parseInt(quantityInput.value) || 1;
2074
- quantity = Math.max(1, quantity - 1);
2075
- quantityInput.value = quantity;
2076
- });
2077
- increaseBtn.addEventListener('click', function () {
2078
- let quantity = parseInt(quantityInput.value) || 1;
2079
- quantity += 1;
2080
- quantityInput.value = quantity;
2081
- });
2082
-
2083
- // === Keyboard Accessibility for Search Bar ===
2084
- searchBar.addEventListener('keydown', function (e) {
2085
- if (e.key === 'Enter' && searchBar.value.trim()) {
2086
- window.location.href = '/search';
2087
- }
2088
  });
2089
- });
2090
  </script>
2091
  </body>
2092
- </html>
2093
-
 
15
  {% endfor %}
16
  {% endfor %}
17
  <style>
 
18
  body {
19
  font-family: Arial, sans-serif;
20
  background-color: #fdf4e3;
 
41
  }
42
  .menu-card.visible {
43
  opacity: 1;
 
44
  }
45
  .menu-card.highlighted {
46
  border: 3px solid #0FAA39;
 
494
  #softDrinkModal .modal-footer .quantity-controls-footer .btn:active {
495
  transform: scale(0.95);
496
  }
497
+ /* Filter Form Styling */
498
+ #filter-form {
499
+ display: flex;
500
+ flex-direction: column;
501
+ align-items: center;
502
+ justify-content: center;
503
+ margin-bottom: 20px;
504
+ }
505
+ .form-label {
506
+ font-size: 1.2rem;
507
+ font-weight: 600;
508
+ color: #333;
509
+ margin-bottom: 10px;
510
+ }
511
  .toggle-container {
512
+ display: flex;
513
  align-items: center;
514
+ gap: 10px;
515
+ margin: 8px 0;
516
  }
517
  .custom-toggle {
 
 
518
  appearance: none;
519
+ width: 48px;
520
+ height: 24px;
521
+ background-color: #ccc;
522
+ border-radius: 12px;
523
  position: relative;
524
  cursor: pointer;
525
+ transition: background-color 0.3s ease;
 
526
  }
527
  .custom-toggle:checked {
528
+ background: linear-gradient(45deg, #FFA07A, #FFB347);
529
  }
530
  .custom-toggle::before {
531
  content: '';
532
  position: absolute;
 
 
 
 
533
  top: 2px;
534
  left: 2px;
535
+ width: 20px;
536
+ height: 20px;
537
+ background-color: #fff;
538
+ border-radius: 50%;
539
+ transition: transform 0.3s ease;
540
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
541
  }
542
  .custom-toggle:checked::before {
543
+ transform: translateX(24px);
544
  }
545
  .toggle-container label {
546
  font-size: 1rem;
 
547
  color: #333;
548
  cursor: pointer;
549
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
550
  @keyframes checkmark {
551
  from { transform: scale(0); }
552
  to { transform: scale(1); }
 
563
  from { opacity: 0; transform: translateY(-20px); }
564
  to { opacity: 1; transform: translateY(0); }
565
  }
 
 
 
 
 
 
 
566
  .modal-header {
567
  padding: 10px 15px;
568
  }
 
809
  font-size: 12px;
810
  margin-left: 8px;
811
  }
812
+ /* Mobile-Specific Styles */
813
  @media (max-width: 576px) {
814
  .fixed-top-bar {
815
  height: 60px;
 
963
  font-size: 10px;
964
  margin-left: 5px;
965
  }
966
+ /* Mobile-Specific Addon Styles */
967
  .addon-section {
968
  margin-bottom: 10px;
969
  }
 
992
  margin-left: 6px;
993
  font-size: 0.8rem;
994
  }
995
+ /* Mobile-Specific Soft Drinks Modal Styles */
996
  #softDrinkModal .modal-dialog {
997
  max-width: 90%;
998
  }
 
1044
  font-size: 1rem;
1045
  line-height: 28px;
1046
  }
1047
+ /* Mobile-Specific Filter Form Styles */
1048
+ #filter-form {
1049
+ margin-bottom: 15px;
1050
+ }
1051
+ .form-label {
1052
+ font-size: 1rem;
1053
+ }
1054
  .toggle-container {
1055
+ margin: 6px 0;
 
1056
  }
1057
  .custom-toggle {
1058
+ width: 40px;
1059
+ height: 20px;
1060
  }
1061
  .custom-toggle::before {
1062
+ width: 16px;
1063
+ height: 16px;
1064
  top: 2px;
1065
  left: 2px;
1066
  }
1067
  .custom-toggle:checked::before {
1068
+ transform: translateX(20px);
1069
  }
1070
  .toggle-container label {
1071
  font-size: 0.9rem;
1072
  }
 
 
 
1073
  }
1074
  </style>
1075
  </head>
1076
  <body>
 
 
1077
  <div class="fixed-top-bar">
1078
  <div class="avatar-dropdown-container">
1079
+ <div class="avatar-icon">
1080
  <span>{{ first_letter }}</span>
1081
  </div>
1082
  <div class="dropdown-menu">
 
1086
  </div>
1087
  </div>
1088
  <div class="search-bar-container">
1089
+ <input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off">
1090
  <i class="bi bi-search search-icon"></i>
1091
+ <i class="bi bi-mic mic-icon" id="micIcon"></i>
 
1092
  </div>
1093
  </div>
1094
 
 
1095
  <form method="get" action="/menu" class="text-center mb-4" id="filter-form">
1096
  <label class="form-label fw-bold">Filters:</label>
1097
  <div class="toggle-container">
1098
+ <!-- Veg Only Toggle -->
1099
  <input type="checkbox" id="veg-toggle" name="veg"
1100
+ {% if selected_category == "Veg" %}checked{% endif %}
1101
+ class="custom-toggle" onchange="handleToggle('veg')"
1102
+ aria-label="Toggle Vegetarian filter">
1103
  <label for="veg-toggle">Veg</label>
1104
  </div>
1105
  <div class="toggle-container">
1106
+ <!-- Customized Dish Toggle -->
1107
+ <input type="radio" id="category-CustomizedDish" name="category" value="Customized Dish"
1108
+ {% if selected_category == "Customized Dish" %}checked{% endif %}
1109
+ class="custom-toggle" onchange="handleToggle('custom')"
1110
+ aria-label="Toggle Customized Dish filter">
1111
  <label for="category-CustomizedDish">Customized Dish</label>
1112
  </div>
1113
  </form>
1114
 
1115
  <div class="container mt-4">
1116
+ {% if selected_category == "Customized Dish" %}
1117
  <div id="custom-dish-form" class="mt-4">
1118
  <h3>Create Your Custom Dish</h3>
1119
  <form method="POST" action="/customdish/generate_custom_dish">
1120
  <div class="mb-3">
1121
  <label for="custom-dish-name" class="form-label">Dish Name</label>
1122
+ <input type="text" class="form-control" id="custom-dish-name" name="name" required>
1123
  </div>
1124
  <div class="mb-3 position-relative">
1125
  <label for="custom-dish-description" class="form-label">Dish Description</label>
1126
+ <textarea class="form-control" id="custom-dish-description" name="description" required></textarea>
1127
  <div id="descriptionSuggestions" class="autocomplete-suggestions"></div>
1128
  </div>
1129
+ <button type="submit" class="btn btn-primary">Submit Custom Dish</button>
1130
  </form>
1131
  </div>
1132
  {% else %}
 
1133
  {% if ordered_menu.items()|length == 0 %}
1134
+ <p>No menu items available for this category.</p>
 
1135
  {% else %}
1136
  {% for section, items in ordered_menu.items() %}
1137
  <h3>{{ section }}</h3>
1138
  <div class="row">
1139
  {% for item in items %}
1140
  <div class="col-md-6 mb-4">
1141
+ <div class="card menu-card" data-item-name="{{ item.Name | default('Unnamed Item') }}" data-item-section="{{ item.Section__c | default(section) }}">
1142
  <video
1143
  class="card-img-top menu-video"
1144
  muted
 
1168
  data-item-section="{{ item.Section__c | default(section) }}"
1169
  data-item-category="{{ selected_category }}"
1170
  data-item-description="{{ item.Description__c | default('No description') }}"
1171
+ data-item-image2="{{ item.Image2__c | default(item.Image1__c) }}">
 
1172
  {% if item.Section__c == 'Soft Drinks' %}
1173
+ <button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)">ADD</button>
1174
  {% else %}
1175
  <button class="btn btn-primary"
1176
  data-bs-toggle="modal"
1177
  data-bs-target="#itemModal"
1178
+ onclick="showItemDetails('{{ item.Name | default('Unnamed Item') }}', '{{ item.Price__c | default('0.00') }}', '{{ item.Image2__c | default(item.Image1__c) }}', '{{ item.Description__c | default('No description') }}', '{{ item.Section__c | default(section) }}', '{{ selected_category }}')">
 
1179
  ADD
1180
  </button>
1181
  {% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' %}
 
1187
  </div>
1188
  </div>
1189
  {% if item.Section__c != 'Soft Drinks' %}
1190
+ <div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}">Show Details</div>
1191
  <div class="item-details" id="details-{{ item.Name | default('unnamed-item') | replace(' ', '-') }}">
1192
  <h6>Description</h6>
1193
  <p>{{ item.Description__c | default('No description available') }}</p>
1194
  <h6>Ingredients</h6>
1195
+ <p>{{ item.IngredientsInfo__c | default('Not specified') }}</p>
1196
  <h6>Nutritional Info</h6>
1197
  <p class="nutritional-info">{{ item.NutritionalInfo__c | default('Not available') }}</p>
1198
  <h6>Allergens</h6>
 
1209
  </div>
1210
 
1211
  <div class="bottom-action-bar">
1212
+ <a href="{{ url_for('orderhistory.order_history') }}" class="btn btn-order-history">
1213
  <i class="bi bi-clock-history"></i> Order History
1214
  </a>
1215
+ <a href="{{ url_for('cart.cart') }}" class="btn btn-view-cart">
1216
  <i class="bi bi-cart"></i> View Cart
1217
  <span id="cart-item-count" class="cart-icon-badge" style="display: none;">0</span>
1218
  </a>
 
1237
  </div>
1238
  <div class="mt-4">
1239
  <h6>Special Instructions</h6>
1240
+ <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
1241
  </div>
1242
  <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
1243
  </div>
1244
  <div class="modal-footer d-flex align-items-center justify-content-between">
1245
  <div class="d-flex align-items-center gap-2">
1246
+ <button type="button" class="btn btn-outline-secondary" id="decreaseQuantity">-</button>
1247
+ <input type="text" class="form-control text-center" id="quantityInput" value="1" readonly style="width: 50px;"/>
1248
+ <button type="button" class="btn btn-outline-secondary" id="increaseQuantity">+</button>
1249
  </div>
1250
+ <button type="button" class="btn btn-primary" onclick="addToCartFromModal()">Add to Cart</button>
1251
  </div>
1252
  </div>
1253
  </div>
 
1286
 
1287
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
1288
  <script>
 
1289
  let isProcessingRequest = false;
1290
  let currentSoftDrinkButton = null;
1291
  let baseItemPrice = 0;
 
 
1292
  const menuItems = [
1293
  {% for section, items in ordered_menu.items() %}
1294
  {% for item in items %}
1295
  {
1296
  name: "{{ item.Name | default('Unnamed Item') }}",
1297
+ section: "{{ item.Section__c | default(section) }}"
 
 
 
 
 
 
1298
  },
1299
  {% endfor %}
1300
  {% endfor %}
1301
  ];
 
 
1302
  const ingredientsList = [
1303
  "Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
1304
  "Chickpea Flour (Besan)", "Chickpea Flour (for batter)", "Chickpeas (Channa)", "Chili Powder",
 
1314
  "Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
1315
  "Whole Wheat Flour", "Yogurt (Curd)"
1316
  ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1317
  function addToCartLocalStorage(payload) {
1318
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
1319
  const existingItem = cart.find(item =>
 
1329
  localStorage.setItem('cart', JSON.stringify(cart));
1330
  return cart;
1331
  }
 
1332
  function removeFromCartLocalStorage(itemName, quantityToRemove, instructions, addons) {
1333
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
1334
  const itemIndex = cart.findIndex(item =>
 
1346
  localStorage.setItem('cart', JSON.stringify(cart));
1347
  return cart;
1348
  }
 
1349
  function getCartLocalStorage() {
1350
  return JSON.parse(localStorage.getItem('cart')) || [];
1351
  }
1352
+ function debounce(func, wait) {
1353
+ let timeout;
1354
+ return function (...args) {
1355
+ clearTimeout(timeout);
1356
+ timeout = setTimeout(() => func.apply(this, args), wait);
1357
+ };
 
 
 
 
 
 
 
 
 
 
1358
  }
 
 
1359
  function updateModalPrice() {
1360
  const selectedAddOns = Array.from(
1361
  document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
 
1364
  const totalPrice = baseItemPrice + totalAddOnPrice;
1365
  document.getElementById('modal-price').innerText = `$${totalPrice.toFixed(2)}`;
1366
  }
 
1367
  function updateSoftDrinkQuantity(delta) {
1368
  const quantityInput = document.getElementById('soft-drink-quantity');
1369
  let currentQuantity = parseInt(quantityInput.value) || 1;
1370
  currentQuantity = Math.max(1, currentQuantity + delta);
1371
  quantityInput.value = currentQuantity;
1372
  }
 
1373
  function showSoftDrinkModal(button) {
1374
  currentSoftDrinkButton = button;
1375
  const buttonContainer = button.closest('.button-container');
 
1378
  const itemImage = buttonContainer.getAttribute('data-item-image');
1379
 
1380
  document.getElementById('soft-drink-name').textContent = itemName;
1381
+ document.getElementById('soft-drink-price').textContent = `${itemPrice}`;
1382
  document.getElementById('soft-drink-quantity').value = '1';
1383
  document.getElementById('soft-drink-image').src = itemImage || '/static/placeholder.jpg';
1384
 
1385
  const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
1386
  modal.show();
1387
  }
 
1388
  function addSoftDrinkToCart() {
1389
  if (!currentSoftDrinkButton) return;
1390
 
 
1423
  modal.hide();
1424
  } else {
1425
  console.error('Failed to add item to cart:', data.error);
 
1426
  const cart = addToCartLocalStorage(cartPayload);
1427
  updateCartUI(cart);
1428
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
 
1431
  })
1432
  .catch(err => {
1433
  console.error('Error adding item to cart:', err);
 
1434
  const cart = addToCartLocalStorage(cartPayload);
1435
  updateCartUI(cart);
1436
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1437
  modal.hide();
1438
  });
1439
  }
1440
+ function updateCartUI(cart) {
1441
+ if (!Array.isArray(cart)) {
1442
+ console.error('Invalid cart data:', cart);
1443
+ return;
1444
+ }
1445
+ let totalQuantity = 0;
1446
+ cart.forEach(item => {
1447
+ totalQuantity += item.quantity;
1448
+ });
1449
+ const cartItemCount = document.getElementById('cart-item-count');
1450
+ if (cartItemCount) {
1451
+ cartItemCount.innerText = totalQuantity;
1452
+ cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
1453
+ }
1454
+ }
1455
  function showItemDetails(name, price, image, description, section, selectedCategory) {
1456
  document.getElementById('modal-name').innerText = name;
1457
  baseItemPrice = parseFloat(price) || 0;
 
1467
  modalSectionEl.setAttribute('data-category', selectedCategory);
1468
  document.getElementById('quantityInput').value = 1;
1469
 
1470
+ fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
1471
+ .then(response => response.json())
1472
+ .then(data => {
1473
+ const addonsList = document.getElementById('addons-list');
1474
+ addonsList.classList.remove('addon-loading');
1475
+ addonsList.innerHTML = '';
1476
+ if (!data.success || !data.addons || data.addons.length === 0) {
1477
+ addonsList.innerHTML = '<p>No customization options available.</p>';
1478
+ return;
1479
+ }
 
 
 
 
 
 
 
 
 
 
 
 
1480
 
1481
+ data.addons.forEach(addon => {
1482
+ const sectionDiv = document.createElement('div');
1483
+ sectionDiv.classList.add('addon-section');
1484
+ const title = document.createElement('h6');
1485
+ title.innerText = addon.name;
1486
+ sectionDiv.appendChild(title);
1487
+ const optionsContainer = document.createElement('div');
1488
+ optionsContainer.classList.add('addon-options');
 
 
 
 
 
 
1489
 
1490
+ addon.options.forEach((option, index) => {
1491
+ const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
1492
+ const listItem = document.createElement('div');
1493
+ listItem.classList.add('form-check');
1494
+ listItem.innerHTML = `
1495
+ <input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
1496
+ data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}"
1497
+ aria-label="Select ${option} for ${addon.name}">
1498
+ <label class="form-check-label" for="${optionId}">
1499
+ ${option} ${addon.extra_charge ? `<span class="extra-charge">($${addon.extra_charge_amount.toFixed(2)})</span>` : ''}
1500
+ </label>
1501
+ `;
1502
+ optionsContainer.appendChild(listItem);
1503
  });
1504
 
1505
+ sectionDiv.appendChild(optionsContainer);
1506
+ addonsList.appendChild(sectionDiv);
1507
+ });
 
 
 
 
 
 
1508
 
1509
+ const addonSections = addonsList.querySelectorAll('.addon-section');
1510
+ addonSections.forEach(section => {
1511
+ const title = section.querySelector('h6');
1512
+ const options = section.querySelector('.addon-options');
1513
+ title.addEventListener('click', () => {
1514
+ section.classList.toggle('collapsed');
1515
+ options.classList.toggle('collapsed');
1516
  });
1517
+ });
1518
 
1519
+ document.querySelectorAll('.addon-option').forEach(checkbox => {
1520
+ checkbox.addEventListener('change', updateModalPrice);
1521
+ });
1522
+
1523
+ document.querySelectorAll('.addon-option').forEach(checkbox => {
1524
+ checkbox.addEventListener('change', function () {
1525
+ const groupName = this.getAttribute('data-group');
1526
+ const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo", "Beverages", "Sauces"].includes(groupName);
1527
+ if (!isMultiSelectGroup && this.checked) {
1528
+ document.querySelectorAll(`.addon-option[data-group="${groupName}"]`).forEach(otherCheckbox => {
1529
+ if (otherCheckbox !== this) {
1530
+ otherCheckbox.checked = false;
1531
+ }
1532
+ });
1533
+ }
1534
  });
 
 
 
 
 
 
 
 
 
 
 
1535
  });
1536
+ })
1537
+ .catch(err => {
1538
+ console.error('Error fetching add-ons:', err);
1539
+ document.getElementById('addons-list').classList.remove('addon-loading');
1540
+ document.getElementById('addons-list').innerHTML = '<p>Error loading customization options.</p>';
1541
+ });
1542
  }
 
1543
  function addToCartFromModal() {
1544
  if (isProcessingRequest) return;
1545
  isProcessingRequest = true;
 
1559
  }));
1560
  if (!itemName || isNaN(itemPrice) || !section || !itemImage || quantity < 1) {
1561
  console.error('Invalid cart item data:', { itemName, itemPrice, section, itemImage, quantity });
1562
+ alert('Invalid item data. Please try again.');
1563
  isProcessingRequest = false;
1564
  return;
1565
  }
 
1588
  modal.hide();
1589
  } else {
1590
  console.error('Failed to add item to cart:', data.error);
 
1591
  const cart = addToCartLocalStorage(cartPayload);
1592
  updateCartUI(cart);
1593
  const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
 
1596
  })
1597
  .catch(err => {
1598
  console.error('Error adding item to cart:', err);
 
1599
  const cart = addToCartLocalStorage(cartPayload);
1600
  updateCartUI(cart);
1601
  const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
 
1605
  isProcessingRequest = false;
1606
  });
1607
  }
 
 
1608
  function handleToggle(source) {
1609
  const form = document.getElementById("filter-form");
1610
  const veg = document.getElementById("veg-toggle");
1611
  const custom = document.getElementById("category-CustomizedDish");
 
 
 
 
 
 
 
1612
  if (source === 'veg') {
1613
  if (veg.checked) {
1614
  custom.checked = false;
 
1618
  veg.checked = false;
1619
  }
1620
  }
1621
+ if (!custom.checked && !veg.checked) {
1622
+ custom.checked = false;
1623
+ }
 
 
 
 
1624
  form.submit();
1625
  }
1626
+ document.addEventListener('DOMContentLoaded', function () {
1627
+ const avatarContainer = document.querySelector('.avatar-dropdown-container');
1628
+ const dropdownMenu = document.querySelector('.dropdown-menu');
1629
+ avatarContainer.addEventListener('click', function (event) {
1630
+ event.stopPropagation();
1631
+ dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
1632
+ });
1633
+ document.addEventListener('click', function (event) {
1634
+ if (!avatarContainer.contains(event.target)) {
1635
+ dropdownMenu.style.display = 'none';
1636
+ }
1637
+ });
1638
+ const dropdownItems = document.querySelectorAll('.dropdown-item');
1639
+ dropdownItems.forEach(item => {
1640
+ item.addEventListener('click', function () {
1641
+ dropdownMenu.style.display = 'none';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1642
  });
1643
+ });
1644
+ const searchBar = document.getElementById('searchBar');
1645
+ searchBar.addEventListener('click', function () {
1646
+ window.location.href = '/search';
1647
+ });
1648
+ const selectedItem = localStorage.getItem('selectedItem');
1649
+ if (selectedItem) {
1650
+ try {
1651
+ const { name, section } = JSON.parse(selectedItem);
1652
+ const menuCards = document.querySelectorAll('.menu-card');
1653
+ let targetCard = null;
1654
+ let buttonContainer = null;
1655
+ menuCards.forEach(card => {
1656
+ const itemName = card.getAttribute('data-item-name');
1657
+ const itemSection = card.getAttribute('data-item-section');
1658
+ if (itemName === name && itemSection === section) {
1659
+ targetCard = card;
1660
+ buttonContainer = card.querySelector('.button-container');
1661
+ card.classList.add('highlighted');
1662
+ card.scrollIntoView({ behavior: 'smooth', block: 'center' });
1663
+ const toggleLink = card.querySelector('.toggle-details');
1664
+ if (toggleLink) {
1665
+ toggleLink.click();
1666
  }
 
 
 
 
 
 
 
1667
  }
1668
  });
1669
+ if (buttonContainer) {
1670
+ if (section === 'Soft Drinks') {
1671
+ showSoftDrinkModal(buttonContainer.querySelector('.add-to-cart-btn'));
1672
+ } else {
1673
+ const name = buttonContainer.getAttribute('data-item-name');
1674
+ const price = buttonContainer.getAttribute('data-item-price');
1675
+ const image = buttonContainer.getAttribute('data-item-image2');
1676
+ const description = buttonContainer.getAttribute('data-item-description');
1677
+ const category = buttonContainer.getAttribute('data-item-category');
1678
+ showItemDetails(name, price, image, description, section, category);
1679
+ const modal = new bootstrap.Modal(document.getElementById('itemModal'));
1680
+ modal.show();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1681
  }
 
 
1682
  }
1683
+ } catch (err) {
1684
+ console.error('Error parsing selected item:', err);
1685
  }
1686
+ localStorage.removeItem('selectedItem');
1687
+ }
1688
+ const menuCards = document.querySelectorAll('.menu-card');
1689
+ const menuVideos = document.querySelectorAll('.menu-video');
1690
+ const cardObserver = new IntersectionObserver((entries, observer) => {
1691
+ entries.forEach(entry => {
1692
+ if (entry.isIntersecting) {
1693
+ entry.target.classList.add('visible');
1694
+ observer.unobserve(entry.target);
1695
+ }
1696
+ });
1697
+ }, {
1698
+ root: null,
1699
+ rootMargin: '0px',
1700
+ threshold: 0.1
1701
  });
1702
+ const videoObserver = new IntersectionObserver((entries, observer) => {
1703
+ entries.forEach(entry => {
1704
+ if (entry.isIntersecting) {
1705
+ const video = entry.target;
1706
+ const src = video.getAttribute('data-src');
1707
+ if (src && !video.querySelector('source[src="' + src + '"]')) {
1708
+ const nextSibling = video.nextElementSibling;
1709
+ if (nextSibling && nextSibling.tagName === 'SOURCE') {
1710
+ nextSibling.src = src;
1711
+ } else {
1712
+ const source = video.querySelector('source');
1713
+ if (source) {
1714
+ source.src = src;
1715
+ }
1716
+ }
1717
+ video.load();
 
 
 
 
 
1718
  }
1719
+ video.classList.add('loaded');
1720
+ observer.unobserve(video);
1721
  }
1722
  });
1723
+ }, {
1724
+ root: null,
1725
+ rootMargin: '200px',
1726
+ threshold: 0.01
 
 
 
1727
  });
1728
+ menuCards.forEach(card => cardObserver.observe(card));
1729
+ menuVideos.forEach(video => videoObserver.observe(video));
1730
+ const toggleLinks = document.querySelectorAll('.toggle-details');
1731
+ toggleLinks.forEach(link => {
1732
+ link.addEventListener('click', function () {
1733
+ const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
1734
+ const detailsDiv = document.getElementById(`details-${itemName}`);
1735
+ const isCurrentlyShown = detailsDiv.classList.contains('show');
1736
+ document.querySelectorAll('.item-details.show').forEach(otherDetails => {
1737
+ if (otherDetails !== detailsDiv) {
1738
+ otherDetails.classList.remove('show');
1739
+ const otherLink = document.querySelector(`.toggle-details[data-item-name="${otherDetails.id.replace('details-', '').replace(/-/g, ' ')}"]`);
1740
+ if (otherLink) {
1741
+ otherLink.innerText = 'Show Details';
1742
+ }
1743
  }
1744
  });
1745
+ if (!isCurrentlyShown) {
1746
+ detailsDiv.classList.add('show');
1747
+ this.innerText = 'Hide Details';
1748
+ } else {
1749
+ detailsDiv.classList.remove('show');
1750
+ this.innerText = 'Show Details';
1751
+ }
1752
+ });
1753
+ });
1754
+ const descriptionTextarea = document.getElementById('custom-dish-description');
1755
+ const descriptionSuggestions = document.getElementById('descriptionSuggestions');
1756
+ if (descriptionTextarea && descriptionSuggestions) {
1757
+ let usedIngredients = new Set();
1758
+ function updateUsedIngredients() {
1759
+ const inputText = descriptionTextarea.value.trim();
1760
+ usedIngredients.clear();
1761
+ if (inputText) {
1762
+ const words = inputText.split(/,\s*/).map(word => word.trim());
1763
+ words.forEach(word => {
1764
+ if (word && ingredientsList.includes(word)) {
1765
+ usedIngredients.add(word);
1766
+ }
 
 
 
 
 
 
1767
  });
 
1768
  }
1769
  }
1770
+ descriptionTextarea.addEventListener('input', function () {
1771
+ const inputText = this.value.trim();
1772
+ const words = inputText.split(/,\s*/);
1773
+ const lastWord = words[words.length - 1].trim().toLowerCase();
1774
+ descriptionSuggestions.innerHTML = '';
1775
  descriptionSuggestions.style.display = 'none';
1776
+ updateUsedIngredients();
1777
+ if (lastWord) {
1778
+ const filteredIngredients = ingredientsList.filter(ingredient =>
1779
+ ingredient.toLowerCase().includes(lastWord) && !usedIngredients.has(ingredient)
1780
+ );
1781
+ if (filteredIngredients.length > 0) {
1782
+ filteredIngredients.forEach(ingredient => {
1783
+ const suggestionDiv = document.createElement('div');
1784
+ suggestionDiv.classList.add('suggestion-item');
1785
+ suggestionDiv.innerText = ingredient;
1786
+ suggestionDiv.addEventListener('click', function () {
1787
+ const currentValue = descriptionTextarea.value;
1788
+ const lastCommaIndex = currentValue.lastIndexOf(',');
1789
+ const baseText = lastCommaIndex !== -1 ? currentValue.substring(0, lastCommaIndex + 1) : '';
1790
+ descriptionTextarea.value = baseText + (baseText ? ' ' : '') + ingredient + ', ';
1791
+ descriptionSuggestions.style.display = 'none';
1792
+ descriptionTextarea.focus();
1793
+ updateUsedIngredients();
1794
+ });
1795
+ descriptionSuggestions.appendChild(suggestionDiv);
1796
+ });
1797
+ descriptionSuggestions.style.display = 'block';
1798
+ }
1799
+ }
1800
+ });
1801
+ document.addEventListener('click', function (event) {
1802
+ if (!descriptionTextarea.contains(event.target) && !descriptionSuggestions.contains(event.target)) {
1803
+ descriptionSuggestions.style.display = 'none';
1804
+ }
1805
+ });
1806
+ }
1807
+ fetch('/cart/get')
1808
+ .then(response => {
1809
+ if (!response.ok) {
1810
+ throw new Error(`HTTP error! Status: ${response.status}`);
1811
+ }
1812
+ return response.json();
1813
+ })
1814
+ .then(data => {
1815
+ if (data.success) {
1816
+ updateCartUI(data.cart);
1817
+ } else {
1818
+ console.error('Failed to fetch cart:', data.error);
1819
+ const cart = getCartLocalStorage();
1820
+ updateCartUI(cart);
1821
+ }
1822
+ })
1823
+ .catch(err => {
1824
+ console.error('Error fetching cart:', err);
1825
  const cart = getCartLocalStorage();
1826
  updateCartUI(cart);
1827
+ });
1828
+ const preloadedVideos = document.querySelectorAll('link[rel="preload"][as="video"]');
1829
+ preloadedVideos.forEach(link => {
1830
+ const video = document.createElement('video');
1831
+ video.src = link.href;
1832
+ video.preload = 'auto';
1833
+ });
1834
+ const decreaseBtn = document.getElementById('decreaseQuantity');
1835
+ const increaseBtn = document.getElementById('increaseQuantity');
1836
+ const quantityInput = document.getElementById('quantityInput');
1837
+ decreaseBtn.addEventListener('click', function () {
1838
+ let quantity = parseInt(quantityInput.value) || 1;
1839
+ quantity = Math.max(1, quantity - 1);
1840
+ quantityInput.value = quantity;
1841
+ });
1842
+ increaseBtn.addEventListener('click', function () {
1843
+ let quantity = parseInt(quantityInput.value) || 1;
1844
+ quantity += 1;
1845
+ quantityInput.value = quantity;
1846
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1847
  });
 
1848
  </script>
1849
  </body>
1850
+ </html>