| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Search Menu</title> |
| |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"> |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet"> |
| |
| <link rel="preload" href="/static/placeholder.jpg" as="image"> |
| <style> |
| body { |
| font-family: Arial, sans-serif; |
| background-color: #fdf4e3; |
| margin: 0; |
| padding: 0; |
| display: flex; |
| flex-direction: column; |
| padding-bottom: 70px; |
| } |
| .container { |
| max-width: 900px; |
| } |
| .menu-heading { |
| font-size: 2rem; |
| font-weight: 700; |
| color: #fff; |
| text-align: center; |
| padding: 15px 20px; |
| margin: 20px 0; |
| background: linear-gradient(45deg, #FFA07A, #FFB347); |
| border-radius: 10px; |
| box-shadow: 0 4px 8px rgba(0,0,0,0.2); |
| width: 100%; |
| max-width: 900px; |
| margin-left: auto; |
| margin-right: auto; |
| } |
| .menu-card { |
| max-width: 350px; |
| border-radius: 15px; |
| overflow: hidden; |
| background-color: #fff; |
| margin: auto; |
| display: flex; |
| flex-direction: column; |
| box-shadow: 0 4px 8px rgba(0,0,0,0.1); |
| cursor: pointer; |
| } |
| .card-img-container { |
| position: relative; |
| width: 100%; |
| height: 200px; |
| } |
| .card-img { |
| height: 100%; |
| width: 100%; |
| object-fit: cover; |
| border-radius: 15px 15px 0 0; |
| display: block; |
| } |
| .card-title { |
| position: absolute; |
| top: 10px; |
| left: 50%; |
| transform: translateX(-50%); |
| font-size: 1.2rem; |
| font-weight: 600; |
| color: #fff; |
| text-align: center; |
| margin: 0; |
| padding: 5px 10px; |
| background-color: rgba(0, 0, 0, 0.5); |
| border-radius: 5px; |
| width: 90%; |
| white-space: nowrap; |
| overflow: hidden; |
| text-overflow: ellipsis; |
| z-index: 1; |
| } |
| .menu-card .card-body { |
| padding: 10px; |
| text-align: center; |
| } |
| .menu-card .card-body .card-text.section { |
| font-size: 0.9rem; |
| color: #6c757d; |
| text-align: center; |
| margin-bottom: 10px; |
| } |
| .avatar-dropdown-container { |
| position: absolute; |
| right: 10px; |
| top: 50%; |
| transform: translateY(-50%); |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| } |
| .avatar-icon { |
| width: 40px; |
| height: 40px; |
| border-radius: 50%; |
| background: linear-gradient(45deg, #FF4500, #000000, #1E90FF); |
| cursor: pointer; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| color: white; |
| font-size: 20px; |
| font-weight: bold; |
| } |
| .dropdown-menu { |
| position: absolute; |
| right: 0; |
| top: 100%; |
| background-color: #fff8f0; |
| border-radius: 5px; |
| width: 220px; |
| box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); |
| display: none; |
| border: 1px solid #ffd8b1; |
| z-index: 1000; |
| } |
| .dropdown-menu .dropdown-item { |
| padding: 12px 16px; |
| text-decoration: none; |
| color: #333; |
| border-bottom: 1px solid #ffd8b1; |
| display: flex; |
| align-items: center; |
| font-size: 15px; |
| transition: background-color 0.2s ease; |
| background: linear-gradient(45deg, #FF4500, #000000, #1E90FF); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| } |
| .dropdown-menu .dropdown-item i { |
| margin-right: 10px; |
| font-size: 16px; |
| } |
| .dropdown-menu .dropdown-item:last-child { |
| border-bottom: none; |
| } |
| .dropdown-menu .dropdown-item:hover { |
| background-color: #ffe4c4; |
| color: #333; |
| -webkit-text-fill-color: #333; |
| } |
| .fixed-top-bar { |
| position: relative; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 54px; |
| background: linear-gradient(45deg, #FFA07A, #FFB347); |
| color: white; |
| padding: 15px; |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| z-index: 1000; |
| } |
| .back-arrow-container { |
| position: absolute; |
| left: 10px; |
| top: 50%; |
| transform: translateY(-50%); |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| } |
| .back-arrow { |
| width: 36px; |
| height: 36px; |
| border-radius: 50%; |
| background: linear-gradient(45deg, #FFA07A, #FFB347); |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| color: white; |
| font-size: 20px; |
| cursor: pointer; |
| transition: transform 0.2s ease, background-color 0.2s ease; |
| text-decoration: none; |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); |
| } |
| .back-arrow:hover { |
| background: linear-gradient(45deg, #FF8C61, #FF9E2C); |
| transform: scale(1.1); |
| } |
| .back-arrow:active { |
| transform: scale(0.95); |
| } |
| .search-bar-container { |
| position: absolute; |
| left: 60px; |
| top: 50%; |
| transform: translateY(-50%); |
| display: flex; |
| align-items: center; |
| width: 300px; |
| max-width: calc(90% - 60px); |
| position: relative; |
| } |
| .search-bar-container input { |
| width: 100%; |
| padding: 8px 40px 8px 40px; |
| font-size: 16px; |
| border-radius: 25px; |
| border: none; |
| background-color: #fff; |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
| outline: none; |
| transition: border-bottom 0.3s ease; |
| } |
| .search-bar-container input:focus { |
| border-bottom: 2px solid #FFA07A; |
| } |
| .search-bar-container input::placeholder { |
| color: #888; |
| } |
| .search-icon { |
| position: absolute; |
| left: 15px; |
| font-size: 18px; |
| color: #888; |
| } |
| .mic-icon { |
| position: absolute; |
| right: 15px; |
| font-size: 18px; |
| color: #888; |
| cursor: pointer; |
| transition: color 0.3s ease; |
| } |
| .mic-icon.active { |
| color: #007bff; |
| } |
| .search-popup { |
| position: absolute; |
| top: 100%; |
| left: 0; |
| right: 0; |
| background-color: #fff; |
| border-radius: 5px; |
| box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); |
| max-height: 300px; |
| overflow-y: auto; |
| z-index: 1000; |
| display: none; |
| margin-top: 5px; |
| } |
| .search-popup-item { |
| display: flex; |
| align-items: center; |
| padding: 10px; |
| border-bottom: 1px solid #eee; |
| cursor: pointer; |
| transition: background-color 0.2s ease; |
| } |
| .search-popup-item:hover { |
| background-color: #f8f9fa; |
| } |
| .search-popup-item img { |
| width: 50px; |
| height: 50px; |
| object-fit: cover; |
| border-radius: 5px; |
| margin-right: 10px; |
| } |
| .search-popup-item span { |
| font-size: 14px; |
| color: #333; |
| } |
| .bottom-action-bar { |
| position: fixed; |
| bottom: 0; |
| left: 0; |
| right: 0; |
| background-color: white; |
| padding: 10px 20px; |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); |
| z-index: 1000; |
| max-width: 900px; |
| margin: 0 auto; |
| } |
| .bottom-action-bar .btn { |
| flex: 1; |
| margin: 0 5px; |
| padding: 10px 15px; |
| border-radius: 8px; |
| font-weight: bold; |
| font-size: 16px; |
| color: white; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| text-align: center; |
| min-width: 0; |
| white-space: nowrap; |
| } |
| .bottom-action-bar .btn-order-history { |
| background-color: #FFA07A; |
| border-color: #FFA07A; |
| } |
| .bottom-action-bar .btn-order-history:hover { |
| background-color: #FF8C61; |
| border-color: #FF8C61; |
| } |
| .bottom-action-bar .btn-view-cart { |
| background-color: #0FAA39; |
| border-color: #0FAA39; |
| } |
| .bottom-action-bar .btn-view-cart:hover { |
| background-color: #0D9232; |
| border-color: #0D9232; |
| } |
| .cart-icon-badge { |
| background-color: white; |
| color: #0FAA39; |
| border-radius: 50%; |
| width: 20px; |
| height: 20px; |
| display: inline-flex; |
| align-items: center; |
| justify-content: center; |
| font-size: 12px; |
| margin-left: 8px; |
| } |
| .no-results { |
| text-align: center; |
| font-size: 1.2rem; |
| color: #6c757d; |
| margin-top: 20px; |
| } |
| @media (max-width: 576px) { |
| .fixed-top-bar { |
| height: 60px; |
| padding: 10px; |
| } |
| .back-arrow-container { |
| left: 8px; |
| } |
| .back-arrow { |
| width: 32px; |
| height: 32px; |
| font-size: 18px; |
| } |
| .search-bar-container { |
| width: calc(80% - 50px); |
| max-width: calc(100% - 50px); |
| left: 50px; |
| } |
| .search-bar-container input { |
| padding: 6px 35px 6px 35px; |
| font-size: 14px; |
| border-radius: 20px; |
| } |
| .search-icon { |
| left: 12px; |
| font-size: 16px; |
| } |
| .mic-icon { |
| right: 12px; |
| font-size: 16px; |
| } |
| .avatar-dropdown-container { |
| right: 10px; |
| } |
| .avatar-icon { |
| width: 40px; |
| height: 40px; |
| font-size: 20px; |
| } |
| .dropdown-menu { |
| width: 220px; |
| } |
| .dropdown-menu .dropdown-item { |
| padding: 12px 16px; |
| font-size: 15px; |
| } |
| .menu-heading { |
| font-size: 1.5rem; |
| padding: 10px 15px; |
| margin: 15px 0; |
| } |
| .menu-card { |
| max-width: 100%; |
| } |
| .card-img-container { |
| height: 150px; |
| } |
| .card-title { |
| font-size: 1rem; |
| top: 8px; |
| padding: 4px 8px; |
| } |
| .menu-card .card-body .card-text.section { |
| font-size: 0.8rem; |
| } |
| .bottom-action-bar { |
| padding: 8px 10px; |
| } |
| .bottom-action-bar .btn { |
| padding: 8px 10px; |
| font-size: 14px; |
| } |
| .cart-icon-badge { |
| width: 18px; |
| height: 18px; |
| font-size: 10px; |
| margin-left: 5px; |
| } |
| .search-popup { |
| width: 100%; |
| } |
| .search-popup-item img { |
| width: 40px; |
| height: 40px; |
| } |
| .search-popup-item span { |
| font-size: 12px; |
| } |
| } |
| </style> |
| </head> |
| <body> |
| <div class="fixed-top-bar"> |
| <div class="back-arrow-container"> |
| <a href="{{ url_for('menu.menu') }}" class="back-arrow" aria-label="Back to Menu"> |
| <i class="bi bi-arrow-left"></i> |
| </a> |
| </div> |
| <div class="avatar-dropdown-container"> |
| <div class="avatar-icon"> |
| <span>{{ first_letter }}</span> |
| </div> |
| <div class="dropdown-menu"> |
| <a href="{{ url_for('user_details.customer_details') }}" class="dropdown-item"><i class="bi bi-person"></i> View Profile</a> |
| <a href="{{ url_for('orderhistory.order_history') }}" class="dropdown-item"><i class="bi bi-clock-history"></i> Order History</a> |
| <a href="{{ url_for('combined_summary.combined_summary') }}" class="dropdown-item"><i class="bi bi-file-earmark-text"></i> MY Summary</a> |
| <a href="{{ url_for('logout') }}" class="dropdown-item"><i class="bi bi-box-arrow-right"></i> Logout</a> |
| </div> |
| </div> |
| <div class="search-bar-container"> |
| <input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off"> |
| <i class="bi bi-search search-icon"></i> |
| <i class="bi bi-mic mic-icon" id="micIcon"></i> |
| <div class="search-popup" id="searchPopup"></div> |
| </div> |
| </div> |
|
|
| |
| <div id="orderTimerContainer" style="display: none; text-align: center; margin-top: 20px;"> |
| <div id="orderTimer" style="font-size: 1.5rem; font-weight: bold; color: #FFA07A;"></div> |
| <div id="orderSuccessMessage" style="font-size: 1.5rem; font-weight: bold; color: #0FAA39; display: none;">Order Successfully Placed!</div> |
| </div> |
|
|
| <div class="container mt-4"> |
| <h1 class="menu-heading">Search Menu Items</h1> |
| <div class="row" id="menuItems"> |
| {% for section, items in ordered_menu.items() %} |
| {% for item in items %} |
| <div class="col-md-6 mb-4 menu-item" data-name="{{ item.Name | default('Unnamed Item') }}" data-section="{{ item.Section__c | default(section) }}"> |
| <div class="card menu-card" onclick="selectItem('{{ item.Name | default('Unnamed Item') }}', '{{ item.Section__c | default(section) }}')"> |
| <div class="card-img-container"> |
| <img src="{{ item.Image1__c | default('/static/placeholder.jpg') }}" alt="{{ item.Name | default('Unnamed Item') }}" class="card-img" loading="eager" decoding="async" width="350" height="200"> |
| <h5 class="card-title">{{ item.Name | default('Unnamed Item') }}</h5> |
| </div> |
| <div class="card-body"> |
| <p class="card-text section">{{ item.Section__c | default(section) }}</p> |
| </div> |
| </div> |
| </div> |
| {% endfor %} |
| {% endfor %} |
| </div> |
| <div class="no-results" id="noResults" style="display: none;"> |
| No items found matching your search. |
| </div> |
| </div> |
|
|
| <div class="bottom-action-bar"> |
| <a href="{{ url_for('orderhistory.order_history') }}" class="btn btn-order-history"> |
| <i class="bi bi-clock-history"></i> Order History |
| </a> |
| <a href="{{ url_for('cart.cart') }}" class="btn btn-view-cart"> |
| <i class="bi bi-cart"></i> View Cart |
| <span id="cart-item-count" class="cart-icon-badge" style="display: none;">0</span> |
| </a> |
| </div> |
|
|
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script> |
| <script> |
| const menuItems = [ |
| {% for section, items in ordered_menu.items() %} |
| {% for item in items %} |
| { |
| name: "{{ item.Name | default('Unnamed Item') }}", |
| section: "{{ item.Section__c | default(section) }}", |
| image: "{{ item.Image1__c | default('/static/placeholder.jpg') }}" |
| }, |
| {% endfor %} |
| {% endfor %} |
| ]; |
| |
| function updateCartUI(cart) { |
| if (!Array.isArray(cart)) { |
| console.error('Invalid cart data:', cart); |
| return; |
| } |
| let totalQuantity = 0; |
| cart.forEach(item => { |
| totalQuantity += item.quantity; |
| }); |
| const cartItemCount = document.getElementById('cart-item-count'); |
| if (cartItemCount) { |
| cartItemCount.innerText = totalQuantity; |
| cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none'; |
| } |
| } |
| |
| function getCartLocalStorage() { |
| return JSON.parse(localStorage.getItem('cart')) || []; |
| } |
| |
| function selectItem(itemName, section) { |
| localStorage.setItem('selectedItem', JSON.stringify({ name: itemName, section: section })); |
| window.location.href = '/menu'; |
| } |
| |
| function filterMenuItems(query) { |
| const menuItemElements = document.querySelectorAll('.menu-item'); |
| const noResults = document.getElementById('noResults'); |
| let hasResults = false; |
| |
| menuItemElements.forEach(item => { |
| const name = item.getAttribute('data-name').toLowerCase(); |
| const section = item.getAttribute('data-section').toLowerCase(); |
| const matches = name.includes(query.toLowerCase()) || section.includes(query.toLowerCase()); |
| item.style.display = matches ? '' : 'none'; |
| if (matches) hasResults = true; |
| }); |
| |
| noResults.style.display = hasResults ? 'none' : 'block'; |
| } |
| |
| function showSearchPopup(query) { |
| const searchPopup = document.getElementById('searchPopup'); |
| searchPopup.innerHTML = ''; |
| if (!query) { |
| searchPopup.style.display = 'none'; |
| return; |
| } |
| |
| const filteredItems = menuItems.filter(item => |
| item.name.toLowerCase().includes(query.toLowerCase()) || |
| item.section.toLowerCase().includes(query.toLowerCase()) |
| ); |
| |
| if (filteredItems.length === 0) { |
| searchPopup.style.display = 'none'; |
| return; |
| } |
| |
| filteredItems.forEach(item => { |
| const popupItem = document.createElement('div'); |
| popupItem.className = 'search-popup-item'; |
| popupItem.innerHTML = ` |
| <img src="${item.image}" alt="${item.name}"> |
| <span>${item.name}</span> |
| `; |
| popupItem.addEventListener('click', () => { |
| selectItem(item.name, item.section); |
| }); |
| searchPopup.appendChild(popupItem); |
| }); |
| |
| searchPopup.style.display = 'block'; |
| } |
| |
| |
| let orderTimerInterval; |
| let orderDurationInSeconds = 0; |
| |
| function startOrderTimer(durationInSeconds) { |
| orderDurationInSeconds = durationInSeconds; |
| const timerElement = document.getElementById('orderTimer'); |
| const successMessageElement = document.getElementById('orderSuccessMessage'); |
| const timerContainer = document.getElementById('orderTimerContainer'); |
| |
| if (!timerElement || !successMessageElement || !timerContainer) { |
| console.error("Timer elements not found."); |
| return; |
| } |
| |
| timerContainer.style.display = 'block'; |
| successMessageElement.style.display = 'none'; |
| |
| let secondsRemaining = orderDurationInSeconds; |
| |
| timerElement.innerText = formatTime(secondsRemaining); |
| timerElement.style.display = 'block'; |
| |
| orderTimerInterval = setInterval(() => { |
| secondsRemaining--; |
| |
| if (secondsRemaining <= 0) { |
| clearInterval(orderTimerInterval); |
| timerElement.style.display = 'none'; |
| successMessageElement.style.display = 'block'; |
| |
| setTimeout(() => { |
| timerContainer.style.display = 'none'; |
| successMessageElement.style.display = 'none'; |
| timerElement.style.display = 'block'; |
| }, 5000); |
| } else { |
| timerElement.innerText = formatTime(secondsRemaining); |
| } |
| }, 1000); |
| } |
| |
| function formatTime(seconds) { |
| const minutes = Math.floor(seconds / 60); |
| const remainingSeconds = seconds % 60; |
| const formattedMinutes = String(minutes).padStart(2, '0'); |
| const formattedSeconds = String(remainingSeconds).padStart(2, '0'); |
| return `${formattedMinutes}:${formattedSeconds}`; |
| } |
| |
| |
| |
| function handleNewOrderSuccess(estimatedCompletionTimeInSeconds) { |
| console.log("New order successful, starting timer..."); |
| startOrderTimer(estimatedCompletionTimeInSeconds); |
| } |
| |
| document.addEventListener('DOMContentLoaded', function () { |
| |
| const avatarContainer = document.querySelector('.avatar-dropdown-container'); |
| const dropdownMenu = document.querySelector('.dropdown-menu'); |
| avatarContainer.addEventListener('click', function (event) { |
| event.stopPropagation(); |
| dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block'; |
| }); |
| document.addEventListener('click', function (event) { |
| if (!avatarContainer.contains(event.target)) { |
| dropdownMenu.style.display = 'none'; |
| } |
| }); |
| const dropdownItems = document.querySelectorAll('.dropdown-item'); |
| dropdownItems.forEach(item => { |
| item.addEventListener('click', function () { |
| dropdownMenu.style.display = 'none'; |
| }); |
| }); |
| |
| |
| const searchBar = document.getElementById('searchBar'); |
| const searchPopup = document.getElementById('searchPopup'); |
| const searchQuery = localStorage.getItem('searchQuery'); |
| if (searchQuery) { |
| searchBar.value = searchQuery; |
| filterMenuItems(searchQuery); |
| showSearchPopup(searchQuery); |
| localStorage.removeItem('searchQuery'); |
| } |
| searchBar.addEventListener('input', function () { |
| filterMenuItems(this.value); |
| showSearchPopup(this.value); |
| }); |
| document.addEventListener('click', function (event) { |
| if (!searchBar.contains(event.target) && !searchPopup.contains(event.target)) { |
| searchPopup.style.display = 'none'; |
| } |
| }); |
| |
| |
| const micIcon = document.getElementById('micIcon'); |
| if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) { |
| const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; |
| const recognition = new SpeechRecognition(); |
| recognition.lang = 'en-US'; |
| recognition.onstart = () => micIcon.classList.add('active'); |
| recognition.onresult = (event) => { |
| const query = event.results[0][0].transcript.trim(); |
| searchBar.value = query; |
| filterMenuItems(query); |
| showSearchPopup(query); |
| }; |
| recognition.onend = () => micIcon.classList.remove('active'); |
| recognition.onerror = (event) => { |
| micIcon.classList.remove('active'); |
| console.error('Speech error:', event.error); |
| }; |
| micIcon.addEventListener('click', () => { |
| recognition.start(); |
| }); |
| } else { |
| micIcon.style.display = 'none'; |
| } |
| |
| |
| fetch('/cart/get') |
| .then(response => { |
| if (!response.ok) { |
| throw new Error(`HTTP error! Status: ${response.status}`); |
| } |
| return response.json(); |
| }) |
| .then(data => { |
| if (data.success) { |
| updateCartUI(data.cart); |
| } else { |
| console.error('Failed to fetch cart:', data.error); |
| const cart = getCartLocalStorage(); |
| updateCartUI(cart); |
| } |
| }) |
| .catch(err => { |
| console.error('Error fetching cart:', err); |
| const cart = getCartLocalStorage(); |
| updateCartUI(cart); |
| }); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| const savedOrderTimer = localStorage.getItem('orderTimer'); |
| if (savedOrderTimer) { |
| const timerData = JSON.parse(savedOrderTimer); |
| const now = Date.now(); |
| const elapsed = Math.floor((now - timerData.startTime) / 1000); |
| const remaining = timerData.duration - elapsed; |
| |
| if (remaining > 0) { |
| startOrderTimer(remaining); |
| } else { |
| |
| const successMessageElement = document.getElementById('orderSuccessMessage'); |
| const timerContainer = document.getElementById('orderTimerContainer'); |
| timerContainer.style.display = 'block'; |
| successMessageElement.style.display = 'block'; |
| setTimeout(() => { |
| timerContainer.style.display = 'none'; |
| successMessageElement.style.display = 'none'; |
| }, 3000); |
| localStorage.removeItem('orderTimer'); |
| } |
| } |
| }); |
| |
| |
| |
| |
| function handleOrderPlacedAndStartTimer(estimatedCompletionTimeInSeconds) { |
| const startTime = Date.now(); |
| localStorage.setItem('orderTimer', JSON.stringify({ |
| startTime: startTime, |
| duration: estimatedCompletionTimeInSeconds |
| })); |
| startOrderTimer(estimatedCompletionTimeInSeconds); |
| } |
| </script> |
| </body> |
| </html> |