lokesh341 commited on
Commit
5174a69
·
verified ·
1 Parent(s): 50de36b

Update templates/menu.html

Browse files
Files changed (1) hide show
  1. templates/menu.html +164 -762
templates/menu.html CHANGED
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
@@ -42,6 +42,10 @@
42
  .menu-card.visible {
43
  opacity: 1;
44
  }
 
 
 
 
45
  .menu-video {
46
  height: 200px;
47
  width: 100%;
@@ -49,14 +53,14 @@
49
  border-radius: 15px 15px 0 0;
50
  opacity: 0;
51
  transition: opacity 0.5s ease-in-out;
52
- background-color: #000;
53
  }
54
  .menu-video.loaded {
55
  opacity: 1;
56
  }
57
  .menu-card:hover .menu-video {
58
  opacity: 1;
59
- transform: scale(1.05);
60
  }
61
  .menu-card .card-body .card-title {
62
  font-size: 1.2rem;
@@ -131,7 +135,7 @@
131
  top: 50%;
132
  transform: translateY(-50%);
133
  display: flex;
134
- align-items: center;
135
  justify-content: center;
136
  }
137
  .avatar-icon {
@@ -146,81 +150,33 @@
146
  color: white;
147
  font-size: 20px;
148
  font-weight: bold;
149
- position: relative;
150
- transition: transform 0.2s ease;
151
- }
152
- .avatar-icon:hover {
153
- transform: scale(1.1);
154
- }
155
- .avatar-icon img {
156
- width: 100%;
157
- height: 100%;
158
- object-fit: cover;
159
- border-radius: 50%;
160
- transition: transform 0.2s ease;
161
- }
162
- .avatar-icon img:hover {
163
- transform: scale(1.1);
164
  }
165
  .dropdown-menu {
166
  position: absolute;
167
  right: 0;
168
  top: 100%;
169
  background-color: #fff8f0;
170
- border-radius: 8px;
171
- width: 200px;
172
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
173
  display: none;
174
  border: 1px solid #ffd8b1;
175
- padding: 5px 0;
176
- z-index: 1000;
177
  }
178
  .dropdown-menu .dropdown-item {
179
- padding: 10px 16px;
180
  text-decoration: none;
181
  color: #333;
182
- font-size: 14px;
183
- transition: background-color 0.2s ease, color 0.2s ease;
184
- cursor: pointer;
 
 
 
 
185
  }
186
  .dropdown-menu .dropdown-item:hover {
187
  background-color: #ffe4c4;
188
- color: #2c2c2c;
189
- }
190
- .upload-item,
191
- .delete-item,
192
- .view-item {
193
- padding: 10px 16px;
194
- text-decoration: none;
195
  color: #333;
196
- font-size: 14px;
197
- transition: background-color 0.2s ease;
198
- cursor: pointer;
199
- }
200
- .upload-item:hover,
201
- .delete-item:hover,
202
- .view-item:hover {
203
- background-color: #ffe4c4;
204
- color: #2c2c2c;
205
- }
206
- .submenu {
207
- position: absolute;
208
- left: 100%;
209
- top: 0;
210
- background-color: #fff8f0;
211
- border-radius: 8px;
212
- width: 250px;
213
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
214
- display: none;
215
- border: 1px solid #ffd8b1;
216
- padding: 5px 0;
217
- max-height: 300px;
218
- overflow-y: auto;
219
- z-index: 1001;
220
- }
221
- .menu-item-name {
222
- padding: 8px 12px;
223
- font-size: 13px;
224
  }
225
  .fixed-top-bar {
226
  position: relative;
@@ -272,22 +228,11 @@
272
  font-size: 18px;
273
  color: #888;
274
  cursor: pointer;
275
- transition: Wcolor 0.3s ease;
276
  }
277
  .mic-icon.active {
278
  color: #007bff;
279
  }
280
- .mic-unsupported {
281
- display: none;
282
- position: absolute;
283
- right: 15px;
284
- font-size: 14px;
285
- color: #888;
286
- background-color: #fff;
287
- padding: 2px 8px;
288
- border-radius: 10px;
289
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
290
- }
291
  .autocomplete-suggestions {
292
  position: absolute;
293
  top: 100%;
@@ -380,15 +325,6 @@
380
  max-height: 60vh;
381
  overflow-y: auto;
382
  padding: 15px;
383
- text-align: center;
384
- }
385
- .modal-body #avatar-modal-img {
386
- max-width: 100%;
387
- max-height: 400px;
388
- object-fit: contain;
389
- border-radius: 8px;
390
- margin: 0 auto;
391
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
392
  }
393
  .modal-body #modal-img {
394
  max-height: 200px;
@@ -463,42 +399,45 @@
463
  width: 40px;
464
  }
465
  .item-details {
466
- display: none;
467
- padding: 15px;
468
  background-color: #f8f9fa;
469
  border-radius: 8px;
470
- margin-top: 10px;
471
  margin: 10px 15px;
472
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
473
  }
474
  .item-details.show {
475
  display: block;
476
  }
477
  .item-details h6 {
478
- color: #0FAA39;
479
- margin-bottom: 10px;
480
- font-size: 1.1rem;
481
  font-weight: bold;
 
 
482
  }
483
  .item-details p {
484
- margin-bottom: 15px;
485
- color: #555;
 
 
 
 
 
 
 
 
 
 
486
  line-height: 1.5;
487
- font-size: 0.9rem;
488
  }
489
  .toggle-details {
490
  cursor: pointer;
491
  color: #0FAA39;
492
  font-size: 0.9rem;
493
- text-align: left;
494
- padding: 5px 0;
495
- transition: color 0.3s ease;
496
- display: block;
497
- width: 100%;
498
- margin-top: 5px;
499
  }
500
  .toggle-details:hover {
501
- color: #0D9232;
502
  text-decoration: underline;
503
  }
504
  .category-buttons {
@@ -650,50 +589,6 @@
650
  font-size: 12px;
651
  margin-left: 8px;
652
  }
653
- .mic-popup {
654
- position: fixed;
655
- top: 50%;
656
- left: 50%;
657
- transform: translate(-50%, -50%);
658
- background-color: rgba(0, 0, 0, 0.8);
659
- color: white;
660
- padding: 30px;
661
- border-radius: 15px;
662
- text-align: center;
663
- z-index: 2000;
664
- display: none;
665
- width: 300px;
666
- max-width: 90%;
667
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
668
- }
669
- .mic-popup.active {
670
- display: block;
671
- }
672
- .mic-popup-icon {
673
- font-size: 48px;
674
- margin-bottom: 20px;
675
- color: #ff4444;
676
- animation: pulse 1.5s infinite;
677
- }
678
- .mic-popup-text {
679
- font-size: 18px;
680
- margin-bottom: 15px;
681
- min-height: 24px;
682
- }
683
- .mic-popup-cancel {
684
- background-color: #ff4444;
685
- color: white;
686
- border: none;
687
- padding: 8px 20px;
688
- border-radius: 20px;
689
- cursor: pointer;
690
- font-weight: bold;
691
- }
692
- @keyframes pulse {
693
- 0% { transform: scale(1); }
694
- 50% { transform: scale(1.1); }
695
- 100% { transform: scale(1); }
696
- }
697
  @media (max-width: 576px) {
698
  .fixed-top-bar {
699
  height: 60px;
@@ -728,17 +623,11 @@
728
  font-size: 20px;
729
  }
730
  .dropdown-menu {
731
- width: 180px;
732
  }
733
  .dropdown-menu .dropdown-item {
734
- padding: 8px 12px;
735
- font-size: 13px;
736
- }
737
- .upload-item,
738
- .delete-item,
739
- .view-item {
740
- padding: 8px 12px;
741
- font-size: 13px;
742
  }
743
  .category-buttons {
744
  gap: 8px;
@@ -761,9 +650,6 @@
761
  max-height: 50vh;
762
  padding: 8px;
763
  }
764
- .modal-body #avatar-modal-img {
765
- max-height: 300px;
766
- }
767
  .modal-body #modal-img {
768
  max-height: 150px;
769
  width: 100%;
@@ -863,71 +749,26 @@
863
  font-size: 10px;
864
  margin-left: 5px;
865
  }
866
- .item-details {
867
- padding: 10px;
868
- margin: 5px 10px;
869
- }
870
- .item-details h6 {
871
- font-size: 0.95rem;
872
- }
873
- .item-details p {
874
- font-size: 0.8rem;
875
- }
876
- .toggle-details {
877
- font-size: 0.8rem;
878
- }
879
- .mic-popup {
880
- padding: 20px;
881
- width: 280px;
882
- }
883
- .mic-popup-icon {
884
- font-size: 36px;
885
- margin-bottom: 15px;
886
- }
887
- .mic-popup-text {
888
- font-size: 16px;
889
- }
890
- .mic-popup-cancel {
891
- padding: 6px 16px;
892
- font-size: 14px;
893
- }
894
  }
895
  </style>
896
  </head>
897
  <body>
 
898
  <div class="fixed-top-bar">
899
  <div class="avatar-dropdown-container">
900
- <div class="avatar-icon" id="avatarIcon">
901
- {% if user_image %}
902
- <img src="{{ user_image }}" alt="User Avatar" class="avatar-image">
903
- {% else %}
904
- <span>{{ first_letter }}</span>
905
- {% endif %}
906
  </div>
907
- <div class="dropdown-menu" id="avatarDropdown">
908
- {% if user_image %}
909
- <div class="dropdown-item delete-item" id="deleteAvatar">Delete Image</div>
910
- <div class="dropdown-item view-item" id="viewAvatar">View Avatar</div>
911
- {% endif %}
912
- <a href="{{ url_for('orderhistory.order_history') }}" class="dropdown-item">Order History</a>
913
  <a href="{{ url_for('user_details.customer_details') }}" class="dropdown-item">View Profile</a>
914
- <div class="dropdown-item upload-item">
915
- <label for="avatarUpload" style="cursor: pointer; margin: 0; width: 100%;">
916
- Upload Image
917
- </label>
918
- <input type="file" id="avatarUpload" accept="image/*" style="display: none;">
919
- </div>
920
- <!-- New Dropdown Item for All Menu Items with Modal Trigger -->
921
- <div class="dropdown-item" id="allMenuItems" data-bs-toggle="modal" data-bs-target="#allMenuModal">All Menu Items</div>
922
  <a href="{{ url_for('logout') }}" class="dropdown-item">Logout</a>
923
  </div>
924
  </div>
925
-
926
  <div class="search-bar-container">
927
  <input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off">
928
  <i class="bi bi-search search-icon"></i>
929
  <i class="bi bi-mic mic-icon" id="micIcon"></i>
930
- <span class="mic-unsupported" id="micUnsupported">Mic not supported</span>
931
  <div id="autocompleteSuggestions" class="autocomplete-suggestions"></div>
932
  </div>
933
  </div>
@@ -947,7 +788,7 @@
947
  {% if selected_category == "Customized Dish" %}
948
  <div id="custom-dish-form" class="mt-4">
949
  <h3>Create Your Custom Dish</h3>
950
- <form method="POST" action="/customdish/generate_custom_dish" id="customDishForm">
951
  <div class="mb-3">
952
  <label for="custom-dish-name" class="form-label">Dish Name</label>
953
  <input type="text" class="form-control" id="custom-dish-name" name="name" required>
@@ -968,8 +809,8 @@
968
  <h3>{{ section }}</h3>
969
  <div class="row">
970
  {% for item in items %}
971
- <div class="col-md-6 mb-4" data-item-name="{{ item.Name | default('Unnamed Item') | e }}">
972
- <div class="card menu-card">
973
  <video
974
  class="card-img-top menu-video"
975
  muted
@@ -990,15 +831,12 @@
990
  <div>
991
  <h5 class="card-title">{{ item.Name | default('Unnamed Item') }}</h5>
992
  <p class="card-text price">${{ item.Price__c | default('0.00') }}</p>
993
- {% if item.Section__c != 'Soft Drinks' %}
994
- <div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}">Show Details</div>
995
- {% endif %}
996
  </div>
997
  <div class="d-flex flex-column align-item-center justify-content-center">
998
  <div class="button-container"
999
  data-item-name="{{ item.Name | default('Unnamed Item') }}"
1000
  data-item-price="{{ item.Price__c | default('0.00') }}"
1001
- data-item-image="{{ item.Image2__c | default(item.Image1__c) | default('/static/placeholder.jpg') }}"
1002
  data-item-section="{{ item.Section__c | default(section) }}"
1003
  data-item-category="{{ selected_category }}">
1004
  {% if item.Section__c == 'Soft Drinks' %}
@@ -1007,7 +845,7 @@
1007
  <button class="btn btn-primary"
1008
  data-bs-toggle="modal"
1009
  data-bs-target="#itemModal"
1010
- onclick="showItemDetails('{{ item.Name | default('Unnamed Item') | e }}', '{{ item.Price__c | default('0.00') }}', '{{ item.Image2__c | default(item.Image1__c) | default('/static/placeholder.jpg') }}', '{{ item.Description__c | default('No description') | e }}', '{{ item.IngredientsInfo__c | default('Not specified') | e }}', '{{ item.NutritionalInfo__c | default('Not available') | e }}', '{{ item.Allergens__c | default('None listed') | e }}', '{{ item.Section__c | default(section) | e }}', '{{ selected_category | e }}')">
1011
  ADD
1012
  </button>
1013
  {% endif %}
@@ -1018,14 +856,16 @@
1018
  </div>
1019
  </div>
1020
  </div>
 
1021
  {% if item.Section__c != 'Soft Drinks' %}
 
1022
  <div class="item-details" id="details-{{ item.Name | default('unnamed-item') | replace(' ', '-') }}">
1023
  <h6>Description</h6>
1024
  <p>{{ item.Description__c | default('No description available') }}</p>
1025
- <h6>Ingredients Info</h6>
1026
- <p>{{ item.IngredientsInfo__c | default('Not specified') }}</p>
1027
  <h6>Nutritional Info</h6>
1028
- <p>{{ item.NutritionalInfo__c | default('Not available') }}</p>
1029
  <h6>Allergens</h6>
1030
  <p>{{ item.Allergens__c | default('None listed') }}</p>
1031
  </div>
@@ -1045,7 +885,7 @@
1045
  </a>
1046
  <a href="{{ url_for('cart.cart') }}" class="btn btn-view-cart">
1047
  <i class="bi bi-cart"></i> View Cart
1048
- <span class="cart-icon-badge" id="cart-item-count">{{ cart_item_count }}</span>
1049
  </a>
1050
  </div>
1051
 
@@ -1062,11 +902,6 @@
1062
  <h5 id="modal-name" class="fw-bold text-center"></h5>
1063
  <p id="modal-price" class="text-muted text-center"></p>
1064
  <p id="modal-description" class="text-secondary"></p>
1065
- <div class="nutritional-info">
1066
- <strong>Ingredients:</strong> <span id="modal-ingredients"></span><br>
1067
- <strong>Nutrition:</strong> <span id="modal-nutrition"></span><br>
1068
- <strong>Allergens:</strong> <span id="modal-allergens"></span>
1069
- </div>
1070
  <div id="modal-addons" class="modal-addons mt-4">
1071
  <h6>Customization Options</h6>
1072
  <div id="addons-list" class="addons-container">Loading customization options...</div>
@@ -1089,62 +924,33 @@
1089
  </div>
1090
  </div>
1091
 
1092
- <!-- Modal for Avatar View -->
1093
- <div class="modal fade" id="avatarModal" tabindex="-1" aria-labelledby="avatarModalLabel" aria-hidden="true">
1094
- <div class="modal-dialog modal-dialog-centered modal-lg">
1095
  <div class="modal-content">
1096
  <div class="modal-header">
1097
- <h5 class="modal-title" id="avatarModalLabel">View Avatar</h5>
1098
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
1099
  </div>
1100
  <div class="modal-body">
1101
- <img id="avatar-modal-img" class="img-fluid rounded mx-auto d-block" alt="Avatar Image" style="max-height: 400px; object-fit: contain;">
1102
- </div>
1103
- <div class="modal-footer">
1104
- <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
1105
- </div>
1106
- </div>
1107
- </div>
1108
- </div>
1109
-
1110
- <!-- Modal for Soft Drinks Quantity Selection -->
1111
- <div class="modal fade" id="softDrinkModal" tabindex="-1" aria-labelledby="softDrinkModalLabel" aria-hidden="true">
1112
- <div class="modal-dialog modal-dialog-centered">
1113
- <div class="modal-content" style="border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.2);">
1114
- <div class="modal-header" style="background: linear-gradient(45deg, #0FAA39, #0D9232); color: white; border-radius: 15px 15px 0 0;">
1115
- <h5 class="modal-title" id="softDrinkModalLabel">Select Your Drink</h5>
1116
- <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
1117
- </div>
1118
- <div class="modal-body" style="padding: 20px;">
1119
- <div class="text-center mb-4">
1120
- <img id="soft-drink-image" class="img-fluid rounded mb-3" alt="Soft Drink Image" style="max-height: 150px; width: auto; object-fit: contain;">
1121
- <h5 id="soft-drink-name" class="fw-bold" style="color: #333;"></h5>
1122
- <p id="soft-drink-price" class="text-muted" style="font-size: 1.1rem;"></p>
1123
  </div>
1124
  <div class="d-flex justify-content-center align-items-center mb-4">
1125
- <div class="quantity-selector" style="background-color: #f8f9fa; padding: 10px; border-radius: 10px;">
1126
- <button type="button" class="btn btn-outline-secondary" id="soft-drink-decrease" style="width: 40px; height: 40px;">-</button>
1127
- <input type="text" class="form-control text-center mx-2" id="soft-drink-quantity" value="1" readonly style="width: 60px; font-weight: bold; font-size: 1.1rem;">
1128
- <button type="button" class="btn btn-outline-secondary" id="soft-drink-increase" style="width: 40px; height: 40px;">+</button>
1129
- </div>
1130
  </div>
1131
  </div>
1132
- <div class="modal-footer" style="border-top: none; padding: 0 20px 20px 20px; justify-content: center;">
1133
- <button type="button" class="btn btn-primary" onclick="addSoftDrinkToCart()" style="width: 200px; padding: 12px; font-size: 1.1rem; background-color: #0FAA39; border-color: #0FAA39;">Add to Cart</button>
 
1134
  </div>
1135
  </div>
1136
  </div>
1137
  </div>
1138
 
1139
- <!-- Mic Popup -->
1140
- <div class="mic-popup" id="micPopup">
1141
- <div class="mic-popup-icon">
1142
- <i class="bi bi-mic-fill"></i>
1143
- </div>
1144
- <div class="mic-popup-text" id="micPopupText">Listening...</div>
1145
- <button class="mic-popup-cancel" id="micPopupCancel">Cancel</button>
1146
- </div>
1147
-
1148
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
1149
  <script>
1150
  let isProcessingRequest = false;
@@ -1153,7 +959,10 @@
1153
  const menuItems = [
1154
  {% for section, items in ordered_menu.items() %}
1155
  {% for item in items %}
1156
- "{{ item.Name | default('Unnamed Item') | e }}",
 
 
 
1157
  {% endfor %}
1158
  {% endfor %}
1159
  ];
@@ -1174,13 +983,6 @@
1174
  "Whole Wheat Flour", "Yogurt (Curd)"
1175
  ];
1176
 
1177
- // Utility function to sanitize input to prevent XSS
1178
- function sanitizeInput(input) {
1179
- const div = document.createElement('div');
1180
- div.textContent = input;
1181
- return div.innerHTML;
1182
- }
1183
-
1184
  function addToCartLocalStorage(payload) {
1185
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
1186
  const existingItem = cart.find(item =>
@@ -1230,15 +1032,12 @@
1230
  function showSoftDrinkModal(button) {
1231
  currentSoftDrinkButton = button;
1232
  const buttonContainer = button.closest('.button-container');
1233
- const itemName = sanitizeInput(buttonContainer.getAttribute('data-item-name'));
1234
  const itemPrice = buttonContainer.getAttribute('data-item-price');
1235
- const itemImage = buttonContainer.getAttribute('data-item-image');
1236
 
1237
  document.getElementById('soft-drink-name').textContent = itemName;
1238
  document.getElementById('soft-drink-price').textContent = `$${itemPrice}`;
1239
  document.getElementById('soft-drink-quantity').value = '1';
1240
- const softDrinkImage = document.getElementById('soft-drink-image');
1241
- softDrinkImage.src = itemImage || '/static/placeholder.jpg';
1242
 
1243
  const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
1244
  modal.show();
@@ -1250,11 +1049,11 @@
1250
  const buttonContainer = currentSoftDrinkButton.closest('.button-container');
1251
  const quantity = parseInt(document.getElementById('soft-drink-quantity').value) || 1;
1252
 
1253
- const itemName = sanitizeInput(buttonContainer.getAttribute('data-item-name'));
1254
  const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
1255
  const itemImage = buttonContainer.getAttribute('data-item-image');
1256
- const section = sanitizeInput(buttonContainer.getAttribute('data-item-section'));
1257
- const selectedCategory = sanitizeInput(buttonContainer.getAttribute('data-item-category'));
1258
 
1259
  const cartPayload = {
1260
  itemName: itemName,
@@ -1277,13 +1076,11 @@
1277
  .then(response => response.json())
1278
  .then(data => {
1279
  if (data.success) {
1280
- alert('Item added to cart successfully!');
1281
  updateCartUI(data.cart);
1282
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1283
  modal.hide();
1284
  } else {
1285
  console.error('Failed to add item to cart:', data.error);
1286
- alert(data.error || 'Failed to add item to cart. Using local storage as fallback.');
1287
  const cart = addToCartLocalStorage(cartPayload);
1288
  updateCartUI(cart);
1289
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
@@ -1292,7 +1089,6 @@
1292
  })
1293
  .catch(err => {
1294
  console.error('Error adding item to cart:', err);
1295
- alert('Error adding item to cart. Using local storage as fallback.');
1296
  const cart = addToCartLocalStorage(cartPayload);
1297
  updateCartUI(cart);
1298
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
@@ -1319,242 +1115,52 @@
1319
  }
1320
 
1321
  document.addEventListener('DOMContentLoaded', function () {
 
1322
  const avatarContainer = document.querySelector('.avatar-dropdown-container');
1323
- const dropdownMenu = document.querySelector('#avatarDropdown');
1324
- const avatarIcon = document.getElementById('avatarIcon');
1325
- const avatarUpload = document.getElementById('avatarUpload');
1326
- const deleteAvatar = document.getElementById('deleteAvatar');
1327
- const viewAvatar = document.getElementById('viewAvatar');
1328
- const allMenuItems = document.getElementById('allMenuItems');
1329
- const menuItemsSubmenu = document.getElementById('menuItemsSubmenu');
1330
-
1331
- // Load avatar from localStorage if available
1332
- function loadAvatar() {
1333
- const savedAvatar = localStorage.getItem('userAvatar');
1334
- const avatarImage = avatarIcon.querySelector('.avatar-image');
1335
- if (savedAvatar && !avatarImage) {
1336
- const img = document.createElement('img');
1337
- img.src = savedAvatar;
1338
- img.alt = 'User Avatar';
1339
- img.className = 'avatar-image';
1340
- img.style.cssText = 'width: 100%; height: 100%; object-fit: cover; border-radius: 50%;';
1341
- avatarIcon.innerHTML = '';
1342
- avatarIcon.appendChild(img);
1343
- ensureAvatarOptions();
1344
- } else if (!savedAvatar && avatarImage) {
1345
- avatarIcon.innerHTML = `<span>{{ first_letter }}</span>`;
1346
- removeAvatarOptions();
1347
- }
1348
- }
1349
-
1350
- // Ensure avatar options (Delete and View) are present only once
1351
- function ensureAvatarOptions() {
1352
- if (!document.querySelector('#deleteAvatar')) {
1353
- const deleteItem = document.createElement('div');
1354
- deleteItem.className = 'dropdown-item delete-item';
1355
- deleteItem.id = 'deleteAvatar';
1356
- deleteItem.innerText = 'Delete Image';
1357
- dropdownMenu.insertBefore(deleteItem, dropdownMenu.firstChild);
1358
- addDeleteListener(deleteItem);
1359
- }
1360
- if (!document.querySelector('#viewAvatar')) {
1361
- const viewItem = document.createElement('div');
1362
- viewItem.className = 'dropdown-item view-item';
1363
- viewItem.id = 'viewAvatar';
1364
- viewItem.innerText = 'View Avatar';
1365
- const firstChild = dropdownMenu.firstChild;
1366
- if (firstChild) dropdownMenu.insertBefore(viewItem, firstChild.nextSibling);
1367
- addViewListener(viewItem);
1368
- }
1369
- }
1370
-
1371
- // Remove avatar options
1372
- function removeAvatarOptions() {
1373
- const deleteItem = document.getElementById('deleteAvatar');
1374
- const viewItem = document.getElementById('viewAvatar');
1375
- if (deleteItem) deleteItem.remove();
1376
- if (viewItem) viewItem.remove();
1377
- }
1378
-
1379
- // Save avatar to localStorage
1380
- function saveAvatar(imageUrl) {
1381
- localStorage.setItem('userAvatar', imageUrl);
1382
- }
1383
-
1384
- // Clear avatar from localStorage
1385
- function clearAvatar() {
1386
- localStorage.removeItem('userAvatar');
1387
- avatarIcon.innerHTML = `<span>{{ first_letter }}</span>`;
1388
- removeAvatarOptions();
1389
- }
1390
-
1391
- // Avatar click handler
1392
- avatarIcon.addEventListener('click', function(event) {
1393
  event.stopPropagation();
1394
  dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
1395
  });
1396
-
1397
- // Show/hide submenu on hover for "All Menu Items"
1398
- allMenuItems.addEventListener('mouseenter', function() {
1399
- menuItemsSubmenu.style.display = 'block';
1400
- });
1401
- allMenuItems.addEventListener('mouseleave', function() {
1402
- setTimeout(() => {
1403
- if (!menuItemsSubmenu.matches(':hover') && !allMenuItems.matches(':hover')) {
1404
- menuItemsSubmenu.style.display = 'none';
1405
- }
1406
- }, 100);
1407
- });
1408
- menuItemsSubmenu.addEventListener('mouseenter', function() {
1409
- menuItemsSubmenu.style.display = 'block';
1410
- });
1411
- menuItemsSubmenu.addEventListener('mouseleave', function() {
1412
- if (!allMenuItems.matches(':hover')) {
1413
- menuItemsSubmenu.style.display = 'none';
1414
  }
1415
  });
 
 
 
 
 
 
1416
 
1417
- // Handle image upload with 15MB limit and error handling
1418
- avatarUpload.addEventListener('change', function(event) {
1419
- const file = event.target.files[0];
1420
- if (file) {
1421
- const maxSize = 15 * 1024 * 1024; // 15MB in bytes
1422
- if (file.size > maxSize) {
1423
- alert('Image size must not exceed 15MB.');
1424
- this.value = '';
1425
- return;
1426
- }
1427
- const reader = new FileReader();
1428
- reader.onload = function(e) {
1429
- const base64Image = e.target.result;
1430
- fetch('/upload_avatar', {
1431
- method: 'POST',
1432
- headers: {
1433
- 'Content-Type': 'application/json',
1434
- },
1435
- body: JSON.stringify({ image: base64Image })
1436
- })
1437
- .then(response => {
1438
- if (!response.ok) throw new Error('Upload failed');
1439
- return response.json();
1440
- })
1441
- .then(data => {
1442
- if (data.success) {
1443
- const img = document.createElement('img');
1444
- img.src = data.image || '/static/default-avatar.jpg';
1445
- img.alt = 'User Avatar';
1446
- img.className = 'avatar-image';
1447
- img.style.cssText = 'width: 100%; height: 100%; object-fit: cover; border-radius: 50%;';
1448
- avatarIcon.innerHTML = '';
1449
- avatarIcon.appendChild(img);
1450
- saveAvatar(data.image);
1451
- ensureAvatarOptions();
1452
- dropdownMenu.style.display = 'none';
1453
- } else {
1454
- alert('Failed to upload image: ' + (data.error || 'Unknown error. Using default image.'));
1455
- const img = document.createElement('img');
1456
- img.src = '/static/default-avatar.jpg';
1457
- img.alt = 'User Avatar';
1458
- img.className = 'avatar-image';
1459
- img.style.cssText = 'width: 100%; height: 100%; object-fit: cover; border-radius: 50%;';
1460
- avatarIcon.innerHTML = '';
1461
- avatarIcon.appendChild(img);
1462
- saveAvatar('/static/default-avatar.jpg');
1463
- ensureAvatarOptions();
1464
- dropdownMenu.style.display = 'none';
1465
- }
1466
- })
1467
- .catch(error => {
1468
- console.error('Upload error:', error);
1469
- alert('Error uploading image. Using default image as fallback.');
1470
- const img = document.createElement('img');
1471
- img.src = '/static/default-avatar.jpg';
1472
- img.alt = 'User Avatar';
1473
- img.className = 'avatar-image';
1474
- img.style.cssText = 'width: 100%; height: 100%; object-fit: cover; border-radius: 50%;';
1475
- avatarIcon.innerHTML = '';
1476
- avatarIcon.appendChild(img);
1477
- saveAvatar('/static/default-avatar.jpg');
1478
- ensureAvatarOptions();
1479
- dropdownMenu.style.display = 'none';
1480
- });
1481
- };
1482
- reader.onerror = function() {
1483
- alert('Error reading the image file. Using default image as fallback.');
1484
- const img = document.createElement('img');
1485
- img.src = '/static/default-avatar.jpg';
1486
- img.alt = 'User Avatar';
1487
- img.className = 'avatar-image';
1488
- img.style.cssText = 'width: 100%; height: 100%; object-fit: cover; border-radius: 50%;';
1489
- avatarIcon.innerHTML = '';
1490
- avatarIcon.appendChild(img);
1491
- saveAvatar('/static/default-avatar.jpg');
1492
- ensureAvatarOptions();
1493
- dropdownMenu.style.display = 'none';
1494
- };
1495
- reader.readAsDataURL(file);
1496
- }
1497
  });
1498
 
1499
- // Handle image deletion
1500
- function addDeleteListener(deleteElement) {
1501
- deleteElement.addEventListener('click', function() {
1502
- fetch('/delete_avatar', {
1503
- method: 'POST',
1504
- headers: {
1505
- 'Content-Type': 'application/json'
1506
- }
1507
- })
1508
- .then(response => {
1509
- if (!response.ok) throw new Error('Delete failed');
1510
- return response.json();
1511
- })
1512
- .then(data => {
1513
- if (data.success) {
1514
- clearAvatar();
1515
- dropdownMenu.style.display = 'none';
1516
- } else {
1517
- alert('Failed to delete image: ' + (data.error || 'Unknown error'));
1518
  }
1519
- })
1520
- .catch(error => {
1521
- console.error('Delete error:', error);
1522
- alert('Error deleting image. Please try again.');
1523
- });
1524
- });
1525
- }
1526
-
1527
- // Handle avatar view
1528
- function addViewListener(viewElement) {
1529
- viewElement.addEventListener('click', function() {
1530
- const avatarImage = avatarIcon.querySelector('.avatar-image');
1531
- if (avatarImage) {
1532
- const modalImg = document.getElementById('avatar-modal-img');
1533
- modalImg.src = avatarImage.src;
1534
- const modal = new bootstrap.Modal(document.getElementById('avatarModal'));
1535
- modal.show();
1536
- } else {
1537
- alert('No avatar image to view.');
1538
  }
1539
- dropdownMenu.style.display = 'none';
1540
  });
 
 
1541
  }
1542
 
1543
- // Add listeners if elements exist
1544
- if (deleteAvatar) addDeleteListener(deleteAvatar);
1545
- if (viewAvatar) addViewListener(viewAvatar);
1546
-
1547
- // Load avatar on page load
1548
- loadAvatar();
1549
-
1550
- // Close dropdown when clicking outside
1551
- document.addEventListener('click', function(event) {
1552
- if (!avatarContainer.contains(event.target)) {
1553
- dropdownMenu.style.display = 'none';
1554
- menuItemsSubmenu.style.display = 'none';
1555
- }
1556
- });
1557
-
1558
  const menuCards = document.querySelectorAll('.menu-card');
1559
  const menuVideos = document.querySelectorAll('.menu-video');
1560
  const cardObserver = new IntersectionObserver((entries, observer) => {
@@ -1591,6 +1197,7 @@
1591
  menuCards.forEach(card => cardObserver.observe(card));
1592
  menuVideos.forEach(video => videoObserver.observe(video));
1593
 
 
1594
  const toggleLinks = document.querySelectorAll('.toggle-details');
1595
  toggleLinks.forEach(link => {
1596
  link.addEventListener('click', function () {
@@ -1598,16 +1205,18 @@
1598
  const detailsDiv = document.getElementById(`details-${itemName}`);
1599
  const isCurrentlyShown = detailsDiv.classList.contains('show');
1600
 
 
1601
  document.querySelectorAll('.item-details.show').forEach(otherDetails => {
1602
  if (otherDetails !== detailsDiv) {
1603
  otherDetails.classList.remove('show');
1604
- const otherLink = otherDetails.previousElementSibling.querySelector('.toggle-details');
1605
  if (otherLink) {
1606
  otherLink.innerText = 'Show Details';
1607
  }
1608
  }
1609
  });
1610
 
 
1611
  if (!isCurrentlyShown) {
1612
  detailsDiv.classList.add('show');
1613
  this.innerText = 'Hide Details';
@@ -1618,13 +1227,14 @@
1618
  });
1619
  });
1620
 
 
1621
  const categoryButtons = document.querySelectorAll('.category-button');
1622
  const categoryForm = document.getElementById('categoryForm');
1623
  const selectedCategoryInput = document.getElementById('selectedCategoryInput');
1624
  if (!selectedCategoryInput.value) {
1625
  selectedCategoryInput.value = "All";
1626
  document.querySelector('.category-button[data-category="All"]').classList.add('selected');
1627
- }
1628
  categoryButtons.forEach(button => {
1629
  button.addEventListener('click', function () {
1630
  categoryButtons.forEach(btn => btn.classList.remove('selected'));
@@ -1634,48 +1244,7 @@
1634
  });
1635
  });
1636
 
1637
- const searchBar = document.getElementById('searchBar');
1638
- const suggestionsContainer = document.getElementById('autocompleteSuggestions');
1639
- const debouncedFilterMenu = debounce(filterMenu, 300);
1640
-
1641
- // Redirect to search page on click
1642
- searchBar.addEventListener('click', function (event) {
1643
- event.stopPropagation();
1644
- window.location.href = '/search';
1645
- });
1646
-
1647
- searchBar.addEventListener('input', function () {
1648
- const input = sanitizeInput(this.value.trim().toLowerCase());
1649
- suggestionsContainer.innerHTML = '';
1650
- suggestionsContainer.style.display = 'none';
1651
- if (input) {
1652
- const filteredItems = menuItems.filter(item =>
1653
- item.toLowerCase().includes(input)
1654
- );
1655
- if (filteredItems.length > 0) {
1656
- filteredItems.forEach(item => {
1657
- const suggestionDiv = document.createElement('div');
1658
- suggestionDiv.classList.add('suggestion-item');
1659
- suggestionDiv.innerText = item;
1660
- suggestionDiv.addEventListener('click', function () {
1661
- searchBar.value = item;
1662
- suggestionsContainer.style.display = 'none';
1663
- debouncedFilterMenu();
1664
- });
1665
- suggestionsContainer.appendChild(suggestionDiv);
1666
- });
1667
- suggestionsContainer.style.display = 'block';
1668
- }
1669
- }
1670
- debouncedFilterMenu();
1671
- });
1672
-
1673
- document.addEventListener('click', function (event) {
1674
- if (!searchBar.contains(event.target) && !suggestionsContainer.contains(event.target)) {
1675
- suggestionsContainer.style.display = 'none';
1676
- }
1677
- });
1678
-
1679
  const descriptionTextarea = document.getElementById('custom-dish-description');
1680
  const descriptionSuggestions = document.getElementById('descriptionSuggestions');
1681
  if (descriptionTextarea && descriptionSuggestions) {
@@ -1730,43 +1299,7 @@
1730
  });
1731
  }
1732
 
1733
- const customDishForm = document.getElementById('customDishForm');
1734
- if (customDishForm) {
1735
- customDishForm.addEventListener('submit', function(event) {
1736
- const dishName = document.getElementById('custom-dish-name').value.trim();
1737
- const description = document.getElementById('custom-dish-description').value.trim();
1738
- if (!dishName || !description) {
1739
- event.preventDefault();
1740
- alert('Please fill in both the dish name and description.');
1741
- return;
1742
- }
1743
- event.preventDefault();
1744
- fetch('/customdish/generate_custom_dish', {
1745
- method: 'POST',
1746
- headers: {
1747
- 'Content-Type': 'application/x-www-form-urlencoded',
1748
- },
1749
- body: new URLSearchParams({
1750
- 'name': dishName,
1751
- 'description': description
1752
- })
1753
- })
1754
- .then(response => response.json())
1755
- .then(data => {
1756
- if (data.success) {
1757
- alert('Custom dish submitted successfully!');
1758
- window.location.reload();
1759
- } else {
1760
- alert('Failed to submit custom dish: ' + (data.error || 'Unknown error'));
1761
- }
1762
- })
1763
- .catch(error => {
1764
- console.error('Error submitting custom dish:', error);
1765
- alert('Error submitting custom dish. Please try again.');
1766
- });
1767
- });
1768
- }
1769
-
1770
  fetch('/cart/get')
1771
  .then(response => {
1772
  if (!response.ok) {
@@ -1789,6 +1322,7 @@
1789
  updateCartUI(cart);
1790
  });
1791
 
 
1792
  const preloadedVideos = document.querySelectorAll('link[rel="preload"][as="video"]');
1793
  preloadedVideos.forEach(link => {
1794
  const video = document.createElement('video');
@@ -1796,6 +1330,7 @@
1796
  video.preload = 'auto';
1797
  });
1798
 
 
1799
  const decreaseBtn = document.getElementById('decreaseQuantity');
1800
  const increaseBtn = document.getElementById('increaseQuantity');
1801
  const quantityInput = document.getElementById('quantityInput');
@@ -1812,6 +1347,7 @@
1812
  quantityInput.value = currentQuantity;
1813
  });
1814
 
 
1815
  const softDrinkDecreaseBtn = document.getElementById('soft-drink-decrease');
1816
  const softDrinkIncreaseBtn = document.getElementById('soft-drink-increase');
1817
  const softDrinkQuantityInput = document.getElementById('soft-drink-quantity');
@@ -1826,183 +1362,44 @@
1826
 
1827
  softDrinkIncreaseBtn.addEventListener('click', function() {
1828
  let currentQuantity = parseInt(softDrinkQuantityInput.value);
1829
- if (currentQuantity < 1000) {
1830
  currentQuantity++;
1831
  softDrinkQuantityInput.value = currentQuantity;
1832
  }
1833
  });
1834
 
1835
- // Mic Popup Functionality
1836
  const micIcon = document.getElementById('micIcon');
1837
- const micUnsupported = document.getElementById('micUnsupported');
1838
- const micPopup = document.getElementById('micPopup');
1839
- const micPopupText = document.getElementById('micPopupText');
1840
- const micPopupCancel = document.getElementById('micPopupCancel');
1841
-
1842
  if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
1843
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
1844
  const recognition = new SpeechRecognition();
1845
- recognition.continuous = false;
1846
- recognition.interimResults = true;
1847
  recognition.lang = 'en-US';
1848
-
1849
- recognition.onstart = () => {
1850
- micIcon.classList.add('active');
1851
- micPopup.classList.add('active');
1852
- micPopupText.textContent = 'Listening...';
1853
- };
1854
-
1855
  recognition.onresult = (event) => {
1856
- let interimTranscript = '';
1857
- let finalTranscript = '';
1858
-
1859
- for (let i = event.resultIndex; i < event.results.length; i++) {
1860
- const transcript = event.results[i][0].transcript;
1861
- if (event.results[i].isFinal) {
1862
- finalTranscript += transcript;
1863
- } else {
1864
- interimTranscript += transcript;
1865
- }
1866
- }
1867
-
1868
- if (interimTranscript) {
1869
- micPopupText.textContent = interimTranscript;
1870
- }
1871
-
1872
- if (finalTranscript) {
1873
- searchBar.value = sanitizeInput(finalTranscript.trim());
1874
- debouncedFilterMenu();
1875
- micPopup.classList.remove('active');
1876
- }
1877
  };
1878
-
1879
- recognition.onend = () => {
1880
- micIcon.classList.remove('active');
1881
- if (micPopup.classList.contains('active')) {
1882
- setTimeout(() => {
1883
- micPopup.classList.remove('active');
1884
- }, 1000);
1885
- }
1886
- };
1887
-
1888
  recognition.onerror = (event) => {
1889
  micIcon.classList.remove('active');
1890
- micPopupText.textContent = 'Error: ' + event.error;
1891
- setTimeout(() => {
1892
- micPopup.classList.remove('active');
1893
- }, 2000);
1894
  console.error('Speech error:', event.error);
1895
  };
1896
-
1897
  micIcon.addEventListener('click', () => {
1898
- try {
1899
- recognition.start();
1900
- } catch (e) {
1901
- micPopupText.textContent = 'Error starting microphone';
1902
- setTimeout(() => {
1903
- micPopup.classList.remove('active');
1904
- }, 2000);
1905
- console.error('Recognition start error:', e);
1906
- }
1907
- });
1908
-
1909
- micPopupCancel.addEventListener('click', () => {
1910
- recognition.stop();
1911
- micPopup.classList.remove('active');
1912
- micIcon.classList.remove('active');
1913
  });
1914
  } else {
1915
  micIcon.style.display = 'none';
1916
- micUnsupported.style.display = 'block';
1917
- }
1918
-
1919
- // Highlight and open modal for item from search redirect
1920
- const highlightItem = "{{ highlight_item | e }}";
1921
- if (highlightItem) {
1922
- const itemElement = document.querySelector(`[data-item-name="${highlightItem}"]`);
1923
- if (itemElement) {
1924
- itemElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
1925
- itemElement.style.backgroundColor = '#FFFFE0'; // Light yellow highlight
1926
- setTimeout(() => {
1927
- itemElement.style.backgroundColor = ''; // Remove highlight after 2 seconds
1928
- }, 2000);
1929
-
1930
- // Find the ADD button and trigger the appropriate modal
1931
- const addButton = itemElement.querySelector('.btn-primary');
1932
- const buttonContainer = addButton.closest('.button-container');
1933
- const section = buttonContainer.getAttribute('data-item-section');
1934
-
1935
- if (section === 'Soft Drinks') {
1936
- showSoftDrinkModal(addButton);
1937
- } else {
1938
- const name = sanitizeInput(buttonContainer.getAttribute('data-item-name'));
1939
- const price = buttonContainer.getAttribute('data-item-price');
1940
- const image = buttonContainer.getAttribute('data-item-image');
1941
- const category = buttonContainer.getAttribute('data-item-category');
1942
- // Use data from the button's onclick attribute or fetch from server
1943
- const onclickAttr = addButton.getAttribute('onclick');
1944
- if (onclickAttr) {
1945
- const argsMatch = onclickAttr.match(/showItemDetails\((.*?)\)/);
1946
- if (argsMatch) {
1947
- const args = argsMatch[1].split(',').map(arg => arg.trim().replace(/['"]/g, ''));
1948
- const [name, price, image, description, ingredients, nutrition, allergens, section, category] = args;
1949
- showItemDetails(name, price, image, description, ingredients, nutrition, allergens, section, category);
1950
- }
1951
- } else {
1952
- // Fallback if onclick isn't sufficient
1953
- showItemDetails(name, price, image, 'No description available', 'Not specified', 'Not available', 'None listed', section, category);
1954
- }
1955
- }
1956
- }
1957
  }
1958
  });
1959
- function filterMenu() {
1960
- const input = sanitizeInput(document.getElementById('searchBar').value.trim().toLowerCase());
1961
- const sections = document.querySelectorAll('h3');
1962
- const items = document.querySelectorAll('.menu-card');
1963
- let matchedSections = new Set();
1964
- items.forEach(item => {
1965
- const itemName = item.querySelector('.card-title').innerText.toLowerCase();
1966
- const itemSection = item.closest('.row').previousElementSibling.innerText.toLowerCase();
1967
- if (itemName.includes(input) || (itemSection && itemSection.includes(input))) {
1968
- item.style.display = 'block';
1969
- item.classList.add('visible');
1970
- matchedSections.add(item.closest('.row'));
1971
- } else {
1972
- item.style.display = 'none';
1973
- }
1974
- });
1975
- sections.forEach(section => {
1976
- const sectionRow = section.nextElementSibling;
1977
- if (matchedSections.has(sectionRow)) {
1978
- section.style.display = 'block';
1979
- sectionRow.style.display = 'flex';
1980
- } else {
1981
- section.style.display = 'none';
1982
- sectionRow.style.display = 'none';
1983
- }
1984
- });
1985
- if (!input) {
1986
- sections.forEach(section => {
1987
- section.style.display = 'block';
1988
- section.nextElementSibling.style.display = 'flex';
1989
- });
1990
- items.forEach(item => {
1991
- item.style.display = 'block';
1992
- item.classList.add('visible');
1993
- });
1994
- }
1995
- }
1996
 
1997
- function showItemDetails(name, price, image, description, ingredients, nutrition, allergens, section, selectedCategory) {
1998
  document.getElementById('modal-name').innerText = name;
1999
  document.getElementById('modal-price').innerText = `$${price}`;
2000
  const modalImg = document.getElementById('modal-img');
2001
  modalImg.src = image || '/static/placeholder.jpg';
2002
  document.getElementById('modal-description').innerText = description || 'No description available.';
2003
- document.getElementById('modal-ingredients').innerText = ingredients || 'Not specified';
2004
- document.getElementById('modal-nutrition').innerText = nutrition || 'Not available';
2005
- document.getElementById('modal-allergens').innerText = allergens || 'None listed';
2006
  document.getElementById('addons-list').innerHTML = 'Loading customization options...';
2007
  document.getElementById('modal-instructions').value = '';
2008
  const modalSectionEl = document.getElementById('modal-section');
@@ -2023,7 +1420,6 @@
2023
  const sectionDiv = document.createElement('div');
2024
  sectionDiv.classList.add('addon-section');
2025
  const title = document.createElement('h6');
2026
-
2027
  title.innerText = addon.name;
2028
  sectionDiv.appendChild(title);
2029
  const optionsContainer = document.createElement('div');
@@ -2058,39 +1454,51 @@
2058
 
2059
  function handleAddonClick(checkbox) {
2060
  const groupName = checkbox.getAttribute('data-group');
2061
- const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it"].includes(groupName);
2062
- const checkboxes = document.querySelectorAll(`.addon-option[data-group="${groupName}"]`);
2063
  if (!isMultiSelectGroup) {
2064
- checkboxes.forEach(cb => {
2065
- if (cb !== checkbox) cb.checked = false;
 
 
 
2066
  });
2067
  }
2068
  }
2069
 
2070
  function addToCartFromModal() {
2071
  const itemName = document.getElementById('modal-name').innerText;
2072
- const itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
 
 
 
 
2073
  const itemImage = document.getElementById('modal-img').src;
2074
- const instructions = document.getElementById('modal-instructions').value.trim();
2075
- const quantity = parseInt(document.getElementById('quantityInput').value);
2076
- const section = document.getElementById('modal-section').getAttribute('data-section');
2077
- const selectedCategory = document.getElementById('modal-section').getAttribute('data-category');
2078
- const addons = Array.from(document.querySelectorAll('.addon-option:checked')).map(cb => ({
2079
- name: cb.getAttribute('data-name'),
2080
- price: parseFloat(cb.getAttribute('data-price') || 0)
 
 
 
 
 
2081
  }));
2082
-
 
2083
  const cartPayload = {
2084
  itemName: itemName,
2085
  itemPrice: itemPrice,
2086
  itemImage: itemImage,
2087
  section: section,
2088
  category: selectedCategory,
2089
- addons: addons,
2090
  instructions: instructions,
2091
  quantity: quantity
2092
  };
2093
-
2094
  fetch('/cart/add', {
2095
  method: 'POST',
2096
  headers: {
@@ -2103,21 +1511,16 @@
2103
  if (data.success) {
2104
  alert('Item added to cart successfully!');
2105
  updateCartUI(data.cart);
2106
- const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
2107
- modal.hide();
2108
- } else {
2109
- console.error('Failed to add item to cart:', data.error);
2110
- alert(data.error || 'Failed to add item to cart. Using local storage as fallback.');
2111
- const cart = addToCartLocalStorage(cartPayload);
2112
- updateCartUI(cart);
2113
  const modal = document.getElementById('itemModal');
2114
  const modalInstance = bootstrap.Modal.getInstance(modal);
2115
  modalInstance.hide();
 
 
 
2116
  }
2117
  })
2118
  .catch(err => {
2119
  console.error('Error adding item to cart:', err);
2120
- alert('Error adding item to cart. Using local storage as fallback.');
2121
  const cart = addToCartLocalStorage(cartPayload);
2122
  updateCartUI(cart);
2123
  const modal = document.getElementById('itemModal');
@@ -2127,5 +1530,4 @@
2127
  }
2128
  </script>
2129
  </body>
2130
- </html>
2131
-
 
1
+ <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
 
42
  .menu-card.visible {
43
  opacity: 1;
44
  }
45
+ .menu-card.highlighted {
46
+ border: 3px solid #0FAA39;
47
+ box-shadow: 0 0 10px rgba(15, 170, 57, 0.5);
48
+ }
49
  .menu-video {
50
  height: 200px;
51
  width: 100%;
 
53
  border-radius: 15px 15px 0 0;
54
  opacity: 0;
55
  transition: opacity 0.5s ease-in-out;
56
+ background-color: #000; /* Fallback color if video fails */
57
  }
58
  .menu-video.loaded {
59
  opacity: 1;
60
  }
61
  .menu-card:hover .menu-video {
62
  opacity: 1;
63
+ transform: scale(1.05); /* Slight zoom effect on hover */
64
  }
65
  .menu-card .card-body .card-title {
66
  font-size: 1.2rem;
 
135
  top: 50%;
136
  transform: translateY(-50%);
137
  display: flex;
138
+ align-items: right;
139
  justify-content: center;
140
  }
141
  .avatar-icon {
 
150
  color: white;
151
  font-size: 20px;
152
  font-weight: bold;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  }
154
  .dropdown-menu {
155
  position: absolute;
156
  right: 0;
157
  top: 100%;
158
  background-color: #fff8f0;
159
+ border-radius: 5px;
160
+ width: 220px;
161
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
162
  display: none;
163
  border: 1px solid #ffd8b1;
 
 
164
  }
165
  .dropdown-menu .dropdown-item {
166
+ padding: 12px 16px;
167
  text-decoration: none;
168
  color: #333;
169
+ border-bottom: 1px solid #ffd8b1;
170
+ display: block;
171
+ font-size: 15px;
172
+ transition: background-color 0.2s ease;
173
+ }
174
+ .dropdown-menu .dropdown-item:last-child {
175
+ border-bottom: none;
176
  }
177
  .dropdown-menu .dropdown-item:hover {
178
  background-color: #ffe4c4;
 
 
 
 
 
 
 
179
  color: #333;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  }
181
  .fixed-top-bar {
182
  position: relative;
 
228
  font-size: 18px;
229
  color: #888;
230
  cursor: pointer;
231
+ transition: color 0.3s ease;
232
  }
233
  .mic-icon.active {
234
  color: #007bff;
235
  }
 
 
 
 
 
 
 
 
 
 
 
236
  .autocomplete-suggestions {
237
  position: absolute;
238
  top: 100%;
 
325
  max-height: 60vh;
326
  overflow-y: auto;
327
  padding: 15px;
 
 
 
 
 
 
 
 
 
328
  }
329
  .modal-body #modal-img {
330
  max-height: 200px;
 
399
  width: 40px;
400
  }
401
  .item-details {
 
 
402
  background-color: #f8f9fa;
403
  border-radius: 8px;
404
+ padding: 10px;
405
  margin: 10px 15px;
406
+ display: none;
407
  }
408
  .item-details.show {
409
  display: block;
410
  }
411
  .item-details h6 {
412
+ font-size: 0.9rem;
 
 
413
  font-weight: bold;
414
+ margin-bottom: 5px;
415
+ color: #333333;
416
  }
417
  .item-details p {
418
+ font-size: 0.85rem;
419
+ margin-bottom: 5px;
420
+ color: #333;
421
+ }
422
+ .item-details .nutritional-info {
423
+ display: grid;
424
+ grid-template-columns: 1fr 1fr;
425
+ gap: 10px;
426
+ background-color: #e9ecef;
427
+ padding: 10px;
428
+ border-radius: 5px;
429
+ font-size: 0.85rem;
430
  line-height: 1.5;
 
431
  }
432
  .toggle-details {
433
  cursor: pointer;
434
  color: #0FAA39;
435
  font-size: 0.9rem;
436
+ margin-left: 15px;
437
+ margin-bottom: 10px;
438
+ display: inline-block;
 
 
 
439
  }
440
  .toggle-details:hover {
 
441
  text-decoration: underline;
442
  }
443
  .category-buttons {
 
589
  font-size: 12px;
590
  margin-left: 8px;
591
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
  @media (max-width: 576px) {
593
  .fixed-top-bar {
594
  height: 60px;
 
623
  font-size: 20px;
624
  }
625
  .dropdown-menu {
626
+ width: 220px;
627
  }
628
  .dropdown-menu .dropdown-item {
629
+ padding: 12px 16px;
630
+ font-size: 15px;
 
 
 
 
 
 
631
  }
632
  .category-buttons {
633
  gap: 8px;
 
650
  max-height: 50vh;
651
  padding: 8px;
652
  }
 
 
 
653
  .modal-body #modal-img {
654
  max-height: 150px;
655
  width: 100%;
 
749
  font-size: 10px;
750
  margin-left: 5px;
751
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
752
  }
753
  </style>
754
  </head>
755
  <body>
756
+
757
  <div class="fixed-top-bar">
758
  <div class="avatar-dropdown-container">
759
+ <div class="avatar-icon">
760
+ <span>{{ first_letter }}</span>
 
 
 
 
761
  </div>
762
+ <div class="dropdown-menu">
 
 
 
 
 
763
  <a href="{{ url_for('user_details.customer_details') }}" class="dropdown-item">View Profile</a>
764
+ <a href="{{ url_for('orderhistory.order_history') }}" class="dropdown-item">Order History</a>
 
 
 
 
 
 
 
765
  <a href="{{ url_for('logout') }}" class="dropdown-item">Logout</a>
766
  </div>
767
  </div>
 
768
  <div class="search-bar-container">
769
  <input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off">
770
  <i class="bi bi-search search-icon"></i>
771
  <i class="bi bi-mic mic-icon" id="micIcon"></i>
 
772
  <div id="autocompleteSuggestions" class="autocomplete-suggestions"></div>
773
  </div>
774
  </div>
 
788
  {% if selected_category == "Customized Dish" %}
789
  <div id="custom-dish-form" class="mt-4">
790
  <h3>Create Your Custom Dish</h3>
791
+ <form method="POST" action="/customdish/generate_custom_dish">
792
  <div class="mb-3">
793
  <label for="custom-dish-name" class="form-label">Dish Name</label>
794
  <input type="text" class="form-control" id="custom-dish-name" name="name" required>
 
809
  <h3>{{ section }}</h3>
810
  <div class="row">
811
  {% for item in items %}
812
+ <div class="col-md-6 mb-4">
813
+ <div class="card menu-card" data-item-name="{{ item.Name | default('Unnamed Item') }}">
814
  <video
815
  class="card-img-top menu-video"
816
  muted
 
831
  <div>
832
  <h5 class="card-title">{{ item.Name | default('Unnamed Item') }}</h5>
833
  <p class="card-text price">${{ item.Price__c | default('0.00') }}</p>
 
 
 
834
  </div>
835
  <div class="d-flex flex-column align-item-center justify-content-center">
836
  <div class="button-container"
837
  data-item-name="{{ item.Name | default('Unnamed Item') }}"
838
  data-item-price="{{ item.Price__c | default('0.00') }}"
839
+ data-item-image="{{ item.Image1__c | default('/static/placeholder.jpg') }}"
840
  data-item-section="{{ item.Section__c | default(section) }}"
841
  data-item-category="{{ selected_category }}">
842
  {% if item.Section__c == 'Soft Drinks' %}
 
845
  <button class="btn btn-primary"
846
  data-bs-toggle="modal"
847
  data-bs-target="#itemModal"
848
+ 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 }}')">
849
  ADD
850
  </button>
851
  {% endif %}
 
856
  </div>
857
  </div>
858
  </div>
859
+ <!-- Only show toggle-details if not Soft Drinks -->
860
  {% if item.Section__c != 'Soft Drinks' %}
861
+ <div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}">Show Details</div>
862
  <div class="item-details" id="details-{{ item.Name | default('unnamed-item') | replace(' ', '-') }}">
863
  <h6>Description</h6>
864
  <p>{{ item.Description__c | default('No description available') }}</p>
865
+ <h6>Ingredients</h6>
866
+ <p>{{ item.Ingredientsinfo__c | default('Not specified') }}</p>
867
  <h6>Nutritional Info</h6>
868
+ <p class="nutritional-info">{{ item.NutritionalInfo__c | default('Not available') }}</p>
869
  <h6>Allergens</h6>
870
  <p>{{ item.Allergens__c | default('None listed') }}</p>
871
  </div>
 
885
  </a>
886
  <a href="{{ url_for('cart.cart') }}" class="btn btn-view-cart">
887
  <i class="bi bi-cart"></i> View Cart
888
+ <span id="cart-item-count" class="cart-icon-badge" style="display: none;">0</span>
889
  </a>
890
  </div>
891
 
 
902
  <h5 id="modal-name" class="fw-bold text-center"></h5>
903
  <p id="modal-price" class="text-muted text-center"></p>
904
  <p id="modal-description" class="text-secondary"></p>
 
 
 
 
 
905
  <div id="modal-addons" class="modal-addons mt-4">
906
  <h6>Customization Options</h6>
907
  <div id="addons-list" class="addons-container">Loading customization options...</div>
 
924
  </div>
925
  </div>
926
 
927
+ <!-- Modal for Soft Drinks Quantity Selection -->
928
+ <div class="modal fade" id="softDrinkModal" tabindex="-1" aria-labelledby="softDrinkModalLabel" aria-hidden="true">
929
+ <div class="modal-dialog modal-dialog-centered">
930
  <div class="modal-content">
931
  <div class="modal-header">
932
+ <h5 class="modal-title" id="softDrinkModalLabel">Select Quantity</h5>
933
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
934
  </div>
935
  <div class="modal-body">
936
+ <div class="text-center mb-3">
937
+ <h5 id="soft-drink-name"></h5>
938
+ <p id="soft-drink-price"></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
939
  </div>
940
  <div class="d-flex justify-content-center align-items-center mb-4">
941
+ <button type="button" class="btn btn-outline-secondary" id="soft-drink-decrease">-</button>
942
+ <input type="text" class="form-control text-center mx-2" id="soft-drink-quantity" value="1" readonly style="width: 60px;">
943
+ <button type="button" class="btn btn-outline-secondary" id="soft-drink-increase">+</button>
 
 
944
  </div>
945
  </div>
946
+ <div class="modal-footer">
947
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
948
+ <button type="button" class="btn btn-primary" onclick="addSoftDrinkToCart()">Add to Cart</button>
949
  </div>
950
  </div>
951
  </div>
952
  </div>
953
 
 
 
 
 
 
 
 
 
 
954
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
955
  <script>
956
  let isProcessingRequest = false;
 
959
  const menuItems = [
960
  {% for section, items in ordered_menu.items() %}
961
  {% for item in items %}
962
+ {
963
+ name: "{{ item.Name | default('Unnamed Item') }}",
964
+ section: "{{ item.Section__c | default(section) }}"
965
+ },
966
  {% endfor %}
967
  {% endfor %}
968
  ];
 
983
  "Whole Wheat Flour", "Yogurt (Curd)"
984
  ];
985
 
 
 
 
 
 
 
 
986
  function addToCartLocalStorage(payload) {
987
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
988
  const existingItem = cart.find(item =>
 
1032
  function showSoftDrinkModal(button) {
1033
  currentSoftDrinkButton = button;
1034
  const buttonContainer = button.closest('.button-container');
1035
+ const itemName = buttonContainer.getAttribute('data-item-name');
1036
  const itemPrice = buttonContainer.getAttribute('data-item-price');
 
1037
 
1038
  document.getElementById('soft-drink-name').textContent = itemName;
1039
  document.getElementById('soft-drink-price').textContent = `$${itemPrice}`;
1040
  document.getElementById('soft-drink-quantity').value = '1';
 
 
1041
 
1042
  const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
1043
  modal.show();
 
1049
  const buttonContainer = currentSoftDrinkButton.closest('.button-container');
1050
  const quantity = parseInt(document.getElementById('soft-drink-quantity').value) || 1;
1051
 
1052
+ const itemName = buttonContainer.getAttribute('data-item-name');
1053
  const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
1054
  const itemImage = buttonContainer.getAttribute('data-item-image');
1055
+ const section = buttonContainer.getAttribute('data-item-section');
1056
+ const selectedCategory = buttonContainer.getAttribute('data-item-category');
1057
 
1058
  const cartPayload = {
1059
  itemName: itemName,
 
1076
  .then(response => response.json())
1077
  .then(data => {
1078
  if (data.success) {
 
1079
  updateCartUI(data.cart);
1080
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1081
  modal.hide();
1082
  } else {
1083
  console.error('Failed to add item to cart:', data.error);
 
1084
  const cart = addToCartLocalStorage(cartPayload);
1085
  updateCartUI(cart);
1086
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
 
1089
  })
1090
  .catch(err => {
1091
  console.error('Error adding item to cart:', err);
 
1092
  const cart = addToCartLocalStorage(cartPayload);
1093
  updateCartUI(cart);
1094
  const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
 
1115
  }
1116
 
1117
  document.addEventListener('DOMContentLoaded', function () {
1118
+ // Avatar Dropdown
1119
  const avatarContainer = document.querySelector('.avatar-dropdown-container');
1120
+ const dropdownMenu = document.querySelector('.dropdown-menu');
1121
+ avatarContainer.addEventListener('click', function (event) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1122
  event.stopPropagation();
1123
  dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
1124
  });
1125
+ document.addEventListener('click', function (event) {
1126
+ if (!avatarContainer.contains(event.target)) {
1127
+ dropdownMenu.style.display = 'none';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1128
  }
1129
  });
1130
+ const dropdownItems = document.querySelectorAll('.dropdown-item');
1131
+ dropdownItems.forEach(item => {
1132
+ item.addEventListener('click', function () {
1133
+ dropdownMenu.style.display = 'none';
1134
+ });
1135
+ });
1136
 
1137
+ // Navigate to search page on search bar click
1138
+ const searchBar = document.getElementById('searchBar');
1139
+ searchBar.addEventListener('click', function () {
1140
+ window.location.href = '/search';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1141
  });
1142
 
1143
+ // Highlight selected item from search
1144
+ const selectedItem = localStorage.getItem('selectedItem');
1145
+ if (selectedItem) {
1146
+ const menuCards = document.querySelectorAll('.menu-card');
1147
+ menuCards.forEach(card => {
1148
+ const itemName = card.getAttribute('data-item-name');
1149
+ if (itemName === selectedItem) {
1150
+ card.classList.add('highlighted');
1151
+ card.scrollIntoView({ behavior: 'smooth', block: 'center' });
1152
+ // Show details if available
1153
+ const toggleLink = card.querySelector('.toggle-details');
1154
+ if (toggleLink) {
1155
+ toggleLink.click();
 
 
 
 
 
 
1156
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1157
  }
 
1158
  });
1159
+ // Clear the selected item after highlighting
1160
+ localStorage.removeItem('selectedItem');
1161
  }
1162
 
1163
+ // Lazy Loading for Cards and Videos
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1164
  const menuCards = document.querySelectorAll('.menu-card');
1165
  const menuVideos = document.querySelectorAll('.menu-video');
1166
  const cardObserver = new IntersectionObserver((entries, observer) => {
 
1197
  menuCards.forEach(card => cardObserver.observe(card));
1198
  menuVideos.forEach(video => videoObserver.observe(video));
1199
 
1200
+ // Toggle Details
1201
  const toggleLinks = document.querySelectorAll('.toggle-details');
1202
  toggleLinks.forEach(link => {
1203
  link.addEventListener('click', function () {
 
1205
  const detailsDiv = document.getElementById(`details-${itemName}`);
1206
  const isCurrentlyShown = detailsDiv.classList.contains('show');
1207
 
1208
+ // Hide all other details sections
1209
  document.querySelectorAll('.item-details.show').forEach(otherDetails => {
1210
  if (otherDetails !== detailsDiv) {
1211
  otherDetails.classList.remove('show');
1212
+ const otherLink = document.querySelector(`.toggle-details[data-item-name="${otherDetails.id.replace('details-', '').replace(/-/g, ' ')}"]`);
1213
  if (otherLink) {
1214
  otherLink.innerText = 'Show Details';
1215
  }
1216
  }
1217
  });
1218
 
1219
+ // Toggle the current details section
1220
  if (!isCurrentlyShown) {
1221
  detailsDiv.classList.add('show');
1222
  this.innerText = 'Hide Details';
 
1227
  });
1228
  });
1229
 
1230
+ // Category Selection
1231
  const categoryButtons = document.querySelectorAll('.category-button');
1232
  const categoryForm = document.getElementById('categoryForm');
1233
  const selectedCategoryInput = document.getElementById('selectedCategoryInput');
1234
  if (!selectedCategoryInput.value) {
1235
  selectedCategoryInput.value = "All";
1236
  document.querySelector('.category-button[data-category="All"]').classList.add('selected');
1237
+ визуальны�� эффект
1238
  categoryButtons.forEach(button => {
1239
  button.addEventListener('click', function () {
1240
  categoryButtons.forEach(btn => btn.classList.remove('selected'));
 
1244
  });
1245
  });
1246
 
1247
+ // Custom Dish Form Suggestions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1248
  const descriptionTextarea = document.getElementById('custom-dish-description');
1249
  const descriptionSuggestions = document.getElementById('descriptionSuggestions');
1250
  if (descriptionTextarea && descriptionSuggestions) {
 
1299
  });
1300
  }
1301
 
1302
+ // Fetch Cart
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1303
  fetch('/cart/get')
1304
  .then(response => {
1305
  if (!response.ok) {
 
1322
  updateCartUI(cart);
1323
  });
1324
 
1325
+ // Preload Videos
1326
  const preloadedVideos = document.querySelectorAll('link[rel="preload"][as="video"]');
1327
  preloadedVideos.forEach(link => {
1328
  const video = document.createElement('video');
 
1330
  video.preload = 'auto';
1331
  });
1332
 
1333
+ // Quantity Controls for Item Modal
1334
  const decreaseBtn = document.getElementById('decreaseQuantity');
1335
  const increaseBtn = document.getElementById('increaseQuantity');
1336
  const quantityInput = document.getElementById('quantityInput');
 
1347
  quantityInput.value = currentQuantity;
1348
  });
1349
 
1350
+ // Soft Drinks Modal Quantity Controls
1351
  const softDrinkDecreaseBtn = document.getElementById('soft-drink-decrease');
1352
  const softDrinkIncreaseBtn = document.getElementById('soft-drink-increase');
1353
  const softDrinkQuantityInput = document.getElementById('soft-drink-quantity');
 
1362
 
1363
  softDrinkIncreaseBtn.addEventListener('click', function() {
1364
  let currentQuantity = parseInt(softDrinkQuantityInput.value);
1365
+ if (currentQuantity < 500) {
1366
  currentQuantity++;
1367
  softDrinkQuantityInput.value = currentQuantity;
1368
  }
1369
  });
1370
 
1371
+ // Voice Recognition
1372
  const micIcon = document.getElementById('micIcon');
 
 
 
 
 
1373
  if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
1374
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
1375
  const recognition = new SpeechRecognition();
 
 
1376
  recognition.lang = 'en-US';
1377
+ recognition.onstart = () => micIcon.classList.add('active');
 
 
 
 
 
 
1378
  recognition.onresult = (event) => {
1379
+ // Navigate to search page with the transcribed query
1380
+ const query = event.results[0][0].transcript.trim();
1381
+ localStorage.setItem('searchQuery', query);
1382
+ window.location.href = '/search';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1383
  };
1384
+ recognition.onend = () => micIcon.classList.remove('active');
 
 
 
 
 
 
 
 
 
1385
  recognition.onerror = (event) => {
1386
  micIcon.classList.remove('active');
 
 
 
 
1387
  console.error('Speech error:', event.error);
1388
  };
 
1389
  micIcon.addEventListener('click', () => {
1390
+ recognition.start();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1391
  });
1392
  } else {
1393
  micIcon.style.display = 'none';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1394
  }
1395
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1396
 
1397
+ function showItemDetails(name, price, image, description, section, selectedCategory) {
1398
  document.getElementById('modal-name').innerText = name;
1399
  document.getElementById('modal-price').innerText = `$${price}`;
1400
  const modalImg = document.getElementById('modal-img');
1401
  modalImg.src = image || '/static/placeholder.jpg';
1402
  document.getElementById('modal-description').innerText = description || 'No description available.';
 
 
 
1403
  document.getElementById('addons-list').innerHTML = 'Loading customization options...';
1404
  document.getElementById('modal-instructions').value = '';
1405
  const modalSectionEl = document.getElementById('modal-section');
 
1420
  const sectionDiv = document.createElement('div');
1421
  sectionDiv.classList.add('addon-section');
1422
  const title = document.createElement('h6');
 
1423
  title.innerText = addon.name;
1424
  sectionDiv.appendChild(title);
1425
  const optionsContainer = document.createElement('div');
 
1454
 
1455
  function handleAddonClick(checkbox) {
1456
  const groupName = checkbox.getAttribute('data-group');
1457
+ const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo", "Beverages", "Sauces"].includes(groupName);
 
1458
  if (!isMultiSelectGroup) {
1459
+ const checkboxes = document.querySelectorAll(`.addon-option[data-group="${groupName}"]`);
1460
+ checkboxes.forEach(otherCheckbox => {
1461
+ if (otherCheckbox !== checkbox) {
1462
+ otherCheckbox.checked = false;
1463
+ }
1464
  });
1465
  }
1466
  }
1467
 
1468
  function addToCartFromModal() {
1469
  const itemName = document.getElementById('modal-name').innerText;
1470
+ let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
1471
+ if (isNaN(itemPrice)) {
1472
+ alert('Invalid price for the item. Please check the item details.');
1473
+ return;
1474
+ }
1475
  const itemImage = document.getElementById('modal-img').src;
1476
+ const modalSectionEl = document.getElementById('modal-section');
1477
+ const section = modalSectionEl.getAttribute('data-section');
1478
+ const selectedCategory = modalSectionEl.getAttribute('data-category');
1479
+ if (!itemName || !itemPrice || !section || !itemImage) {
1480
+ console.error('Missing data for cart item:', { itemName, itemPrice, section, itemImage });
1481
+ return;
1482
+ }
1483
+ const selectedAddOns = Array.from(
1484
+ document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
1485
+ ).map(addon => ({
1486
+ name: addon.getAttribute('data-name') || 'Default Name',
1487
+ price: parseFloat(addon.getAttribute('data-price') || 0)
1488
  }));
1489
+ const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
1490
+ const instructions = document.getElementById('modal-instructions').value;
1491
  const cartPayload = {
1492
  itemName: itemName,
1493
  itemPrice: itemPrice,
1494
  itemImage: itemImage,
1495
  section: section,
1496
  category: selectedCategory,
1497
+ addons: selectedAddOns,
1498
  instructions: instructions,
1499
  quantity: quantity
1500
  };
1501
+
1502
  fetch('/cart/add', {
1503
  method: 'POST',
1504
  headers: {
 
1511
  if (data.success) {
1512
  alert('Item added to cart successfully!');
1513
  updateCartUI(data.cart);
 
 
 
 
 
 
 
1514
  const modal = document.getElementById('itemModal');
1515
  const modalInstance = bootstrap.Modal.getInstance(modal);
1516
  modalInstance.hide();
1517
+ } else {
1518
+ console.error('Failed to add item to cart:', data.error);
1519
+ alert(data.error || 'Failed to add item to cart.');
1520
  }
1521
  })
1522
  .catch(err => {
1523
  console.error('Error adding item to cart:', err);
 
1524
  const cart = addToCartLocalStorage(cartPayload);
1525
  updateCartUI(cart);
1526
  const modal = document.getElementById('itemModal');
 
1530
  }
1531
  </script>
1532
  </body>
1533
+ </html>