Update templates/menu.html
Browse files- templates/menu.html +352 -288
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;
|
@@ -41,7 +42,6 @@
|
|
41 |
}
|
42 |
.menu-card.visible {
|
43 |
opacity: 1;
|
44 |
-
/* NEW: Staggered animation for smoother loading */
|
45 |
animation: fadeIn 0.3s ease-in-out;
|
46 |
}
|
47 |
.menu-card.highlighted {
|
@@ -550,7 +550,6 @@
|
|
550 |
font-size: 1.2rem;
|
551 |
color: #333;
|
552 |
}
|
553 |
-
/* NEW: Toast Notification Styling */
|
554 |
.toast-container {
|
555 |
position: fixed;
|
556 |
top: 20px;
|
@@ -569,7 +568,6 @@
|
|
569 |
.toast.show {
|
570 |
opacity: 1;
|
571 |
}
|
572 |
-
/* NEW: Search Suggestions */
|
573 |
.search-suggestions {
|
574 |
position: absolute;
|
575 |
top: 100%;
|
@@ -680,7 +678,6 @@
|
|
680 |
height: 40px;
|
681 |
text-align: center;
|
682 |
}
|
683 |
-
/* NEW: Streamline modal-footer btn-primary */
|
684 |
.modal-footer .btn-primary {
|
685 |
background-color: #0FAA39;
|
686 |
border-color: #0FAA39;
|
@@ -862,7 +859,6 @@
|
|
862 |
font-size: 12px;
|
863 |
margin-left: 8px;
|
864 |
}
|
865 |
-
/* Mobile-Specific Styles */
|
866 |
@media (max-width: 576px) {
|
867 |
.fixed-top-bar {
|
868 |
height: 60px;
|
@@ -1016,7 +1012,6 @@
|
|
1016 |
font-size: 10px;
|
1017 |
margin-left: 5px;
|
1018 |
}
|
1019 |
-
/* Mobile-Specific Addon Styles */
|
1020 |
.addon-section {
|
1021 |
margin-bottom: 10px;
|
1022 |
}
|
@@ -1045,7 +1040,6 @@
|
|
1045 |
margin-left: 6px;
|
1046 |
font-size: 0.8rem;
|
1047 |
}
|
1048 |
-
/* Mobile-Specific Soft Drinks Modal Styles */
|
1049 |
#softDrinkModal .modal-dialog {
|
1050 |
max-width: 90%;
|
1051 |
}
|
@@ -1097,7 +1091,6 @@
|
|
1097 |
font-size: 1rem;
|
1098 |
line-height: 28px;
|
1099 |
}
|
1100 |
-
/* Mobile-Specific Toggle Styles */
|
1101 |
.toggle-container {
|
1102 |
margin: 0 10px;
|
1103 |
gap: 6px;
|
@@ -1125,7 +1118,6 @@
|
|
1125 |
</style>
|
1126 |
</head>
|
1127 |
<body>
|
1128 |
-
<!-- NEW: Toast Container -->
|
1129 |
<div class="toast-container" id="toastContainer"></div>
|
1130 |
|
1131 |
<div class="fixed-top-bar">
|
@@ -1143,29 +1135,29 @@
|
|
1143 |
<input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off" aria-label="Search menu items">
|
1144 |
<i class="bi bi-search search-icon"></i>
|
1145 |
<i class="bi bi-mic mic-icon" id="micIcon" aria-label="Voice search"></i>
|
1146 |
-
<!-- NEW: Search Suggestions -->
|
1147 |
<div class="search-suggestions" id="searchSuggestions"></div>
|
1148 |
</div>
|
1149 |
</div>
|
1150 |
|
|
|
1151 |
<form method="get" action="/menu" class="text-center mb-4" id="filter-form">
|
1152 |
<label class="form-label fw-bold">Filters:</label>
|
1153 |
<div class="toggle-container">
|
1154 |
<input type="checkbox" id="veg-toggle" name="veg"
|
1155 |
-
{% if
|
1156 |
class="custom-toggle" onchange="handleToggle('veg')" aria-label="Filter vegetarian items">
|
1157 |
<label for="veg-toggle">Veg</label>
|
1158 |
</div>
|
1159 |
<div class="toggle-container">
|
1160 |
-
<input type="
|
1161 |
-
{% if
|
1162 |
class="custom-toggle" onchange="handleToggle('custom')" aria-label="Filter customized dishes">
|
1163 |
<label for="category-CustomizedDish">Customized Dish</label>
|
1164 |
</div>
|
1165 |
</form>
|
1166 |
|
1167 |
<div class="container mt-4">
|
1168 |
-
{% if
|
1169 |
<div id="custom-dish-form" class="mt-4">
|
1170 |
<h3>Create Your Custom Dish</h3>
|
1171 |
<form method="POST" action="/customdish/generate_custom_dish">
|
@@ -1182,15 +1174,17 @@
|
|
1182 |
</form>
|
1183 |
</div>
|
1184 |
{% else %}
|
|
|
1185 |
{% if ordered_menu.items()|length == 0 %}
|
1186 |
-
<p>No menu items available for this
|
|
|
1187 |
{% else %}
|
1188 |
{% for section, items in ordered_menu.items() %}
|
1189 |
<h3>{{ section }}</h3>
|
1190 |
<div class="row">
|
1191 |
{% for item in items %}
|
1192 |
<div class="col-md-6 mb-4">
|
1193 |
-
<div class="card menu-card" data-item-name="{{ item.Name | default('Unnamed Item') }}" data-item-section="{{ item.Section__c | default(section) }}">
|
1194 |
<video
|
1195 |
class="card-img-top menu-video"
|
1196 |
muted
|
@@ -1220,7 +1214,8 @@
|
|
1220 |
data-item-section="{{ item.Section__c | default(section) }}"
|
1221 |
data-item-category="{{ selected_category }}"
|
1222 |
data-item-description="{{ item.Description__c | default('No description') }}"
|
1223 |
-
data-item-image2="{{ item.Image2__c | default(item.Image1__c) }}"
|
|
|
1224 |
{% if item.Section__c == 'Soft Drinks' %}
|
1225 |
<button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)" aria-label="Add {{ item.Name | default('Unnamed Item') }} to cart">ADD</button>
|
1226 |
{% else %}
|
@@ -1350,7 +1345,13 @@
|
|
1350 |
{% for item in items %}
|
1351 |
{
|
1352 |
name: "{{ item.Name | default('Unnamed Item') }}",
|
1353 |
-
section: "{{ item.Section__c | default(section) }}"
|
|
|
|
|
|
|
|
|
|
|
|
|
1354 |
},
|
1355 |
{% endfor %}
|
1356 |
{% endfor %}
|
@@ -1382,7 +1383,6 @@
|
|
1382 |
};
|
1383 |
}
|
1384 |
|
1385 |
-
// NEW: Show Toast Notification
|
1386 |
function showToast(message) {
|
1387 |
const toastContainer = document.getElementById('toastContainer');
|
1388 |
const toast = document.createElement('div');
|
@@ -1555,7 +1555,6 @@
|
|
1555 |
modalSectionEl.setAttribute('data-category', selectedCategory);
|
1556 |
document.getElementById('quantityInput').value = 1;
|
1557 |
|
1558 |
-
// NEW: Retry mechanism for add-ons
|
1559 |
let retryCount = 0;
|
1560 |
const maxRetries = 2;
|
1561 |
function fetchAddons() {
|
@@ -1709,7 +1708,7 @@
|
|
1709 |
});
|
1710 |
}
|
1711 |
|
1712 |
-
//
|
1713 |
function handleToggle(source) {
|
1714 |
const form = document.getElementById("filter-form");
|
1715 |
const veg = document.getElementById("veg-toggle");
|
@@ -1731,299 +1730,364 @@
|
|
1731 |
}
|
1732 |
}
|
1733 |
|
1734 |
-
|
1735 |
-
|
1736 |
-
|
|
|
|
|
1737 |
|
1738 |
form.submit();
|
1739 |
}
|
1740 |
|
1741 |
-
//
|
1742 |
-
|
1743 |
-
|
1744 |
-
const
|
1745 |
-
|
1746 |
-
|
1747 |
-
|
1748 |
-
|
1749 |
-
|
1750 |
-
|
1751 |
-
|
1752 |
-
|
1753 |
-
|
1754 |
-
|
1755 |
-
|
1756 |
-
|
1757 |
-
|
1758 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1759 |
});
|
1760 |
-
});
|
1761 |
|
1762 |
-
|
1763 |
-
|
1764 |
-
|
1765 |
-
|
1766 |
-
|
1767 |
-
searchSuggestions.innerHTML = '';
|
1768 |
-
searchSuggestions.style.display = 'none';
|
1769 |
-
if (query.length > 0) {
|
1770 |
-
const filteredItems = menuItems.filter(item =>
|
1771 |
-
item.name.toLowerCase().includes(query) ||
|
1772 |
-
item.section.toLowerCase().includes(query)
|
1773 |
-
);
|
1774 |
-
if (filteredItems.length > 0) {
|
1775 |
-
filteredItems.forEach(item => {
|
1776 |
-
const suggestionDiv = document.createElement('div');
|
1777 |
-
suggestionDiv.classList.add('suggestion-item');
|
1778 |
-
suggestionDiv.innerText = `${item.name} (${item.section})`;
|
1779 |
-
suggestionDiv.addEventListener('click', () => {
|
1780 |
-
localStorage.setItem('selectedItem', JSON.stringify(item));
|
1781 |
-
window.location.reload();
|
1782 |
-
});
|
1783 |
-
searchSuggestions.appendChild(suggestionDiv);
|
1784 |
-
});
|
1785 |
-
searchSuggestions.style.display = 'block';
|
1786 |
-
}
|
1787 |
-
}
|
1788 |
-
}, 300));
|
1789 |
-
searchBar.addEventListener('click', function (e) {
|
1790 |
-
e.stopPropagation();
|
1791 |
-
if (searchBar.value.trim()) {
|
1792 |
-
searchSuggestions.style.display = 'block';
|
1793 |
-
}
|
1794 |
-
});
|
1795 |
-
document.addEventListener('click', function (e) {
|
1796 |
-
if (!searchBar.contains(e.target) && !searchSuggestions.contains(e.target)) {
|
1797 |
-
searchSuggestions.style.display = 'none';
|
1798 |
-
}
|
1799 |
-
});
|
1800 |
|
1801 |
-
|
1802 |
-
|
1803 |
-
|
1804 |
-
|
1805 |
-
|
1806 |
-
|
1807 |
-
|
1808 |
-
|
1809 |
-
|
1810 |
-
|
1811 |
-
|
1812 |
-
|
1813 |
-
|
1814 |
-
|
1815 |
-
card.classList.add('highlighted');
|
1816 |
-
card.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
1817 |
-
const toggleLink = card.querySelector('.toggle-details');
|
1818 |
-
if (toggleLink) {
|
1819 |
-
toggleLink.click();
|
1820 |
}
|
1821 |
-
}
|
1822 |
-
|
1823 |
-
|
1824 |
-
|
1825 |
-
showSoftDrinkModal(buttonContainer.querySelector('.add-to-cart-btn'));
|
1826 |
} else {
|
1827 |
-
|
1828 |
-
|
1829 |
-
const image = buttonContainer.getAttribute('data-item-image2');
|
1830 |
-
const description = buttonContainer.getAttribute('data-item-description');
|
1831 |
-
const category = buttonContainer.getAttribute('data-item-category');
|
1832 |
-
showItemDetails(name, price, image, description, section, category);
|
1833 |
-
const modal = new bootstrap.Modal(document.getElementById('itemModal'));
|
1834 |
-
modal.show();
|
1835 |
}
|
1836 |
-
}
|
1837 |
-
}
|
1838 |
-
|
1839 |
-
|
1840 |
-
}
|
1841 |
-
localStorage.removeItem('selectedItem');
|
1842 |
}
|
|
|
1843 |
|
1844 |
-
|
1845 |
-
|
1846 |
-
|
1847 |
-
const cardObserver = new IntersectionObserver((entries, observer) => {
|
1848 |
-
entries.forEach(entry => {
|
1849 |
-
if (entry.isIntersecting) {
|
1850 |
-
entry.target.classList.add('visible');
|
1851 |
-
observer.unobserve(entry.target);
|
1852 |
}
|
1853 |
-
|
1854 |
-
|
1855 |
-
|
1856 |
-
|
1857 |
-
|
1858 |
-
|
1859 |
-
|
1860 |
-
|
1861 |
-
|
1862 |
-
|
1863 |
-
|
1864 |
-
|
1865 |
-
|
1866 |
-
|
1867 |
-
if (
|
1868 |
-
|
1869 |
-
|
1870 |
-
|
1871 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1872 |
});
|
|
|
1873 |
}
|
1874 |
-
} else {
|
1875 |
-
video.poster = '/static/placeholder.jpg';
|
1876 |
}
|
1877 |
-
|
1878 |
-
|
1879 |
-
|
1880 |
-
|
1881 |
-
|
1882 |
-
|
1883 |
-
|
1884 |
-
threshold: 0.01
|
1885 |
-
});
|
1886 |
-
menuCards.forEach(card => cardObserver.observe(card));
|
1887 |
-
menuVideos.forEach(video => videoObserver.observe(video));
|
1888 |
|
1889 |
-
//
|
1890 |
-
const
|
1891 |
-
|
1892 |
-
|
1893 |
-
|
1894 |
-
|
1895 |
-
|
1896 |
-
|
1897 |
-
|
1898 |
-
otherDetails.classList.remove('show');
|
1899 |
-
const otherLink = document.querySelector(`.toggle-details[data-item-name="${otherDetails.id.replace('details-', '').replace(/-/g, ' ')}"]`);
|
1900 |
-
if (otherLink) {
|
1901 |
-
otherLink.innerText = 'Show Details';
|
1902 |
-
}
|
1903 |
}
|
1904 |
});
|
1905 |
-
if (!isCurrentlyShown) {
|
1906 |
-
detailsDiv.classList.add('show');
|
1907 |
-
this.innerText = 'Hide Details';
|
1908 |
-
} else {
|
1909 |
-
detailsDiv.classList.remove('show');
|
1910 |
-
this.innerText = 'Show Details';
|
1911 |
-
}
|
1912 |
-
});
|
1913 |
-
});
|
1914 |
|
1915 |
-
//
|
1916 |
-
const
|
1917 |
-
const
|
1918 |
-
|
1919 |
-
|
1920 |
-
|
1921 |
-
|
1922 |
-
|
1923 |
-
if (inputText) {
|
1924 |
-
const words = inputText.split(/,\s*/).map(word => word.trim());
|
1925 |
-
words.forEach(word => {
|
1926 |
-
if (word && ingredientsList.includes(word)) {
|
1927 |
-
usedIngredients.add(word);
|
1928 |
}
|
1929 |
});
|
1930 |
-
}
|
1931 |
-
|
1932 |
-
|
1933 |
-
|
1934 |
-
|
1935 |
-
const
|
1936 |
-
|
1937 |
-
|
1938 |
-
|
1939 |
-
|
1940 |
-
|
1941 |
-
|
1942 |
-
|
1943 |
-
|
1944 |
-
|
1945 |
-
|
1946 |
-
|
1947 |
-
|
1948 |
-
|
1949 |
-
|
1950 |
-
|
1951 |
-
|
1952 |
-
|
1953 |
-
|
1954 |
-
|
1955 |
-
|
1956 |
-
|
1957 |
-
|
1958 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1959 |
});
|
1960 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1961 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1962 |
}
|
1963 |
-
}, 300);
|
1964 |
-
descriptionTextarea.addEventListener('input', debouncedSuggestions);
|
1965 |
-
document.addEventListener('click', function (event) {
|
1966 |
-
if (!descriptionTextarea.contains(event.target) && !descriptionSuggestions.contains(event.target)) {
|
1967 |
-
descriptionSuggestions.style.display = 'none';
|
1968 |
-
}
|
1969 |
-
});
|
1970 |
-
}
|
1971 |
|
1972 |
-
// Fetch Initial Cart
|
1973 |
-
fetch('/cart/get')
|
1974 |
-
|
1975 |
-
|
1976 |
-
|
1977 |
-
|
1978 |
-
|
1979 |
-
|
1980 |
-
|
1981 |
-
|
1982 |
-
|
1983 |
-
|
1984 |
-
|
1985 |
-
|
1986 |
-
|
1987 |
-
|
1988 |
-
|
1989 |
-
|
1990 |
-
|
1991 |
-
|
1992 |
-
|
1993 |
-
|
1994 |
-
|
1995 |
-
|
1996 |
-
|
1997 |
-
// NEW: Remove redundant video preloading (handled by <link rel="preload">)
|
1998 |
-
// const preloadedVideos = document.querySelectorAll('link[rel="preload"][as="video"]');
|
1999 |
-
// preloadedVideos.forEach(link => {
|
2000 |
-
// const video = document.createElement('video');
|
2001 |
-
// video.src = link.href;
|
2002 |
-
// video.preload = 'auto';
|
2003 |
-
// });
|
2004 |
|
2005 |
-
// Quantity Controls for Item Modal
|
2006 |
-
const decreaseBtn = document.getElementById('decreaseQuantity');
|
2007 |
-
const increaseBtn = document.getElementById('increaseQuantity');
|
2008 |
-
const quantityInput = document.getElementById('quantityInput');
|
2009 |
-
decreaseBtn.addEventListener('click', function () {
|
2010 |
-
|
2011 |
-
|
2012 |
-
|
2013 |
-
});
|
2014 |
-
increaseBtn.addEventListener('click', function () {
|
2015 |
-
|
2016 |
-
|
2017 |
-
|
2018 |
-
});
|
2019 |
|
2020 |
-
//
|
2021 |
-
searchBar.addEventListener('keydown', function (e) {
|
2022 |
-
|
2023 |
-
|
2024 |
-
|
2025 |
-
});
|
2026 |
-
});
|
2027 |
-
</script>
|
2028 |
</body>
|
2029 |
-
</html>
|
|
|
|
15 |
{% endfor %}
|
16 |
{% endfor %}
|
17 |
<style>
|
18 |
+
/* Same styles as previous response */
|
19 |
body {
|
20 |
font-family: Arial, sans-serif;
|
21 |
background-color: #fdf4e3;
|
|
|
42 |
}
|
43 |
.menu-card.visible {
|
44 |
opacity: 1;
|
|
|
45 |
animation: fadeIn 0.3s ease-in-out;
|
46 |
}
|
47 |
.menu-card.highlighted {
|
|
|
550 |
font-size: 1.2rem;
|
551 |
color: #333;
|
552 |
}
|
|
|
553 |
.toast-container {
|
554 |
position: fixed;
|
555 |
top: 20px;
|
|
|
568 |
.toast.show {
|
569 |
opacity: 1;
|
570 |
}
|
|
|
571 |
.search-suggestions {
|
572 |
position: absolute;
|
573 |
top: 100%;
|
|
|
678 |
height: 40px;
|
679 |
text-align: center;
|
680 |
}
|
|
|
681 |
.modal-footer .btn-primary {
|
682 |
background-color: #0FAA39;
|
683 |
border-color: #0FAA39;
|
|
|
859 |
font-size: 12px;
|
860 |
margin-left: 8px;
|
861 |
}
|
|
|
862 |
@media (max-width: 576px) {
|
863 |
.fixed-top-bar {
|
864 |
height: 60px;
|
|
|
1012 |
font-size: 10px;
|
1013 |
margin-left: 5px;
|
1014 |
}
|
|
|
1015 |
.addon-section {
|
1016 |
margin-bottom: 10px;
|
1017 |
}
|
|
|
1040 |
margin-left: 6px;
|
1041 |
font-size: 0.8rem;
|
1042 |
}
|
|
|
1043 |
#softDrinkModal .modal-dialog {
|
1044 |
max-width: 90%;
|
1045 |
}
|
|
|
1091 |
font-size: 1rem;
|
1092 |
line-height: 28px;
|
1093 |
}
|
|
|
1094 |
.toggle-container {
|
1095 |
margin: 0 10px;
|
1096 |
gap: 6px;
|
|
|
1118 |
</style>
|
1119 |
</head>
|
1120 |
<body>
|
|
|
1121 |
<div class="toast-container" id="toastContainer"></div>
|
1122 |
|
1123 |
<div class="fixed-top-bar">
|
|
|
1135 |
<input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off" aria-label="Search menu items">
|
1136 |
<i class="bi bi-search search-icon"></i>
|
1137 |
<i class="bi bi-mic mic-icon" id="micIcon" aria-label="Voice search"></i>
|
|
|
1138 |
<div class="search-suggestions" id="searchSuggestions"></div>
|
1139 |
</div>
|
1140 |
</div>
|
1141 |
|
1142 |
+
<!-- NEW: Updated Filter Form -->
|
1143 |
<form method="get" action="/menu" class="text-center mb-4" id="filter-form">
|
1144 |
<label class="form-label fw-bold">Filters:</label>
|
1145 |
<div class="toggle-container">
|
1146 |
<input type="checkbox" id="veg-toggle" name="veg"
|
1147 |
+
{% if veg_filter %}checked{% endif %}
|
1148 |
class="custom-toggle" onchange="handleToggle('veg')" aria-label="Filter vegetarian items">
|
1149 |
<label for="veg-toggle">Veg</label>
|
1150 |
</div>
|
1151 |
<div class="toggle-container">
|
1152 |
+
<input type="checkbox" id="category-CustomizedDish" name="custom"
|
1153 |
+
{% if custom_filter %}checked{% endif %}
|
1154 |
class="custom-toggle" onchange="handleToggle('custom')" aria-label="Filter customized dishes">
|
1155 |
<label for="category-CustomizedDish">Customized Dish</label>
|
1156 |
</div>
|
1157 |
</form>
|
1158 |
|
1159 |
<div class="container mt-4">
|
1160 |
+
{% if custom_filter %}
|
1161 |
<div id="custom-dish-form" class="mt-4">
|
1162 |
<h3>Create Your Custom Dish</h3>
|
1163 |
<form method="POST" action="/customdish/generate_custom_dish">
|
|
|
1174 |
</form>
|
1175 |
</div>
|
1176 |
{% else %}
|
1177 |
+
<!-- NEW: Enhanced Empty State Handling -->
|
1178 |
{% if ordered_menu.items()|length == 0 %}
|
1179 |
+
<p id="no-items-message">No menu items available for this filter. Please try adjusting the filters or contact support.</p>
|
1180 |
+
<div id="client-side-menu" class="row"></div>
|
1181 |
{% else %}
|
1182 |
{% for section, items in ordered_menu.items() %}
|
1183 |
<h3>{{ section }}</h3>
|
1184 |
<div class="row">
|
1185 |
{% for item in items %}
|
1186 |
<div class="col-md-6 mb-4">
|
1187 |
+
<div class="card menu-card" data-item-name="{{ item.Name | default('Unnamed Item') }}" data-item-section="{{ item.Section__c | default(section) }}" data-is-veg="{{ item.IsVeg__c | default('false') | lower }}">
|
1188 |
<video
|
1189 |
class="card-img-top menu-video"
|
1190 |
muted
|
|
|
1214 |
data-item-section="{{ item.Section__c | default(section) }}"
|
1215 |
data-item-category="{{ selected_category }}"
|
1216 |
data-item-description="{{ item.Description__c | default('No description') }}"
|
1217 |
+
data-item-image2="{{ item.Image2__c | default(item.Image1__c) }}"
|
1218 |
+
data-is-veg="{{ item.IsVeg__c | default('false') | lower }}">
|
1219 |
{% if item.Section__c == 'Soft Drinks' %}
|
1220 |
<button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)" aria-label="Add {{ item.Name | default('Unnamed Item') }} to cart">ADD</button>
|
1221 |
{% else %}
|
|
|
1345 |
{% for item in items %}
|
1346 |
{
|
1347 |
name: "{{ item.Name | default('Unnamed Item') }}",
|
1348 |
+
section: "{{ item.Section__c | default(section) }}",
|
1349 |
+
isVeg: {{ item.IsVeg__c | default('false') | lower }},
|
1350 |
+
price: "{{ item.Price__c | default('0.00') }}",
|
1351 |
+
image: "{{ item.Image1__c | default('/static/placeholder.jpg') }}",
|
1352 |
+
image2: "{{ item.Image2__c | default(item.Image1__c) }}",
|
1353 |
+
description: "{{ item.Description__c | default('No description') }}",
|
1354 |
+
video: "{{ item.Video1__c | default('/static/placeholder.mp4') }}"
|
1355 |
},
|
1356 |
{% endfor %}
|
1357 |
{% endfor %}
|
|
|
1383 |
};
|
1384 |
}
|
1385 |
|
|
|
1386 |
function showToast(message) {
|
1387 |
const toastContainer = document.getElementById('toastContainer');
|
1388 |
const toast = document.createElement('div');
|
|
|
1555 |
modalSectionEl.setAttribute('data-category', selectedCategory);
|
1556 |
document.getElementById('quantityInput').value = 1;
|
1557 |
|
|
|
1558 |
let retryCount = 0;
|
1559 |
const maxRetries = 2;
|
1560 |
function fetchAddons() {
|
|
|
1708 |
});
|
1709 |
}
|
1710 |
|
1711 |
+
// NEW: Updated Filter Form Logic
|
1712 |
function handleToggle(source) {
|
1713 |
const form = document.getElementById("filter-form");
|
1714 |
const veg = document.getElementById("veg-toggle");
|
|
|
1730 |
}
|
1731 |
}
|
1732 |
|
1733 |
+
// NEW: Log query parameters for debugging
|
1734 |
+
const params = new URLSearchParams();
|
1735 |
+
if (veg.checked) params.set('veg', 'on');
|
1736 |
+
if (custom.checked) params.set('custom', 'on');
|
1737 |
+
console.log('Filter form submitting with:', params.toString());
|
1738 |
|
1739 |
form.submit();
|
1740 |
}
|
1741 |
|
1742 |
+
// NEW: Client-Side Filtering for Veg
|
1743 |
+
function applyClientSideVegFilter() {
|
1744 |
+
const noItemsMessage = document.getElementById('no-items-message');
|
1745 |
+
const clientSideMenu = document.getElementById('client-side-menu');
|
1746 |
+
if (!noItemsMessage || !clientSideMenu) return;
|
1747 |
+
|
1748 |
+
const vegItems = menuItems.filter(item => item.isVeg === true);
|
1749 |
+
if (vegItems.length > 0) {
|
1750 |
+
noItemsMessage.innerText = 'Showing vegetarian items (client-side)';
|
1751 |
+
clientSideMenu.innerHTML = '';
|
1752 |
+
|
1753 |
+
const sections = [...new Set(vegItems.map(item => item.section))];
|
1754 |
+
sections.forEach(section => {
|
1755 |
+
const sectionItems = vegItems.filter(item => item.section === section);
|
1756 |
+
const sectionDiv = document.createElement('div');
|
1757 |
+
sectionDiv.innerHTML = `<h3>${section}</h3>`;
|
1758 |
+
const rowDiv = document.createElement('div');
|
1759 |
+
rowDiv.classList.add('row');
|
1760 |
+
|
1761 |
+
sectionItems.forEach(item => {
|
1762 |
+
const itemDiv = document.createElement('div');
|
1763 |
+
itemDiv.classList.add('col-md-6', 'mb-4');
|
1764 |
+
itemDiv.innerHTML = `
|
1765 |
+
<div class="card menu-card" data-item-name="${item.name}" data-item-section="${item.section}" data-is-veg="${item.isVeg}">
|
1766 |
+
<video
|
1767 |
+
class="card-img-top menu-video"
|
1768 |
+
muted
|
1769 |
+
loop
|
1770 |
+
preload="auto"
|
1771 |
+
data-src="${item.video}"
|
1772 |
+
poster="${item.image}"
|
1773 |
+
width="350"
|
1774 |
+
height="200"
|
1775 |
+
onmouseover="this.play()"
|
1776 |
+
onmouseout="this.pause(); this.currentTime = 0;"
|
1777 |
+
onerror="this.poster='/static/placeholder.jpg';">
|
1778 |
+
<source src="${item.video}" type="video/mp4">
|
1779 |
+
Your browser does not support the video tag.
|
1780 |
+
</video>
|
1781 |
+
<div class="addbutton">
|
1782 |
+
<div class="card-body d-flex align-items-center justify-content-between">
|
1783 |
+
<div>
|
1784 |
+
<h5 class="card-title">${item.name}</h5>
|
1785 |
+
<p class="card-text price">$${item.price}</p>
|
1786 |
+
</div>
|
1787 |
+
<div class="d-flex flex-column align-items-center justify-content-center
|
1788 |
+
<div class="button-container"
|
1789 |
+
data-item-name="${item.name}"
|
1790 |
+
data-item-price="${item.price}"
|
1791 |
+
data-item-image="${item.image}"
|
1792 |
+
data-item-section="${item.section}"
|
1793 |
+
data-item-category="Veg"
|
1794 |
+
data-item-description="${item.description}"
|
1795 |
+
data-item-image2="${item.image2}"
|
1796 |
+
data-is-veg="${item.isVeg}">
|
1797 |
+
<button class="btn btn-primary"
|
1798 |
+
data-bs-toggle="modal"
|
1799 |
+
data-bs-target="#itemModal"
|
1800 |
+
onclick="showItemDetails('${item.name}', '${item.price}', '${item.image2}', '${item.description}', '${item.section}', 'Veg')"
|
1801 |
+
aria-label="Customize ${item.name}">
|
1802 |
+
ADD
|
1803 |
+
</button>
|
1804 |
+
${item.section !== 'Apetizer' && item.section !== 'Customized Dish' ? '<span class="customisable-text">Customisable</span>' : ''}
|
1805 |
+
</div>
|
1806 |
+
</div>
|
1807 |
+
</div>
|
1808 |
+
<div class="toggle-details" data-item-name="${item.name}" role="button" aria-label="Toggle details for ${item.name}">Show Details</div>
|
1809 |
+
<div class="item-details" id="details-${item.name.replace(/ /g, '-')}">
|
1810 |
+
<h6>Description</h6>
|
1811 |
+
<p>${item.description}</p>
|
1812 |
+
<!-- NEW: Placeholder for ingredients and nutritional info -->
|
1813 |
+
<h6>Ingredients</h6>
|
1814 |
+
<p>Not specified</p>
|
1815 |
+
<h6>Nutritional Info</h6>
|
1816 |
+
<p class="nutritional-info">Not available</p>
|
1817 |
+
<h6>Allergens</h6>
|
1818 |
+
<p>None listed</p>
|
1819 |
+
</div>
|
1820 |
+
</div>
|
1821 |
+
`;
|
1822 |
+
rowDiv.appendChild(itemDiv);
|
1823 |
+
});
|
1824 |
+
sectionDiv.appendChild(rowDiv);
|
1825 |
+
clientSideMenu.appendChild(sectionDiv);
|
1826 |
});
|
|
|
1827 |
|
1828 |
+
// NEW: Re-apply Intersection Observers for client-side rendered cards
|
1829 |
+
const newMenuCards = clientSideMenu.querySelectorAll('.menu-card');
|
1830 |
+
const newMenuVideos = clientSideMenu.querySelectorAll('.menu-video');
|
1831 |
+
newMenuCards.forEach(card => cardObserver.observe(card));
|
1832 |
+
newMenuVideos.forEach(video => videoObserver.observe(video));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1833 |
|
1834 |
+
// NEW: Re-apply toggle details listeners
|
1835 |
+
const newToggleLinks = clientSideMenu.querySelectorAll('.toggle-details');
|
1836 |
+
newToggleLinks.forEach(link => {
|
1837 |
+
link.addEventListener('click', function () {
|
1838 |
+
const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
|
1839 |
+
const detailsDiv = document.getElementById(`details-${itemName}`);
|
1840 |
+
const isCurrentlyShown = detailsDiv.classList.contains('show');
|
1841 |
+
document.querySelectorAll('.item-details.show').forEach(otherDetails => {
|
1842 |
+
if (otherDetails !== detailsDiv) {
|
1843 |
+
otherDetails.classList.remove('show');
|
1844 |
+
const otherLink = document.querySelector(`.toggle-details[data-item-name="${otherDetails.id.replace('details-', '').replace(/-/g, ' ')}"]`);
|
1845 |
+
if (otherLink) {
|
1846 |
+
otherLink.innerText = 'Show Details';
|
1847 |
+
}
|
|
|
|
|
|
|
|
|
|
|
1848 |
}
|
1849 |
+
});
|
1850 |
+
if (!isCurrentlyShown) {
|
1851 |
+
detailsDiv.classList.add('show');
|
1852 |
+
this.innerText = 'Hide Details';
|
|
|
1853 |
} else {
|
1854 |
+
detailsDiv.classList.remove('show');
|
1855 |
+
this.innerText = 'Show Details';
|
|
|
|
|
|
|
|
|
|
|
|
|
1856 |
}
|
1857 |
+
});
|
1858 |
+
});
|
1859 |
+
} else {
|
1860 |
+
noItemsMessage.innerText = 'No vegetarian items available. Please try adjusting the filters or contact support.';
|
|
|
|
|
1861 |
}
|
1862 |
+
}
|
1863 |
|
1864 |
+
// NEW: Apply client-side filter if no items are returned
|
1865 |
+
if (document.getElementById('no-items-message')) {
|
1866 |
+
applyClientSideVegFilter();
|
|
|
|
|
|
|
|
|
|
|
1867 |
}
|
1868 |
+
|
1869 |
+
// === Search Functionality ===
|
1870 |
+
const searchBar = document.getElementById('searchBar');
|
1871 |
+
const searchSuggestions = document.getElementById('searchSuggestions');
|
1872 |
+
const debouncedSearch = debounce(function () {
|
1873 |
+
const query = searchBar.value.trim().toLowerCase();
|
1874 |
+
searchSuggestions.innerHTML = '';
|
1875 |
+
searchSuggestions.style.display = 'none';
|
1876 |
+
if (query.length >= 2) {
|
1877 |
+
const filteredItems = menuItems.filter(item =>
|
1878 |
+
item.name.toLowerCase().includes(query) ||
|
1879 |
+
item.section.toLowerCase().includes(query) ||
|
1880 |
+
item.description.toLowerCase().includes(query)
|
1881 |
+
);
|
1882 |
+
if (filteredItems.length > 0) {
|
1883 |
+
filteredItems.forEach(item => {
|
1884 |
+
const suggestionDiv = document.createElement('div');
|
1885 |
+
suggestionDiv.classList.add('suggestion-item');
|
1886 |
+
suggestionDiv.innerText = item.name;
|
1887 |
+
suggestionDiv.addEventListener('click', () => {
|
1888 |
+
searchBar.value = item.name;
|
1889 |
+
searchSuggestions.style.display = 'none';
|
1890 |
+
window.location.href = '/search';
|
1891 |
+
});
|
1892 |
+
searchSuggestions.appendChild(suggestionDiv);
|
1893 |
});
|
1894 |
+
searchSuggestions.style.display = 'block';
|
1895 |
}
|
|
|
|
|
1896 |
}
|
1897 |
+
}, 300);
|
1898 |
+
searchBar.addEventListener('input', debouncedSearch);
|
1899 |
+
document.addEventListener('click', function (event) {
|
1900 |
+
if (!searchBar.contains(event.target) && !searchSuggestions.contains(event.target)) {
|
1901 |
+
searchSuggestions.style.display = 'none';
|
1902 |
+
}
|
1903 |
+
});
|
|
|
|
|
|
|
|
|
1904 |
|
1905 |
+
// === Dropdown Menu ===
|
1906 |
+
const avatarIcon = document.querySelector('.avatar-icon');
|
1907 |
+
const dropdownMenu = document.querySelector('.dropdown-menu');
|
1908 |
+
avatarIcon.addEventListener('click', function () {
|
1909 |
+
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
|
1910 |
+
});
|
1911 |
+
document.addEventListener('click', function (event) {
|
1912 |
+
if (!avatarIcon.contains(event.target) && !dropdownMenu.contains(event.target)) {
|
1913 |
+
dropdownMenu.style.display = 'none';
|
|
|
|
|
|
|
|
|
|
|
1914 |
}
|
1915 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1916 |
|
1917 |
+
// === Intersection Observers ===
|
1918 |
+
const menuCards = document.querySelectorAll('.menu-card');
|
1919 |
+
const menuVideos = document.querySelectorAll('.menu-video');
|
1920 |
+
const cardObserver = new IntersectionObserver((entries, observer) => {
|
1921 |
+
entries.forEach(entry => {
|
1922 |
+
if (entry.isIntersecting) {
|
1923 |
+
entry.target.classList.add('visible');
|
1924 |
+
observer.unobserve(entry.target);
|
|
|
|
|
|
|
|
|
|
|
1925 |
}
|
1926 |
});
|
1927 |
+
}, {
|
1928 |
+
root: null,
|
1929 |
+
rootMargin: '0px',
|
1930 |
+
threshold: 0.1
|
1931 |
+
});
|
1932 |
+
const videoObserver = new IntersectionObserver((entries, observer) => {
|
1933 |
+
entries.forEach(entry => {
|
1934 |
+
if (entry.isIntersecting) {
|
1935 |
+
const video = entry.target;
|
1936 |
+
const src = video.getAttribute('data-src');
|
1937 |
+
if (src && src !== '/static/placeholder.mp4') {
|
1938 |
+
const source = video.querySelector('source');
|
1939 |
+
if (source && !source.src) {
|
1940 |
+
source.src = src;
|
1941 |
+
video.load().catch(err => {
|
1942 |
+
console.error('Error loading video:', err);
|
1943 |
+
video.poster = '/static/placeholder.jpg';
|
1944 |
+
});
|
1945 |
+
}
|
1946 |
+
} else {
|
1947 |
+
video.poster = '/static/placeholder.jpg';
|
1948 |
+
}
|
1949 |
+
video.classList.add('loaded');
|
1950 |
+
observer.unobserve(video);
|
1951 |
+
}
|
1952 |
+
});
|
1953 |
+
}, {
|
1954 |
+
root: null,
|
1955 |
+
rootMargin: '200px',
|
1956 |
+
threshold: 0.01
|
1957 |
+
});
|
1958 |
+
menuCards.forEach(card => cardObserver.observe(card));
|
1959 |
+
menuVideos.forEach(video => videoObserver.observe(video));
|
1960 |
+
|
1961 |
+
// === Toggle Details ===
|
1962 |
+
const toggleLinks = document.querySelectorAll('.toggle-details');
|
1963 |
+
toggleLinks.forEach(link => {
|
1964 |
+
link.addEventListener('click', function () {
|
1965 |
+
const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
|
1966 |
+
const detailsDiv = document.getElementById(`details-${itemName}`);
|
1967 |
+
const isCurrentlyShown = detailsDiv.classList.contains('show');
|
1968 |
+
document.querySelectorAll('.item-details.show').forEach(otherDetails => {
|
1969 |
+
if (otherDetails !== detailsDiv) {
|
1970 |
+
otherDetails.classList.remove('show');
|
1971 |
+
const otherLink = document.querySelector(`.toggle-details[data-item-name="${otherDetails.id.replace('details-', '').replace(/-/g, ' ')}"]`);
|
1972 |
+
if (otherLink) {
|
1973 |
+
otherLink.innerText = 'Show Details';
|
1974 |
+
}
|
1975 |
+
}
|
1976 |
});
|
1977 |
+
if (!isCurrentlyShown) {
|
1978 |
+
detailsDiv.classList.add('show');
|
1979 |
+
this.innerText = 'Hide Details';
|
1980 |
+
} else {
|
1981 |
+
detailsDiv.classList.remove('show');
|
1982 |
+
this.innerText = 'Show Details';
|
1983 |
+
}
|
1984 |
+
});
|
1985 |
+
});
|
1986 |
+
|
1987 |
+
// === Custom Dish Form Suggestions ===
|
1988 |
+
const descriptionTextarea = document.getElementById('custom-dish-description');
|
1989 |
+
const descriptionSuggestions = document.getElementById('descriptionSuggestions');
|
1990 |
+
if (descriptionTextarea && descriptionSuggestions) {
|
1991 |
+
let usedIngredients = new Set();
|
1992 |
+
function updateUsedIngredients() {
|
1993 |
+
const inputText = descriptionTextarea.value.trim();
|
1994 |
+
usedIngredients.clear();
|
1995 |
+
if (inputText) {
|
1996 |
+
const words = inputText.split(/,\s*/).map(word => word.trim());
|
1997 |
+
words.forEach(word => {
|
1998 |
+
if (word && ingredientsList.includes(word)) {
|
1999 |
+
usedIngredients.add(word);
|
2000 |
+
}
|
2001 |
+
});
|
2002 |
+
}
|
2003 |
}
|
2004 |
+
const debouncedSuggestions = debounce(function () {
|
2005 |
+
const inputText = descriptionTextarea.value.trim();
|
2006 |
+
const words = inputText.split(/,\s*/);
|
2007 |
+
const lastWord = words[words.length - 1].trim().toLowerCase();
|
2008 |
+
descriptionSuggestions.innerHTML = '';
|
2009 |
+
descriptionSuggestions.style.display = 'none';
|
2010 |
+
updateUsedIngredients();
|
2011 |
+
if (lastWord) {
|
2012 |
+
const filteredIngredients = ingredientsList.filter(ingredient =>
|
2013 |
+
ingredient.toLowerCase().includes(lastWord) && !usedIngredients.has(ingredient)
|
2014 |
+
);
|
2015 |
+
if (filteredIngredients.length > 0) {
|
2016 |
+
filteredIngredients.forEach(ingredient => {
|
2017 |
+
const suggestionDiv = document.createElement('div');
|
2018 |
+
suggestionDiv.classList.add('suggestion-item');
|
2019 |
+
suggestionDiv.innerText = ingredient;
|
2020 |
+
suggestionDiv.addEventListener('click', function () {
|
2021 |
+
const currentValue = descriptionTextarea.value;
|
2022 |
+
const lastCommaIndex = currentValue.lastIndexOf(',');
|
2023 |
+
const baseText = lastCommaIndex !== -1 ? currentValue.substring(0, lastCommaIndex + 1) : '';
|
2024 |
+
descriptionTextarea.value = baseText + (baseText ? ' ' : '') + ingredient + ', ';
|
2025 |
+
descriptionSuggestions.style.display = 'none';
|
2026 |
+
descriptionTextarea.focus();
|
2027 |
+
updateUsedIngredients();
|
2028 |
+
});
|
2029 |
+
descriptionSuggestions.appendChild(suggestionDiv);
|
2030 |
+
});
|
2031 |
+
descriptionSuggestions.style.display = 'block';
|
2032 |
+
}
|
2033 |
+
}
|
2034 |
+
}, 300);
|
2035 |
+
descriptionTextarea.addEventListener('input', debouncedSuggestions);
|
2036 |
+
document.addEventListener('click', function (event) {
|
2037 |
+
if (!descriptionTextarea.contains(event.target) && !descriptionSuggestions.contains(event.target)) {
|
2038 |
+
descriptionSuggestions.style.display = 'none';
|
2039 |
+
}
|
2040 |
+
});
|
2041 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2042 |
|
2043 |
+
// === Fetch Initial Cart ===
|
2044 |
+
fetch('/cart/get')
|
2045 |
+
.then(response => {
|
2046 |
+
if (!response.ok) {
|
2047 |
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
2048 |
+
}
|
2049 |
+
return response.json();
|
2050 |
+
})
|
2051 |
+
.then(data => {
|
2052 |
+
if (data.success) {
|
2053 |
+
updateCartUI(data.cart);
|
2054 |
+
} else {
|
2055 |
+
console.error('Failed to fetch cart:', data.error);
|
2056 |
+
showToast('Failed to load cart');
|
2057 |
+
const cart = getCartLocalStorage();
|
2058 |
+
updateCartUI(cart);
|
2059 |
+
}
|
2060 |
+
})
|
2061 |
+
.catch(err => {
|
2062 |
+
console.error('Error fetching cart:', err);
|
2063 |
+
showToast('Error loading cart');
|
2064 |
+
const cart = getCartLocalStorage();
|
2065 |
+
updateCartUI(cart);
|
2066 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2067 |
|
2068 |
+
// === Quantity Controls for Item Modal ===
|
2069 |
+
const decreaseBtn = document.getElementById('decreaseQuantity');
|
2070 |
+
const increaseBtn = document.getElementById('increaseQuantity');
|
2071 |
+
const quantityInput = document.getElementById('quantityInput');
|
2072 |
+
decreaseBtn.addEventListener('click', function () {
|
2073 |
+
let quantity = parseInt(quantityInput.value) || 1;
|
2074 |
+
quantity = Math.max(1, quantity - 1);
|
2075 |
+
quantityInput.value = quantity;
|
2076 |
+
});
|
2077 |
+
increaseBtn.addEventListener('click', function () {
|
2078 |
+
let quantity = parseInt(quantityInput.value) || 1;
|
2079 |
+
quantity += 1;
|
2080 |
+
quantityInput.value = quantity;
|
2081 |
+
});
|
2082 |
|
2083 |
+
// === Keyboard Accessibility for Search Bar ===
|
2084 |
+
searchBar.addEventListener('keydown', function (e) {
|
2085 |
+
if (e.key === 'Enter' && searchBar.value.trim()) {
|
2086 |
+
window.location.href = '/search';
|
2087 |
+
}
|
2088 |
+
});
|
2089 |
+
});
|
2090 |
+
</script>
|
2091 |
</body>
|
2092 |
+
</html>
|
2093 |
+
|