lokesh341 commited on
Commit
72acf5c
·
verified ·
1 Parent(s): 4601337

Update templates/menu.html

Browse files
Files changed (1) hide show
  1. templates/menu.html +452 -44
templates/menu.html CHANGED
@@ -95,6 +95,14 @@
95
  justify-content: center;
96
  gap: 6px;
97
  }
 
 
 
 
 
 
 
 
98
  .btn-primary {
99
  font-size: 12px;
100
  font-weight: bold;
@@ -208,6 +216,9 @@
208
  .search-bar-container input::placeholder {
209
  color: #888;
210
  }
 
 
 
211
  .search-icon {
212
  position: absolute;
213
  left: 15px;
@@ -225,6 +236,136 @@
225
  .mic-icon.active {
226
  color: #007bff;
227
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  form.text-center.mb-4 {
229
  display: flex;
230
  flex-direction: column;
@@ -268,7 +409,14 @@
268
  .modal-body #modal-description {
269
  font-size: 14px;
270
  color: #6c757d;
271
- margin-bottom: 10px;
 
 
 
 
 
 
 
272
  }
273
  .modal-footer {
274
  display: flex;
@@ -496,6 +644,107 @@
496
  font-size: 12px;
497
  margin-left: 8px;
498
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
  @media (max-width: 576px) {
500
  .fixed-top-bar {
501
  height: 60px;
@@ -555,7 +804,7 @@
555
  }
556
  .modal-body {
557
  max-height: 50vh;
558
- padding: 8px;
559
  }
560
  .modal-body #modal-img {
561
  max-height: 150px;
@@ -576,6 +825,15 @@
576
  font-size: 12px;
577
  margin-bottom: 5px;
578
  }
 
 
 
 
 
 
 
 
 
579
  .modal-footer {
580
  padding: 5px;
581
  }
@@ -606,6 +864,9 @@
606
  width: 50px;
607
  height: 25px;
608
  }
 
 
 
609
  .button-container {
610
  gap: 3px;
611
  }
@@ -644,6 +905,79 @@
644
  font-size: 10px;
645
  margin-left: 5px;
646
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
647
  }
648
  </style>
649
  </head>
@@ -743,6 +1077,9 @@
743
  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 }}')">
744
  ADD
745
  </button>
 
 
 
746
  {% endif %}
747
  </div>
748
  </div>
@@ -793,8 +1130,12 @@
793
  <h5 id="modal-name" class="fw-bold text-center"></h5>
794
  <p id="modal-price" class="text-muted text-center"></p>
795
  <p id="modal-description" class="text-secondary"></p>
 
 
 
 
796
  <div class="mt-4">
797
- <h6>Custom Request</h6>
798
  <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
799
  </div>
800
  <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
@@ -820,18 +1161,18 @@
820
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
821
  </div>
822
  <div class="modal-body">
 
823
  <div class="text-center mb-3">
824
  <h5 id="soft-drink-name"></h5>
825
  <p id="soft-drink-price"></p>
826
  </div>
827
- <div class="d-flex justify-content-center align-items-center mb-4">
828
- <button type="button" class="btn btn-outline-secondary" id="soft-drink-decrease">-</button>
829
- <input type="text" class="form-control text-center mx-2" id="soft-drink-quantity" value="1" readonly style="width: 60px;">
830
  <button type="button" class="btn btn-outline-secondary" id="soft-drink-increase">+</button>
831
  </div>
832
  </div>
833
  <div class="modal-footer">
834
- <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
835
  <button type="button" class="btn btn-primary" onclick="addSoftDrinkToCart()">Add to Cart</button>
836
  </div>
837
  </div>
@@ -842,7 +1183,7 @@
842
  <script>
843
  let isProcessingRequest = false;
844
  let currentSoftDrinkButton = null;
845
-
846
  const menuItems = [
847
  {% for section, items in ordered_menu.items() %}
848
  {% for item in items %}
@@ -853,7 +1194,6 @@
853
  {% endfor %}
854
  {% endfor %}
855
  ];
856
-
857
  const ingredientsList = [
858
  "Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
859
  "Chickpea Flour (Besan)", "Chickpea Flour (for batter)", "Chickpeas (Channa)", "Chili Powder",
@@ -869,12 +1209,12 @@
869
  "Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
870
  "Whole Wheat Flour", "Yogurt (Curd)"
871
  ];
872
-
873
  function addToCartLocalStorage(payload) {
874
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
875
  const existingItem = cart.find(item =>
876
  item.itemName === payload.itemName &&
877
- item.instructions === payload.instructions
 
878
  );
879
  if (existingItem) {
880
  existingItem.quantity = payload.quantity;
@@ -884,12 +1224,12 @@
884
  localStorage.setItem('cart', JSON.stringify(cart));
885
  return cart;
886
  }
887
-
888
- function removeFromCartLocalStorage(itemName, quantityToRemove, instructions) {
889
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
890
  const itemIndex = cart.findIndex(item =>
891
  item.itemName === itemName &&
892
- item.instructions === instructions
 
893
  );
894
  if (itemIndex !== -1) {
895
  if (quantityToRemove >= cart[itemIndex].quantity) {
@@ -901,11 +1241,9 @@
901
  localStorage.setItem('cart', JSON.stringify(cart));
902
  return cart;
903
  }
904
-
905
  function getCartLocalStorage() {
906
  return JSON.parse(localStorage.getItem('cart')) || [];
907
  }
908
-
909
  function debounce(func, wait) {
910
  let timeout;
911
  return function (...args) {
@@ -913,21 +1251,29 @@
913
  timeout = setTimeout(() => func.apply(this, args), wait);
914
  };
915
  }
916
-
 
 
 
 
 
 
 
917
  function showSoftDrinkModal(button) {
918
  currentSoftDrinkButton = button;
919
  const buttonContainer = button.closest('.button-container');
920
  const itemName = buttonContainer.getAttribute('data-item-name');
921
  const itemPrice = buttonContainer.getAttribute('data-item-price');
 
922
 
923
  document.getElementById('soft-drink-name').textContent = itemName;
924
  document.getElementById('soft-drink-price').textContent = `$${itemPrice}`;
925
  document.getElementById('soft-drink-quantity').value = '1';
 
926
 
927
  const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
928
  modal.show();
929
  }
930
-
931
  function addSoftDrinkToCart() {
932
  if (!currentSoftDrinkButton) return;
933
 
@@ -946,6 +1292,7 @@
946
  itemImage: itemImage,
947
  section: section,
948
  category: selectedCategory,
 
949
  instructions: '',
950
  quantity: quantity
951
  };
@@ -979,42 +1326,115 @@
979
  modal.hide();
980
  });
981
  }
982
-
983
  function updateCartUI(cart) {
984
  if (!Array.isArray(cart)) {
985
  console.error('Invalid cart data:', cart);
986
  return;
987
  }
988
-
989
  let totalQuantity = 0;
990
  cart.forEach(item => {
991
  totalQuantity += item.quantity;
992
  });
993
-
994
  const cartItemCount = document.getElementById('cart-item-count');
995
  if (cartItemCount) {
996
  cartItemCount.innerText = totalQuantity;
997
  cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
998
  }
999
  }
1000
-
1001
  function showItemDetails(name, price, image, description, section, selectedCategory) {
1002
  document.getElementById('modal-name').innerText = name;
1003
- document.getElementById('modal-price').innerText = `$${price}`;
 
1004
  const modalImg = document.getElementById('modal-img');
1005
  modalImg.src = image || '/static/placeholder.jpg';
1006
  document.getElementById('modal-description').innerText = description || 'No description available.';
 
 
1007
  document.getElementById('modal-instructions').value = '';
1008
  const modalSectionEl = document.getElementById('modal-section');
1009
  modalSectionEl.setAttribute('data-section', section);
1010
  modalSectionEl.setAttribute('data-category', selectedCategory);
1011
  document.getElementById('quantityInput').value = 1;
1012
- }
1013
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1014
  function addToCartFromModal() {
1015
  if (isProcessingRequest) return;
1016
  isProcessingRequest = true;
1017
-
1018
  const modalSectionEl = document.getElementById('modal-section');
1019
  const section = modalSectionEl.getAttribute('data-section');
1020
  const selectedCategory = modalSectionEl.getAttribute('data-category');
@@ -1023,24 +1443,28 @@
1023
  const itemImage = document.getElementById('modal-img').src;
1024
  const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
1025
  const instructions = document.getElementById('modal-instructions').value;
1026
-
 
 
 
 
 
1027
  if (!itemName || isNaN(itemPrice) || !section || !itemImage || quantity < 1) {
1028
  console.error('Invalid cart item data:', { itemName, itemPrice, section, itemImage, quantity });
1029
  alert('Invalid item data. Please try again.');
1030
  isProcessingRequest = false;
1031
  return;
1032
  }
1033
-
1034
  const cartPayload = {
1035
  itemName: itemName,
1036
  itemPrice: itemPrice,
1037
  itemImage: itemImage,
1038
  section: section,
1039
  category: selectedCategory,
 
1040
  instructions: instructions,
1041
  quantity: quantity
1042
  };
1043
-
1044
  fetch('/cart/add', {
1045
  method: 'POST',
1046
  headers: {
@@ -1073,7 +1497,6 @@
1073
  isProcessingRequest = false;
1074
  });
1075
  }
1076
-
1077
  document.addEventListener('DOMContentLoaded', function () {
1078
  // Avatar Dropdown
1079
  const avatarContainer = document.querySelector('.avatar-dropdown-container');
@@ -1093,13 +1516,11 @@
1093
  dropdownMenu.style.display = 'none';
1094
  });
1095
  });
1096
-
1097
  // Navigate to search page on search bar click
1098
  const searchBar = document.getElementById('searchBar');
1099
  searchBar.addEventListener('click', function () {
1100
  window.location.href = '/search';
1101
  });
1102
-
1103
  // Auto-open modal for selected item
1104
  const selectedItem = localStorage.getItem('selectedItem');
1105
  if (selectedItem) {
@@ -1108,7 +1529,6 @@
1108
  const menuCards = document.querySelectorAll('.menu-card');
1109
  let targetCard = null;
1110
  let buttonContainer = null;
1111
-
1112
  menuCards.forEach(card => {
1113
  const itemName = card.getAttribute('data-item-name');
1114
  const itemSection = card.getAttribute('data-item-section');
@@ -1123,7 +1543,6 @@
1123
  }
1124
  }
1125
  });
1126
-
1127
  if (buttonContainer) {
1128
  if (section === 'Soft Drinks') {
1129
  showSoftDrinkModal(buttonContainer.querySelector('.add-to-cart-btn'));
@@ -1143,7 +1562,6 @@
1143
  }
1144
  localStorage.removeItem('selectedItem');
1145
  }
1146
-
1147
  // Lazy Loading for Cards and Videos
1148
  const menuCards = document.querySelectorAll('.menu-card');
1149
  const menuVideos = document.querySelectorAll('.menu-video');
@@ -1180,7 +1598,6 @@
1180
  });
1181
  menuCards.forEach(card => cardObserver.observe(card));
1182
  menuVideos.forEach(video => videoObserver.observe(video));
1183
-
1184
  // Toggle Details
1185
  const toggleLinks = document.querySelectorAll('.toggle-details');
1186
  toggleLinks.forEach(link => {
@@ -1188,7 +1605,6 @@
1188
  const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
1189
  const detailsDiv = document.getElementById(`details-${itemName}`);
1190
  const isCurrentlyShown = detailsDiv.classList.contains('show');
1191
-
1192
  document.querySelectorAll('.item-details.show').forEach(otherDetails => {
1193
  if (otherDetails !== detailsDiv) {
1194
  otherDetails.classList.remove('show');
@@ -1198,7 +1614,6 @@
1198
  }
1199
  }
1200
  });
1201
-
1202
  if (!isCurrentlyShown) {
1203
  detailsDiv.classList.add('show');
1204
  this.innerText = 'Hide Details';
@@ -1208,7 +1623,6 @@
1208
  }
1209
  });
1210
  });
1211
-
1212
  // Category Selection
1213
  const categoryButtons = document.querySelectorAll('.category-button');
1214
  const categoryForm = document.getElementById('categoryForm');
@@ -1225,7 +1639,6 @@
1225
  categoryForm.submit();
1226
  });
1227
  });
1228
-
1229
  // Custom Dish Form Suggestions
1230
  const descriptionTextarea = document.getElementById('custom-dish-description');
1231
  const descriptionSuggestions = document.getElementById('descriptionSuggestions');
@@ -1280,7 +1693,6 @@
1280
  }
1281
  });
1282
  }
1283
-
1284
  // Fetch Cart
1285
  fetch('/cart/get')
1286
  .then(response => {
@@ -1303,7 +1715,6 @@
1303
  const cart = getCartLocalStorage();
1304
  updateCartUI(cart);
1305
  });
1306
-
1307
  // Preload Videos
1308
  const preloadedVideos = document.querySelectorAll('link[rel="preload"][as="video"]');
1309
  preloadedVideos.forEach(link => {
@@ -1311,7 +1722,6 @@
1311
  video.src = link.href;
1312
  video.preload = 'auto';
1313
  });
1314
-
1315
  // Quantity Controls for Item Modal
1316
  const decreaseBtn = document.getElementById('decreaseQuantity');
1317
  const increaseBtn = document.getElementById('increaseQuantity');
@@ -1330,7 +1740,6 @@
1330
  quantityInput.value = currentQuantity;
1331
  }
1332
  });
1333
-
1334
  // Soft Drinks Modal Quantity Controls
1335
  const softDrinkDecreaseBtn = document.getElementById('soft-drink-decrease');
1336
  const softDrinkIncreaseBtn = document.getElementById('soft-drink-increase');
@@ -1351,7 +1760,6 @@
1351
  softDrinkQuantityInput.value = currentQuantity;
1352
  }
1353
  });
1354
-
1355
  // Voice Recognition
1356
  const micIcon = document.getElementById('micIcon');
1357
  if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
 
95
  justify-content: center;
96
  gap: 6px;
97
  }
98
+ .customisable-text {
99
+ color: #0FAA39;
100
+ font-size: 10px;
101
+ font-weight: 500;
102
+ margin: 0;
103
+ text-align: center;
104
+ line-height: 1;
105
+ }
106
  .btn-primary {
107
  font-size: 12px;
108
  font-weight: bold;
 
216
  .search-bar-container input::placeholder {
217
  color: #888;
218
  }
219
+ .search-bar-container input:focus {
220
+ border-bottom: 2px solid #FFA07A;
221
+ }
222
  .search-icon {
223
  position: absolute;
224
  left: 15px;
 
236
  .mic-icon.active {
237
  color: #007bff;
238
  }
239
+ /* Updated Addon Section */
240
+ .addon-section {
241
+ background-color: #fff;
242
+ border-radius: 10px;
243
+ margin-bottom: 15px;
244
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
245
+ overflow: hidden;
246
+ transition: transform 0.2s ease;
247
+ }
248
+ .addon-section:hover {
249
+ transform: translateY(-2px);
250
+ }
251
+ .addon-section h6 {
252
+ margin: 0;
253
+ padding: 12px 15px;
254
+ font-size: 1.1rem;
255
+ font-weight: 600;
256
+ color: #fff;
257
+ background: linear-gradient(45deg, #FFA07A, #FFB347);
258
+ cursor: pointer;
259
+ display: flex;
260
+ justify-content: space-between;
261
+ align-items: center;
262
+ }
263
+ .addon-section h6::after {
264
+ content: '\25BC';
265
+ font-size: 0.9rem;
266
+ transition: transform 0.2s ease;
267
+ }
268
+ .addon-section.collapsed h6::after {
269
+ transform: rotate(180deg);
270
+ }
271
+ .addon-section .form-check {
272
+ display: flex;
273
+ flex-direction: row-reverse;
274
+ align-items: center;
275
+ justify-content: space-between;
276
+ margin: 10px 15px;
277
+ padding: 0;
278
+ }
279
+ .addon-section .form-check-input {
280
+ -webkit-appearance: none;
281
+ -moz-appearance: none;
282
+ appearance: none;
283
+ width: 20px;
284
+ height: 20px;
285
+ border: 2px solid #6c757d;
286
+ border-radius: 4px;
287
+ background-color: #fff;
288
+ position: relative;
289
+ margin-left: 10px;
290
+ cursor: pointer;
291
+ transition: all 0.2s ease;
292
+ }
293
+ .addon-section .form-check-input:checked {
294
+ background-color: #0FAA39;
295
+ border-color: #0FAA39;
296
+ }
297
+ .addon-section .form-check-input:checked::before {
298
+ content: '\2713';
299
+ font-size: 12px;
300
+ position: absolute;
301
+ top: 2px;
302
+ left: 4px;
303
+ color: white;
304
+ animation: checkmark 0.2s ease-in-out;
305
+ }
306
+ .addon-section .form-check-input:hover {
307
+ transform: scale(1.1);
308
+ border-color: #0FAA39;
309
+ }
310
+ .addon-section .form-check-input:focus {
311
+ outline: none;
312
+ box-shadow: 0 0 0 3px rgba(15, 170, 57, 0.2);
313
+ }
314
+ .addon-section .form-check-label {
315
+ font-size: 0.95rem;
316
+ color: #343a40;
317
+ cursor: pointer;
318
+ flex: 1;
319
+ padding: 5px 8px;
320
+ border-radius: 4px;
321
+ transition: background-color 0.2s ease;
322
+ text-align: left;
323
+ }
324
+ .addon-section .form-check-label:hover {
325
+ background-color: #e6f4ea;
326
+ }
327
+ .addon-section .form-check-label .extra-charge {
328
+ color: #FFA07A;
329
+ font-weight: 600;
330
+ margin-left: 8px;
331
+ }
332
+ .addon-options {
333
+ max-height: 500px;
334
+ opacity: 1;
335
+ overflow: hidden;
336
+ transition: max-height 0.3s ease, opacity 0.3s ease;
337
+ }
338
+ .addon-options.collapsed {
339
+ max-height: 0;
340
+ opacity: 0;
341
+ }
342
+ .addon-loading {
343
+ display: flex;
344
+ justify-content: center;
345
+ align-items: center;
346
+ padding: 15px;
347
+ }
348
+ .addon-loading::after {
349
+ content: '';
350
+ width: 20px;
351
+ height: 20px;
352
+ border: 3px solid #0FAA39;
353
+ border-top: 3px solid transparent;
354
+ border-radius: 50%;
355
+ animation: spin 1s linear infinite;
356
+ }
357
+ @keyframes checkmark {
358
+ from { transform: scale(0); }
359
+ to { transform: scale(1); }
360
+ }
361
+ @keyframes spin {
362
+ 0% { transform: rotate(0deg); }
363
+ 100% { transform: rotate(360deg); }
364
+ }
365
+ @keyframes fadeIn {
366
+ from { opacity: 0; transform: translateY(10px); }
367
+ to { opacity: 1; transform: translateY(0); }
368
+ }
369
  form.text-center.mb-4 {
370
  display: flex;
371
  flex-direction: column;
 
409
  .modal-body #modal-description {
410
  font-size: 14px;
411
  color: #6c757d;
412
+ margin-bottom: 15px;
413
+ }
414
+ .modal-body #modal-addons h5,
415
+ .modal-body #first-row h6 {
416
+ font-size: 1.2rem;
417
+ font-weight: 600;
418
+ margin-bottom: 15px;
419
+ color: #343a40;
420
  }
421
  .modal-footer {
422
  display: flex;
 
644
  font-size: 12px;
645
  margin-left: 8px;
646
  }
647
+ /* Soft Drinks Modal Styles */
648
+ #softDrinkModal .modal-content {
649
+ border-radius: 10px;
650
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
651
+ animation: fadeIn 0.3s ease-in;
652
+ }
653
+ #softDrinkModal .modal-header {
654
+ background: linear-gradient(45deg, #FFA07A, #FFB347);
655
+ color: white;
656
+ border-top-left-radius: 10px;
657
+ border-top-right-radius: 10px;
658
+ padding: 12px 15px;
659
+ }
660
+ #softDrinkModal .modal-title {
661
+ font-size: 1.2rem;
662
+ font-weight: 600;
663
+ }
664
+ #softDrinkModal .modal-body {
665
+ padding: 20px;
666
+ text-align: center;
667
+ background-color: #fff;
668
+ }
669
+ #softDrinkModal #soft-drink-img {
670
+ max-height: 150px;
671
+ width: 100%;
672
+ max-width: 150px;
673
+ object-fit: cover;
674
+ border-radius: 8px;
675
+ margin: 0 auto 15px;
676
+ display: block;
677
+ }
678
+ #softDrinkModal #soft-drink-name {
679
+ font-size: 1.5rem;
680
+ font-weight: 600;
681
+ color: #333333;
682
+ margin-bottom: 5px;
683
+ }
684
+ #softDrinkModal #soft-drink-price {
685
+ font-size: 1.1rem;
686
+ font-weight: 500;
687
+ color: #000000;
688
+ margin-bottom: 20px;
689
+ }
690
+ #softDrinkModal .quantity-selector {
691
+ display: flex;
692
+ justify-content: center;
693
+ align-items: center;
694
+ gap: 10px;
695
+ margin-bottom: 20px;
696
+ }
697
+ #softDrinkModal .quantity-selector .btn {
698
+ width: 40px;
699
+ height: 40px;
700
+ font-size: 1rem;
701
+ line-height: 40px;
702
+ border-radius: 8px;
703
+ background-color: #f8f9fa;
704
+ border: 1px solid #ced4da;
705
+ color: #333;
706
+ transition: background-color 0.2s ease, transform 0.1s ease;
707
+ }
708
+ #softDrinkModal .quantity-selector .btn:hover {
709
+ background-color: #e6f4ea;
710
+ transform: scale(1.05);
711
+ }
712
+ #softDrinkModal .quantity-selector .btn:active {
713
+ transform: scale(0.95);
714
+ }
715
+ #softDrinkModal .quantity-selector input {
716
+ width: 60px;
717
+ height: 40px;
718
+ text-align: center;
719
+ font-size: 1rem;
720
+ font-weight: bold;
721
+ border-radius: 8px;
722
+ border: 1px solid #ced4da;
723
+ background-color: #fff;
724
+ }
725
+ #softDrinkModal .modal-footer {
726
+ justify-content: center;
727
+ padding: 15px;
728
+ border-top: none;
729
+ }
730
+ #softDrinkModal .modal-footer .btn-primary {
731
+ width: 150px;
732
+ height: 45px;
733
+ font-size: 1rem;
734
+ border-radius: 8px;
735
+ background-color: #0FAA39;
736
+ border-color: #0FAA39;
737
+ transition: background-color 0.2s ease, transform 0.1s ease;
738
+ }
739
+ #softDrinkModal .modal-footer .btn-primary:hover {
740
+ background-color: #0D9232;
741
+ transform: scale(1.05);
742
+ }
743
+ #softDrinkModal .modal-footer .btn-primary:active {
744
+ background-color: #0B7A29;
745
+ transform: scale(0.95);
746
+ }
747
+ /* Mobile-Specific Styles */
748
  @media (max-width: 576px) {
749
  .fixed-top-bar {
750
  height: 60px;
 
804
  }
805
  .modal-body {
806
  max-height: 50vh;
807
+ padding: 10px;
808
  }
809
  .modal-body #modal-img {
810
  max-height: 150px;
 
825
  font-size: 12px;
826
  margin-bottom: 5px;
827
  }
828
+ .modal-body .nutritional-info {
829
+ font-size: 10px;
830
+ margin-bottom: 5px;
831
+ }
832
+ .modal-body #modal-addons h5,
833
+ .modal-body #first-row h6 {
834
+ font-size: 1rem;
835
+ margin-bottom: 10px;
836
+ }
837
  .modal-footer {
838
  padding: 5px;
839
  }
 
864
  width: 50px;
865
  height: 25px;
866
  }
867
+ .customisable-text {
868
+ font-size: 8px;
869
+ }
870
  .button-container {
871
  gap: 3px;
872
  }
 
905
  font-size: 10px;
906
  margin-left: 5px;
907
  }
908
+ /* Mobile-Specific Addon Styles */
909
+ .addon-section {
910
+ margin-bottom: 10px;
911
+ }
912
+ .addon-section h6 {
913
+ font-size: 1rem;
914
+ padding: 10px 12px;
915
+ }
916
+ .addon-section .form-check {
917
+ margin: 8px 12px;
918
+ }
919
+ .addon-section .form-check-input {
920
+ width: 18px;
921
+ height: 18px;
922
+ margin-left: 8px;
923
+ }
924
+ .addon-section .form-check-input:checked::before {
925
+ font-size: 10px;
926
+ top: 2px;
927
+ left: 3px;
928
+ }
929
+ .addon-section .form-check-label {
930
+ font-size: 0.85rem;
931
+ padding: 4px 6px;
932
+ }
933
+ .addon-section .form-check-label .extra-charge {
934
+ margin-left: 6px;
935
+ font-size: 0.8rem;
936
+ }
937
+ /* Mobile-Specific Soft Drinks Modal Styles */
938
+ #softDrinkModal .modal-content {
939
+ border-radius: 8px;
940
+ }
941
+ #softDrinkModal .modal-header {
942
+ padding: 10px 12px;
943
+ }
944
+ #softDrinkModal .modal-title {
945
+ font-size: 1rem;
946
+ }
947
+ #softDrinkModal .modal-body {
948
+ padding: 15px;
949
+ }
950
+ #softDrinkModal #soft-drink-img {
951
+ max-height: 120px;
952
+ max-width: 120px;
953
+ margin-bottom: 10px;
954
+ }
955
+ #softDrinkModal #soft-drink-name {
956
+ font-size: 1.3rem;
957
+ }
958
+ #softDrinkModal #soft-drink-price {
959
+ font-size: 1rem;
960
+ margin-bottom: 15px;
961
+ }
962
+ #softDrinkModal .quantity-selector .btn {
963
+ width: 35px;
964
+ height: 35px;
965
+ font-size: 0.9rem;
966
+ line-height: 35px;
967
+ border-radius: 6px;
968
+ }
969
+ #softDrinkModal .quantity-selector input {
970
+ width: 50px;
971
+ height: 35px;
972
+ font-size: 0.9rem;
973
+ border-radius: 6px;
974
+ }
975
+ #softDrinkModal .modal-footer .btn-primary {
976
+ width: 120px;
977
+ height: 40px;
978
+ font-size: 0.9rem;
979
+ border-radius: 6px;
980
+ }
981
  }
982
  </style>
983
  </head>
 
1077
  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 }}')">
1078
  ADD
1079
  </button>
1080
+ {% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' %}
1081
+ <span class="customisable-text">Customisable</span>
1082
+ {% endif %}
1083
  {% endif %}
1084
  </div>
1085
  </div>
 
1130
  <h5 id="modal-name" class="fw-bold text-center"></h5>
1131
  <p id="modal-price" class="text-muted text-center"></p>
1132
  <p id="modal-description" class="text-secondary"></p>
1133
+ <div id="modal-addons" class="modal-addons mt-4">
1134
+ <h5>Customization Options</h5>
1135
+ <div id="addons-list" class="addons-container addon-loading"></div>
1136
+ </div>
1137
  <div class="mt-4">
1138
+ <h6>Special Instructions</h6>
1139
  <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
1140
  </div>
1141
  <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
 
1161
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
1162
  </div>
1163
  <div class="modal-body">
1164
+ <img id="soft-drink-img" class="img-fluid rounded mb-3" alt="Soft Drink Image">
1165
  <div class="text-center mb-3">
1166
  <h5 id="soft-drink-name"></h5>
1167
  <p id="soft-drink-price"></p>
1168
  </div>
1169
+ <div class="quantity-selector">
1170
+ <button type="button" class="btn btn-outline-secondary" id="soft-drink-decrease">-1</button>
1171
+ <input type="text" class="form-control text-center" id="soft-drink-quantity" value="1" readonly>
1172
  <button type="button" class="btn btn-outline-secondary" id="soft-drink-increase">+</button>
1173
  </div>
1174
  </div>
1175
  <div class="modal-footer">
 
1176
  <button type="button" class="btn btn-primary" onclick="addSoftDrinkToCart()">Add to Cart</button>
1177
  </div>
1178
  </div>
 
1183
  <script>
1184
  let isProcessingRequest = false;
1185
  let currentSoftDrinkButton = null;
1186
+ let baseItemPrice = 0;
1187
  const menuItems = [
1188
  {% for section, items in ordered_menu.items() %}
1189
  {% for item in items %}
 
1194
  {% endfor %}
1195
  {% endfor %}
1196
  ];
 
1197
  const ingredientsList = [
1198
  "Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
1199
  "Chickpea Flour (Besan)", "Chickpea Flour (for batter)", "Chickpeas (Channa)", "Chili Powder",
 
1209
  "Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
1210
  "Whole Wheat Flour", "Yogurt (Curd)"
1211
  ];
 
1212
  function addToCartLocalStorage(payload) {
1213
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
1214
  const existingItem = cart.find(item =>
1215
  item.itemName === payload.itemName &&
1216
+ item.instructions === payload.instructions &&
1217
+ JSON.stringify(item.addons) === JSON.stringify(payload.addons)
1218
  );
1219
  if (existingItem) {
1220
  existingItem.quantity = payload.quantity;
 
1224
  localStorage.setItem('cart', JSON.stringify(cart));
1225
  return cart;
1226
  }
1227
+ function removeFromCartLocalStorage(itemName, quantityToRemove, instructions, addons) {
 
1228
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
1229
  const itemIndex = cart.findIndex(item =>
1230
  item.itemName === itemName &&
1231
+ item.instructions === instructions &&
1232
+ JSON.stringify(item.addons) === JSON.stringify(addons)
1233
  );
1234
  if (itemIndex !== -1) {
1235
  if (quantityToRemove >= cart[itemIndex].quantity) {
 
1241
  localStorage.setItem('cart', JSON.stringify(cart));
1242
  return cart;
1243
  }
 
1244
  function getCartLocalStorage() {
1245
  return JSON.parse(localStorage.getItem('cart')) || [];
1246
  }
 
1247
  function debounce(func, wait) {
1248
  let timeout;
1249
  return function (...args) {
 
1251
  timeout = setTimeout(() => func.apply(this, args), wait);
1252
  };
1253
  }
1254
+ function updateModalPrice() {
1255
+ const selectedAddOns = Array.from(
1256
+ document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
1257
+ ).map(addon => parseFloat(addon.getAttribute('data-price')) || 0);
1258
+ const totalAddOnPrice = selectedAddOns.reduce((sum, price) => sum + price, 0);
1259
+ const totalPrice = baseItemPrice + totalAddOnPrice;
1260
+ document.getElementById('modal-price').innerText = `$${totalPrice.toFixed(2)}`;
1261
+ }
1262
  function showSoftDrinkModal(button) {
1263
  currentSoftDrinkButton = button;
1264
  const buttonContainer = button.closest('.button-container');
1265
  const itemName = buttonContainer.getAttribute('data-item-name');
1266
  const itemPrice = buttonContainer.getAttribute('data-item-price');
1267
+ const itemImage = buttonContainer.getAttribute('data-item-image');
1268
 
1269
  document.getElementById('soft-drink-name').textContent = itemName;
1270
  document.getElementById('soft-drink-price').textContent = `$${itemPrice}`;
1271
  document.getElementById('soft-drink-quantity').value = '1';
1272
+ document.getElementById('soft-drink-img').src = itemImage || '/static/placeholder.jpg';
1273
 
1274
  const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
1275
  modal.show();
1276
  }
 
1277
  function addSoftDrinkToCart() {
1278
  if (!currentSoftDrinkButton) return;
1279
 
 
1292
  itemImage: itemImage,
1293
  section: section,
1294
  category: selectedCategory,
1295
+ addons: [],
1296
  instructions: '',
1297
  quantity: quantity
1298
  };
 
1326
  modal.hide();
1327
  });
1328
  }
 
1329
  function updateCartUI(cart) {
1330
  if (!Array.isArray(cart)) {
1331
  console.error('Invalid cart data:', cart);
1332
  return;
1333
  }
 
1334
  let totalQuantity = 0;
1335
  cart.forEach(item => {
1336
  totalQuantity += item.quantity;
1337
  });
 
1338
  const cartItemCount = document.getElementById('cart-item-count');
1339
  if (cartItemCount) {
1340
  cartItemCount.innerText = totalQuantity;
1341
  cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
1342
  }
1343
  }
 
1344
  function showItemDetails(name, price, image, description, section, selectedCategory) {
1345
  document.getElementById('modal-name').innerText = name;
1346
+ baseItemPrice = parseFloat(price) || 0;
1347
+ document.getElementById('modal-price').innerText = `$${baseItemPrice.toFixed(2)}`;
1348
  const modalImg = document.getElementById('modal-img');
1349
  modalImg.src = image || '/static/placeholder.jpg';
1350
  document.getElementById('modal-description').innerText = description || 'No description available.';
1351
+ document.getElementById('addons-list').innerHTML = '';
1352
+ document.getElementById('addons-list').classList.add('addon-loading');
1353
  document.getElementById('modal-instructions').value = '';
1354
  const modalSectionEl = document.getElementById('modal-section');
1355
  modalSectionEl.setAttribute('data-section', section);
1356
  modalSectionEl.setAttribute('data-category', selectedCategory);
1357
  document.getElementById('quantityInput').value = 1;
 
1358
 
1359
+ fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
1360
+ .then(response => response.json())
1361
+ .then(data => {
1362
+ const addonsList = document.getElementById('addons-list');
1363
+ addonsList.classList.remove('addon-loading');
1364
+ addonsList.innerHTML = '';
1365
+ if (!data.success || !data.addons || data.addons.length === 0) {
1366
+ addonsList.innerHTML = '<p>No customization options available.</p>';
1367
+ return;
1368
+ }
1369
+
1370
+ data.addons.forEach(addon => {
1371
+ const sectionDiv = document.createElement('div');
1372
+ sectionDiv.classList.add('addon-section');
1373
+ const title = document.createElement('h6');
1374
+ title.innerText = addon.name;
1375
+ sectionDiv.appendChild(title);
1376
+ const optionsContainer = document.createElement('div');
1377
+ optionsContainer.classList.add('addon-options');
1378
+
1379
+ addon.options.forEach((option, index) => {
1380
+ const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
1381
+ const listItem = document.createElement('div');
1382
+ listItem.classList.add('form-check');
1383
+ listItem.innerHTML = `
1384
+ <input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
1385
+ data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}"
1386
+ aria-label="Select ${option} for ${addon.name}">
1387
+ <label class="form-check-label" for="${optionId}">
1388
+ ${option} ${addon.extra_charge ? `<span class="extra-charge">($${addon.extra_charge_amount.toFixed(2)})</span>` : ''}
1389
+ </label>
1390
+ `;
1391
+ optionsContainer.appendChild(listItem);
1392
+ });
1393
+
1394
+ sectionDiv.appendChild(optionsContainer);
1395
+ addonsList.appendChild(sectionDiv);
1396
+ });
1397
+
1398
+ // Add collapsible behavior
1399
+ const addonSections = addonsList.querySelectorAll('.addon-section');
1400
+ addonSections.forEach(section => {
1401
+ const title = section.querySelector('h6');
1402
+ const options = section.querySelector('.addon-options');
1403
+ title.addEventListener('click', () => {
1404
+ section.classList.toggle('collapsed');
1405
+ options.classList.toggle('collapsed');
1406
+ });
1407
+ });
1408
+
1409
+ // Update price on addon selection
1410
+ document.querySelectorAll('.addon-option').forEach(checkbox => {
1411
+ checkbox.addEventListener('change', updateModalPrice);
1412
+ });
1413
+
1414
+ // Handle single-select groups
1415
+ document.querySelectorAll('.addon-option').forEach(checkbox => {
1416
+ checkbox.addEventListener('change', function () {
1417
+ const groupName = this.getAttribute('data-group');
1418
+ const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo", "Beverages", "Sauces"].includes(groupName);
1419
+ if (!isMultiSelectGroup && this.checked) {
1420
+ document.querySelectorAll(`.addon-option[data-group="${groupName}"]`).forEach(otherCheckbox => {
1421
+ if (otherCheckbox !== this) {
1422
+ otherCheckbox.checked = false;
1423
+ }
1424
+ });
1425
+ }
1426
+ });
1427
+ });
1428
+ })
1429
+ .catch(err => {
1430
+ console.error('Error fetching add-ons:', err);
1431
+ document.getElementById('addons-list').classList.remove('addon-loading');
1432
+ document.getElementById('addons-list').innerHTML = '<p>Error loading customization options.</p>';
1433
+ });
1434
+ }
1435
  function addToCartFromModal() {
1436
  if (isProcessingRequest) return;
1437
  isProcessingRequest = true;
 
1438
  const modalSectionEl = document.getElementById('modal-section');
1439
  const section = modalSectionEl.getAttribute('data-section');
1440
  const selectedCategory = modalSectionEl.getAttribute('data-category');
 
1443
  const itemImage = document.getElementById('modal-img').src;
1444
  const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
1445
  const instructions = document.getElementById('modal-instructions').value;
1446
+ const selectedAddOns = Array.from(
1447
+ document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
1448
+ ).map(addon => ({
1449
+ name: addon.getAttribute('data-name'),
1450
+ price: parseFloat(addon.getAttribute('data-price')) || 0
1451
+ }));
1452
  if (!itemName || isNaN(itemPrice) || !section || !itemImage || quantity < 1) {
1453
  console.error('Invalid cart item data:', { itemName, itemPrice, section, itemImage, quantity });
1454
  alert('Invalid item data. Please try again.');
1455
  isProcessingRequest = false;
1456
  return;
1457
  }
 
1458
  const cartPayload = {
1459
  itemName: itemName,
1460
  itemPrice: itemPrice,
1461
  itemImage: itemImage,
1462
  section: section,
1463
  category: selectedCategory,
1464
+ addons: selectedAddOns,
1465
  instructions: instructions,
1466
  quantity: quantity
1467
  };
 
1468
  fetch('/cart/add', {
1469
  method: 'POST',
1470
  headers: {
 
1497
  isProcessingRequest = false;
1498
  });
1499
  }
 
1500
  document.addEventListener('DOMContentLoaded', function () {
1501
  // Avatar Dropdown
1502
  const avatarContainer = document.querySelector('.avatar-dropdown-container');
 
1516
  dropdownMenu.style.display = 'none';
1517
  });
1518
  });
 
1519
  // Navigate to search page on search bar click
1520
  const searchBar = document.getElementById('searchBar');
1521
  searchBar.addEventListener('click', function () {
1522
  window.location.href = '/search';
1523
  });
 
1524
  // Auto-open modal for selected item
1525
  const selectedItem = localStorage.getItem('selectedItem');
1526
  if (selectedItem) {
 
1529
  const menuCards = document.querySelectorAll('.menu-card');
1530
  let targetCard = null;
1531
  let buttonContainer = null;
 
1532
  menuCards.forEach(card => {
1533
  const itemName = card.getAttribute('data-item-name');
1534
  const itemSection = card.getAttribute('data-item-section');
 
1543
  }
1544
  }
1545
  });
 
1546
  if (buttonContainer) {
1547
  if (section === 'Soft Drinks') {
1548
  showSoftDrinkModal(buttonContainer.querySelector('.add-to-cart-btn'));
 
1562
  }
1563
  localStorage.removeItem('selectedItem');
1564
  }
 
1565
  // Lazy Loading for Cards and Videos
1566
  const menuCards = document.querySelectorAll('.menu-card');
1567
  const menuVideos = document.querySelectorAll('.menu-video');
 
1598
  });
1599
  menuCards.forEach(card => cardObserver.observe(card));
1600
  menuVideos.forEach(video => videoObserver.observe(video));
 
1601
  // Toggle Details
1602
  const toggleLinks = document.querySelectorAll('.toggle-details');
1603
  toggleLinks.forEach(link => {
 
1605
  const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
1606
  const detailsDiv = document.getElementById(`details-${itemName}`);
1607
  const isCurrentlyShown = detailsDiv.classList.contains('show');
 
1608
  document.querySelectorAll('.item-details.show').forEach(otherDetails => {
1609
  if (otherDetails !== detailsDiv) {
1610
  otherDetails.classList.remove('show');
 
1614
  }
1615
  }
1616
  });
 
1617
  if (!isCurrentlyShown) {
1618
  detailsDiv.classList.add('show');
1619
  this.innerText = 'Hide Details';
 
1623
  }
1624
  });
1625
  });
 
1626
  // Category Selection
1627
  const categoryButtons = document.querySelectorAll('.category-button');
1628
  const categoryForm = document.getElementById('categoryForm');
 
1639
  categoryForm.submit();
1640
  });
1641
  });
 
1642
  // Custom Dish Form Suggestions
1643
  const descriptionTextarea = document.getElementById('custom-dish-description');
1644
  const descriptionSuggestions = document.getElementById('descriptionSuggestions');
 
1693
  }
1694
  });
1695
  }
 
1696
  // Fetch Cart
1697
  fetch('/cart/get')
1698
  .then(response => {
 
1715
  const cart = getCartLocalStorage();
1716
  updateCartUI(cart);
1717
  });
 
1718
  // Preload Videos
1719
  const preloadedVideos = document.querySelectorAll('link[rel="preload"][as="video"]');
1720
  preloadedVideos.forEach(link => {
 
1722
  video.src = link.href;
1723
  video.preload = 'auto';
1724
  });
 
1725
  // Quantity Controls for Item Modal
1726
  const decreaseBtn = document.getElementById('decreaseQuantity');
1727
  const increaseBtn = document.getElementById('increaseQuantity');
 
1740
  quantityInput.value = currentQuantity;
1741
  }
1742
  });
 
1743
  // Soft Drinks Modal Quantity Controls
1744
  const softDrinkDecreaseBtn = document.getElementById('soft-drink-decrease');
1745
  const softDrinkIncreaseBtn = document.getElementById('soft-drink-increase');
 
1760
  softDrinkQuantityInput.value = currentQuantity;
1761
  }
1762
  });
 
1763
  // Voice Recognition
1764
  const micIcon = document.getElementById('micIcon');
1765
  if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {