lokesh341 commited on
Commit
1313645
·
verified ·
1 Parent(s): 145bd7d

Update templates/menu.html

Browse files
Files changed (1) hide show
  1. templates/menu.html +638 -393
templates/menu.html CHANGED
@@ -15,6 +15,7 @@
15
  {% endfor %}
16
  {% endfor %}
17
  <style>
 
18
  body {
19
  font-family: Arial, sans-serif;
20
  background-color: #fdf4e3;
@@ -23,100 +24,99 @@
23
  display: flex;
24
  flex-direction: column;
25
  padding-bottom: 70px;
 
26
  }
27
  .container {
28
- max-width: 900px;
 
29
  }
30
- .menu-card {
31
- max-width: 350px;
32
- border-radius: 15px;
33
- overflow: hidden;
34
- background-color: #fff;
35
- margin: auto;
 
 
 
 
 
 
 
 
 
 
36
  display: flex;
37
- flex-direction: column;
38
- opacity: 0;
39
- transition: opacity 0.3s ease-in-out;
40
- box-shadow: 0 4px 8px rgba(0,0,0,0.1);
41
  }
42
- .menu-card.visible {
43
- opacity: 1;
 
 
 
 
 
 
 
 
44
  }
45
- .menu-video {
46
- height: 200px;
47
  width: 100%;
48
- object-fit: cover;
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;
63
- font-weight: 600;
64
- margin: 10px 0;
65
- color: #333333;
 
 
66
  }
67
- .menu-card .card-body .card-text.price {
68
- font-size: 1rem;
69
- font-weight: 500;
70
- color: #000000;
71
- margin-bottom: 5px;
72
  }
73
- .addbutton .btn {
74
- background-color: #28a745;
75
- color: white;
76
- padding: 10px 20px;
77
- font-size: 16px;
78
- font-weight: bold;
 
 
 
79
  border-radius: 5px;
80
- border: none;
81
- transition: background-color 0.3s ease;
82
- margin-left: 13px;
83
- }
84
- .addbutton .btn:hover {
85
- background-color: #218838;
86
- }
87
- .button-container {
88
- display: flex;
89
- flex-direction: column;
90
- align-items: center;
91
- justify-content: center;
92
- gap: 6px;
93
- }
94
- .customisable-text {
95
- color: #0FAA39;
96
- font-size: 10px;
97
- font-weight: 500;
98
- margin: 0;
99
- text-align: center;
100
- line-height: 1;
101
  }
102
- .btn-primary {
103
- font-size: 12px;
104
- font-weight: bold;
105
- border-radius: 8px;
106
- width: 70px;
107
- height: 35px;
108
- background-color: #0FAA39;
109
- border-color: #0FAA39;
110
- display: flex;
111
- align-items: center;
112
- justify-content: center;
113
- padding: 0;
114
- transition: background-color 0.3s ease, transform 0.1s ease;
115
  }
116
- .btn-primary:hover {
117
- background-color: #0D9232;
118
- border-color: #0D9232;
119
- transform: scale(1.05);
120
  }
121
  /* Avatar Styles */
122
  .avatar-dropdown-container {
@@ -138,10 +138,11 @@
138
  justify-content: center;
139
  overflow: hidden;
140
  background-color: #007bff;
141
- transition: transform 0.2s ease;
142
  color: white;
143
  font-weight: bold;
144
  font-size: 18px;
 
145
  }
146
  .avatar-icon img {
147
  width: 100%;
@@ -150,17 +151,19 @@
150
  }
151
  .avatar-icon:hover {
152
  transform: scale(1.1);
 
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;
@@ -169,7 +172,7 @@
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;
@@ -178,10 +181,11 @@
178
  background-color: #ffe4c4;
179
  color: #333;
180
  }
181
- /* Avatar Modal Styles */
182
  .avatar-modal .modal-content {
183
  border-radius: 20px;
184
  overflow: hidden;
 
185
  }
186
  .avatar-modal-img {
187
  width: 300px;
@@ -190,87 +194,163 @@
190
  object-fit: cover;
191
  margin: 20px auto;
192
  border: 4px solid #0FAA39;
193
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
194
  display: block;
 
195
  }
196
- .fixed-top-bar {
197
- position: relative;
198
- top: 0;
199
- left: 0;
200
- width: 100%;
201
- height: 54px;
202
- background: linear-gradient(45deg, #FFA07A, #FFB347);
203
- color: white;
204
- padding: 15px;
 
 
 
 
205
  display: flex;
206
- justify-content: space-between;
207
- align-items: center;
208
- z-index: 1000;
 
209
  }
210
- .search-bar-container {
211
- position: absolute;
212
- left: 20px;
213
- top: 50%;
214
- transform: translateY(-50%);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  display: flex;
216
- align-items: center;
217
- width: 300px;
218
- max-width: 90%;
 
219
  }
220
- .search-bar-container input {
 
 
 
 
 
221
  width: 100%;
222
- padding: 8px 40px 8px 40px;
223
- font-size: 16px;
224
- border-radius: 25px;
225
- border: none;
226
- background-color: #fff;
227
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
228
- outline: none;
229
  }
230
- .search-bar-container input::placeholder {
231
- color: #888;
232
  }
233
- .search-icon {
234
- position: absolute;
235
- left: 15px;
236
- font-size: 18px;
237
- color: #888;
238
  }
239
- .mic-icon {
240
- position: absolute;
241
- right: 15px;
242
- font-size: 18px;
243
- color: #888;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  cursor: pointer;
 
 
245
  transition: color 0.3s ease;
246
  }
247
- .mic-icon.active {
248
- color: #007bff;
249
  }
250
- .autocomplete-suggestions {
251
- position: absolute;
252
- top: 100%;
253
- left: 0;
254
- width: 100%;
255
- max-height: 200px;
256
- overflow-y: auto;
257
- background-color: #fff;
258
- border: 1px solid #ddd;
259
- border-radius: 5px;
260
- box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
261
- z-index: 1000;
262
  display: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  }
264
- .autocomplete-suggestions .suggestion-item {
265
- padding: 8px 15px;
266
- cursor: pointer;
267
- font-size: 14px;
268
- color: #333;
269
  }
270
- .autocomplete-suggestions .suggestion-item:hover {
271
- background-color: #f1f1f1;
 
 
 
 
 
272
  }
273
- /* Add rest of your existing CSS here */
274
  .bottom-action-bar {
275
  position: fixed;
276
  bottom: 0;
@@ -283,17 +363,19 @@
283
  align-items: center;
284
  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
285
  z-index: 1000;
286
- max-width: 900px;
287
  margin: 0 auto;
288
  }
289
  .bottom-action-bar .btn {
290
  flex: 1;
291
  margin: 0 5px;
292
- padding: 10px 15px;
293
  border-radius: 8px;
294
  font-weight: bold;
295
  font-size: 16px;
296
  color: white;
 
 
297
  }
298
  .bottom-action-bar .btn-order-history {
299
  background-color: #FFA07A;
@@ -303,6 +385,9 @@
303
  background-color: #0FAA39;
304
  border-color: #0FAA39;
305
  }
 
 
 
306
  .cart-icon-badge {
307
  background-color: white;
308
  color: #0FAA39;
@@ -314,7 +399,61 @@
314
  justify-content: center;
315
  font-size: 12px;
316
  margin-left: 8px;
 
317
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318
  .mic-popup {
319
  position: fixed;
320
  top: 50%;
@@ -339,11 +478,52 @@
339
  color: #ff4444;
340
  animation: pulse 1.5s infinite;
341
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  @keyframes pulse {
343
  0% { transform: scale(1); }
344
  50% { transform: scale(1.1); }
345
  100% { transform: scale(1); }
346
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  </style>
348
  </head>
349
  <body>
@@ -397,19 +577,20 @@
397
  </div>
398
  </div>
399
 
400
- <!-- Menu Content -->
401
- <form method="get" action="/menu" class="text-center mb-4" id="categoryForm">
402
- <label class="form-label fw-bold">Select a Category:</label>
403
- <div class="category-buttons">
404
- {% for category in categories %}
405
- <button type="button" class="category-button {% if selected_category == category %}selected{% endif %}" data-category="{{ category }}">{{ category }}</button>
406
- {% endfor %}
407
- <button type="button" class="category-button {% if selected_category == 'Customized Dish' %}selected{% endif %}" data-category="Customized Dish">Customized Dish</button>
408
- </div>
409
- <input type="hidden" name="category" id="selectedCategoryInput" value="{{ selected_category }}">
410
- </form>
 
411
 
412
- <div class="container mt-4">
413
  {% if selected_category == "Customized Dish" %}
414
  <div id="custom-dish-form" class="mt-4">
415
  <h3>Create Your Custom Dish</h3>
@@ -428,13 +609,13 @@
428
  </div>
429
  {% else %}
430
  {% if ordered_menu.items()|length == 0 %}
431
- <p>No menu items available for this category.</p>
432
  {% else %}
433
  {% for section, items in ordered_menu.items() %}
434
  <h3>{{ section }}</h3>
435
  <div class="row">
436
  {% for item in items %}
437
- <div class="col-md-6 mb-4">
438
  <div class="card menu-card">
439
  <video
440
  class="card-img-top menu-video"
@@ -460,27 +641,25 @@
460
  <div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}">Show Details</div>
461
  {% endif %}
462
  </div>
463
- <div class="d-flex flex-column align-item-center justify-content-center">
464
- <div class="button-container"
465
- data-item-name="{{ item.Name | default('Unnamed Item') }}"
466
- data-item-price="{{ item.Price__c | default('0.00') }}"
467
- data-item-image="{{ item.Image2__c | default(item.Image1__c) | default('/static/placeholder.jpg') }}"
468
- data-item-section="{{ item.Section__c | default(section) }}"
469
- data-item-category="{{ selected_category }}">
470
- {% if item.Section__c == 'Soft Drinks' %}
471
- <button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)">ADD</button>
472
- {% else %}
473
- <button class="btn btn-primary"
474
- data-bs-toggle="modal"
475
- data-bs-target="#itemModal"
476
- onclick="showItemDetails('{{ item.Name | default('Unnamed Item') }}', '{{ item.Price__c | default('0.00') }}', '{{ item.Image2__c | default(item.Image1__c) | default('/static/placeholder.jpg') }}', '{{ item.Description__c | default('No description') }}', '{{ item.IngredientsInfo__c | default('Not specified') }}', '{{ item.NutritionalInfo__c | default('Not available') }}', '{{ item.Allergens__c | default('None listed') }}', '{{ item.Section__c | default(section) }}', '{{ selected_category }}')">
477
- ADD
478
- </button>
479
- {% endif %}
480
- {% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' and item.Section__c !='Soft Drinks' %}
481
- <span class="customisable-text">Customisable</span>
482
- {% endif %}
483
- </div>
484
  </div>
485
  </div>
486
  </div>
@@ -540,7 +719,7 @@
540
  </div>
541
  <div class="mt-4">
542
  <h6>Custom Request</h6>
543
- <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
544
  </div>
545
  <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
546
  </div>
@@ -559,27 +738,27 @@
559
  <!-- Soft Drink Modal -->
560
  <div class="modal fade" id="softDrinkModal" tabindex="-1" aria-labelledby="softDrinkModalLabel" aria-hidden="true">
561
  <div class="modal-dialog modal-dialog-centered">
562
- <div class="modal-content" style="border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.2);">
563
- <div class="modal-header" style="background: linear-gradient(45deg, #0FAA39, #0D9232); color: white; border-radius: 15px 15px 0 0;">
564
  <h5 class="modal-title" id="softDrinkModalLabel">Select Your Drink</h5>
565
  <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
566
  </div>
567
- <div class="modal-body" style="padding: 20px;">
568
  <div class="text-center mb-4">
569
  <img id="soft-drink-image" class="img-fluid rounded mb-3" alt="Soft Drink Image" style="max-height: 150px; width: auto; object-fit: contain;">
570
  <h5 id="soft-drink-name" class="fw-bold" style="color: #333;"></h5>
571
  <p id="soft-drink-price" style="font-size: 1.1rem;"></p>
572
  </div>
573
  <div class="d-flex justify-content-center align-items-center mb-4">
574
- <div class="quantity-selector" style="background-color: #f8f9fa; padding: 10px; border-radius: 10px;">
575
- <button type="button" class="btn btn-outline-secondary" id="soft-drink-decrease" style="width: 40px; height: 40px;">-</button>
576
- <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;">
577
- <button type="button" class="btn btn-outline-secondary" id="soft-drink-increase" style="width: 40px; height: 40px;">+</button>
578
  </div>
579
  </div>
580
  </div>
581
- <div class="modal-footer" style="border-top: none; padding: 0 20px 20px 20px; justify-content: center;">
582
- <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>
583
  </div>
584
  </div>
585
  </div>
@@ -599,8 +778,6 @@
599
  // Initial data from Flask
600
  const firstLetter = "{{ first_letter | default('G') }}";
601
  let userAvatar = "{{ user_avatar | default('') }}";
602
-
603
- // Menu item details
604
  const menuItemDetails = {
605
  {% for section, items in ordered_menu.items() %}
606
  {% for item in items %}
@@ -613,7 +790,6 @@
613
  {% endfor %}
614
  {% endfor %}
615
  };
616
-
617
  let isProcessingRequest = false;
618
  let currentSoftDrinkButton = null;
619
 
@@ -628,10 +804,15 @@
628
  const ingredientsList = [
629
  "Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
630
  "Chickpea Flour (Besan)", "Chickpeas (Channa)", "Chili Powder", "Chili Sauce",
631
- // Add rest of your ingredients here
 
 
 
 
 
632
  ];
633
 
634
- // LocalStorage cart functions
635
  function addToCartLocalStorage(payload) {
636
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
637
  const existingItem = cart.find(item =>
@@ -645,6 +826,26 @@
645
  cart.push(payload);
646
  }
647
  localStorage.setItem('cart', JSON.stringify(cart));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
648
  return cart;
649
  }
650
 
@@ -652,7 +853,7 @@
652
  return JSON.parse(localStorage.getItem('cart')) || [];
653
  }
654
 
655
- // Avatar functions
656
  function updateAvatarUI(imageSrc) {
657
  const avatarIcon = document.getElementById('avatarIcon');
658
  const avatarDropdown = document.getElementById('avatarDropdown');
@@ -730,6 +931,7 @@
730
  const maxSizeMB = 50;
731
  if (file.size > maxSizeMB * 1024 * 1024) {
732
  alert(`File size exceeds ${maxSizeMB}MB limit`);
 
733
  return;
734
  }
735
 
@@ -790,10 +992,219 @@
790
  });
791
  }
792
 
793
- // Main DOMContentLoaded event listener
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
794
  document.addEventListener('DOMContentLoaded', function () {
795
  attachAvatarEventListeners();
796
 
 
797
  const menuCards = document.querySelectorAll('.menu-card');
798
  const menuVideos = document.querySelectorAll('.menu-video');
799
  const cardObserver = new IntersectionObserver((entries) => {
@@ -818,9 +1229,11 @@
818
  }
819
  });
820
  }, { rootMargin: '200px', threshold: 0.01 });
 
821
  menuCards.forEach(card => cardObserver.observe(card));
822
  menuVideos.forEach(video => videoObserver.observe(video));
823
 
 
824
  const toggleLinks = document.querySelectorAll('.toggle-details');
825
  toggleLinks.forEach(link => {
826
  link.addEventListener('click', function () {
@@ -839,12 +1252,14 @@
839
  });
840
  });
841
 
 
842
  const categoryButtons = document.querySelectorAll('.category-button');
843
  const categoryForm = document.getElementById('categoryForm');
844
  const selectedCategoryInput = document.getElementById('selectedCategoryInput');
845
  if (!selectedCategoryInput.value) {
846
  selectedCategoryInput.value = "All";
847
- document.querySelector('.category-button[data-category="All"]').classList.add('selected');
 
848
  }
849
  categoryButtons.forEach(button => {
850
  button.addEventListener('click', function () {
@@ -855,6 +1270,7 @@
855
  });
856
  });
857
 
 
858
  const searchBar = document.getElementById('searchBar');
859
  const suggestionsContainer = document.getElementById('autocompleteSuggestions');
860
  searchBar.addEventListener('input', function () {
@@ -862,9 +1278,7 @@
862
  suggestionsContainer.innerHTML = '';
863
  suggestionsContainer.style.display = 'none';
864
  if (input) {
865
- const filteredItems = menuItems.filter(item =>
866
- item.toLowerCase().includes(input)
867
- );
868
  if (filteredItems.length > 0) {
869
  filteredItems.forEach(item => {
870
  const suggestionDiv = document.createElement('div');
@@ -883,157 +1297,7 @@
883
  filterMenu();
884
  });
885
 
886
- // Soft Drink Modal Logic
887
- function showSoftDrinkModal(button) {
888
- currentSoftDrinkButton = button;
889
- const buttonContainer = button.closest('.button-container');
890
- const itemName = buttonContainer.getAttribute('data-item-name');
891
- const itemPrice = buttonContainer.getAttribute('data-item-price');
892
- const itemImage = buttonContainer.getAttribute('data-item-image');
893
-
894
- document.getElementById('soft-drink-name').textContent = itemName;
895
- document.getElementById('soft-drink-price').textContent = `$${itemPrice}`;
896
- document.getElementById('soft-drink-quantity').value = '1';
897
- document.getElementById('soft-drink-image').src = itemImage || '/static/placeholder.jpg';
898
-
899
- const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
900
- modal.show();
901
- }
902
-
903
- function addSoftDrinkToCart() {
904
- if (!currentSoftDrinkButton) return;
905
-
906
- const buttonContainer = currentSoftDrinkButton.closest('.button-container');
907
- const quantity = parseInt(document.getElementById('soft-drink-quantity').value) || 1;
908
- const itemName = buttonContainer.getAttribute('data-item-name');
909
- const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
910
- const itemImage = buttonContainer.getAttribute('data-item-image');
911
- const section = buttonContainer.getAttribute('data-item-section');
912
- const selectedCategory = buttonContainer.getAttribute('data-item-category');
913
-
914
- const cartPayload = {
915
- itemName: itemName,
916
- itemPrice: itemPrice,
917
- itemImage: itemImage,
918
- section: section,
919
- category: selectedCategory,
920
- addons: [],
921
- instructions: '',
922
- quantity: quantity
923
- };
924
-
925
- fetch('/cart/add', {
926
- method: 'POST',
927
- headers: { 'Content-Type': 'application/json' },
928
- body: JSON.stringify(cartPayload)
929
- })
930
- .then(response => response.json())
931
- .then(data => {
932
- if (data.success) {
933
- updateCartUI(data.cart);
934
- const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
935
- modal.hide();
936
- } else {
937
- const cart = addToCartLocalStorage(cartPayload);
938
- updateCartUI(cart);
939
- const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
940
- modal.hide();
941
- }
942
- });
943
- }
944
-
945
- function updateCartUI(cart) {
946
- if (!Array.isArray(cart)) return;
947
- let totalQuantity = cart.reduce((sum, item) => sum + item.quantity, 0);
948
- const cartItemCount = document.getElementById('cart-item-count');
949
- if (cartItemCount) {
950
- cartItemCount.innerText = totalQuantity;
951
- cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
952
- }
953
- }
954
-
955
- function showItemDetails(name, price, image, description, ingredients, nutritionalInfo, allergens, section, selectedCategory) {
956
- document.getElementById('modal-name').innerText = name;
957
- document.getElementById('modal-price').innerText = `$${price}`;
958
- document.getElementById('modal-img').src = image || '/static/placeholder.jpg';
959
- document.getElementById('modal-description').innerText = description;
960
- document.getElementById('modal-ingredients').innerText = ingredients;
961
- document.getElementById('modal-nutrition').innerText = nutritionalInfo;
962
- document.getElementById('modal-allergens').innerText = allergens;
963
- document.getElementById('modal-instructions').value = '';
964
- document.getElementById('modal-section').setAttribute('data-section', section);
965
- document.getElementById('modal-section').setAttribute('data-category', selectedCategory);
966
- document.getElementById('quantityInput').value = 1;
967
-
968
- fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
969
- .then(response => response.json())
970
- .then(data => {
971
- const addonsList = document.getElementById('addons-list');
972
- addonsList.innerHTML = data.success && data.addons.length ? '' : '<p>No customization options available.</p>';
973
- if (data.success && data.addons) {
974
- data.addons.forEach(addon => {
975
- const sectionDiv = document.createElement('div');
976
- sectionDiv.classList.add('addon-section');
977
- sectionDiv.innerHTML = `<h6>${addon.name}</h6>`;
978
- addon.options.forEach((option, index) => {
979
- const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
980
- sectionDiv.innerHTML += `
981
- <div class="form-check">
982
- <input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
983
- data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}">
984
- <label class="form-check-label" for="${optionId}">${option} ${addon.extra_charge ? `($${addon.extra_charge_amount})` : ''}</label>
985
- </div>
986
- `;
987
- });
988
- addonsList.appendChild(sectionDiv);
989
- });
990
- }
991
- });
992
- }
993
-
994
- function addToCartFromModal() {
995
- const itemName = document.getElementById('modal-name').innerText;
996
- let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
997
- const itemImage = document.getElementById('modal-img').src;
998
- const section = document.getElementById('modal-section').getAttribute('data-section');
999
- const selectedCategory = document.getElementById('modal-section').getAttribute('data-category');
1000
- const selectedAddOns = Array.from(document.querySelectorAll('#addons-list input[type="checkbox"]:checked')).map(addon => ({
1001
- name: addon.getAttribute('data-name'),
1002
- price: parseFloat(addon.getAttribute('data-price') || 0)
1003
- }));
1004
- const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
1005
- const instructions = document.getElementById('modal-instructions').value;
1006
-
1007
- const cartPayload = {
1008
- itemName: itemName,
1009
- itemPrice: itemPrice,
1010
- itemImage: itemImage,
1011
- section: section,
1012
- category: selectedCategory,
1013
- addons: selectedAddOns,
1014
- instructions: instructions,
1015
- quantity: quantity
1016
- };
1017
-
1018
- fetch('/cart/add', {
1019
- method: 'POST',
1020
- headers: { 'Content-Type': 'application/json' },
1021
- body: JSON.stringify(cartPayload)
1022
- })
1023
- .then(response => response.json())
1024
- .then(data => {
1025
- if (data.success) {
1026
- updateCartUI(data.cart);
1027
- bootstrap.Modal.getInstance(document.getElementById('itemModal')).hide();
1028
- } else {
1029
- const cart = addToCartLocalStorage(cartPayload);
1030
- updateCartUI(cart);
1031
- bootstrap.Modal.getInstance(document.getElementById('itemModal')).hide();
1032
- }
1033
- });
1034
- }
1035
-
1036
- // Quantity controls
1037
  document.getElementById('decreaseQuantity').addEventListener('click', () => {
1038
  let qty = parseInt(document.getElementById('quantityInput').value);
1039
  if (qty > 1) document.getElementById('quantityInput').value = qty - 1;
@@ -1051,52 +1315,33 @@
1051
  if (qty < 1000) document.getElementById('soft-drink-quantity').value = qty + 1;
1052
  });
1053
 
1054
- // Initial cart fetch
1055
  fetch('/cart/get')
1056
  .then(response => response.json())
1057
  .then(data => {
1058
  if (data.success) updateCartUI(data.cart);
1059
  else updateCartUI(getCartLocalStorage());
 
 
 
 
1060
  });
1061
- });
1062
 
1063
- function filterMenu() {
1064
- const input = document.getElementById('searchBar').value.trim().toLowerCase();
1065
- const sections = document.querySelectorAll('h3');
1066
- const items = document.querySelectorAll('.menu-card');
1067
- let matchedSections = new Set();
1068
- items.forEach(item => {
1069
- const itemName = item.querySelector('.card-title').innerText.toLowerCase();
1070
- const itemSection = item.closest('.row').previousElementSibling.innerText.toLowerCase();
1071
- if (itemName.includes(input) || itemSection.includes(input)) {
1072
- item.style.display = 'block';
1073
- item.classList.add('visible');
1074
- matchedSections.add(item.closest('.row'));
1075
- } else {
1076
- item.style.display = 'none';
1077
- }
1078
  });
1079
- sections.forEach(section => {
1080
- const sectionRow = section.nextElementSibling;
1081
- if (matchedSections.has(sectionRow)) {
1082
- section.style.display = 'block';
1083
- sectionRow.style.display = 'flex';
1084
- } else {
1085
- section.style.display = 'none';
1086
- sectionRow.style.display = 'none';
1087
- }
1088
  });
1089
- if (!input) {
1090
- sections.forEach(section => {
1091
- section.style.display = 'block';
1092
- section.nextElementSibling.style.display = 'flex';
1093
- });
1094
- items.forEach(item => {
1095
- item.style.display = 'block';
1096
- item.classList.add('visible');
1097
- });
1098
- }
1099
- }
1100
  </script>
1101
  </body>
1102
  </html>
 
15
  {% endfor %}
16
  {% endfor %}
17
  <style>
18
+ /* General Styles */
19
  body {
20
  font-family: Arial, sans-serif;
21
  background-color: #fdf4e3;
 
24
  display: flex;
25
  flex-direction: column;
26
  padding-bottom: 70px;
27
+ min-height: 100vh;
28
  }
29
  .container {
30
+ max-width: 1200px;
31
+ padding: 0 15px;
32
  }
33
+ h3 {
34
+ color: #333;
35
+ font-size: 1.5rem;
36
+ margin-bottom: 20px;
37
+ font-weight: 600;
38
+ }
39
+ /* Fixed Top Bar */
40
+ .fixed-top-bar {
41
+ position: fixed;
42
+ top: 0;
43
+ left: 0;
44
+ width: 100%;
45
+ height: 60px;
46
+ background: linear-gradient(45deg, #FFA07A, #FFB347);
47
+ color: white;
48
+ padding: 10px 20px;
49
  display: flex;
50
+ justify-content: space-between;
51
+ align-items: center;
52
+ z-index: 1000;
53
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
54
  }
55
+ /* Search Bar */
56
+ .search-bar-container {
57
+ position: absolute;
58
+ left: 20px;
59
+ top: 50%;
60
+ transform: translateY(-50%);
61
+ display: flex;
62
+ align-items: center;
63
+ width: 300px;
64
+ max-width: 90%;
65
  }
66
+ .search-bar-container input {
 
67
  width: 100%;
68
+ padding: 10px 40px 10px 40px;
69
+ font-size: 16px;
70
+ border-radius: 25px;
71
+ border: none;
72
+ background-color: #fff;
73
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
74
+ outline: none;
75
+ transition: box-shadow 0.3s ease;
76
  }
77
+ .search-bar-container input:focus {
78
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
79
  }
80
+ .search-icon {
81
+ position: absolute;
82
+ left: 15px;
83
+ font-size: 18px;
84
+ color: #888;
85
  }
86
+ .mic-icon {
87
+ position: absolute;
88
+ right: 15px;
89
+ font-size: 18px;
90
+ color: #888;
91
+ cursor: pointer;
92
+ transition: color 0.3s ease;
93
  }
94
+ .mic-icon.active {
95
+ color: #007bff;
 
 
 
96
  }
97
+ .autocomplete-suggestions {
98
+ position: absolute;
99
+ top: 100%;
100
+ left: 0;
101
+ width: 100%;
102
+ max-height: 200px;
103
+ overflow-y: auto;
104
+ background-color: #fff;
105
+ border: 1px solid #ddd;
106
  border-radius: 5px;
107
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
108
+ z-index: 1000;
109
+ display: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  }
111
+ .autocomplete-suggestions .suggestion-item {
112
+ padding: 8px 15px;
113
+ cursor: pointer;
114
+ font-size: 14px;
115
+ color: #333;
116
+ transition: background-color 0.2s ease;
 
 
 
 
 
 
 
117
  }
118
+ .autocomplete-suggestions .suggestion-item:hover {
119
+ background-color: #f1f1f1;
 
 
120
  }
121
  /* Avatar Styles */
122
  .avatar-dropdown-container {
 
138
  justify-content: center;
139
  overflow: hidden;
140
  background-color: #007bff;
141
+ transition: transform 0.2s ease, box-shadow 0.3s ease;
142
  color: white;
143
  font-weight: bold;
144
  font-size: 18px;
145
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
146
  }
147
  .avatar-icon img {
148
  width: 100%;
 
151
  }
152
  .avatar-icon:hover {
153
  transform: scale(1.1);
154
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
155
  }
156
  .dropdown-menu {
157
  position: absolute;
158
  right: 0;
159
  top: 100%;
160
  background-color: #fff8f0;
161
+ border-radius: 8px;
162
  width: 220px;
163
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);
164
  display: none;
165
  border: 1px solid #ffd8b1;
166
+ z-index: 1001;
167
  }
168
  .dropdown-menu .dropdown-item {
169
  padding: 12px 16px;
 
172
  border-bottom: 1px solid #ffd8b1;
173
  display: block;
174
  font-size: 15px;
175
+ transition: background-color 0.2s ease, color 0.2s ease;
176
  }
177
  .dropdown-menu .dropdown-item:last-child {
178
  border-bottom: none;
 
181
  background-color: #ffe4c4;
182
  color: #333;
183
  }
184
+ /* Avatar Modal */
185
  .avatar-modal .modal-content {
186
  border-radius: 20px;
187
  overflow: hidden;
188
+ background-color: #fff;
189
  }
190
  .avatar-modal-img {
191
  width: 300px;
 
194
  object-fit: cover;
195
  margin: 20px auto;
196
  border: 4px solid #0FAA39;
197
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
198
  display: block;
199
+ transition: transform 0.3s ease;
200
  }
201
+ .avatar-modal-img:hover {
202
+ transform: scale(1.05);
203
+ }
204
+ .avatar-modal .modal-header {
205
+ background-color: #f8f9fa;
206
+ border-bottom: none;
207
+ }
208
+ .avatar-modal .modal-footer {
209
+ border-top: none;
210
+ justify-content: center;
211
+ }
212
+ /* Category Buttons */
213
+ .category-buttons {
214
  display: flex;
215
+ flex-wrap: wrap;
216
+ gap: 10px;
217
+ justify-content: center;
218
+ margin-top: 10px;
219
  }
220
+ .category-button {
221
+ padding: 10px 20px;
222
+ font-size: 14px;
223
+ border-radius: 20px;
224
+ background-color: #fff;
225
+ border: 1px solid #ddd;
226
+ color: #333;
227
+ cursor: pointer;
228
+ transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
229
+ }
230
+ .category-button:hover {
231
+ background-color: #f1f1f1;
232
+ border-color: #bbb;
233
+ }
234
+ .category-button.selected {
235
+ background-color: #0FAA39;
236
+ color: white;
237
+ border-color: #0FAA39;
238
+ }
239
+ /* Menu Cards */
240
+ .menu-card {
241
+ max-width: 350px;
242
+ border-radius: 15px;
243
+ overflow: hidden;
244
+ background-color: #fff;
245
+ margin: auto;
246
  display: flex;
247
+ flex-direction: column;
248
+ opacity: 0;
249
+ transition: opacity 0.3s ease-in-out, transform 0.3s ease;
250
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
251
  }
252
+ .menu-card.visible {
253
+ opacity: 1;
254
+ transform: translateY(0);
255
+ }
256
+ .menu-video {
257
+ height: 200px;
258
  width: 100%;
259
+ object-fit: cover;
260
+ border-radius: 15px 15px 0 0;
261
+ opacity: 0;
262
+ transition: opacity 0.5s ease-in-out;
263
+ background-color: #000;
 
 
264
  }
265
+ .menu-video.loaded {
266
+ opacity: 1;
267
  }
268
+ .menu-card:hover .menu-video {
269
+ opacity: 1;
 
 
 
270
  }
271
+ .menu-card .card-body {
272
+ padding: 15px;
273
+ display: flex;
274
+ justify-content: space-between;
275
+ align-items: center;
276
+ }
277
+ .menu-card .card-title {
278
+ font-size: 1.2rem;
279
+ font-weight: 600;
280
+ margin: 0 0 5px 0;
281
+ color: #333;
282
+ }
283
+ .menu-card .card-text.price {
284
+ font-size: 1rem;
285
+ font-weight: 500;
286
+ color: #000;
287
+ margin-bottom: 5px;
288
+ }
289
+ .toggle-details {
290
+ color: #0FAA39;
291
  cursor: pointer;
292
+ font-size: 0.9rem;
293
+ text-decoration: underline;
294
  transition: color 0.3s ease;
295
  }
296
+ .toggle-details:hover {
297
+ color: #0D9232;
298
  }
299
+ .item-details {
300
+ padding: 15px;
301
+ background-color: #f9f9f9;
 
 
 
 
 
 
 
 
 
302
  display: none;
303
+ border-top: 1px solid #eee;
304
+ }
305
+ .item-details.show {
306
+ display: block;
307
+ }
308
+ .item-details h6 {
309
+ font-size: 1rem;
310
+ font-weight: 600;
311
+ margin-top: 10px;
312
+ color: #333;
313
+ }
314
+ .item-details p {
315
+ font-size: 0.9rem;
316
+ color: #666;
317
+ margin: 5px 0;
318
+ }
319
+ .button-container {
320
+ display: flex;
321
+ flex-direction: column;
322
+ align-items: center;
323
+ justify-content: center;
324
+ gap: 6px;
325
+ }
326
+ .btn-primary {
327
+ font-size: 12px;
328
+ font-weight: bold;
329
+ border-radius: 8px;
330
+ width: 70px;
331
+ height: 35px;
332
+ background-color: #0FAA39;
333
+ border-color: #0FAA39;
334
+ display: flex;
335
+ align-items: center;
336
+ justify-content: center;
337
+ padding: 0;
338
+ transition: background-color 0.3s ease, transform 0.1s ease;
339
  }
340
+ .btn-primary:hover {
341
+ background-color: #0D9232;
342
+ border-color: #0D9232;
343
+ transform: scale(1.05);
 
344
  }
345
+ .customisable-text {
346
+ color: #0FAA39;
347
+ font-size: 10px;
348
+ font-weight: 500;
349
+ margin: 0;
350
+ text-align: center;
351
+ line-height: 1;
352
  }
353
+ /* Bottom Action Bar */
354
  .bottom-action-bar {
355
  position: fixed;
356
  bottom: 0;
 
363
  align-items: center;
364
  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
365
  z-index: 1000;
366
+ max-width: 1200px;
367
  margin: 0 auto;
368
  }
369
  .bottom-action-bar .btn {
370
  flex: 1;
371
  margin: 0 5px;
372
+ padding: 12px 15px;
373
  border-radius: 8px;
374
  font-weight: bold;
375
  font-size: 16px;
376
  color: white;
377
+ text-align: center;
378
+ transition: background-color 0.3s ease;
379
  }
380
  .bottom-action-bar .btn-order-history {
381
  background-color: #FFA07A;
 
385
  background-color: #0FAA39;
386
  border-color: #0FAA39;
387
  }
388
+ .bottom-action-bar .btn:hover {
389
+ opacity: 0.9;
390
+ }
391
  .cart-icon-badge {
392
  background-color: white;
393
  color: #0FAA39;
 
399
  justify-content: center;
400
  font-size: 12px;
401
  margin-left: 8px;
402
+ font-weight: bold;
403
  }
404
+ /* Modals */
405
+ .modal-content {
406
+ border-radius: 15px;
407
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
408
+ }
409
+ .modal-header {
410
+ background: linear-gradient(45deg, #0FAA39, #0D9232);
411
+ color: white;
412
+ border-radius: 15px 15px 0 0;
413
+ padding: 15px 20px;
414
+ }
415
+ .modal-body {
416
+ padding: 20px;
417
+ }
418
+ .modal-footer {
419
+ padding: 15px 20px;
420
+ border-top: none;
421
+ justify-content: space-between;
422
+ }
423
+ .modal-addons h6 {
424
+ font-size: 1rem;
425
+ font-weight: 600;
426
+ margin-bottom: 10px;
427
+ }
428
+ .addon-section {
429
+ margin-bottom: 15px;
430
+ }
431
+ .form-check {
432
+ margin-bottom: 8px;
433
+ }
434
+ .form-check-label {
435
+ font-size: 0.9rem;
436
+ color: #333;
437
+ }
438
+ .quantity-selector {
439
+ background-color: #f8f9fa;
440
+ padding: 10px;
441
+ border-radius: 10px;
442
+ display: flex;
443
+ align-items: center;
444
+ gap: 10px;
445
+ }
446
+ .quantity-selector button {
447
+ width: 40px;
448
+ height: 40px;
449
+ font-size: 1.2rem;
450
+ }
451
+ .quantity-selector input {
452
+ width: 60px;
453
+ font-weight: bold;
454
+ font-size: 1.1rem;
455
+ }
456
+ /* Mic Popup */
457
  .mic-popup {
458
  position: fixed;
459
  top: 50%;
 
478
  color: #ff4444;
479
  animation: pulse 1.5s infinite;
480
  }
481
+ .mic-popup-text {
482
+ font-size: 1.2rem;
483
+ margin-bottom: 20px;
484
+ }
485
+ .mic-popup-cancel {
486
+ background-color: #ff4444;
487
+ color: white;
488
+ border: none;
489
+ padding: 10px 20px;
490
+ border-radius: 8px;
491
+ cursor: pointer;
492
+ transition: background-color 0.3s ease;
493
+ }
494
+ .mic-popup-cancel:hover {
495
+ background-color: #cc3333;
496
+ }
497
  @keyframes pulse {
498
  0% { transform: scale(1); }
499
  50% { transform: scale(1.1); }
500
  100% { transform: scale(1); }
501
  }
502
+ /* Custom Dish Form */
503
+ #custom-dish-form {
504
+ background-color: #fff;
505
+ padding: 20px;
506
+ border-radius: 15px;
507
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
508
+ }
509
+ #custom-dish-form h3 {
510
+ font-size: 1.5rem;
511
+ margin-bottom: 20px;
512
+ }
513
+ #custom-dish-form .form-label {
514
+ font-weight: 600;
515
+ color: #333;
516
+ }
517
+ #custom-dish-form .form-control {
518
+ border-radius: 8px;
519
+ margin-bottom: 15px;
520
+ }
521
+ #custom-dish-form .btn-primary {
522
+ width: 100%;
523
+ padding: 12px;
524
+ font-size: 1.1rem;
525
+ }
526
+ /* Add any additional styles from your original code here */
527
  </style>
528
  </head>
529
  <body>
 
577
  </div>
578
  </div>
579
 
580
+ <!-- Category Selection -->
581
+ <div class="container mt-5 pt-4">
582
+ <form method="get" action="/menu" class="text-center mb-4" id="categoryForm">
583
+ <label class="form-label fw-bold">Select a Category:</label>
584
+ <div class="category-buttons">
585
+ {% for category in categories %}
586
+ <button type="button" class="category-button {% if selected_category == category %}selected{% endif %}" data-category="{{ category }}">{{ category }}</button>
587
+ {% endfor %}
588
+ <button type="button" class="category-button {% if selected_category == 'Customized Dish' %}selected{% endif %}" data-category="Customized Dish">Customized Dish</button>
589
+ </div>
590
+ <input type="hidden" name="category" id="selectedCategoryInput" value="{{ selected_category }}">
591
+ </form>
592
 
593
+ <!-- Menu Content -->
594
  {% if selected_category == "Customized Dish" %}
595
  <div id="custom-dish-form" class="mt-4">
596
  <h3>Create Your Custom Dish</h3>
 
609
  </div>
610
  {% else %}
611
  {% if ordered_menu.items()|length == 0 %}
612
+ <p class="text-center text-muted">No menu items available for this category.</p>
613
  {% else %}
614
  {% for section, items in ordered_menu.items() %}
615
  <h3>{{ section }}</h3>
616
  <div class="row">
617
  {% for item in items %}
618
+ <div class="col-md-6 col-lg-4 mb-4">
619
  <div class="card menu-card">
620
  <video
621
  class="card-img-top menu-video"
 
641
  <div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}">Show Details</div>
642
  {% endif %}
643
  </div>
644
+ <div class="button-container"
645
+ data-item-name="{{ item.Name | default('Unnamed Item') }}"
646
+ data-item-price="{{ item.Price__c | default('0.00') }}"
647
+ data-item-image="{{ item.Image2__c | default(item.Image1__c) | default('/static/placeholder.jpg') }}"
648
+ data-item-section="{{ item.Section__c | default(section) }}"
649
+ data-item-category="{{ selected_category }}">
650
+ {% if item.Section__c == 'Soft Drinks' %}
651
+ <button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)">ADD</button>
652
+ {% else %}
653
+ <button class="btn btn-primary"
654
+ data-bs-toggle="modal"
655
+ data-bs-target="#itemModal"
656
+ onclick="showItemDetails('{{ item.Name | default('Unnamed Item') }}', '{{ item.Price__c | default('0.00') }}', '{{ item.Image2__c | default(item.Image1__c) | default('/static/placeholder.jpg') }}', '{{ item.Description__c | default('No description') }}', '{{ item.IngredientsInfo__c | default('Not specified') }}', '{{ item.NutritionalInfo__c | default('Not available') }}', '{{ item.Allergens__c | default('None listed') }}', '{{ item.Section__c | default(section) }}', '{{ selected_category }}')">
657
+ ADD
658
+ </button>
659
+ {% endif %}
660
+ {% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' and item.Section__c != 'Soft Drinks' %}
661
+ <span class="customisable-text">Customisable</span>
662
+ {% endif %}
 
 
663
  </div>
664
  </div>
665
  </div>
 
719
  </div>
720
  <div class="mt-4">
721
  <h6>Custom Request</h6>
722
+ <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..." rows="3"></textarea>
723
  </div>
724
  <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
725
  </div>
 
738
  <!-- Soft Drink Modal -->
739
  <div class="modal fade" id="softDrinkModal" tabindex="-1" aria-labelledby="softDrinkModalLabel" aria-hidden="true">
740
  <div class="modal-dialog modal-dialog-centered">
741
+ <div class="modal-content">
742
+ <div class="modal-header">
743
  <h5 class="modal-title" id="softDrinkModalLabel">Select Your Drink</h5>
744
  <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
745
  </div>
746
+ <div class="modal-body">
747
  <div class="text-center mb-4">
748
  <img id="soft-drink-image" class="img-fluid rounded mb-3" alt="Soft Drink Image" style="max-height: 150px; width: auto; object-fit: contain;">
749
  <h5 id="soft-drink-name" class="fw-bold" style="color: #333;"></h5>
750
  <p id="soft-drink-price" style="font-size: 1.1rem;"></p>
751
  </div>
752
  <div class="d-flex justify-content-center align-items-center mb-4">
753
+ <div class="quantity-selector">
754
+ <button type="button" class="btn btn-outline-secondary" id="soft-drink-decrease">-</button>
755
+ <input type="text" class="form-control text-center mx-2" id="soft-drink-quantity" value="1" readonly>
756
+ <button type="button" class="btn btn-outline-secondary" id="soft-drink-increase">+</button>
757
  </div>
758
  </div>
759
  </div>
760
+ <div class="modal-footer">
761
+ <button type="button" class="btn btn-primary" onclick="addSoftDrinkToCart()">Add to Cart</button>
762
  </div>
763
  </div>
764
  </div>
 
778
  // Initial data from Flask
779
  const firstLetter = "{{ first_letter | default('G') }}";
780
  let userAvatar = "{{ user_avatar | default('') }}";
 
 
781
  const menuItemDetails = {
782
  {% for section, items in ordered_menu.items() %}
783
  {% for item in items %}
 
790
  {% endfor %}
791
  {% endfor %}
792
  };
 
793
  let isProcessingRequest = false;
794
  let currentSoftDrinkButton = null;
795
 
 
804
  const ingredientsList = [
805
  "Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
806
  "Chickpea Flour (Besan)", "Chickpeas (Channa)", "Chili Powder", "Chili Sauce",
807
+ "Cilantro", "Cinnamon", "Cloves", "Coconut Milk", "Coriander Powder", "Cumin Seeds",
808
+ "Curry Leaves", "Egg", "Fish Sauce", "Garam Masala", "Garlic", "Ginger",
809
+ "Green Beans", "Green Chili", "Lemon Grass", "Mint Leaves", "Mustard Seeds",
810
+ "Onion", "Paneer", "Peanuts", "Red Chili", "Rice Flour", "Saffron", "Salt",
811
+ "Soy Sauce", "Spinach", "Sugar", "Tamarind", "Tomato", "Turmeric", "Yogurt"
812
+ // Add any additional ingredients from your original code here
813
  ];
814
 
815
+ // LocalStorage Cart Functions
816
  function addToCartLocalStorage(payload) {
817
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
818
  const existingItem = cart.find(item =>
 
826
  cart.push(payload);
827
  }
828
  localStorage.setItem('cart', JSON.stringify(cart));
829
+ updateCartUI(cart);
830
+ return cart;
831
+ }
832
+
833
+ function removeFromCartLocalStorage(itemName, quantityToRemove, instructions, addons) {
834
+ let cart = JSON.parse(localStorage.getItem('cart')) || [];
835
+ const itemIndex = cart.findIndex(item =>
836
+ item.itemName === itemName &&
837
+ item.instructions === instructions &&
838
+ JSON.stringify(item.addons) === JSON.stringify(addons)
839
+ );
840
+ if (itemIndex !== -1) {
841
+ if (quantityToRemove >= cart[itemIndex].quantity) {
842
+ cart.splice(itemIndex, 1);
843
+ } else {
844
+ cart[itemIndex].quantity -= quantityToRemove;
845
+ }
846
+ }
847
+ localStorage.setItem('cart', JSON.stringify(cart));
848
+ updateCartUI(cart);
849
  return cart;
850
  }
851
 
 
853
  return JSON.parse(localStorage.getItem('cart')) || [];
854
  }
855
 
856
+ // Avatar Functions
857
  function updateAvatarUI(imageSrc) {
858
  const avatarIcon = document.getElementById('avatarIcon');
859
  const avatarDropdown = document.getElementById('avatarDropdown');
 
931
  const maxSizeMB = 50;
932
  if (file.size > maxSizeMB * 1024 * 1024) {
933
  alert(`File size exceeds ${maxSizeMB}MB limit`);
934
+ e.target.value = '';
935
  return;
936
  }
937
 
 
992
  });
993
  }
994
 
995
+ // Menu and Interaction Functions
996
+ function updateCartUI(cart) {
997
+ if (!Array.isArray(cart)) return;
998
+ let totalQuantity = cart.reduce((sum, item) => sum + item.quantity, 0);
999
+ const cartItemCount = document.getElementById('cart-item-count');
1000
+ if (cartItemCount) {
1001
+ cartItemCount.innerText = totalQuantity;
1002
+ cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
1003
+ }
1004
+ }
1005
+
1006
+ function showSoftDrinkModal(button) {
1007
+ currentSoftDrinkButton = button;
1008
+ const buttonContainer = button.closest('.button-container');
1009
+ const itemName = buttonContainer.getAttribute('data-item-name');
1010
+ const itemPrice = buttonContainer.getAttribute('data-item-price');
1011
+ const itemImage = buttonContainer.getAttribute('data-item-image');
1012
+
1013
+ document.getElementById('soft-drink-name').textContent = itemName;
1014
+ document.getElementById('soft-drink-price').textContent = `$${itemPrice}`;
1015
+ document.getElementById('soft-drink-quantity').value = '1';
1016
+ document.getElementById('soft-drink-image').src = itemImage || '/static/placeholder.jpg';
1017
+
1018
+ const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
1019
+ modal.show();
1020
+ }
1021
+
1022
+ function addSoftDrinkToCart() {
1023
+ if (!currentSoftDrinkButton) return;
1024
+
1025
+ const buttonContainer = currentSoftDrinkButton.closest('.button-container');
1026
+ const quantity = parseInt(document.getElementById('soft-drink-quantity').value) || 1;
1027
+ const itemName = buttonContainer.getAttribute('data-item-name');
1028
+ const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
1029
+ const itemImage = buttonContainer.getAttribute('data-item-image');
1030
+ const section = buttonContainer.getAttribute('data-item-section');
1031
+ const selectedCategory = buttonContainer.getAttribute('data-item-category');
1032
+
1033
+ const cartPayload = {
1034
+ itemName: itemName,
1035
+ itemPrice: itemPrice,
1036
+ itemImage: itemImage,
1037
+ section: section,
1038
+ category: selectedCategory,
1039
+ addons: [],
1040
+ instructions: '',
1041
+ quantity: quantity
1042
+ };
1043
+
1044
+ fetch('/cart/add', {
1045
+ method: 'POST',
1046
+ headers: { 'Content-Type': 'application/json' },
1047
+ body: JSON.stringify(cartPayload)
1048
+ })
1049
+ .then(response => response.json())
1050
+ .then(data => {
1051
+ if (data.success) {
1052
+ updateCartUI(data.cart);
1053
+ const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1054
+ modal.hide();
1055
+ } else {
1056
+ const cart = addToCartLocalStorage(cartPayload);
1057
+ updateCartUI(cart);
1058
+ const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1059
+ modal.hide();
1060
+ }
1061
+ })
1062
+ .catch(error => {
1063
+ console.error('Error adding to cart:', error);
1064
+ const cart = addToCartLocalStorage(cartPayload);
1065
+ updateCartUI(cart);
1066
+ const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1067
+ modal.hide();
1068
+ });
1069
+ }
1070
+
1071
+ function showItemDetails(name, price, image, description, ingredients, nutritionalInfo, allergens, section, selectedCategory) {
1072
+ document.getElementById('modal-name').innerText = name;
1073
+ document.getElementById('modal-price').innerText = `$${price}`;
1074
+ document.getElementById('modal-img').src = image || '/static/placeholder.jpg';
1075
+ document.getElementById('modal-description').innerText = description;
1076
+ document.getElementById('modal-ingredients').innerText = ingredients;
1077
+ document.getElementById('modal-nutrition').innerText = nutritionalInfo;
1078
+ document.getElementById('modal-allergens').innerText = allergens;
1079
+ document.getElementById('modal-instructions').value = '';
1080
+ document.getElementById('modal-section').setAttribute('data-section', section);
1081
+ document.getElementById('modal-section').setAttribute('data-category', selectedCategory);
1082
+ document.getElementById('quantityInput').value = 1;
1083
+
1084
+ fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
1085
+ .then(response => response.json())
1086
+ .then(data => {
1087
+ const addonsList = document.getElementById('addons-list');
1088
+ addonsList.innerHTML = data.success && data.addons.length ? '' : '<p>No customization options available.</p>';
1089
+ if (data.success && data.addons) {
1090
+ data.addons.forEach(addon => {
1091
+ const sectionDiv = document.createElement('div');
1092
+ sectionDiv.classList.add('addon-section');
1093
+ sectionDiv.innerHTML = `<h6>${addon.name}</h6>`;
1094
+ addon.options.forEach((option, index) => {
1095
+ const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
1096
+ sectionDiv.innerHTML += `
1097
+ <div class="form-check">
1098
+ <input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
1099
+ data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}">
1100
+ <label class="form-check-label" for="${optionId}">${option} ${addon.extra_charge ? `($${addon.extra_charge_amount})` : ''}</label>
1101
+ </div>
1102
+ `;
1103
+ });
1104
+ addonsList.appendChild(sectionDiv);
1105
+ });
1106
+ }
1107
+ })
1108
+ .catch(error => {
1109
+ console.error('Error fetching addons:', error);
1110
+ document.getElementById('addons-list').innerHTML = '<p>Failed to load customization options.</p>';
1111
+ });
1112
+ }
1113
+
1114
+ function addToCartFromModal() {
1115
+ const itemName = document.getElementById('modal-name').innerText;
1116
+ let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
1117
+ const itemImage = document.getElementById('modal-img').src;
1118
+ const section = document.getElementById('modal-section').getAttribute('data-section');
1119
+ const selectedCategory = document.getElementById('modal-section').getAttribute('data-category');
1120
+ const selectedAddOns = Array.from(document.querySelectorAll('#addons-list input[type="checkbox"]:checked')).map(addon => ({
1121
+ name: addon.getAttribute('data-name'),
1122
+ price: parseFloat(addon.getAttribute('data-price') || 0)
1123
+ }));
1124
+ const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
1125
+ const instructions = document.getElementById('modal-instructions').value;
1126
+
1127
+ const cartPayload = {
1128
+ itemName: itemName,
1129
+ itemPrice: itemPrice,
1130
+ itemImage: itemImage,
1131
+ section: section,
1132
+ category: selectedCategory,
1133
+ addons: selectedAddOns,
1134
+ instructions: instructions,
1135
+ quantity: quantity
1136
+ };
1137
+
1138
+ fetch('/cart/add', {
1139
+ method: 'POST',
1140
+ headers: { 'Content-Type': 'application/json' },
1141
+ body: JSON.stringify(cartPayload)
1142
+ })
1143
+ .then(response => response.json())
1144
+ .then(data => {
1145
+ if (data.success) {
1146
+ updateCartUI(data.cart);
1147
+ bootstrap.Modal.getInstance(document.getElementById('itemModal')).hide();
1148
+ } else {
1149
+ const cart = addToCartLocalStorage(cartPayload);
1150
+ updateCartUI(cart);
1151
+ bootstrap.Modal.getInstance(document.getElementById('itemModal')).hide();
1152
+ }
1153
+ })
1154
+ .catch(error => {
1155
+ console.error('Error adding to cart:', error);
1156
+ const cart = addToCartLocalStorage(cartPayload);
1157
+ updateCartUI(cart);
1158
+ bootstrap.Modal.getInstance(document.getElementById('itemModal')).hide();
1159
+ });
1160
+ }
1161
+
1162
+ function filterMenu() {
1163
+ const input = document.getElementById('searchBar').value.trim().toLowerCase();
1164
+ const sections = document.querySelectorAll('h3');
1165
+ const items = document.querySelectorAll('.menu-card');
1166
+ let matchedSections = new Set();
1167
+
1168
+ items.forEach(item => {
1169
+ const itemName = item.querySelector('.card-title').innerText.toLowerCase();
1170
+ const itemSection = item.closest('.row').previousElementSibling.innerText.toLowerCase();
1171
+ if (itemName.includes(input) || itemSection.includes(input)) {
1172
+ item.style.display = 'block';
1173
+ item.classList.add('visible');
1174
+ matchedSections.add(item.closest('.row'));
1175
+ } else {
1176
+ item.style.display = 'none';
1177
+ }
1178
+ });
1179
+
1180
+ sections.forEach(section => {
1181
+ const sectionRow = section.nextElementSibling;
1182
+ if (matchedSections.has(sectionRow)) {
1183
+ section.style.display = 'block';
1184
+ sectionRow.style.display = 'flex';
1185
+ } else {
1186
+ section.style.display = 'none';
1187
+ sectionRow.style.display = 'none';
1188
+ }
1189
+ });
1190
+
1191
+ if (!input) {
1192
+ sections.forEach(section => {
1193
+ section.style.display = 'block';
1194
+ section.nextElementSibling.style.display = 'flex';
1195
+ });
1196
+ items.forEach(item => {
1197
+ item.style.display = 'block';
1198
+ item.classList.add('visible');
1199
+ });
1200
+ }
1201
+ }
1202
+
1203
+ // DOMContentLoaded Event Listener
1204
  document.addEventListener('DOMContentLoaded', function () {
1205
  attachAvatarEventListeners();
1206
 
1207
+ // Intersection Observers for Lazy Loading
1208
  const menuCards = document.querySelectorAll('.menu-card');
1209
  const menuVideos = document.querySelectorAll('.menu-video');
1210
  const cardObserver = new IntersectionObserver((entries) => {
 
1229
  }
1230
  });
1231
  }, { rootMargin: '200px', threshold: 0.01 });
1232
+
1233
  menuCards.forEach(card => cardObserver.observe(card));
1234
  menuVideos.forEach(video => videoObserver.observe(video));
1235
 
1236
+ // Toggle Details
1237
  const toggleLinks = document.querySelectorAll('.toggle-details');
1238
  toggleLinks.forEach(link => {
1239
  link.addEventListener('click', function () {
 
1252
  });
1253
  });
1254
 
1255
+ // Category Selection
1256
  const categoryButtons = document.querySelectorAll('.category-button');
1257
  const categoryForm = document.getElementById('categoryForm');
1258
  const selectedCategoryInput = document.getElementById('selectedCategoryInput');
1259
  if (!selectedCategoryInput.value) {
1260
  selectedCategoryInput.value = "All";
1261
+ const allButton = document.querySelector('.category-button[data-category="All"]');
1262
+ if (allButton) allButton.classList.add('selected');
1263
  }
1264
  categoryButtons.forEach(button => {
1265
  button.addEventListener('click', function () {
 
1270
  });
1271
  });
1272
 
1273
+ // Search Functionality
1274
  const searchBar = document.getElementById('searchBar');
1275
  const suggestionsContainer = document.getElementById('autocompleteSuggestions');
1276
  searchBar.addEventListener('input', function () {
 
1278
  suggestionsContainer.innerHTML = '';
1279
  suggestionsContainer.style.display = 'none';
1280
  if (input) {
1281
+ const filteredItems = menuItems.filter(item => item.toLowerCase().includes(input));
 
 
1282
  if (filteredItems.length > 0) {
1283
  filteredItems.forEach(item => {
1284
  const suggestionDiv = document.createElement('div');
 
1297
  filterMenu();
1298
  });
1299
 
1300
+ // Quantity Controls
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1301
  document.getElementById('decreaseQuantity').addEventListener('click', () => {
1302
  let qty = parseInt(document.getElementById('quantityInput').value);
1303
  if (qty > 1) document.getElementById('quantityInput').value = qty - 1;
 
1315
  if (qty < 1000) document.getElementById('soft-drink-quantity').value = qty + 1;
1316
  });
1317
 
1318
+ // Initial Cart Fetch
1319
  fetch('/cart/get')
1320
  .then(response => response.json())
1321
  .then(data => {
1322
  if (data.success) updateCartUI(data.cart);
1323
  else updateCartUI(getCartLocalStorage());
1324
+ })
1325
+ .catch(error => {
1326
+ console.error('Error fetching cart:', error);
1327
+ updateCartUI(getCartLocalStorage());
1328
  });
 
1329
 
1330
+ // Mic Functionality (placeholder for your implementation)
1331
+ const micIcon = document.getElementById('micIcon');
1332
+ const micPopup = document.getElementById('micPopup');
1333
+ const micPopupCancel = document.getElementById('micPopupCancel');
1334
+ micIcon.addEventListener('click', () => {
1335
+ micPopup.classList.add('active');
1336
+ // Add your speech recognition logic here
 
 
 
 
 
 
 
 
1337
  });
1338
+ micPopupCancel.addEventListener('click', () => {
1339
+ micPopup.classList.remove('active');
1340
+ // Stop speech recognition here
 
 
 
 
 
 
1341
  });
1342
+
1343
+ // Add any additional JavaScript from your original code here
1344
+ });
 
 
 
 
 
 
 
 
1345
  </script>
1346
  </body>
1347
  </html>