lokesh341 commited on
Commit
00a8647
·
verified ·
1 Parent(s): 98bd236

Update templates/menu.html

Browse files
Files changed (1) hide show
  1. templates/menu.html +706 -296
templates/menu.html CHANGED
@@ -23,11 +23,9 @@
23
  display: flex;
24
  flex-direction: column;
25
  padding-bottom: 70px;
26
- overflow-x: hidden;
27
  }
28
  .container {
29
  max-width: 900px;
30
- padding: 0 15px;
31
  }
32
  .menu-card {
33
  max-width: 350px;
@@ -51,22 +49,19 @@
51
  border-radius: 15px 15px 0 0;
52
  opacity: 0;
53
  transition: opacity 0.5s ease-in-out;
54
- background-color: #000;
55
  }
56
  .menu-video.loaded {
57
  opacity: 1;
58
  }
59
  .menu-card:hover .menu-video {
60
  opacity: 1;
61
- transform: scale(1.05);
62
- }
63
- .menu-card .card-body {
64
- padding: 15px;
65
  }
66
  .menu-card .card-body .card-title {
67
  font-size: 1.2rem;
68
  font-weight: 600;
69
- margin: 0 0 5px 0;
70
  color: #333333;
71
  }
72
  .menu-card .card-body .card-text.price {
@@ -136,7 +131,7 @@
136
  top: 50%;
137
  transform: translateY(-50%);
138
  display: flex;
139
- align-items: center;
140
  justify-content: center;
141
  }
142
  .avatar-icon {
@@ -162,7 +157,6 @@
162
  box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
163
  display: none;
164
  border: 1px solid #ffd8b1;
165
- z-index: 1001;
166
  }
167
  .dropdown-menu .dropdown-item {
168
  padding: 12px 16px;
@@ -181,7 +175,7 @@
181
  color: #333;
182
  }
183
  .fixed-top-bar {
184
- position: fixed;
185
  top: 0;
186
  left: 0;
187
  width: 100%;
@@ -203,6 +197,7 @@
203
  align-items: center;
204
  width: 300px;
205
  max-width: 90%;
 
206
  }
207
  .search-bar-container input {
208
  width: 100%;
@@ -271,12 +266,15 @@
271
  color: #343a40;
272
  }
273
  .addon-section .form-check {
274
- display: flex;
275
  align-items: center;
276
  margin-left: 10px;
277
  color: #343a40;
278
  }
279
  .addon-section .form-check-input {
 
 
 
280
  width: 20px;
281
  height: 20px;
282
  border: 2px solid #343a40;
@@ -284,7 +282,6 @@
284
  background-color: #f0f0f0;
285
  position: relative;
286
  margin-right: 10px;
287
- cursor: pointer;
288
  }
289
  .addon-section .form-check-input:checked {
290
  background-color: #006400;
@@ -300,21 +297,21 @@
300
  }
301
  .addon-section .form-check-label {
302
  font-size: 16px;
 
303
  margin-right: 15px;
304
  cursor: pointer;
 
 
305
  }
306
  form.text-center.mb-4 {
307
  display: flex;
308
  flex-direction: column;
309
  align-items: center;
310
  justify-content: center;
311
- margin-bottom: 20px;
312
  }
313
  .modal-header {
314
  padding: 10px 15px;
315
- background: linear-gradient(45deg, #0FAA39, #0D9232);
316
- color: white;
317
- border-radius: 15px 15px 0 0;
318
  }
319
  .modal-title {
320
  font-size: 16px;
@@ -323,14 +320,14 @@
323
  .modal-body {
324
  max-height: 60vh;
325
  overflow-y: auto;
326
- padding: 20px;
327
  }
328
  .modal-body #modal-img {
329
  max-height: 200px;
330
  width: 100%;
331
  object-fit: cover;
332
  border-radius: 8px;
333
- margin-bottom: 15px;
334
  }
335
  .modal-body #modal-name {
336
  font-size: 20px;
@@ -349,61 +346,60 @@
349
  .modal-body #modal-description {
350
  font-size: 14px;
351
  color: #6c757d;
352
- margin-bottom: 15px;
353
- text-align: center;
354
  }
355
  .modal-body .nutritional-info {
356
  font-size: 12px;
357
  color: #6c757d;
358
- margin-bottom: 15px;
359
- text-align: center;
360
  }
361
- .modal-body #modal-addons h6 {
 
362
  font-size: 14px;
363
  font-weight: bold;
364
  margin-bottom: 10px;
365
- text-align: center;
366
  }
367
  .modal-footer {
368
  display: flex;
369
  align-items: center;
370
  justify-content: space-between;
371
- padding: 15px;
372
- border-top: none;
373
  }
374
- .modal-footer .quantity-selector {
375
  display: flex;
376
  align-items: center;
377
- background-color: #f8f9fa;
378
- padding: 5px;
379
- border-radius: 10px;
380
  }
381
- .modal-footer .btn-outline-secondary {
382
- width: 40px;
383
  height: 40px;
384
- padding: 0;
385
- font-size: 16px;
386
- line-height: 40px;
387
  }
388
  .modal-footer .form-control {
389
- width: 60px;
390
  height: 40px;
391
  text-align: center;
392
- font-weight: bold;
393
- font-size: 16px;
394
  }
395
  .modal-footer .btn-primary {
396
  background-color: #0FAA39;
397
  border-color: #0FAA39;
398
  font-weight: bold;
399
  padding: 10px 20px;
400
- border-radius: 8px;
 
 
 
 
 
 
 
 
401
  }
402
  .item-details {
403
  display: none;
404
  padding: 15px;
405
  background-color: #f8f9fa;
406
  border-radius: 8px;
 
407
  margin: 10px 15px;
408
  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
409
  }
@@ -462,6 +458,36 @@
462
  .category-button:hover {
463
  background-color: #e6f4ea;
464
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
465
  .modal-body::-webkit-scrollbar {
466
  width: 8px;
467
  }
@@ -480,6 +506,13 @@
480
  opacity: 0.65;
481
  cursor: not-allowed;
482
  }
 
 
 
 
 
 
 
483
  #custom-dish-form {
484
  position: relative;
485
  padding-bottom: 80px;
@@ -549,6 +582,8 @@
549
  font-size: 12px;
550
  margin-left: 8px;
551
  }
 
 
552
  .mic-popup {
553
  position: fixed;
554
  top: 50%;
@@ -565,20 +600,24 @@
565
  max-width: 90%;
566
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
567
  }
 
568
  .mic-popup.active {
569
  display: block;
570
  }
 
571
  .mic-popup-icon {
572
  font-size: 48px;
573
  margin-bottom: 20px;
574
  color: #ff4444;
575
  animation: pulse 1.5s infinite;
576
  }
 
577
  .mic-popup-text {
578
  font-size: 18px;
579
  margin-bottom: 15px;
580
  min-height: 24px;
581
  }
 
582
  .mic-popup-cancel {
583
  background-color: #ff4444;
584
  color: white;
@@ -587,16 +626,14 @@
587
  border-radius: 20px;
588
  cursor: pointer;
589
  font-weight: bold;
590
- transition: background-color 0.3s ease;
591
- }
592
- .mic-popup-cancel:hover {
593
- background-color: #cc3333;
594
  }
 
595
  @keyframes pulse {
596
  0% { transform: scale(1); }
597
  50% { transform: scale(1.1); }
598
  100% { transform: scale(1); }
599
  }
 
600
  @media (max-width: 576px) {
601
  .fixed-top-bar {
602
  height: 60px;
@@ -604,66 +641,146 @@
604
  }
605
  .search-bar-container {
606
  width: 80%;
 
607
  left: 10px;
 
 
608
  }
609
  .search-bar-container input {
610
- padding: 6px 35px;
611
  font-size: 14px;
612
  border-radius: 20px;
613
  }
614
- .search-icon, .mic-icon {
 
615
  font-size: 16px;
616
  }
 
 
 
 
 
 
 
617
  .avatar-icon {
618
- width: 35px;
619
- height: 35px;
620
- font-size: 18px;
621
  }
622
  .dropdown-menu {
623
- width: 200px;
 
 
 
 
 
 
 
624
  }
625
  .category-button {
626
  padding: 4px 12px;
627
  font-size: 0.85rem;
628
  }
 
 
 
 
 
 
 
 
 
 
629
  .modal-body {
630
  max-height: 50vh;
631
- padding: 15px;
632
  }
633
  .modal-body #modal-img {
634
  max-height: 150px;
 
 
 
 
635
  }
636
  .modal-body #modal-name {
637
  font-size: 18px;
 
638
  }
639
  .modal-body #modal-price {
640
  font-size: 14px;
 
641
  }
642
- .modal-body #modal-description, .modal-body .nutritional-info {
643
  font-size: 12px;
 
644
  }
645
- .modal-footer .btn-outline-secondary {
646
- width: 30px;
 
 
 
 
 
 
 
 
 
 
 
647
  height: 30px;
648
- font-size: 14px;
649
  }
650
  .modal-footer .form-control {
651
- width: 50px;
652
  height: 30px;
653
- font-size: 14px;
 
 
 
 
 
 
 
654
  }
655
  .modal-footer .btn-primary {
656
- padding: 8px 15px;
657
- font-size: 14px;
 
 
658
  }
659
  .btn-primary {
660
- width: 60px;
661
- height: 30px;
662
  font-size: 10px;
 
 
663
  }
664
  .customisable-text {
665
  font-size: 8px;
666
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
667
  .bottom-action-bar {
668
  padding: 8px 10px;
669
  }
@@ -675,28 +792,46 @@
675
  width: 18px;
676
  height: 18px;
677
  font-size: 10px;
 
 
 
 
 
 
 
 
678
  }
 
 
 
 
 
 
 
679
  .mic-popup {
680
- width: 280px;
681
  padding: 20px;
 
682
  }
683
  .mic-popup-icon {
684
  font-size: 36px;
 
685
  }
686
  .mic-popup-text {
687
  font-size: 16px;
688
  }
689
  .mic-popup-cancel {
690
  padding: 6px 16px;
 
691
  }
692
  }
693
  </style>
694
  </head>
695
  <body>
 
696
  <div class="fixed-top-bar">
697
  <div class="avatar-dropdown-container">
698
  <div class="avatar-icon">
699
- <span>{{ first_letter | default('U') }}</span>
700
  </div>
701
  <div class="dropdown-menu">
702
  <a href="{{ url_for('user_details.customer_details') }}" class="dropdown-item">View Profile</a>
@@ -720,7 +855,7 @@
720
  {% endfor %}
721
  <button type="button" class="category-button {% if selected_category == 'Customized Dish' %}selected{% endif %}" data-category="Customized Dish">Customized Dish</button>
722
  </div>
723
- <input type="hidden" name="category" id="selectedCategoryInput" value="{{ selected_category | default('All') }}">
724
  </form>
725
 
726
  <div class="container mt-4">
@@ -742,7 +877,7 @@
742
  </div>
743
  {% else %}
744
  {% if ordered_menu.items()|length == 0 %}
745
- <p class="text-center">No menu items available for this category.</p>
746
  {% else %}
747
  {% for section, items in ordered_menu.items() %}
748
  <h3>{{ section }}</h3>
@@ -774,25 +909,27 @@
774
  <div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}">Show Details</div>
775
  {% endif %}
776
  </div>
777
- <div class="button-container"
778
- data-item-name="{{ item.Name | default('Unnamed Item') }}"
779
- data-item-price="{{ item.Price__c | default('0.00') }}"
780
- data-item-image="{{ item.Image2__c | default(item.Image1__c) | default('/static/placeholder.jpg') }}"
781
- data-item-section="{{ item.Section__c | default(section) }}"
782
- data-item-category="{{ selected_category }}">
783
- {% if item.Section__c == 'Soft Drinks' %}
784
- <button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)">ADD</button>
785
- {% else %}
786
- <button class="btn btn-primary"
787
- data-bs-toggle="modal"
788
- data-bs-target="#itemModal"
789
- 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 }}')">
790
- ADD
791
- </button>
792
- {% if item.Section__c not in ['Appetizer', 'Customized Dish', 'Soft Drinks'] %}
 
 
793
  <span class="customisable-text">Customisable</span>
794
  {% endif %}
795
- {% endif %}
796
  </div>
797
  </div>
798
  </div>
@@ -800,8 +937,8 @@
800
  <div class="item-details" id="details-{{ item.Name | default('unnamed-item') | replace(' ', '-') }}">
801
  <h6>Description</h6>
802
  <p>{{ item.Description__c | default('No description available') }}</p>
803
- <h6>Ingredients</h6>
804
- <p>{{ item.IngredientsInfo__c | default('Not specified') }}</p>
805
  <h6>Nutritional Info</h6>
806
  <p>{{ item.NutritionalInfo__c | default('Not available') }}</p>
807
  <h6>Allergens</h6>
@@ -823,20 +960,20 @@
823
  </a>
824
  <a href="{{ url_for('cart.cart') }}" class="btn btn-view-cart">
825
  <i class="bi bi-cart"></i> View Cart
826
- <span class="cart-icon-badge" id="cart-item-count">{{ cart_item_count | default(0) }}</span>
827
  </a>
828
  </div>
829
 
830
- <!-- Item Modal -->
831
  <div class="modal fade" id="itemModal" tabindex="-1" aria-labelledby="itemModalLabel" aria-hidden="true">
832
  <div class="modal-dialog modal-dialog-centered">
833
- <div class="modal-content" style="border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.2);">
834
  <div class="modal-header">
835
  <h5 class="modal-title" id="itemModalLabel">Item Details</h5>
836
- <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
837
  </div>
838
  <div class="modal-body">
839
- <img id="modal-img" class="img-fluid rounded mb-3 d-block mx-auto" alt="Item Image">
840
  <h5 id="modal-name" class="fw-bold text-center"></h5>
841
  <p id="modal-price" class="text-muted text-center"></p>
842
  <p id="modal-description" class="text-secondary"></p>
@@ -851,46 +988,46 @@
851
  </div>
852
  <div class="mt-4">
853
  <h6>Custom Request</h6>
854
- <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..." rows="2"></textarea>
855
  </div>
856
  <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
857
  </div>
858
- <div class="modal-footer">
859
- <div class="quantity-selector">
860
  <button type="button" class="btn btn-outline-secondary" id="decreaseQuantity">-</button>
861
- <input type="text" class="form-control text-center" id="quantityInput" value="1" readonly>
862
  <button type="button" class="btn btn-outline-secondary" id="increaseQuantity">+</button>
863
  </div>
864
- <button type="button" class="btn btn-primary" id="addToCartBtn" onclick="addToCartFromModal()">Add to Cart</button>
865
  </div>
866
  </div>
867
  </div>
868
  </div>
869
 
870
- <!-- Soft Drink Modal -->
871
  <div class="modal fade" id="softDrinkModal" tabindex="-1" aria-labelledby="softDrinkModalLabel" aria-hidden="true">
872
  <div class="modal-dialog modal-dialog-centered">
873
  <div class="modal-content" style="border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.2);">
874
- <div class="modal-header">
875
  <h5 class="modal-title" id="softDrinkModalLabel">Select Your Drink</h5>
876
  <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
877
  </div>
878
- <div class="modal-body">
879
  <div class="text-center mb-4">
880
  <img id="soft-drink-image" class="img-fluid rounded mb-3" alt="Soft Drink Image" style="max-height: 150px; width: auto; object-fit: contain;">
881
  <h5 id="soft-drink-name" class="fw-bold" style="color: #333;"></h5>
882
  <p id="soft-drink-price" class="text-muted" style="font-size: 1.1rem;"></p>
883
  </div>
884
  <div class="d-flex justify-content-center align-items-center mb-4">
885
- <div class="quantity-selector">
886
- <button type="button" class="btn btn-outline-secondary" id="soft-drink-decrease">-</button>
887
- <input type="text" class="form-control text-center mx-2" id="soft-drink-quantity" value="1" readonly>
888
- <button type="button" class="btn btn-outline-secondary" id="soft-drink-increase">+</button>
889
  </div>
890
  </div>
891
  </div>
892
- <div class="modal-footer">
893
- <button type="button" class="btn btn-primary" onclick="addSoftDrinkToCart()">Add to Cart</button>
894
  </div>
895
  </div>
896
  </div>
@@ -907,7 +1044,9 @@
907
 
908
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
909
  <script>
 
910
  let currentSoftDrinkButton = null;
 
911
  const menuItems = [
912
  {% for section, items in ordered_menu.items() %}
913
  {% for item in items %}
@@ -915,15 +1054,18 @@
915
  {% endfor %}
916
  {% endfor %}
917
  ];
 
918
  const ingredientsList = [
919
  "Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
920
- "Chickpea Flour (Besan)", "Chickpeas (Channa)", "Chili Powder", "Chili Sauce", "Coconut Milk",
921
- "Coriander Powder", "Cornflour", "Cream", "Cumin Powder", "Cumin Seeds", "Curd (Yogurt)",
922
- "Curry Leaves", "Fish (e.g., King Fish or Salmon)", "Fresh Coriander Leaves", "Garam Masala",
923
- "Garlic", "Ghee (Clarified Butter)", "Ginger", "Ginger-Garlic Paste", "Goat Meat (Mutton)",
924
- "Green Chilies", "Honey", "Kasuri Methi (dried fenugreek leaves)", "Lemon Juice", "Mango Puree",
925
- "Mint Leaves", "Mixed Vegetables (Carrot, Peas, Potato, Cauliflower)", "Mustard Seeds", "Oil",
926
- "Onion", "Paneer (Indian Cottage Cheese)", "Peas", "Potatoes", "Prawns", "Red Chili Powder",
 
 
927
  "Rice Flour", "Saffron", "Salt", "Soy Sauce", "Spring Onion", "Tamarind (for sourness)",
928
  "Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
929
  "Whole Wheat Flour", "Yogurt (Curd)"
@@ -931,13 +1073,13 @@
931
 
932
  function addToCartLocalStorage(payload) {
933
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
934
- const existingItem = cart.find(item =>
935
- item.itemName === payload.itemName &&
936
- item.instructions === payload.instructions &&
937
  JSON.stringify(item.addons) === JSON.stringify(payload.addons)
938
  );
939
  if (existingItem) {
940
- existingItem.quantity += payload.quantity;
941
  } else {
942
  cart.push(payload);
943
  }
@@ -945,232 +1087,450 @@
945
  return cart;
946
  }
947
 
948
- function updateCartUI(cart) {
949
- let totalQuantity = cart.reduce((sum, item) => sum + (item.quantity || 0), 0);
950
- const cartItemCount = document.getElementById('cart-item-count');
951
- if (cartItemCount) {
952
- cartItemCount.innerText = totalQuantity;
953
- cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
 
 
 
 
 
 
 
954
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
955
  }
956
 
957
  function showSoftDrinkModal(button) {
958
  currentSoftDrinkButton = button;
959
  const buttonContainer = button.closest('.button-container');
960
- document.getElementById('soft-drink-name').textContent = buttonContainer.getAttribute('data-item-name');
961
- document.getElementById('soft-drink-price').textContent = `$${buttonContainer.getAttribute('data-item-price')}`;
 
 
 
 
962
  document.getElementById('soft-drink-quantity').value = '1';
963
- document.getElementById('soft-drink-image').src = buttonContainer.getAttribute('data-item-image') || '/static/placeholder.jpg';
 
 
964
  const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
965
  modal.show();
966
  }
967
 
968
  function addSoftDrinkToCart() {
969
  if (!currentSoftDrinkButton) return;
 
970
  const buttonContainer = currentSoftDrinkButton.closest('.button-container');
971
  const quantity = parseInt(document.getElementById('soft-drink-quantity').value) || 1;
 
 
 
 
 
 
 
972
  const cartPayload = {
973
- itemName: buttonContainer.getAttribute('data-item-name'),
974
- itemPrice: parseFloat(buttonContainer.getAttribute('data-item-price')) || 0,
975
- itemImage: buttonContainer.getAttribute('data-item-image'),
976
- section: buttonContainer.getAttribute('data-item-section'),
977
- category: buttonContainer.getAttribute('data-item-category'),
978
  addons: [],
979
  instructions: '',
980
  quantity: quantity
981
  };
 
982
  fetch('/cart/add', {
983
  method: 'POST',
984
- headers: { 'Content-Type': 'application/json' },
 
 
985
  body: JSON.stringify(cartPayload)
986
  })
987
  .then(response => response.json())
988
  .then(data => {
989
- updateCartUI(data.success ? data.cart : addToCartLocalStorage(cartPayload));
990
- bootstrap.Modal.getInstance(document.getElementById('softDrinkModal')).hide();
 
 
 
 
 
 
 
 
 
991
  })
992
- .catch(() => {
993
- updateCartUI(addToCartLocalStorage(cartPayload));
994
- bootstrap.Modal.getInstance(document.getElementById('softDrinkModal')).hide();
 
 
 
995
  });
996
  }
997
 
998
- document.addEventListener('DOMContentLoaded', () => {
999
- // Avatar Dropdown
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1000
  const avatarContainer = document.querySelector('.avatar-dropdown-container');
1001
  const dropdownMenu = document.querySelector('.dropdown-menu');
1002
- avatarContainer.addEventListener('click', (e) => {
1003
- e.stopPropagation();
1004
  dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
1005
  });
1006
- document.addEventListener('click', (e) => {
1007
- if (!avatarContainer.contains(e.target)) dropdownMenu.style.display = 'none';
 
 
 
 
 
 
 
 
1008
  });
1009
 
1010
- // Lazy Loading
1011
- const cardObserver = new IntersectionObserver((entries) => {
 
1012
  entries.forEach(entry => {
1013
  if (entry.isIntersecting) {
1014
  entry.target.classList.add('visible');
1015
- cardObserver.unobserve(entry.target);
1016
  }
1017
  });
1018
- }, { threshold: 0.1 });
1019
- const videoObserver = new IntersectionObserver((entries) => {
 
 
 
 
1020
  entries.forEach(entry => {
1021
  if (entry.isIntersecting) {
1022
  const video = entry.target;
1023
  const src = video.getAttribute('data-src');
1024
- if (src) video.querySelector('source').src = src;
1025
- video.load();
 
 
 
1026
  video.classList.add('loaded');
1027
- videoObserver.unobserve(video);
1028
  }
1029
  });
1030
- }, { rootMargin: '200px' });
1031
- document.querySelectorAll('.menu-card').forEach(card => cardObserver.observe(card));
1032
- document.querySelectorAll('.menu-video').forEach(video => videoObserver.observe(video));
 
 
 
 
1033
 
1034
- // Toggle Details
1035
- document.querySelectorAll('.toggle-details').forEach(link => {
1036
- link.addEventListener('click', () => {
1037
- const detailsDiv = document.getElementById(`details-${link.getAttribute('data-item-name').replace(/ /g, '-')}`);
1038
- detailsDiv.classList.toggle('show');
1039
- link.innerText = detailsDiv.classList.contains('show') ? 'Hide Details' : 'Show Details';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1040
  });
1041
  });
1042
 
1043
- // Category Selection
1044
  const categoryButtons = document.querySelectorAll('.category-button');
1045
  const categoryForm = document.getElementById('categoryForm');
1046
  const selectedCategoryInput = document.getElementById('selectedCategoryInput');
1047
  if (!selectedCategoryInput.value) {
1048
- selectedCategoryInput.value = 'All';
1049
  document.querySelector('.category-button[data-category="All"]').classList.add('selected');
1050
  }
1051
  categoryButtons.forEach(button => {
1052
- button.addEventListener('click', () => {
1053
  categoryButtons.forEach(btn => btn.classList.remove('selected'));
1054
- button.classList.add('selected');
1055
- selectedCategoryInput.value = button.getAttribute('data-category');
1056
  categoryForm.submit();
1057
  });
1058
  });
1059
-
1060
- // Search Functionality
1061
  const searchBar = document.getElementById('searchBar');
1062
  const suggestionsContainer = document.getElementById('autocompleteSuggestions');
1063
- searchBar.addEventListener('input', () => {
1064
- const input = searchBar.value.trim().toLowerCase();
1065
  suggestionsContainer.innerHTML = '';
1066
- suggestionsContainer.style.display = input && menuItems.some(item => item.toLowerCase().includes(input)) ? 'block' : 'none';
1067
  if (input) {
1068
- menuItems.filter(item => item.toLowerCase().includes(input)).forEach(item => {
1069
- const div = document.createElement('div');
1070
- div.classList.add('suggestion-item');
1071
- div.innerText = item;
1072
- div.addEventListener('click', () => {
1073
- searchBar.value = item;
1074
- suggestionsContainer.style.display = 'none';
1075
- filterMenu();
 
 
 
 
 
 
1076
  });
1077
- suggestionsContainer.appendChild(div);
1078
- });
1079
  }
1080
  filterMenu();
1081
  });
1082
- document.addEventListener('click', (e) => {
1083
- if (!searchBar.contains(e.target) && !suggestionsContainer.contains(e.target)) suggestionsContainer.style.display = 'none';
 
 
1084
  });
1085
-
1086
- // Custom Dish Suggestions
1087
  const descriptionTextarea = document.getElementById('custom-dish-description');
1088
  const descriptionSuggestions = document.getElementById('descriptionSuggestions');
1089
- if (descriptionTextarea) {
1090
- descriptionTextarea.addEventListener('input', () => {
1091
- const words = descriptionTextarea.value.trim().split(/,\s*/);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1092
  const lastWord = words[words.length - 1].trim().toLowerCase();
1093
  descriptionSuggestions.innerHTML = '';
1094
- descriptionSuggestions.style.display = lastWord && ingredientsList.some(ing => ing.toLowerCase().includes(lastWord)) ? 'block' : 'none';
 
1095
  if (lastWord) {
1096
- ingredientsList.filter(ing => ing.toLowerCase().includes(lastWord)).forEach(ingredient => {
1097
- const div = document.createElement('div');
1098
- div.classList.add('suggestion-item');
1099
- div.innerText = ingredient;
1100
- div.addEventListener('click', () => {
1101
- const base = descriptionTextarea.value.substring(0, descriptionTextarea.value.lastIndexOf(lastWord));
1102
- descriptionTextarea.value = base + ingredient + ', ';
1103
- descriptionSuggestions.style.display = 'none';
 
 
 
 
 
 
 
 
 
 
1104
  });
1105
- descriptionSuggestions.appendChild(div);
1106
- });
 
 
 
 
 
1107
  }
1108
  });
1109
  }
1110
-
1111
- // Initial Cart Load
1112
  fetch('/cart/get')
1113
- .then(response => response.json())
1114
- .then(data => updateCartUI(data.success ? data.cart : JSON.parse(localStorage.getItem('cart') || '[]')))
1115
- .catch(() => updateCartUI(JSON.parse(localStorage.getItem('cart') || '[]')));
1116
-
1117
- // Quantity Controls
1118
- const modals = ['itemModal', 'softDrinkModal'];
1119
- modals.forEach(modalId => {
1120
- const decreaseBtn = document.getElementById(modalId === 'itemModal' ? 'decreaseQuantity' : 'soft-drink-decrease');
1121
- const increaseBtn = document.getElementById(modalId === 'itemModal' ? 'increaseQuantity' : 'soft-drink-increase');
1122
- const quantityInput = document.getElementById(modalId === 'itemModal' ? 'quantityInput' : 'soft-drink-quantity');
1123
- decreaseBtn.addEventListener('click', () => {
1124
- let qty = parseInt(quantityInput.value);
1125
- if (qty > 1) quantityInput.value = qty - 1;
1126
- });
1127
- increaseBtn.addEventListener('click', () => {
1128
- let qty = parseInt(quantityInput.value);
1129
- if (qty < 99) quantityInput.value = qty + 1;
 
 
1130
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1131
  });
1132
 
1133
- // Microphone Functionality
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1134
  const micIcon = document.getElementById('micIcon');
1135
  const micPopup = document.getElementById('micPopup');
1136
  const micPopupText = document.getElementById('micPopupText');
1137
  const micPopupCancel = document.getElementById('micPopupCancel');
 
1138
  if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
1139
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
1140
  const recognition = new SpeechRecognition();
1141
  recognition.continuous = false;
1142
  recognition.interimResults = true;
1143
  recognition.lang = 'en-US';
1144
-
1145
  recognition.onstart = () => {
1146
  micIcon.classList.add('active');
1147
  micPopup.classList.add('active');
1148
  micPopupText.textContent = 'Listening...';
1149
  };
 
1150
  recognition.onresult = (event) => {
 
1151
  let finalTranscript = '';
 
1152
  for (let i = event.resultIndex; i < event.results.length; i++) {
1153
- if (event.results[i].isFinal) finalTranscript = event.results[i][0].transcript;
1154
- else micPopupText.textContent = event.results[i][0].transcript;
 
 
 
 
1155
  }
 
 
 
 
 
 
 
1156
  if (finalTranscript) {
1157
  searchBar.value = finalTranscript.trim();
1158
  filterMenu();
1159
  micPopup.classList.remove('active');
1160
- micIcon.classList.remove('active');
1161
  }
1162
  };
 
1163
  recognition.onend = () => {
1164
  micIcon.classList.remove('active');
1165
- micPopup.classList.remove('active');
 
 
 
 
 
1166
  };
 
1167
  recognition.onerror = (event) => {
1168
- micPopupText.textContent = `Error: ${event.error}`;
1169
- setTimeout(() => micPopup.classList.remove('active'), 2000);
1170
  micIcon.classList.remove('active');
 
 
 
 
 
1171
  };
1172
- micIcon.addEventListener('click', () => recognition.start());
1173
- micPopupCancel.addEventListener('click', () => recognition.stop());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1174
  } else {
1175
  micIcon.style.display = 'none';
1176
  }
@@ -1183,122 +1543,172 @@
1183
  let matchedSections = new Set();
1184
  items.forEach(item => {
1185
  const itemName = item.querySelector('.card-title').innerText.toLowerCase();
1186
- const sectionTitle = item.closest('.row').previousElementSibling.innerText.toLowerCase();
1187
- if (itemName.includes(input) || sectionTitle.includes(input)) {
1188
  item.style.display = 'block';
 
1189
  matchedSections.add(item.closest('.row'));
1190
  } else {
1191
  item.style.display = 'none';
1192
  }
1193
  });
1194
  sections.forEach(section => {
1195
- const row = section.nextElementSibling;
1196
- row.style.display = matchedSections.has(row) ? 'flex' : 'none';
1197
- section.style.display = matchedSections.has(row) ? 'block' : 'none';
 
 
 
 
 
1198
  });
1199
  if (!input) {
1200
  sections.forEach(section => {
1201
  section.style.display = 'block';
1202
  section.nextElementSibling.style.display = 'flex';
1203
  });
1204
- items.forEach(item => item.style.display = 'block');
 
 
 
1205
  }
1206
  }
1207
 
1208
- function showItemDetails(name, price, image, description, ingredients, nutrition, allergens, section, category) {
1209
  document.getElementById('modal-name').innerText = name;
1210
- document.getElementById('modal-price').innerText = `$${parseFloat(price).toFixed(2)}`;
1211
- document.getElementById('modal-img').src = image || '/static/placeholder.jpg';
1212
- document.getElementById('modal-description').innerText = description;
1213
- document.getElementById('modal-ingredients').innerText = ingredients;
1214
- document.getElementById('modal-nutrition').innerText = nutrition;
1215
- document.getElementById('modal-allergens').innerText = allergens;
 
 
1216
  document.getElementById('modal-instructions').value = '';
1217
- document.getElementById('quantityInput').value = '1';
1218
- document.getElementById('modal-section').setAttribute('data-section', section);
1219
- document.getElementById('modal-section').setAttribute('data-category', category);
1220
-
1221
- const addonsList = document.getElementById('addons-list');
1222
- const addToCartBtn = document.getElementById('addToCartBtn');
1223
- addonsList.innerHTML = 'Loading customization options...';
1224
- addToCartBtn.disabled = true;
1225
 
1226
  fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
1227
  .then(response => response.json())
1228
  .then(data => {
 
1229
  addonsList.innerHTML = '';
1230
- if (data.success && data.addons && data.addons.length > 0) {
1231
- data.addons.forEach(addon => {
1232
- const sectionDiv = document.createElement('div');
1233
- sectionDiv.classList.add('addon-section');
1234
- sectionDiv.innerHTML = `<h6>${addon.name}</h6>`;
1235
- addon.options.forEach((option, index) => {
1236
- const optionId = `addon-${addon.name.replace(/\s+/g, '-')}-${index}`;
1237
- const div = document.createElement('div');
1238
- div.classList.add('form-check');
1239
- div.innerHTML = `
1240
- <input type="checkbox" class="form-check-input" id="${optionId}" value="${option}" data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}">
1241
- <label class="form-check-label" for="${optionId}">${option} ${addon.extra_charge ? `($${addon.extra_charge_amount})` : ''}</label>
1242
- `;
1243
- sectionDiv.appendChild(div);
1244
- });
1245
- addonsList.appendChild(sectionDiv);
1246
- });
1247
- } else {
1248
  addonsList.innerHTML = '<p>No customization options available.</p>';
 
1249
  }
1250
- addToCartBtn.disabled = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1251
  })
1252
- .catch(() => {
1253
- addonsList.innerHTML = '<p>Failed to load customization options.</p>';
1254
- addToCartBtn.disabled = false;
1255
  });
1256
  }
1257
 
1258
- document.addEventListener('click', (e) => {
1259
- if (e.target.classList.contains('form-check-input')) {
1260
- const group = e.target.getAttribute('data-group');
1261
- const multiSelectGroups = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo", "Beverages", "Sauces"];
1262
- if (!multiSelectGroups.includes(group)) {
1263
- document.querySelectorAll(`.form-check-input[data-group="${group}"]`).forEach(cb => {
1264
- if (cb !== e.target) cb.checked = false;
1265
- });
1266
- }
1267
  }
1268
  });
1269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1270
  function addToCartFromModal() {
1271
- const payload = {
1272
- itemName: document.getElementById('modal-name').innerText,
1273
- itemPrice: parseFloat(document.getElementById('modal-price').innerText.replace('$', '')) || 0,
1274
- itemImage: document.getElementById('modal-img').src,
1275
- section: document.getElementById('modal-section').getAttribute('data-section'),
1276
- category: document.getElementById('modal-section').getAttribute('data-category'),
1277
- addons: Array.from(document.querySelectorAll('#addons-list .form-check-input:checked')).map(cb => ({
1278
- name: cb.getAttribute('data-name'),
1279
- price: parseFloat(cb.getAttribute('data-price')) || 0
1280
- })),
1281
- instructions: document.getElementById('modal-instructions').value,
1282
- quantity: parseInt(document.getElementById('quantityInput').value) || 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1283
  };
 
1284
  fetch('/cart/add', {
1285
  method: 'POST',
1286
- headers: { 'Content-Type': 'application/json' },
1287
- body: JSON.stringify(payload)
 
 
1288
  })
1289
  .then(response => response.json())
1290
  .then(data => {
1291
  if (data.success) {
 
1292
  updateCartUI(data.cart);
1293
- bootstrap.Modal.getInstance(document.getElementById('itemModal')).hide();
 
 
1294
  } else {
1295
- updateCartUI(addToCartLocalStorage(payload));
1296
- bootstrap.Modal.getInstance(document.getElementById('itemModal')).hide();
1297
  }
1298
  })
1299
- .catch(() => {
1300
- updateCartUI(addToCartLocalStorage(payload));
1301
- bootstrap.Modal.getInstance(document.getElementById('itemModal')).hide();
 
 
 
 
1302
  });
1303
  }
1304
  </script>
 
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;
 
49
  border-radius: 15px 15px 0 0;
50
  opacity: 0;
51
  transition: opacity 0.5s ease-in-out;
52
+ background-color: #000; /* Fallback color if video fails */
53
  }
54
  .menu-video.loaded {
55
  opacity: 1;
56
  }
57
  .menu-card:hover .menu-video {
58
  opacity: 1;
59
+ transform: scale(1.05); /* Slight zoom effect on hover */
 
 
 
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 {
 
131
  top: 50%;
132
  transform: translateY(-50%);
133
  display: flex;
134
+ align-items: right;
135
  justify-content: center;
136
  }
137
  .avatar-icon {
 
157
  box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
158
  display: none;
159
  border: 1px solid #ffd8b1;
 
160
  }
161
  .dropdown-menu .dropdown-item {
162
  padding: 12px 16px;
 
175
  color: #333;
176
  }
177
  .fixed-top-bar {
178
+ position: relative;
179
  top: 0;
180
  left: 0;
181
  width: 100%;
 
197
  align-items: center;
198
  width: 300px;
199
  max-width: 90%;
200
+ position: relative;
201
  }
202
  .search-bar-container input {
203
  width: 100%;
 
266
  color: #343a40;
267
  }
268
  .addon-section .form-check {
269
+ display: inline-flex;
270
  align-items: center;
271
  margin-left: 10px;
272
  color: #343a40;
273
  }
274
  .addon-section .form-check-input {
275
+ -webkit-appearance: none;
276
+ -moz-appearance: none;
277
+ appearance: none;
278
  width: 20px;
279
  height: 20px;
280
  border: 2px solid #343a40;
 
282
  background-color: #f0f0f0;
283
  position: relative;
284
  margin-right: 10px;
 
285
  }
286
  .addon-section .form-check-input:checked {
287
  background-color: #006400;
 
297
  }
298
  .addon-section .form-check-label {
299
  font-size: 16px;
300
+ margin-left: 5px;
301
  margin-right: 15px;
302
  cursor: pointer;
303
+ display: inline-block;
304
+ vertical-align: middle;
305
  }
306
  form.text-center.mb-4 {
307
  display: flex;
308
  flex-direction: column;
309
  align-items: center;
310
  justify-content: center;
311
+ margin-bottom: 5px;
312
  }
313
  .modal-header {
314
  padding: 10px 15px;
 
 
 
315
  }
316
  .modal-title {
317
  font-size: 16px;
 
320
  .modal-body {
321
  max-height: 60vh;
322
  overflow-y: auto;
323
+ padding: 15px;
324
  }
325
  .modal-body #modal-img {
326
  max-height: 200px;
327
  width: 100%;
328
  object-fit: cover;
329
  border-radius: 8px;
330
+ margin-bottom: 10px;
331
  }
332
  .modal-body #modal-name {
333
  font-size: 20px;
 
346
  .modal-body #modal-description {
347
  font-size: 14px;
348
  color: #6c757d;
349
+ margin-bottom: 10px;
 
350
  }
351
  .modal-body .nutritional-info {
352
  font-size: 12px;
353
  color: #6c757d;
354
+ margin-bottom: 10px;
 
355
  }
356
+ .modal-body #modal-addons h6,
357
+ .modal-body #first-row h6 {
358
  font-size: 14px;
359
  font-weight: bold;
360
  margin-bottom: 10px;
 
361
  }
362
  .modal-footer {
363
  display: flex;
364
  align-items: center;
365
  justify-content: space-between;
366
+ padding: 10px;
 
367
  }
368
+ .modal-footer .d-flex {
369
  display: flex;
370
  align-items: center;
371
+ gap: 10px;
 
 
372
  }
373
+ .modal-footer .btn {
 
374
  height: 40px;
375
+ padding: 0 15px;
 
 
376
  }
377
  .modal-footer .form-control {
378
+ width: 50px;
379
  height: 40px;
380
  text-align: center;
 
 
381
  }
382
  .modal-footer .btn-primary {
383
  background-color: #0FAA39;
384
  border-color: #0FAA39;
385
  font-weight: bold;
386
  padding: 10px 20px;
387
+ height: 40px;
388
+ display: flex;
389
+ justify-content: center;
390
+ align-items: center;
391
+ width: auto;
392
+ }
393
+ .modal-footer .btn-outline-secondary {
394
+ height: 40px;
395
+ width: 40px;
396
  }
397
  .item-details {
398
  display: none;
399
  padding: 15px;
400
  background-color: #f8f9fa;
401
  border-radius: 8px;
402
+ margin-top: 10px;
403
  margin: 10px 15px;
404
  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
405
  }
 
458
  .category-button:hover {
459
  background-color: #e6f4ea;
460
  }
461
+ .quantity-selector {
462
+ display: flex;
463
+ align-items: center;
464
+ gap: 5px;
465
+ }
466
+ .quantity-selector .btn {
467
+ width: 25px;
468
+ height: 25px;
469
+ padding: 0;
470
+ font-size: 12px;
471
+ line-height: 25px;
472
+ text-align: center;
473
+ }
474
+ .quantity-selector .quantity-display {
475
+ width: 25px;
476
+ text-align: center;
477
+ font-size: 12px;
478
+ font-weight: bold;
479
+ line-height: 25px;
480
+ }
481
+ .quantity-selector .quantity-to-add,
482
+ .quantity-selector .quantity-to-remove {
483
+ width: 45px;
484
+ height: 25px;
485
+ font-size: 12px;
486
+ padding: 0 5px;
487
+ }
488
+ .modal-dialog {
489
+ max-height: 90vh;
490
+ }
491
  .modal-body::-webkit-scrollbar {
492
  width: 8px;
493
  }
 
506
  opacity: 0.65;
507
  cursor: not-allowed;
508
  }
509
+ .quantity-selector select {
510
+ width: 60px;
511
+ height: 35px;
512
+ padding: 5px;
513
+ border-radius: 5px;
514
+ border: 1px solid #ced4da;
515
+ }
516
  #custom-dish-form {
517
  position: relative;
518
  padding-bottom: 80px;
 
582
  font-size: 12px;
583
  margin-left: 8px;
584
  }
585
+
586
+ /* Mic Popup Styles */
587
  .mic-popup {
588
  position: fixed;
589
  top: 50%;
 
600
  max-width: 90%;
601
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
602
  }
603
+
604
  .mic-popup.active {
605
  display: block;
606
  }
607
+
608
  .mic-popup-icon {
609
  font-size: 48px;
610
  margin-bottom: 20px;
611
  color: #ff4444;
612
  animation: pulse 1.5s infinite;
613
  }
614
+
615
  .mic-popup-text {
616
  font-size: 18px;
617
  margin-bottom: 15px;
618
  min-height: 24px;
619
  }
620
+
621
  .mic-popup-cancel {
622
  background-color: #ff4444;
623
  color: white;
 
626
  border-radius: 20px;
627
  cursor: pointer;
628
  font-weight: bold;
 
 
 
 
629
  }
630
+
631
  @keyframes pulse {
632
  0% { transform: scale(1); }
633
  50% { transform: scale(1.1); }
634
  100% { transform: scale(1); }
635
  }
636
+
637
  @media (max-width: 576px) {
638
  .fixed-top-bar {
639
  height: 60px;
 
641
  }
642
  .search-bar-container {
643
  width: 80%;
644
+ max-width: 100%;
645
  left: 10px;
646
+ top: 50%;
647
+ transform: translateY(-50%);
648
  }
649
  .search-bar-container input {
650
+ padding: 6px 35px 6px 35px;
651
  font-size: 14px;
652
  border-radius: 20px;
653
  }
654
+ .search-icon {
655
+ left: 12px;
656
  font-size: 16px;
657
  }
658
+ .mic-icon {
659
+ right: 12px;
660
+ font-size: 16px;
661
+ }
662
+ .avatar-dropdown-container {
663
+ right: 10px;
664
+ }
665
  .avatar-icon {
666
+ width: 40px;
667
+ height: 40px;
668
+ font-size: 20px;
669
  }
670
  .dropdown-menu {
671
+ width: 220px;
672
+ }
673
+ .dropdown-menu .dropdown-item {
674
+ padding: 12px 16px;
675
+ font-size: 15px;
676
+ }
677
+ .category-buttons {
678
+ gap: 8px;
679
  }
680
  .category-button {
681
  padding: 4px 12px;
682
  font-size: 0.85rem;
683
  }
684
+ .modal-dialog {
685
+ max-width: 96%;
686
+ margin: 5px auto;
687
+ }
688
+ .modal-header {
689
+ padding: 5px 10px;
690
+ }
691
+ .modal-title {
692
+ font-size: 14px;
693
+ }
694
  .modal-body {
695
  max-height: 50vh;
696
+ padding: 8px;
697
  }
698
  .modal-body #modal-img {
699
  max-height: 150px;
700
+ width: 100%;
701
+ max-width: 150px;
702
+ margin: 0 auto 5px;
703
+ display: block;
704
  }
705
  .modal-body #modal-name {
706
  font-size: 18px;
707
+ margin-bottom: 3px;
708
  }
709
  .modal-body #modal-price {
710
  font-size: 14px;
711
+ margin-bottom: 5px;
712
  }
713
+ .modal-body #modal-description {
714
  font-size: 12px;
715
+ margin-bottom: 5px;
716
  }
717
+ .modal-body .nutritional-info {
718
+ font-size: 10px;
719
+ margin-bottom: 5px;
720
+ }
721
+ .modal-body #modal-addons h6,
722
+ .modal-body #first-row h6 {
723
+ font-size: 12px;
724
+ margin-bottom: 5px;
725
+ }
726
+ .modal-footer {
727
+ padding: 5px;
728
+ }
729
+ .modal-footer .btn {
730
  height: 30px;
731
+ padding: 0 10px;
732
  }
733
  .modal-footer .form-control {
734
+ width: 30px;
735
  height: 30px;
736
+ font-size: 12px;
737
+ font-weight: bold;
738
+ }
739
+ .modal-footer .btn-outline-secondary {
740
+ width: 25px;
741
+ height: 25px;
742
+ font-size: 12px;
743
+ line-height: 25px;
744
  }
745
  .modal-footer .btn-primary {
746
+ font-size: 12px;
747
+ height: 30px;
748
+ padding: 0 15px;
749
+ border-radius: 5px;
750
  }
751
  .btn-primary {
 
 
752
  font-size: 10px;
753
+ width: 50px;
754
+ height: 25px;
755
  }
756
  .customisable-text {
757
  font-size: 8px;
758
  }
759
+ .button-container {
760
+ gap: 3px;
761
+ }
762
+ .quantity-selector .btn {
763
+ width: 18px;
764
+ height: 18px;
765
+ font-size: 9px;
766
+ line-height: 18px;
767
+ }
768
+ .quantity-selector .quantity-display {
769
+ width: 18px;
770
+ font-size: 9px;
771
+ line-height: 18px;
772
+ }
773
+ .quantity-selector .quantity-to-add,
774
+ .quantity-selector .quantity-to-remove {
775
+ width: 35px;
776
+ height: 18px;
777
+ font-size: 9px;
778
+ }
779
+ .quantity-selector select {
780
+ width: 50px;
781
+ height: 30px;
782
+ font-size: 12px;
783
+ }
784
  .bottom-action-bar {
785
  padding: 8px 10px;
786
  }
 
792
  width: 18px;
793
  height: 18px;
794
  font-size: 10px;
795
+ margin-left: 5px;
796
+ }
797
+ .item-details {
798
+ padding: 10px;
799
+ margin: 5px 10px;
800
+ }
801
+ .item-details h6 {
802
+ font-size: 0.95rem;
803
  }
804
+ .item-details p {
805
+ font-size: 0.8rem;
806
+ }
807
+ .toggle-details {
808
+ font-size: 0.8rem;
809
+ }
810
+ /* Mic Popup Mobile Styles */
811
  .mic-popup {
 
812
  padding: 20px;
813
+ width: 280px;
814
  }
815
  .mic-popup-icon {
816
  font-size: 36px;
817
+ margin-bottom: 15px;
818
  }
819
  .mic-popup-text {
820
  font-size: 16px;
821
  }
822
  .mic-popup-cancel {
823
  padding: 6px 16px;
824
+ font-size: 14px;
825
  }
826
  }
827
  </style>
828
  </head>
829
  <body>
830
+
831
  <div class="fixed-top-bar">
832
  <div class="avatar-dropdown-container">
833
  <div class="avatar-icon">
834
+ <span>{{ first_letter }}</span>
835
  </div>
836
  <div class="dropdown-menu">
837
  <a href="{{ url_for('user_details.customer_details') }}" class="dropdown-item">View Profile</a>
 
855
  {% endfor %}
856
  <button type="button" class="category-button {% if selected_category == 'Customized Dish' %}selected{% endif %}" data-category="Customized Dish">Customized Dish</button>
857
  </div>
858
+ <input type="hidden" name="category" id="selectedCategoryInput" value="{{ selected_category }}">
859
  </form>
860
 
861
  <div class="container mt-4">
 
877
  </div>
878
  {% else %}
879
  {% if ordered_menu.items()|length == 0 %}
880
+ <p>No menu items available for this category.</p>
881
  {% else %}
882
  {% for section, items in ordered_menu.items() %}
883
  <h3>{{ section }}</h3>
 
909
  <div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}">Show Details</div>
910
  {% endif %}
911
  </div>
912
+ <div class="d-flex flex-column align-item-center justify-content-center">
913
+ <div class="button-container"
914
+ data-item-name="{{ item.Name | default('Unnamed Item') }}"
915
+ data-item-price="{{ item.Price__c | default('0.00') }}"
916
+ data-item-image="{{ item.Image2__c | default(item.Image1__c) | default('/static/placeholder.jpg') }}"
917
+ data-item-section="{{ item.Section__c | default(section) }}"
918
+ data-item-category="{{ selected_category }}">
919
+ {% if item.Section__c == 'Soft Drinks' %}
920
+ <button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)">ADD</button>
921
+ {% else %}
922
+ <button class="btn btn-primary"
923
+ data-bs-toggle="modal"
924
+ data-bs-target="#itemModal"
925
+ 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.IngredientsInfo__c | default('Not specified') }}', '{{ item.NutritionalInfo__c | default('Not available') }}', '{{ item.Allergens__c | default('None listed') }}', '{{ item.Section__c | default(section) }}', '{{ selected_category }}')">
926
+ ADD
927
+ </button>
928
+ {% endif %}
929
+ {% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' and item.Section__c !='Soft Drinks' %}
930
  <span class="customisable-text">Customisable</span>
931
  {% endif %}
932
+ </div>
933
  </div>
934
  </div>
935
  </div>
 
937
  <div class="item-details" id="details-{{ item.Name | default('unnamed-item') | replace(' ', '-') }}">
938
  <h6>Description</h6>
939
  <p>{{ item.Description__c | default('No description available') }}</p>
940
+ <h6>Ingredientsinfo</h6>
941
+ <p>{{ item.Ingredientsinfo__c | default('Not specified') }}</p>
942
  <h6>Nutritional Info</h6>
943
  <p>{{ item.NutritionalInfo__c | default('Not available') }}</p>
944
  <h6>Allergens</h6>
 
960
  </a>
961
  <a href="{{ url_for('cart.cart') }}" class="btn btn-view-cart">
962
  <i class="bi bi-cart"></i> View Cart
963
+ <span class="cart-icon-badge" id="cart-item-count">{{ cart_item_count }}</span>
964
  </a>
965
  </div>
966
 
967
+ <!-- Modal for Item Details -->
968
  <div class="modal fade" id="itemModal" tabindex="-1" aria-labelledby="itemModalLabel" aria-hidden="true">
969
  <div class="modal-dialog modal-dialog-centered">
970
+ <div class="modal-content">
971
  <div class="modal-header">
972
  <h5 class="modal-title" id="itemModalLabel">Item Details</h5>
973
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
974
  </div>
975
  <div class="modal-body">
976
+ <img id="modal-img" class="img-fluid rounded mb-3 d-block mx-auto" alt="Item Image" style="max-height: 200px; object-fit: cover;">
977
  <h5 id="modal-name" class="fw-bold text-center"></h5>
978
  <p id="modal-price" class="text-muted text-center"></p>
979
  <p id="modal-description" class="text-secondary"></p>
 
988
  </div>
989
  <div class="mt-4">
990
  <h6>Custom Request</h6>
991
+ <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
992
  </div>
993
  <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
994
  </div>
995
+ <div class="modal-footer d-flex align-items-center justify-content-between">
996
+ <div class="d-flex align-items-center gap-2">
997
  <button type="button" class="btn btn-outline-secondary" id="decreaseQuantity">-</button>
998
+ <input type="text" class="form-control text-center" id="quantityInput" value="1" readonly style="width: 50px;"/>
999
  <button type="button" class="btn btn-outline-secondary" id="increaseQuantity">+</button>
1000
  </div>
1001
+ <button type="button" class="btn btn-primary" onclick="addToCartFromModal()">Add to Cart</button>
1002
  </div>
1003
  </div>
1004
  </div>
1005
  </div>
1006
 
1007
+ <!-- Modal for Soft Drinks Quantity Selection -->
1008
  <div class="modal fade" id="softDrinkModal" tabindex="-1" aria-labelledby="softDrinkModalLabel" aria-hidden="true">
1009
  <div class="modal-dialog modal-dialog-centered">
1010
  <div class="modal-content" style="border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.2);">
1011
+ <div class="modal-header" style="background: linear-gradient(45deg, #0FAA39, #0D9232); color: white; border-radius: 15px 15px 0 0;">
1012
  <h5 class="modal-title" id="softDrinkModalLabel">Select Your Drink</h5>
1013
  <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
1014
  </div>
1015
+ <div class="modal-body" style="padding: 20px;">
1016
  <div class="text-center mb-4">
1017
  <img id="soft-drink-image" class="img-fluid rounded mb-3" alt="Soft Drink Image" style="max-height: 150px; width: auto; object-fit: contain;">
1018
  <h5 id="soft-drink-name" class="fw-bold" style="color: #333;"></h5>
1019
  <p id="soft-drink-price" class="text-muted" style="font-size: 1.1rem;"></p>
1020
  </div>
1021
  <div class="d-flex justify-content-center align-items-center mb-4">
1022
+ <div class="quantity-selector" style="background-color: #f8f9fa; padding: 10px; border-radius: 10px;">
1023
+ <button type="button" class="btn btn-outline-secondary" id="soft-drink-decrease" style="width: 40px; height: 40px;">-</button>
1024
+ <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;">
1025
+ <button type="button" class="btn btn-outline-secondary" id="soft-drink-increase" style="width: 40px; height: 40px;">+</button>
1026
  </div>
1027
  </div>
1028
  </div>
1029
+ <div class="modal-footer" style="border-top: none; padding: 0 20px 20px 20px; justify-content: center;">
1030
+ <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>
1031
  </div>
1032
  </div>
1033
  </div>
 
1044
 
1045
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
1046
  <script>
1047
+ let isProcessingRequest = false;
1048
  let currentSoftDrinkButton = null;
1049
+
1050
  const menuItems = [
1051
  {% for section, items in ordered_menu.items() %}
1052
  {% for item in items %}
 
1054
  {% endfor %}
1055
  {% endfor %}
1056
  ];
1057
+
1058
  const ingredientsList = [
1059
  "Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
1060
+ "Chickpea Flour (Besan)", "Chickpea Flour (for batter)", "Chickpeas (Channa)", "Chili Powder",
1061
+ "Chili Sauce", "Coconut Milk", "Coriander Powder", "Cornflour", "Cream", "Cumin Powder",
1062
+ "Cumin Seeds", "Curd (Yogurt)", "Curry Leaves", "Fish (e.g., King Fish or Salmon)",
1063
+ "Fresh Coriander Leaves", "Garam Masala", "Garlic", "Ghee (Clarified Butter)", "Ginger",
1064
+ "Ginger-Garlic Paste", "Goat Meat (Mutton)", "Green Chilies", "Honey",
1065
+ "Kasuri Methi (dried fenugreek leaves)", "Lemon Juice", "Mango Puree", "Mint Leaves",
1066
+ "Mixed Vegetables (Carrot, Peas, Potato, Cauliflower)", "Mixed Vegetables (Carrot, Peas, Potato)",
1067
+ "Mustard Seeds", "Mutton (Goat Meat)", "Oil", "Oil (for frying)", "Onion",
1068
+ "Paneer (Indian Cottage Cheese)", "Peas", "Potatoes", "Prawns", "Red Chili Powder",
1069
  "Rice Flour", "Saffron", "Salt", "Soy Sauce", "Spring Onion", "Tamarind (for sourness)",
1070
  "Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
1071
  "Whole Wheat Flour", "Yogurt (Curd)"
 
1073
 
1074
  function addToCartLocalStorage(payload) {
1075
  let cart = JSON.parse(localStorage.getItem('cart')) || [];
1076
+ const existingItem = cart.find(item =>
1077
+ item.itemName === payload.itemName &&
1078
+ item.instructions === payload.instructions &&
1079
  JSON.stringify(item.addons) === JSON.stringify(payload.addons)
1080
  );
1081
  if (existingItem) {
1082
+ existingItem.quantity = payload.quantity;
1083
  } else {
1084
  cart.push(payload);
1085
  }
 
1087
  return cart;
1088
  }
1089
 
1090
+ function removeFromCartLocalStorage(itemName, quantityToRemove, instructions, addons) {
1091
+ let cart = JSON.parse(localStorage.getItem('cart')) || [];
1092
+ const itemIndex = cart.findIndex(item =>
1093
+ item.itemName === itemName &&
1094
+ item.instructions === instructions &&
1095
+ JSON.stringify(item.addons) === JSON.stringify(addons)
1096
+ );
1097
+ if (itemIndex !== -1) {
1098
+ if (quantityToRemove >= cart[itemIndex].quantity) {
1099
+ cart.splice(itemIndex, 1);
1100
+ } else {
1101
+ cart[itemIndex].quantity -= quantityToRemove;
1102
+ }
1103
  }
1104
+ localStorage.setItem('cart', JSON.stringify(cart));
1105
+ return cart;
1106
+ }
1107
+
1108
+ function getCartLocalStorage() {
1109
+ return JSON.parse(localStorage.getItem('cart')) || [];
1110
+ }
1111
+
1112
+ function debounce(func, wait) {
1113
+ let timeout;
1114
+ return function (...args) {
1115
+ clearTimeout(timeout);
1116
+ timeout = setTimeout(() => func.apply(this, args), wait);
1117
+ };
1118
  }
1119
 
1120
  function showSoftDrinkModal(button) {
1121
  currentSoftDrinkButton = button;
1122
  const buttonContainer = button.closest('.button-container');
1123
+ const itemName = buttonContainer.getAttribute('data-item-name');
1124
+ const itemPrice = buttonContainer.getAttribute('data-item-price');
1125
+ const itemImage = buttonContainer.getAttribute('data-item-image');
1126
+
1127
+ document.getElementById('soft-drink-name').textContent = itemName;
1128
+ document.getElementById('soft-drink-price').textContent = `$${itemPrice}`;
1129
  document.getElementById('soft-drink-quantity').value = '1';
1130
+ const softDrinkImage = document.getElementById('soft-drink-image');
1131
+ softDrinkImage.src = itemImage || '/static/placeholder.jpg';
1132
+
1133
  const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
1134
  modal.show();
1135
  }
1136
 
1137
  function addSoftDrinkToCart() {
1138
  if (!currentSoftDrinkButton) return;
1139
+
1140
  const buttonContainer = currentSoftDrinkButton.closest('.button-container');
1141
  const quantity = parseInt(document.getElementById('soft-drink-quantity').value) || 1;
1142
+
1143
+ const itemName = buttonContainer.getAttribute('data-item-name');
1144
+ const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
1145
+ const itemImage = buttonContainer.getAttribute('data-item-image');
1146
+ const section = buttonContainer.getAttribute('data-item-section');
1147
+ const selectedCategory = buttonContainer.getAttribute('data-item-category');
1148
+
1149
  const cartPayload = {
1150
+ itemName: itemName,
1151
+ itemPrice: itemPrice,
1152
+ itemImage: itemImage,
1153
+ section: section,
1154
+ category: selectedCategory,
1155
  addons: [],
1156
  instructions: '',
1157
  quantity: quantity
1158
  };
1159
+
1160
  fetch('/cart/add', {
1161
  method: 'POST',
1162
+ headers: {
1163
+ 'Content-Type': 'application/json',
1164
+ },
1165
  body: JSON.stringify(cartPayload)
1166
  })
1167
  .then(response => response.json())
1168
  .then(data => {
1169
+ if (data.success) {
1170
+ updateCartUI(data.cart);
1171
+ const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1172
+ modal.hide();
1173
+ } else {
1174
+ console.error('Failed to add item to cart:', data.error);
1175
+ const cart = addToCartLocalStorage(cartPayload);
1176
+ updateCartUI(cart);
1177
+ const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1178
+ modal.hide();
1179
+ }
1180
  })
1181
+ .catch(err => {
1182
+ console.error('Error adding item to cart:', err);
1183
+ const cart = addToCartLocalStorage(cartPayload);
1184
+ updateCartUI(cart);
1185
+ const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
1186
+ modal.hide();
1187
  });
1188
  }
1189
 
1190
+ function updateCartUI(cart) {
1191
+ if (!Array.isArray(cart)) {
1192
+ console.error('Invalid cart data:', cart);
1193
+ return;
1194
+ }
1195
+
1196
+ let totalQuantity = 0;
1197
+ cart.forEach(item => {
1198
+ totalQuantity += item.quantity;
1199
+ });
1200
+
1201
+ const cartItemCount = document.getElementById('cart-item-count');
1202
+ if (cartItemCount) {
1203
+ cartItemCount.innerText = totalQuantity;
1204
+ cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
1205
+ }
1206
+ }
1207
+
1208
+ document.addEventListener('DOMContentLoaded', function () {
1209
  const avatarContainer = document.querySelector('.avatar-dropdown-container');
1210
  const dropdownMenu = document.querySelector('.dropdown-menu');
1211
+ avatarContainer.addEventListener('click', function (event) {
1212
+ event.stopPropagation();
1213
  dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
1214
  });
1215
+ document.addEventListener('click', function (event) {
1216
+ if (!avatarContainer.contains(event.target)) {
1217
+ dropdownMenu.style.display = 'none';
1218
+ }
1219
+ });
1220
+ const dropdownItems = document.querySelectorAll('.dropdown-item');
1221
+ dropdownItems.forEach(item => {
1222
+ item.addEventListener('click', function () {
1223
+ dropdownMenu.style.display = 'none';
1224
+ });
1225
  });
1226
 
1227
+ const menuCards = document.querySelectorAll('.menu-card');
1228
+ const menuVideos = document.querySelectorAll('.menu-video');
1229
+ const cardObserver = new IntersectionObserver((entries, observer) => {
1230
  entries.forEach(entry => {
1231
  if (entry.isIntersecting) {
1232
  entry.target.classList.add('visible');
1233
+ observer.unobserve(entry.target);
1234
  }
1235
  });
1236
+ }, {
1237
+ root: null,
1238
+ rootMargin: '0px',
1239
+ threshold: 0.1
1240
+ });
1241
+ const videoObserver = new IntersectionObserver((entries, observer) => {
1242
  entries.forEach(entry => {
1243
  if (entry.isIntersecting) {
1244
  const video = entry.target;
1245
  const src = video.getAttribute('data-src');
1246
+ if (src && !video.querySelector('source[src="' + src + '"]')) {
1247
+ const source = video.querySelector('source');
1248
+ source.src = src;
1249
+ video.load();
1250
+ }
1251
  video.classList.add('loaded');
1252
+ observer.unobserve(video);
1253
  }
1254
  });
1255
+ }, {
1256
+ root: null,
1257
+ rootMargin: '200px',
1258
+ threshold: 0.01
1259
+ });
1260
+ menuCards.forEach(card => cardObserver.observe(card));
1261
+ menuVideos.forEach(video => videoObserver.observe(video));
1262
 
1263
+ const toggleLinks = document.querySelectorAll('.toggle-details');
1264
+ toggleLinks.forEach(link => {
1265
+ link.addEventListener('click', function () {
1266
+ const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
1267
+ const detailsDiv = document.getElementById(`details-${itemName}`);
1268
+ const isCurrentlyShown = detailsDiv.classList.contains('show');
1269
+
1270
+ document.querySelectorAll('.item-details.show').forEach(otherDetails => {
1271
+ if (otherDetails !== detailsDiv) {
1272
+ otherDetails.classList.remove('show');
1273
+ const otherLink = otherDetails.previousElementSibling.querySelector('.toggle-details');
1274
+ if (otherLink) {
1275
+ otherLink.innerText = 'Show Details';
1276
+ }
1277
+ }
1278
+ });
1279
+
1280
+ if (!isCurrentlyShown) {
1281
+ detailsDiv.classList.add('show');
1282
+ this.innerText = 'Hide Details';
1283
+ } else {
1284
+ detailsDiv.classList.remove('show');
1285
+ this.innerText = 'Show Details';
1286
+ }
1287
  });
1288
  });
1289
 
 
1290
  const categoryButtons = document.querySelectorAll('.category-button');
1291
  const categoryForm = document.getElementById('categoryForm');
1292
  const selectedCategoryInput = document.getElementById('selectedCategoryInput');
1293
  if (!selectedCategoryInput.value) {
1294
+ selectedCategoryInput.value = "All";
1295
  document.querySelector('.category-button[data-category="All"]').classList.add('selected');
1296
  }
1297
  categoryButtons.forEach(button => {
1298
+ button.addEventListener('click', function () {
1299
  categoryButtons.forEach(btn => btn.classList.remove('selected'));
1300
+ this.classList.add('selected');
1301
+ selectedCategoryInput.value = this.getAttribute('data-category');
1302
  categoryForm.submit();
1303
  });
1304
  });
 
 
1305
  const searchBar = document.getElementById('searchBar');
1306
  const suggestionsContainer = document.getElementById('autocompleteSuggestions');
1307
+ searchBar.addEventListener('input', function () {
1308
+ const input = this.value.trim().toLowerCase();
1309
  suggestionsContainer.innerHTML = '';
1310
+ suggestionsContainer.style.display = 'none';
1311
  if (input) {
1312
+ const filteredItems = menuItems.filter(item =>
1313
+ item.toLowerCase().includes(input)
1314
+ );
1315
+ if (filteredItems.length > 0) {
1316
+ filteredItems.forEach(item => {
1317
+ const suggestionDiv = document.createElement('div');
1318
+ suggestionDiv.classList.add('suggestion-item');
1319
+ suggestionDiv.innerText = item;
1320
+ suggestionDiv.addEventListener('click', function () {
1321
+ searchBar.value = item;
1322
+ suggestionsContainer.style.display = 'none';
1323
+ filterMenu();
1324
+ });
1325
+ suggestionsContainer.appendChild(suggestionDiv);
1326
  });
1327
+ suggestionsContainer.style.display = 'block';
1328
+ }
1329
  }
1330
  filterMenu();
1331
  });
1332
+ document.addEventListener('click', function (event) {
1333
+ if (!searchBar.contains(event.target) && !suggestionsContainer.contains(event.target)) {
1334
+ suggestionsContainer.style.display = 'none';
1335
+ }
1336
  });
 
 
1337
  const descriptionTextarea = document.getElementById('custom-dish-description');
1338
  const descriptionSuggestions = document.getElementById('descriptionSuggestions');
1339
+ if (descriptionTextarea && descriptionSuggestions) {
1340
+ let usedIngredients = new Set();
1341
+ function updateUsedIngredients() {
1342
+ const inputText = descriptionTextarea.value.trim();
1343
+ usedIngredients.clear();
1344
+ if (inputText) {
1345
+ const words = inputText.split(/,\s*/).map(word => word.trim());
1346
+ words.forEach(word => {
1347
+ if (word && ingredientsList.includes(word)) {
1348
+ usedIngredients.add(word);
1349
+ }
1350
+ });
1351
+ }
1352
+ }
1353
+ descriptionTextarea.addEventListener('input', function () {
1354
+ const inputText = this.value.trim();
1355
+ const words = inputText.split(/,\s*/);
1356
  const lastWord = words[words.length - 1].trim().toLowerCase();
1357
  descriptionSuggestions.innerHTML = '';
1358
+ descriptionSuggestions.style.display = 'none';
1359
+ updateUsedIngredients();
1360
  if (lastWord) {
1361
+ const filteredIngredients = ingredientsList.filter(ingredient =>
1362
+ ingredient.toLowerCase().includes(lastWord) && !usedIngredients.has(ingredient)
1363
+ );
1364
+ if (filteredIngredients.length > 0) {
1365
+ filteredIngredients.forEach(ingredient => {
1366
+ const suggestionDiv = document.createElement('div');
1367
+ suggestionDiv.classList.add('suggestion-item');
1368
+ suggestionDiv.innerText = ingredient;
1369
+ suggestionDiv.addEventListener('click', function () {
1370
+ const currentValue = descriptionTextarea.value;
1371
+ const lastCommaIndex = currentValue.lastIndexOf(',');
1372
+ const baseText = lastCommaIndex !== -1 ? currentValue.substring(0, lastCommaIndex + 1) : '';
1373
+ descriptionTextarea.value = baseText + (baseText ? ' ' : '') + ingredient + ', ';
1374
+ descriptionSuggestions.style.display = 'none';
1375
+ descriptionTextarea.focus();
1376
+ updateUsedIngredients();
1377
+ });
1378
+ descriptionSuggestions.appendChild(suggestionDiv);
1379
  });
1380
+ descriptionSuggestions.style.display = 'block';
1381
+ }
1382
+ }
1383
+ });
1384
+ document.addEventListener('click', function (event) {
1385
+ if (!descriptionTextarea.contains(event.target) && !descriptionSuggestions.contains(event.target)) {
1386
+ descriptionSuggestions.style.display = 'none';
1387
  }
1388
  });
1389
  }
 
 
1390
  fetch('/cart/get')
1391
+ .then(response => {
1392
+ if (!response.ok) {
1393
+ throw new Error(`HTTP error! Status: ${response.status}`);
1394
+ }
1395
+ return response.json();
1396
+ })
1397
+ .then(data => {
1398
+ if (data.success) {
1399
+ updateCartUI(data.cart);
1400
+ } else {
1401
+ console.error('Failed to fetch cart:', data.error);
1402
+ const cart = getCartLocalStorage();
1403
+ updateCartUI(cart);
1404
+ }
1405
+ })
1406
+ .catch(err => {
1407
+ console.error('Error fetching cart:', err);
1408
+ const cart = getCartLocalStorage();
1409
+ updateCartUI(cart);
1410
  });
1411
+ const preloadedVideos = document.querySelectorAll('link[rel="preload"][as="video"]');
1412
+ preloadedVideos.forEach(link => {
1413
+ const video = document.createElement('video');
1414
+ video.src = link.href;
1415
+ video.preload = 'auto';
1416
+ });
1417
+ const decreaseBtn = document.getElementById('decreaseQuantity');
1418
+ const increaseBtn = document.getElementById('increaseQuantity');
1419
+ const quantityInput = document.getElementById('quantityInput');
1420
+ decreaseBtn.addEventListener('click', function () {
1421
+ let currentQuantity = parseInt(quantityInput.value);
1422
+ if (currentQuantity > 1) {
1423
+ currentQuantity--;
1424
+ quantityInput.value = currentQuantity;
1425
+ }
1426
+ });
1427
+ increaseBtn.addEventListener('click', function () {
1428
+ let currentQuantity = parseInt(quantityInput.value);
1429
+ currentQuantity++;
1430
+ quantityInput.value = currentQuantity;
1431
  });
1432
 
1433
+ const softDrinkDecreaseBtn = document.getElementById('soft-drink-decrease');
1434
+ const softDrinkIncreaseBtn = document.getElementById('soft-drink-increase');
1435
+ const softDrinkQuantityInput = document.getElementById('soft-drink-quantity');
1436
+
1437
+ softDrinkDecreaseBtn.addEventListener('click', function() {
1438
+ let currentQuantity = parseInt(softDrinkQuantityInput.value);
1439
+ if (currentQuantity > 1) {
1440
+ currentQuantity--;
1441
+ softDrinkQuantityInput.value = currentQuantity;
1442
+ }
1443
+ });
1444
+
1445
+ softDrinkIncreaseBtn.addEventListener('click', function() {
1446
+ let currentQuantity = parseInt(softDrinkQuantityInput.value);
1447
+ if (currentQuantity < 1000) {
1448
+ currentQuantity++;
1449
+ softDrinkQuantityInput.value = currentQuantity;
1450
+ }
1451
+ });
1452
+
1453
+ // Mic Popup Functionality
1454
  const micIcon = document.getElementById('micIcon');
1455
  const micPopup = document.getElementById('micPopup');
1456
  const micPopupText = document.getElementById('micPopupText');
1457
  const micPopupCancel = document.getElementById('micPopupCancel');
1458
+
1459
  if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
1460
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
1461
  const recognition = new SpeechRecognition();
1462
  recognition.continuous = false;
1463
  recognition.interimResults = true;
1464
  recognition.lang = 'en-US';
1465
+
1466
  recognition.onstart = () => {
1467
  micIcon.classList.add('active');
1468
  micPopup.classList.add('active');
1469
  micPopupText.textContent = 'Listening...';
1470
  };
1471
+
1472
  recognition.onresult = (event) => {
1473
+ let interimTranscript = '';
1474
  let finalTranscript = '';
1475
+
1476
  for (let i = event.resultIndex; i < event.results.length; i++) {
1477
+ const transcript = event.results[i][0].transcript;
1478
+ if (event.results[i].isFinal) {
1479
+ finalTranscript += transcript;
1480
+ } else {
1481
+ interimTranscript += transcript;
1482
+ }
1483
  }
1484
+
1485
+ // Display interim results
1486
+ if (interimTranscript) {
1487
+ micPopupText.textContent = interimTranscript;
1488
+ }
1489
+
1490
+ // When we have a final result
1491
  if (finalTranscript) {
1492
  searchBar.value = finalTranscript.trim();
1493
  filterMenu();
1494
  micPopup.classList.remove('active');
 
1495
  }
1496
  };
1497
+
1498
  recognition.onend = () => {
1499
  micIcon.classList.remove('active');
1500
+ if (micPopup.classList.contains('active')) {
1501
+ // If still active, it means it ended unexpectedly
1502
+ setTimeout(() => {
1503
+ micPopup.classList.remove('active');
1504
+ }, 1000);
1505
+ }
1506
  };
1507
+
1508
  recognition.onerror = (event) => {
 
 
1509
  micIcon.classList.remove('active');
1510
+ micPopupText.textContent = 'Error: ' + event.error;
1511
+ setTimeout(() => {
1512
+ micPopup.classList.remove('active');
1513
+ }, 2000);
1514
+ console.error('Speech error:', event.error);
1515
  };
1516
+
1517
+ micIcon.addEventListener('click', () => {
1518
+ try {
1519
+ recognition.start();
1520
+ } catch (e) {
1521
+ micPopupText.textContent = 'Error starting microphone';
1522
+ setTimeout(() => {
1523
+ micPopup.classList.remove('active');
1524
+ }, 2000);
1525
+ console.error('Recognition start error:', e);
1526
+ }
1527
+ });
1528
+
1529
+ micPopupCancel.addEventListener('click', () => {
1530
+ recognition.stop();
1531
+ micPopup.classList.remove('active');
1532
+ micIcon.classList.remove('active');
1533
+ });
1534
  } else {
1535
  micIcon.style.display = 'none';
1536
  }
 
1543
  let matchedSections = new Set();
1544
  items.forEach(item => {
1545
  const itemName = item.querySelector('.card-title').innerText.toLowerCase();
1546
+ const itemSection = item.closest('.row').previousElementSibling.innerText.toLowerCase();
1547
+ if (itemName.includes(input) || (itemSection && itemSection.includes(input))) {
1548
  item.style.display = 'block';
1549
+ item.classList.add('visible');
1550
  matchedSections.add(item.closest('.row'));
1551
  } else {
1552
  item.style.display = 'none';
1553
  }
1554
  });
1555
  sections.forEach(section => {
1556
+ const sectionRow = section.nextElementSibling;
1557
+ if (matchedSections.has(sectionRow)) {
1558
+ section.style.display = 'block';
1559
+ sectionRow.style.display = 'flex';
1560
+ } else {
1561
+ section.style.display = 'none';
1562
+ sectionRow.style.display = 'none';
1563
+ }
1564
  });
1565
  if (!input) {
1566
  sections.forEach(section => {
1567
  section.style.display = 'block';
1568
  section.nextElementSibling.style.display = 'flex';
1569
  });
1570
+ items.forEach(item => {
1571
+ item.style.display = 'block';
1572
+ item.classList.add('visible');
1573
+ });
1574
  }
1575
  }
1576
 
1577
+ function showItemDetails(name, price, image, description, ingredients, nutrition, allergens, section, selectedCategory) {
1578
  document.getElementById('modal-name').innerText = name;
1579
+ document.getElementById('modal-price').innerText = `$${price}`;
1580
+ const modalImg = document.getElementById('modal-img');
1581
+ modalImg.src = image || '/static/placeholder.jpg';
1582
+ document.getElementById('modal-description').innerText = description || 'No description available.';
1583
+ document.getElementById('modal-ingredients').innerText = ingredients || 'Not specified';
1584
+ document.getElementById('modal-nutrition').innerText = nutrition || 'Not available';
1585
+ document.getElementById('modal-allergens').innerText = allergens || 'None listed';
1586
+ document.getElementById('addons-list').innerHTML = 'Loading customization options...';
1587
  document.getElementById('modal-instructions').value = '';
1588
+ const modalSectionEl = document.getElementById('modal-section');
1589
+ modalSectionEl.setAttribute('data-section', section);
1590
+ modalSectionEl.setAttribute('data-category', selectedCategory);
1591
+ document.getElementById('quantityInput').value = 1;
 
 
 
 
1592
 
1593
  fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
1594
  .then(response => response.json())
1595
  .then(data => {
1596
+ const addonsList = document.getElementById('addons-list');
1597
  addonsList.innerHTML = '';
1598
+ if (!data.success || !data.addons || data.addons.length === 0) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1599
  addonsList.innerHTML = '<p>No customization options available.</p>';
1600
+ return;
1601
  }
1602
+ data.addons.forEach(addon => {
1603
+ const sectionDiv = document.createElement('div');
1604
+ sectionDiv.classList.add('addon-section');
1605
+ const title = document.createElement('h6');
1606
+ title.innerText = addon.name;
1607
+ sectionDiv.appendChild(title);
1608
+ const optionsContainer = document.createElement('div');
1609
+ addon.options.forEach((option, index) => {
1610
+ const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
1611
+ const listItem = document.createElement('div');
1612
+ listItem.classList.add('form-check');
1613
+ listItem.innerHTML = `
1614
+ <input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
1615
+ data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}">
1616
+ <label class="form-check-label" for="${optionId}">
1617
+ ${option} ${addon.extra_charge ? `($${addon.extra_charge_amount})` : ''}
1618
+ </label>
1619
+ `;
1620
+ optionsContainer.appendChild(listItem);
1621
+ });
1622
+ sectionDiv.appendChild(optionsContainer);
1623
+ addonsList.appendChild(sectionDiv);
1624
+ });
1625
  })
1626
+ .catch(err => {
1627
+ console.error('Error fetching add-ons:', err);
1628
+ document.getElementById('addons-list').innerHTML = '<p>Error loading customization options.</p>';
1629
  });
1630
  }
1631
 
1632
+ document.addEventListener('click', function(event) {
1633
+ if (event.target.classList.contains('addon-option')) {
1634
+ handleAddonClick(event.target);
 
 
 
 
 
 
1635
  }
1636
  });
1637
 
1638
+ function handleAddonClick(checkbox) {
1639
+ const groupName = checkbox.getAttribute('data-group');
1640
+ const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo","Beverages","Sauces"].includes(groupName);
1641
+ if (!isMultiSelectGroup) {
1642
+ const checkboxes = document.querySelectorAll(`.addon-option[data-group="${groupName}"]`);
1643
+ checkboxes.forEach(otherCheckbox => {
1644
+ if (otherCheckbox !== checkbox) {
1645
+ otherCheckbox.checked = false;
1646
+ }
1647
+ });
1648
+ }
1649
+ }
1650
+
1651
  function addToCartFromModal() {
1652
+ const itemName = document.getElementById('modal-name').innerText;
1653
+ let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
1654
+ if (isNaN(itemPrice)) {
1655
+ alert('Invalid price for the item. Please check the item details.');
1656
+ return;
1657
+ }
1658
+ const itemImage = document.getElementById('modal-img').src;
1659
+ const modalSectionEl = document.getElementById('modal-section');
1660
+ const section = modalSectionEl.getAttribute('data-section');
1661
+ const selectedCategory = modalSectionEl.getAttribute('data-category');
1662
+ if (!itemName || !itemPrice || !section || !itemImage) {
1663
+ console.error('Missing data for cart item:', { itemName, itemPrice, section, itemImage });
1664
+ return;
1665
+ }
1666
+ const selectedAddOns = Array.from(
1667
+ document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
1668
+ ).map(addon => ({
1669
+ name: addon.getAttribute('data-name') || 'Default Name',
1670
+ price: parseFloat(addon.getAttribute('data-price') || 0)
1671
+ }));
1672
+ const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
1673
+ const instructions = document.getElementById('modal-instructions').value;
1674
+ const cartPayload = {
1675
+ itemName: itemName,
1676
+ itemPrice: itemPrice,
1677
+ itemImage: itemImage,
1678
+ section: section,
1679
+ category: selectedCategory,
1680
+ addons: selectedAddOns,
1681
+ instructions: instructions,
1682
+ quantity: quantity
1683
  };
1684
+
1685
  fetch('/cart/add', {
1686
  method: 'POST',
1687
+ headers: {
1688
+ 'Content-Type': 'application/json',
1689
+ },
1690
+ body: JSON.stringify(cartPayload)
1691
  })
1692
  .then(response => response.json())
1693
  .then(data => {
1694
  if (data.success) {
1695
+ alert('Item added to cart successfully!');
1696
  updateCartUI(data.cart);
1697
+ const modal = document.getElementById('itemModal');
1698
+ const modalInstance = bootstrap.Modal.getInstance(modal);
1699
+ modalInstance.hide();
1700
  } else {
1701
+ console.error('Failed to add item to cart:', data.error);
1702
+ alert(data.error || 'Failed to add item to cart.');
1703
  }
1704
  })
1705
+ .catch(err => {
1706
+ console.error('Error adding item to cart:', err);
1707
+ const cart = addToCartLocalStorage(cartPayload);
1708
+ updateCartUI(cart);
1709
+ const modal = document.getElementById('itemModal');
1710
+ const modalInstance = bootstrap.Modal.getInstance(modal);
1711
+ modalInstance.hide();
1712
  });
1713
  }
1714
  </script>