lokeshloki143's picture
Update templates/menu.html
0270e24 verified
<!DOCTYPE688 html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Menu</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/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.mp4" as="video">
{% for section, items in ordered_menu.items() %}
{% for item in items[:1] %}
<link rel="preload" href="{{ item.Video1__c | default('/static/placeholder.mp4') }}" as="video" fetchpriority="high">
{% endfor %}
{% endfor %}
<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-card {
max-width: 350px;
border-radius: 15px;
overflow: hidden;
background-color: #fff;
margin: auto;
display: flex;
flex-direction: column;
opacity: 0;
transition: opacity 0.3s ease-in-out;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.menu-card.visible {
opacity: 1;
}
.menu-card.highlighted {
border: 3px solid #0FAA39;
box-shadow: 0 0 10px rgba(15, 170, 57, 0.5);
}
.menu-video {
height: 200px;
width: 100%;
object-fit: cover;
border-radius: 15px 15px 0 0;
opacity: 0;
transition: opacity 0.5s ease-in-out;
background-color: #000;
}
.menu-video.loaded {
opacity: 1;
}
.menu-card:hover .menu-video {
opacity: 1;
transform: scale(1.05);
}
.menu-card .card-body .card-title {
font-size: 1.2rem;
font-weight: 600;
margin: 10px 0;
color: #333333;
}
.menu-card .card-body .card-text.price {
font-size: 1rem;
font-weight: 500;
color: #000000;
margin-bottom: 5px;
}
.addbutton .btn {
background-color: #28a745;
color: white;
padding: 10px 20px;
font-size: 16px;
font-weight: bold;
border-radius: 5px;
border: none;
transition: background-color 0.3s ease;
margin-left: 13px;
}
.addbutton .btn:hover {
background-color: #218838;
}
.button-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
}
.customisable-text {
color: #0FAA39;
font-size: 10px;
font-weight: 500;
margin: 0;
text-align: center;
line-height: 1;
}
.btn-primary {
font-size: 12px;
font-weight: bold;
border-radius: 8px;
width: 70px;
height: 35px;
background-color: #0FAA39;
border-color: #0FAA39;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
transition: background-color 0.3s ease, transform 0.1s ease;
}
.btn-primary:hover {
background-color: #0D9232;
border-color: #0D9232;
transform: scale(1.05);
}
.btn-primary:active,
.btn-primary:focus {
background-color: #0B7A29;
border-color: #0B7A29;
box-shadow: none;
transform: scale(0.98);
}
.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-color: #007bff;
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;
}
.dropdown-menu .dropdown-item {
padding: 12px 16px;
text-decoration: none;
color: #333;
border-bottom: 1px solid #ffd8b1;
display: block;
font-size: 15px;
transition: background-color 0.2s ease;
}
.dropdown-menu .dropdown-item:last-child {
border-bottom: none;
}
.dropdown-menu .dropdown-item:hover {
background-color: #ffe4c4;
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;
}
.search-bar-container {
position: absolute;
left: 20px;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: center;
width: 300px;
max-width: 90%;
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;
}
.search-bar-container input::placeholder {
color: #888;
}
.search-bar-container input:focus {
border-bottom: 2px solid #FFA07A;
}
.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;
}
.addon-section {
background-color: #fff;
border-radius: 10px;
margin-bottom: 15px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: transform 0.2s ease;
}
.addon-section:hover {
transform: translateY(-2px);
}
.addon-section h6 {
margin: 0;
padding: 12px 15px;
font-size: 1.1rem;
font-weight: 600;
color: #fff;
background: linear-gradient(45deg, #FFA07A, #FFB347);
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
.addon-section h6::after {
content: '\25BC';
font-size: 0.9rem;
transition: transform 0.2s ease;
}
.addon-section.collapsed h6::after {
transform: rotate(180deg);
}
.addon-section .form-check {
display: flex;
flex-direction: row-reverse;
align-items: center;
justify-content: space-between;
margin: 10px 15px;
padding: 0;
}
.addon-section .form-check-input {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border: 2px solid #6c757d;
border-radius: 4px;
background-color: #fff;
position: relative;
margin-left: 10px;
cursor: to;
transition: all 0.2s ease;
}
.addon-section .form-check-input:checked {
background-color: #0FAA39;
border-color: #0FAA39;
}
.addon-section .form-check-input:checked::before {
content: '\2713';
font-size: 12px;
position: absolute;
top: 2px;
left: 4px;
color: white;
animation: checkmark 0.2s ease-in-out;
}
.addon-section .form-check-input:hover {
transform: scale(1.1);
border-color: #0FAA39;
}
.addon-section .form-check-input:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(15, 170, 57, 0.2);
}
.addon-section .form-check-label {
font-size: 0.95rem;
color: #343a40;
cursor: pointer;
flex: 1;
padding: 5px 8px;
border-radius: 4px;
transition: background-color 0.2s ease;
text-align: left;
}
.addon-section .form-check-label:hover {
background-color: #e6f4ea;
}
.addon-section .form-check-label .extra-charge {
color: #FFA07A;
font-weight: 600;
margin-left: 8px;
}
.addon-options {
max-height: 500px;
opacity: 1;
overflow: hidden;
transition: max-height 0.3s ease, opacity 0.3s ease;
}
.addon-options.collapsed {
max-height: 0;
opacity: 0;
}
.addon-loading {
display: flex;
justify-content: center;
align-items: center;
padding: 15px;
}
.addon-loading::after {
content: '';
width: 20px;
height: 20px;
border: 3px solid #0FAA39;
border-top: 3px solid transparent;
border-radius: 50%;
animation: spin 1s linear infinite;
}
#softDrinkModal .modal-dialog {
max-width: 400px;
margin: 1.75rem auto;
animation: fadeInModal 0.3s ease-out;
}
#softDrinkModal .modal-content {
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
background-color: #fff;
overflow: hidden;
}
#softDrinkModal .modal-header {
background: linear-gradient(45deg, #FFA07A, #FFB347);
border-top-left-radius: 12px;
border-top-right-radius: 12px;
padding: 12px 15px;
border-bottom: none;
}
#softDrinkModal .modal-title {
font-size: 1.3rem;
font-weight: 600;
color: #fff;
}
#softDrinkModal .modal-body {
padding: 20px;
text-align: center;
}
#softDrinkModal .modal-body img {
max-height: 160px;
width: 100%;
object-fit: cover;
border-radius: 8px;
margin-bottom: 15px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
#softDrinkModal .modal-body h5 {
font-size: 1.4rem;
font-weight: 600;
color: #333333;
margin-bottom: 10px;
}
#softDrinkModal .modal-body p {
font-size: 1.2rem;
font-weight: 500;
color: #000000;
margin-bottom: 20px;
}
#softDrinkModal .modal-body p::before {
content: '$';
color: #FFA07A;
font-weight: 600;
margin-right: 2px;
}
#softDrinkModal .quantity-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
#softDrinkModal .quantity-controls .btn {
width: 32px;
height: 32px;
border-radius: 50%;
padding: 0;
font-size: 1.1rem;
line-height: 32px;
text-align: center;
background-color: #e9ecef;
border: none;
color: #333;
transition: background-color 0.2s ease, transform 0.1s ease;
}
#softDrinkModal .quantity-controls .btn:hover {
background-color: #d1d4d7;
transform: scale(1.1);
}
#softDrinkModal .quantity-controls .btn:active {
transform: scale(0.95);
}
#softDrinkModal .quantity-controls input {
width: 50px;
height: 32px;
text-align: center;
font-size: 1rem;
font-weight: 600;
border: 1px solid #ced4da;
border-radius: 6px;
background-color: #f8f9fa;
}
#softDrinkModal .modal-footer {
padding: 15px;
border-top: none;
display: flex;
justify-content: space-between;
align-items: center;
}
#softDrinkModal .modal-footer .btn-primary {
background-color: #0FAA39;
border-color: #0FAA39;
padding: 12px 30px;
font-size: 1.1rem;
font-weight: 600;
border-radius: 8px;
transition: background-color 0.2s ease, transform 0.1s ease;
width: auto;
}
#softDrinkModal .modal-footer .btn-primary:hover {
background-color: #0D9232;
transform: scale(1.05);
}
#softDrinkModal .modal-footer .btn-primary:active {
background-color: #0B7A29;
transform: scale(0.98);
}
#softDrinkModal .modal-footer .quantity-controls-footer {
display: flex;
gap: 12px;
}
#softDrinkModal .modal-footer .quantity-controls-footer .btn {
width: 32px;
height: 32px;
border-radius: 50%;
padding: 0;
font-size: 1.1rem;
line-height: 32px;
text-align: center;
background-color: #e9ecef;
border: none;
color: #333;
transition: background-color 0.2s ease, transform 0.1s ease;
}
#softDrinkModal .modal-footer .quantity-controls-footer .btn:hover {
background-color: #d1d4d7;
transform: scale(1.1);
}
#softDrinkModal .modal-footer .quantity-controls-footer .btn:active {
transform: scale(0.95);
}
#filter-form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 20px;
}
.form-label {
font-size: 1.2rem;
font-weight: 600;
color: #333;
margin-bottom: 10px;
}
.toggle-container {
display: flex;
align-items: center;
gap: 10px;
margin: 8px 0;
}
.custom-toggle {
appearance: none;
width: 48px;
height: 24px;
background-color: #ccc;
border-radius: 12px;
position: relative;
cursor: pointer;
transition: background-color 0.3s ease;
}
.custom-toggle:checked {
background: linear-gradient(45deg, #FFA07A, #FFB347);
}
.custom-toggle::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background-color: #fff;
border-radius: 50%;
transition: transform 0.3s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.custom-toggle:checked::before {
transform: translateX(24px);
}
.toggle-container label {
font-size: 1rem;
color: #333;
cursor: pointer;
}
#micModal .modal-dialog {
max-width: 300px;
margin: 1.75rem auto;
}
#micModal .modal-content {
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
background-color: #fff;
text-align: center;
}
#micModal .modal-header {
background: linear-gradient(45deg, #FFA07A, #FFB347);
border-top-left-radius: 12px;
border-top-right-radius: 12px;
padding: 12px 15px;
border-bottom: none;
}
#micModal .modal-title {
font-size: 1.3rem;
font-weight: 600;
color: #fff;
margin: 0 auto;
}
#micModal .modal-body {
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
min-height: 200px;
}
#micModal .modal-body i#mic-icon-animation {
font-size: 2.5rem;
color: #007bff;
animation: pulse 2s infinite;
}
#micModal .modal-body p#mic-status {
font-size: 1.1rem;
color: #333;
margin: 0;
transition: opacity 0.3s ease;
}
#micModal .modal-body #mic-item-details {
width: 100%;
text-align: center;
}
#micModal .modal-body #mic-item-image {
max-height: 100px;
width: 100%;
object-fit: cover;
border-radius: 8px;
margin-bottom: 10px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
transition: opacity 0.3s ease;
}
#micModal .modal-body #mic-item-name {
font-size: 1.2rem;
font-weight: 600;
color: #333333;
margin-bottom: 10px;
transition: opacity 0.3s ease;
}
#micModal .modal-body #mic-item-details.show {
animation: fadeIn 0.3s ease;
}
#micModal .modal-footer {
padding: 15px;
border-top: none;
justify-content: center;
}
#micModal .modal-footer .btn-secondary {
background-color: #6c757d;
border-color: #6c757d;
padding: 10px 20px;
font-size: 1rem;
border-radius: 8px;
}
#micModal .modal-footer .btn-secondary:hover {
background-color: #5a6268;
border-color: #5a6268;
}
.autocomplete-suggestions {
position: absolute;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
max-height: 150px;
overflow-y: auto;
width: 100%;
z-index: 1000;
display: none;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.suggestion-item {
padding: 8px 12px;
cursor: pointer;
font-size: 0.9rem;
color: #333;
}
.suggestion-item:hover {
background-color: #f0f0f0;
}
@keyframes checkmark {
from { transform: scale(0); }
to { transform: scale(1); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeInModal {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.modal-header {
padding: 10px 15px;
}
.modal-title {
font-size: 16px;
font-weight: bold;
}
.modal-body {
max-height: 60vh;
overflow-y: auto;
padding: 15px;
}
.modal-body #modal-img {
max-height: 200px;
width: 100%;
object-fit: cover;
border-radius: 8px;
margin-bottom: 10px;
}
.modal-body #modal-name {
font-size: 20px;
font-weight: bold;
text-align: center;
margin-bottom: 5px;
color: #333333;
}
.modal-body #modal-price {
font-size: 16px;
font-weight: 500;
color: #000000;
text-align: center;
margin-bottom: 10px;
}
.modal-body #modal-description {
font-size: 14px;
color: #6c757d;
margin-bottom: 15px;
}
.modal-body #modal-addons h5,
.modal-body #first-row h6 {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 15px;
color: #343a40;
}
.modal-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
}
.modal-footer .d-flex {
display: flex;
align-items: center;
gap: 10px;
}
.modal-footer .btn {
height: 40px;
padding: 0 15px;
}
.modal-footer .form-control {
width: 50px;
height: 40px;
text-align: center;
}
.modal-footer .btn-primary {
background-color: #0FAA39;
border-color: #0FAA39;
font-weight: bold;
padding: 10px 20px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
width: auto;
}
.modal-footer .btn-outline-secondary {
height: 40px;
width: 40px;
}
.item-details {
background-color: #f8f9fa;
border-radius: 8px;
padding: 10px;
margin: 10px 15px;
display: none;
}
.item-details.show {
display: block;
}
.item-details h6 {
font-size: 0.9rem;
font-weight: bold;
margin-bottom: 5px;
color: #333333;
}
.item-details p {
font-size: 0.85rem;
margin-bottom: 5px;
color: #333;
}
.item-details .nutritional-info {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
background-color: #e9ecef;
padding: 10px;
border-radius: 5px;
font-size: 0.85rem;
line-height: 1.5;
}
.toggle-details {
cursor: pointer;
color: #0FAA39;
font-size: 0.9rem;
margin-left: 15px;
margin-bottom: 10px;
display: inline-block;
}
.toggle-details:hover {
text-decoration: underline;
}
.quantity-selector {
display: flex;
align-items: center;
gap: 5px;
}
.quantity-selector .btn {
width: 25px;
height: 25px;
padding: 0;
font-size: 12px;
line-height: 25px;
text-align: center;
}
.quantity-selector .quantity-display {
width: 25px;
text-align: center;
font-size: 12px;
font-weight: bold;
line-height: 25px;
}
.quantity-selector .quantity-to-add,
.quantity-selector .quantity-to-remove {
width: 45px;
height: 25px;
font-size: 12px;
padding: 0 5px;
}
.modal-dialog {
max-height: 90vh;
}
.modal-body::-webkit-scrollbar {
width: 8px;
}
.modal-body::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.modal-body::-webkit-scrollbar-thumb {
background: #0FAA39;
border-radius: 10px;
}
.modal-body::-webkit-scrollbar-thumb:hover {
background: #0D9232;
}
.btn-primary:disabled {
opacity: 0.65;
cursor: not-allowed;
}
.quantity-selector select {
width: 60px;
height: 35px;
padding: 5px;
border-radius: 5px;
border: 1px solid #ced4da;
}
#custom-dish-form {
position: relative;
padding-bottom: 80px;
}
#custom-dish-form .btn-primary {
position: absolute;
right: 15px;
bottom: 15px;
width: auto;
padding: 10px 20px;
}
.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;
}
@media (max-width: 576px) {
.fixed-top-bar {
height: 60px;
padding: 10px;
}
.search-bar-container {
width: 80%;
max-width: 100%;
left: 10px;
top: 50%;
transform: translateY(-50%);
}
.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;
}
.modal-dialog {
max-width: 90%;
margin: 10px auto;
}
.modal-header {
padding: 8px 12px;
}
.modal-title {
font-size: 14px;
}
.modal-body {
max-height: 50vh;
padding: 12px;
}
.modal-body #modal-img {
max-height: 150px;
width: 100%;
max-width: 150px;
margin: 0 auto 8px;
display: block;
}
.modal-body #modal-name {
font-size: 18px;
margin-bottom: 5px;
}
.modal-body #modal-price {
font-size: 14px;
margin-bottom: 8px;
}
.modal-body #modal-description {
font-size: 12px;
margin-bottom: 10px;
}
.modal-body .nutritional-info {
font-size: 10px;
margin-bottom: 5px;
}
.modal-body #modal-addons h5,
.modal-body #first-row h6 {
font-size: 1rem;
margin-bottom: 10px;
}
.modal-footer {
padding: 8px;
}
.modal-footer .btn {
height: 30px;
padding: 0 10px;
}
.modal-footer .form-control {
width: 30px;
height: 30px;
font-size: 12px;
font-weight: bold;
}
.modal-footer .btn-outline-secondary {
width: 25px;
height: 25px;
font-size: 12px;
line-height: 25px;
}
.modal-footer .btn-primary {
font-size: 12px;
height: 30px;
padding: 0 15px;
border-radius: 5px;
}
.btn-primary {
font-size: 10px;
width: 50px;
height: 25px;
}
.customisable-text {
font-size: 8px;
}
.button-container {
gap: 3px;
}
.quantity-selector .btn {
width: 18px;
height: 18px;
font-size: 9px;
line-height: 18px;
}
.quantity-selector .quantity-display {
width: 18px;
font-size: 9px;
line-height: 18px;
}
.quantity-selector .quantity-to-add,
.quantity-selector .quantity-to-remove {
width: 35px;
height: 18px;
font-size: 9px;
}
.quantity-selector select {
width: 50px;
height: 30px;
font-size: 12px;
}
.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;
}
.addon-section {
margin-bottom: 10px;
}
.addon-section h6 {
font-size: 1rem;
padding: 10px 12px;
}
.addon-section .form-check {
margin: 8px 12px;
}
.addon-section .form-check-input {
width: 18px;
height: 18px;
margin-left: 8px;
}
.addon-section .form-check-input:checked::before {
font-size: 10px;
top: 2px;
left: 3px;
}
.addon-section .form-check-label {
font-size: 0.85rem;
padding: 4px 6px;
}
.addon-section .form-check-label .extra-charge {
margin-left: 6px;
font-size: 0.8rem;
}
#softDrinkModal .modal-dialog {
max-width: 90%;
}
#softDrinkModal .modal-content {
border-radius: 10px;
}
#softDrinkModal .modal-header {
padding: 10px 12px;
}
#softDrinkModal .modal-title {
font-size: 1.2rem;
}
#softDrinkModal .modal-body {
padding: 15px;
}
#softDrinkModal .modal-body img {
max-height: 130px;
margin-bottom: 12px;
}
#softDrinkModal .modal-body h5 {
font-size: 1.2rem;
margin-bottom: 8px;
}
#softDrinkModal .modal-body p {
font-size: 1rem;
margin-bottom: 15px;
}
#softDrinkModal .quantity-controls .btn {
width: 28px;
height: 28px;
font-size: 1rem;
line-height: 28px;
}
#softDrinkModal .quantity-controls input {
width: 45px;
height: 28px;
font-size: 0.9rem;
}
#softDrinkModal .modal-footer {
padding: 10px;
}
#softDrinkModal .modal-footer .btn-primary {
padding: 10px 25px;
font-size: 1rem;
}
#softDrinkModal .modal-footer .quantity-controls-footer .btn {
width: 28px;
height: 28px;
font-size: 1rem;
line-height: 28px;
}
#filter-form {
margin-bottom: 15px;
}
.form-label {
font-size: 1rem;
}
.toggle-container {
margin: 6px 0;
}
.custom-toggle {
width: 40px;
height: 20px;
}
.custom-toggle::before {
width: 16px;
height: 16px;
top: 2px;
left: 2px;
}
.custom-toggle:checked::before {
transform: translateX(20px);
}
.toggle-container label {
font-size: 0.9rem;
}
#micModal .modal-dialog {
max-width: 90%;
}
#micModal .modal-body i {
font-size: 2rem;
}
#micModal .modal-body p {
font-size: 1rem;
}
#micModal .modal-body img {
max-height: 80px;
margin-bottom: 8px;
}
#micModal .modal-body h5 {
font-size: 1rem;
margin-bottom: 8px;
}
#micModal .modal-footer .btn-secondary {
padding: 8px 15px;
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div class="fixed-top-bar">
<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">View Profile</a>
<a href="{{ url_for('orderhistory.order_history') }}" class="dropdown-item">Order History</a>
<a href="{{ url_for('combined_summary.combined_summary') }}" class="dropdown-item">MY Summary</a>
<a href="{{ url_for('logout') }}" class="dropdown-item">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>
</div>
<form method="get" action="/menu" class="text-center mb-4" id="filter-form">
<label class="form-label fw-bold">Filters:</label>
<div class="toggle-container">
<input type="checkbox" id="veg-toggle" name="veg" {% if selected_category == "Veg" %}checked{% endif %} class="custom-toggle" onchange="handleToggle('veg')" aria-label="Toggle Vegetarian filter">
<label for="veg-toggle">Veg</label>
</div>
<div class="toggle-container">
<input type="radio" id="category-CustomizedDish" name="category" value="Customized Dish" {% if selected_category == "Customized Dish" %}checked{% endif %} class="custom-toggle" onchange="handleToggle('custom')" aria-label="Toggle Customized Dish filter">
<label for="category-CustomizedDish">Customized Dish</label>
</div>
</form>
<div class="container mt-4">
{% if selected_category == "Customized Dish" %}
<div id="custom-dish-form" class="mt-4">
<h3>Create Your Custom Dish</h3>
<form method="POST" action="/customdish/generate_custom_dish">
<div class="mb-3">
<label for="custom-dish-name" class="form-label">Dish Name</label>
<input type="text" class="form-control" id="custom-dish-name" name="name" required>
</div>
<div class="mb-3 position-relative">
<label for="custom-dish-description" class="form-label">Dish Description</label>
<textarea class="form-control" id="custom-dish-description" name="description" required></textarea>
<div id="descriptionSuggestions" class="autocomplete-suggestions"></div>
</div>
<button type="submit" class="btn btn-primary">Submit Custom Dish</button>
</form>
</div>
{% else %}
{% if ordered_menu.items()|length == 0 %}
<p>No menu items available for this category.</p>
{% else %}
{% for section, items in ordered_menu.items() %}
<h3>{{ section }}</h3>
<div class="row">
{% for item in items %}
<div class="col-md-6 mb-4">
<div class="card menu-card" data-item-name="{{ item.Name | default('Unnamed Item') }}" data-item-section="{{ item.Section__c | default(section) }}">
<video class="card-img-top menu-video" muted loop preload="auto" data-src="{{ item.Video1__c | default('/static/placeholder.mp4') }}" poster="{{ item.Image1__c | default('/static/placeholder.jpg') }}" width="350" height="200" onmouseover="this.play()" onmouseout="this.pause(); this.currentTime = 0;" onerror="this.poster='/static/placeholder.jpg';">
<source src="{{ item.Video1__c | default('/static/placeholder.mp4') }}" type="video/mp4">
Your browser does not support the video tag.
</video>
<div class="addbutton">
<div class="card-body d-flex align-items-center justify-content-between">
<div>
<h5 class="card-title">{{ item.Name | default('Unnamed Item') }}</h5>
<p class="card-text price">${{ item.Price__c | default('0.00') }}</p>
</div>
<div class="d-flex flex-column align-items-center justify-content-center">
<div class="button-container" data-item-name="{{ item.Name | default('Unnamed Item') }}" data-item-price="{{ item.Price__c | default('0.00') }}" data-item-image="{{ item.Image1__c | default('/static/placeholder.jpg') }}" data-item-section="{{ item.Section__c | default(section) }}" data-item-category="{{ selected_category }}" data-item-description="{{ item.Description__c | default('No description') }}" data-item-image2="{{ item.Image2__c | default(item.Image1__c) }}">
{% if item.Section__c == 'Soft Drinks' %}
<button class="btn btn-primary add-to-cart-btn" onclick="showSoftDrinkModal(this)">ADD</button>
{% else %}
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#itemModal" onclick="showItemDetails('{{ item.Name | default('Unnamed Item') }}', '{{ item.Price__c | default('0.00') }}', '{{ item.Image2__c | default(item.Image1__c) }}', '{{ item.Description__c | default('No description') }}', '{{ item.Section__c | default(section) }}', '{{ selected_category }}')">ADD</button>
{% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' %}
<span class="customisable-text">Customisable</span>
{% endif %}
{% endif %}
</div>
</div>
</div>
</div>
{% if item.Section__c != 'Soft Drinks' %}
<div class="toggle-details" data-item-name="{{ item.Name | default('Unnamed Item') }}">Show Details</div>
<div class="item-details" id="details-{{ item.Name | default('unnamed-item') | replace(' ', '-') }}">
<h6>Description</h6>
<p>{{ item.Description__c | default('No description available') }}</p>
<h6>Ingredients</h6>
<p>{{ item.Ingredientsinfo__c | default('Not specified') }}</p>
<h6>Nutritional Info</h6>
<p class="nutritional-info">{{ item.NutritionalInfo__c | default('Not available') }}</p>
<h6>Allergens</h6>
<p>{{ item.Allergens__c | default('None listed') }}</p>
</div>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% endfor %}
{% endif %}
{% endif %}
</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>
<div class="modal fade" id="itemModal" tabindex="-1" aria-labelledby="itemModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="itemModalLabel">Item Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<img id="modal-img" class="img-fluid rounded mb-3 d-block mx-auto" alt="Item Image" style="max-height: 200px; object-fit: cover;">
<h5 id="modal-name" class="fw-bold text-center"></h5>
<p id="modal-price" class="text-muted text-center"></p>
<p id="modal-description" class="text-secondary"></p>
<div id="modal-addons" class="modal-addons mt-4">
<h5>Customization Options</h5>
<div id="addons-list" class="addons-container addon-loading"></div>
</div>
<div class="mt-4">
<h6>Special Instructions</h6>
<textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
</div>
<span id="modal-section" data-section="" data-category="" style="display: none;"></span>
</div>
<div class="modal-footer d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center gap-2">
<button type="button" class="btn btn-outline-secondary" id="decreaseQuantity">-</button>
<input type="text" class="form-control text-center" id="quantityInput" value="1" readonly style="width: 50px;"/>
<button type="button" class="btn btn-outline-secondary" id="increaseQuantity">+</button>
</div>
<button type="button" class="btn btn-primary" onclick="addToCartFromModal()">Add to Cart</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="softDrinkModal" tabindex="-1" aria-labelledby="softDrinkModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="softDrinkModalLabel">Select Quantity</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<img id="soft-drink-image" class="img-fluid rounded mb-3 d-block mx-auto" alt="Soft Drink Image">
<div class="text-center mb-3">
<h5 id="soft-drink-name"></h5>
<p id="soft-drink-price"></p>
</div>
<div class="quantity-controls">
<button type="button" class="btn" id="soft-drink-decrease" onclick="updateSoftDrinkQuantity(-1)" aria-label="Decrease quantity by 1">-</button>
<input type="text" class="form-control text-center" id="soft-drink-quantity" value="1" readonly aria-label="Selected quantity">
<button type="button" class="btn" id="soft-drink-increase" onclick="updateSoftDrinkQuantity(1)" aria-label="Increase quantity by 1">+</button>
</div>
</div>
<div class="modal-footer">
<div class="quantity-controls-footer">
<button type="button" class="btn" id="soft-drink-decrease-footer" onclick="updateSoftDrinkQuantity(-1)" aria-label="Decrease quantity by 1">-1</button>
<button type="button" class="btn" id="soft-drink-increase-footer" onclick="updateSoftDrinkQuantity(1)" aria-label="Increase quantity by 1">+1</button>
</div>
<button type="button" class="btn btn-primary" onclick="addSoftDrinkToCart()" aria-label="Add soft drink to cart">Add to Cart</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="micModal" tabindex="-1" aria-labelledby="micModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="micModalLabel">Speak Now</h5>
</div>
<div class="modal-body">
<i class="bi bi-mic" id="mic-icon-animation"></i>
<p id="mic-status" class="mt-3">Say the name of a menu item...</p>
<div id="mic-item-details" style="display: none;">
<img id="mic-item-image" class="img-fluid rounded mb-3 d-block mx-auto" alt="Spoken Item Image">
<h5 id="mic-item-name" class="fw-bold text-center"></h5>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="stopMicBtn" onclick="stopSpeechRecognition()">Stop</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script>
let isProcessingRequest = false;
let currentSoftDrinkButton = null;
let baseItemPrice = 0;
let recognition = null;
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 %}
];
const ingredientsList = [
"Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
"Chickpea Flour (Besan)", "Chickpea Flour (for batter)", "Chickpeas (Channa)", "Chili Powder",
"Chili Sauce", "Coconut Milk", "Coriander Powder", "Cornflour", "Cream", "Cumin Powder",
"Cumin Seeds", "Curd (Yogurt)", "Curry Leaves", "Fish (e.g., King Fish or Salmon)",
"Fresh Coriander Leaves", "Garam Masala", "Garlic", "Ghee (Clarified Butter)", "Ginger",
"Ginger-Garlic Paste", "Goat Meat (Mutton)", "Green Chilies", "Honey",
"Kasuri Methi (dried fenugreek leaves)", "Lemon Juice", "Mango Puree", "Mint Leaves",
"Mixed Vegetables (Carrot, Peas, Potato, Cauliflower)", "Mixed Vegetables (Carrot, Peas, Potato)",
"Mustard Seeds", "Mutton (Goat Meat)", "Oil", "Oil (for frying)", "Onion",
"Paneer (Indian Cottage Cheese)", "Peas", "Potatoes", "Prawns", "Red Chili Powder",
"Rice Flour", "Saffron", "Salt", "Soy Sauce", "Spring Onion", "Tamarind (for sourness)",
"Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
"Whole Wheat Flour", "Yogurt (Curd)"
];
function addToCartLocalStorage(payload) {
let cart = JSON.parse(localStorage.getItem('cart')) || [];
const existingItem = cart.find(item =>
item.itemName === payload.itemName &&
item.instructions === payload.instructions &&
JSON.stringify(item.addons) === JSON.stringify(payload.addons)
);
if (existingItem) {
existingItem.quantity += payload.quantity;
} else {
cart.push(payload);
}
localStorage.setItem('cart', JSON.stringify(cart));
return cart;
}
function removeFromCartLocalStorage(itemName, quantityToRemove, instructions, addons) {
let cart = JSON.parse(localStorage.getItem('cart')) || [];
const itemIndex = cart.findIndex(item =>
item.itemName === itemName &&
item.instructions === instructions &&
JSON.stringify(item.addons) === JSON.stringify(addons)
);
if (itemIndex !== -1) {
if (quantityToRemove >= cart[itemIndex].quantity) {
cart.splice(itemIndex, 1);
} else {
cart[itemIndex].quantity -= quantityToRemove;
}
}
localStorage.setItem('cart', JSON.stringify(cart));
return cart;
}
function getCartLocalStorage() {
return JSON.parse(localStorage.getItem('cart')) || [];
}
function updateModalPrice() {
const selectedAddOns = Array.from(
document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
).map(addon => parseFloat(addon.getAttribute('data-price')) || 0);
const totalAddOnPrice = selectedAddOns.reduce((sum, price) => sum + price, 0);
const totalPrice = baseItemPrice + totalAddOnPrice;
document.getElementById('modal-price').innerText = `$${totalPrice.toFixed(2)}`;
}
function updateSoftDrinkQuantity(delta) {
const quantityInput = document.getElementById('soft-drink-quantity');
let currentQuantity = parseInt(quantityInput.value) || 1;
currentQuantity = Math.max(1, currentQuantity + delta);
quantityInput.value = currentQuantity;
}
function showSoftDrinkModal(button) {
currentSoftDrinkButton = button;
const buttonContainer = button.closest('.button-container');
const itemName = buttonContainer.getAttribute('data-item-name');
const itemPrice = buttonContainer.getAttribute('data-item-price');
const itemImage = buttonContainer.getAttribute('data-item-image');
document.getElementById('soft-drink-name').textContent = itemName;
document.getElementById('soft-drink-price').textContent = `$${parseFloat(itemPrice).toFixed(2)}`;
document.getElementById('soft-drink-quantity').value = '1';
document.getElementById('soft-drink-image').src = itemImage || '/static/placeholder.jpg';
const modal = new bootstrap.Modal(document.getElementById('softDrinkModal'));
modal.show();
}
function addSoftDrinkToCart() {
if (!currentSoftDrinkButton) return;
const buttonContainer = currentSoftDrinkButton.closest('.button-container');
const quantity = parseInt(document.getElementById('soft-drink-quantity').value) || 1;
const itemName = buttonContainer.getAttribute('data-item-name');
const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
const itemImage = buttonContainer.getAttribute('data-item-image');
const section = buttonContainer.getAttribute('data-item-section');
const selectedCategory = buttonContainer.getAttribute('data-item-category');
const cartPayload = {
itemName: itemName,
itemPrice: itemPrice,
itemImage: itemImage,
section: section,
category: selectedCategory,
addons: [],
instructions: '',
quantity: quantity
};
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(cartPayload)
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateCartUI(data.cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
modal.hide();
} else {
console.error('Failed to add item to cart:', data.error);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
modal.hide();
}
})
.catch(err => {
console.error('Error adding item to cart:', err);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('softDrinkModal'));
modal.hide();
});
}
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 showItemDetails(name, price, image, description, section, selectedCategory) {
document.getElementById('modal-name').innerText = name;
baseItemPrice = parseFloat(price) || 0;
document.getElementById('modal-price').innerText = `$${baseItemPrice.toFixed(2)}`;
const modalImg = document.getElementById('modal-img');
modalImg.src = image || '/static/placeholder.jpg';
document.getElementById('modal-description').innerText = description || 'No description available.';
document.getElementById('addons-list').innerHTML = '';
document.getElementById('addons-list').classList.add('addon-loading');
document.getElementById('modal-instructions').value = '';
const modalSectionEl = document.getElementById('modal-section');
modalSectionEl.setAttribute('data-section', section);
modalSectionEl.setAttribute('data-category', selectedCategory);
document.getElementById('quantityInput').value = 1;
fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
.then(response => response.json())
.then(data => {
const addonsList = document.getElementById('addons-list');
addonsList.classList.remove('addon-loading');
addonsList.innerHTML = '';
if (!data.success || !data.addons || data.addons.length === 0) {
addonsList.innerHTML = '<p>No customization options available.</p>';
return;
}
data.addons.forEach(addon => {
const sectionDiv = document.createElement('div');
sectionDiv.classList.add('addon-section');
const title = document.createElement('h6');
title.innerText = addon.name;
sectionDiv.appendChild(title);
const optionsContainer = document.createElement('div');
optionsContainer.classList.add('addon-options');
addon.options.forEach((option, index) => {
const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
const listItem = document.createElement('div');
listItem.classList.add('form-check');
listItem.innerHTML = `
<input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}"
aria-label="Select ${option} for ${addon.name}">
<label class="form-check-label" for="${optionId}">
${option} ${addon.extra_charge ? `<span class="extra-charge">($${addon.extra_charge_amount.toFixed(2)})</span>` : ''}
</label>
`;
optionsContainer.appendChild(listItem);
});
sectionDiv.appendChild(optionsContainer);
addonsList.appendChild(sectionDiv);
});
const addonSections = addonsList.querySelectorAll('.addon-section');
addonSections.forEach(section => {
const title = section.querySelector('h6');
const options = section.querySelector('.addon-options');
title.addEventListener('click', () => {
section.classList.toggle('collapsed');
options.classList.toggle('collapsed');
});
});
document.querySelectorAll('.addon-option').forEach(checkbox => {
checkbox.addEventListener('change', updateModalPrice);
});
document.querySelectorAll('.addon-option').forEach(checkbox => {
checkbox.addEventListener('change', function () {
const groupName = this.getAttribute('data-group');
const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo", "Beverages", "Sauces"].includes(groupName);
if (!isMultiSelectGroup && this.checked) {
document.querySelectorAll(`.addon-option[data-group="${groupName}"]`).forEach(otherCheckbox => {
if (otherCheckbox !== this) {
otherCheckbox.checked = false;
}
});
}
});
});
})
.catch(err => {
console.error('Error fetching add-ons:', err);
document.getElementById('addons-list').classList.remove('addon-loading');
document.getElementById('addons-list').innerHTML = '<p>Error loading customization options.</p>';
});
}
function addToCartFromModal() {
if (isProcessingRequest) return;
isProcessingRequest = true;
const modalSectionEl = document.getElementById('modal-section');
const section = modalSectionEl.getAttribute('data-section');
const selectedartifactCategory = modalSectionEl.getAttribute('data-category');
const itemName = document.getElementById('modal-name').innerText;
const itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', '')) || 0;
const itemImage = document.getElementById('modal-img').src;
const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
const instructions = document.getElementById('modal-instructions').value;
const selectedAddOns = Array.from(
document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
).map(addon => ({
name: addon.getAttribute('data-name'),
price: parseFloat(addon.getAttribute('data-price')) || 0
}));
if (!itemName || isNaN(itemPrice) || !section || !itemImage || quantity < 1) {
console.error('Invalid cart item data:', { itemName, itemPrice, section, itemImage, quantity });
alert('Invalid item data. Please try again.');
isProcessingRequest = false;
return;
}
const cartPayload = {
itemName: itemName,
itemPrice: itemPrice,
itemImage: itemImage,
section: section,
category: selectedCategory,
addons: selectedAddOns,
instructions: instructions,
quantity: quantity
};
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(cartPayload)
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateCartUI(data.cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
modal.hide();
} else {
console.error('Failed to add item to cart:', data.error);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
modal.hide();
}
})
.catch(err => {
console.error('Error adding item to cart:', err);
const cart = addToCartLocalStorage(cartPayload);
updateCartUI(cart);
const modal = bootstrap.Modal.getInstance(document.getElementById('itemModal'));
modal.hide();
})
.finally(() => {
isProcessingRequest = false;
});
}
function handleToggle(source) {
const form = document.getElementById("filter-form");
const veg = document.getElementById("veg-toggle");
const custom = document.getElementById("category-CustomizedDish");
if (source === 'veg') {
if (veg.checked) {
custom.checked = false;
}
} else if (source === 'custom') {
if (custom.checked) {
veg.checked = false;
}
}
form.submit();
}
function stopSpeechRecognition() {
if (recognition) {
recognition.stop();
document.getElementById('micIcon').classList.remove('active');
const micModal = bootstrap.Modal.getInstance(document.getElementById('micModal'));
if (micModal) {
micModal.hide();
resetMicModal();
}
}
}
function resetMicModal() {
document.getElementById('mic-status').textContent = 'Say the name of a menu item...';
document.getElementById('mic-status').style.display = 'block';
document.getElementById('mic-item-details').style.display = 'none';
document.getElementById('mic-item-image').src = '';
document.getElementById('mic-item-name').textContent = '';
}
document.addEventListener('DOMContentLoaded', function () {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
if (SpeechRecognition) {
recognition = new SpeechRecognition();
recognition.continuous = false;
recognition.interimResults = false;
recognition.lang = 'en-US';
recognition.onstart = function () {
document.getElementById('micIcon').classList.add('active');
document.getElementById('mic-status').textContent = 'Listening...';
document.getElementById('mic-item-details').style.display = 'none';
const micModal = new bootstrap.Modal(document.getElementById('micModal'));
micModal.show();
};
recognition.onresult = function (event) {
const transcript = event.results[0][0].transcript.trim().toLowerCase();
document.getElementById('searchBar').value = transcript;
const menuCards = document.querySelectorAll('.menu-card');
let matchedItem = null;
let matchedCard = null;
menuCards.forEach(card => {
const itemName = card.getAttribute('data-item-name').toLowerCase();
const itemSection = card.getAttribute('data-item-section');
if (itemName.includes(transcript) || transcript.includes(itemName)) {
matchedItem = menuItems.find(item =>
item.name.toLowerCase() === card.getAttribute('data-item-name').toLowerCase() &&
item.section === itemSection
);
matchedCard = card;
}
});
const micModal = bootstrap.Modal.getInstance(document.getElementById('micModal'));
if (matchedItem && matchedCard) {
document.getElementById('mic-status').style.display = 'none';
const micItemDetails = document.getElementById('mic-item-details');
const micItemImage = document.getElementById('mic-item-image');
const micItemName = document.getElementById('mic-item-name');
micItemImage.src = matchedItem.image || '/static/placeholder.jpg';
micItemName.textContent = matchedItem.name;
micItemDetails.style.display = 'block';
matchedCard.classList.add('highlighted');
matchedCard.scrollIntoView({ behavior: 'smooth', block: 'center' });
const toggleLink = matchedCard.querySelector('.toggle-details');
if (toggleLink) {
toggleLink.click();
}
const buttonContainer = matchedCard.querySelector('.button-container');
if (buttonContainer) {
const section = buttonContainer.getAttribute('data-item-section');
setTimeout(() => {
micModal.hide();
if (section === 'Soft Drinks') {
showSoftDrinkModal(buttonContainer.querySelector('.add-to-cart-btn'));
} else {
const name = buttonContainer.getAttribute('data-item-name');
const price = buttonContainer.getAttribute('data-item-price');
const image = buttonContainer.getAttribute('data-item-image2');
const description = buttonContainer.getAttribute('data-item-description');
const category = buttonContainer.getAttribute('data-item-category');
showItemDetails(name, price, image, description, section, category);
const itemModal = new bootstrap.Modal(document.getElementById('itemModal'));
itemModal.show();
}
resetMicModal();
}, 1500);
}
} else {
document.getElementById('mic-status').textContent = 'No matching item found. Try again...';
setTimeout(() => {
micModal.hide();
resetMicModal();
alert('No matching menu item found for: ' + transcript);
}, 1500);
}
};
recognition.onerror = function (event) {
console.error('Speech recognition error:', event.error);
document.getElementById('mic-status').textContent = 'Error occurred. Please try again.';
document.getElementById('micIcon').classList.remove('active');
const micModal = bootstrap.Modal.getInstance(document.getElementById('micModal'));
setTimeout(() => {
micModal.hide();
resetMicModal();
alert('Speech recognition failed: ' + event.error);
}, 1500);
};
recognition.onend = function () {
document.getElementById('micIcon').classList.remove('active');
const micModal = bootstrap.Modal.getInstance(document.getElementById('micModal'));
if (micModal && !matchedItem) {
micModal.hide();
resetMicModal();
}
};
}
document.getElementById('micIcon').addEventListener('click', function () {
if (!recognition) {
alert('Speech recognition is not supported in this browser.');
return;
}
if (this.classList.contains('active')) {
stopSpeechRecognition();
} else {
resetMicModal();
this.classList.add('active');
recognition.start();
}
});
document.getElementById('increaseQuantity').addEventListener('click', function () {
const quantityInput = document.getElementById('quantityInput');
let quantity = parseInt(quantityInput.value) || 1;
quantityInput.value = quantity + 1;
});
document.getElementById('decreaseQuantity').addEventListener('click', function () {
const quantityInput = document.getElementById('quantityInput');
let quantity = parseInt(quantityInput.value) || 1;
if (quantity > 1) {
quantityInput.value = quantity - 1;
}
});
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');
searchBar.addEventListener('click', function () {
window.location.href = '/search';
});
const selectedItem = localStorage.getItem('selectedItem');
if (selectedItem) {
try {
const { name, section } = JSON.parse(selectedItem);
const menuCards = document.querySelectorAll('.menu-card');
let targetCard = null;
let buttonContainer = null;
menuCards.forEach(card => {
const itemName = card.getAttribute('data-item-name');
const itemSection = card.getAttribute('data-item-section');
if (itemName === name && itemSection === section) {
targetCard = card;
buttonContainer = card.querySelector('.button-container');
card.classList.add('highlighted');
card.scrollIntoView({ behavior: 'smooth', block: 'center' });
const toggleLink = card.querySelector('.toggle-details');
if (toggleLink) {
toggleLink.click();
}
buttonContainer = card.querySelector('.button-container');
}
});
if (buttonContainer) {
const section = buttonContainer.getAttribute('data-item-section');
if (section === 'Soft Drinks') {
showSoftDrinkModal(buttonContainer.querySelector('.add-to-cart-btn'));
} else {
const name = buttonContainer.getAttribute('data-item-name');
const price = buttonContainer.getAttribute('data-item-price');
const image = buttonContainer.getAttribute('data-item-image2');
const description = buttonContainer.getAttribute('data-item-description');
const category = buttonContainer.getAttribute('data-item-category');
showItemDetails(name, price, image, description, section, category);
const itemModal = new bootstrap.Modal(document.getElementById('itemModal'));
itemModal.show();
}
}
localStorage.removeItem('selectedItem');
} catch (error) {
console.error('Error parsing selectedItem from localStorage:', error);
localStorage.removeItem('selectedItem');
}
}
const menuVideos = document.querySelectorAll('.menu-video');
menuVideos.forEach(video => {
const src = video.getAttribute('data-src');
if (src) {
video.src = src;
video.load();
video.addEventListener('loadeddata', () => {
video.classList.add('loaded');
});
video.addEventListener('error', () => {
console.error('Error loading video:', src);
video.poster = video.poster || '/static/placeholder.jpg';
});
}
});
const menuCards = document.querySelectorAll('.menu-card');
menuCards.forEach((card, index) => {
setTimeout(() => {
card.classList.add('visible');
}, index * 100);
});
const toggleLinks = document.querySelectorAll('.toggle-details');
toggleLinks.forEach(link => {
link.addEventListener('click', function () {
const itemName = this.getAttribute('data-item-name').replace(/\s+/g, '-');
const details = document.getElementById(`details-${itemName}`);
if (details) {
details.classList.toggle('show');
this.textContent = details.classList.contains('show') ? 'Hide Details' : 'Show Details';
}
});
});
function updateDescriptionSuggestions(input) {
const suggestionsContainer = document.getElementById('descriptionSuggestions');
suggestionsContainer.innerHTML = '';
if (input.length === 0) {
suggestionsContainer.style.display = 'none';
return;
}
const filteredIngredients = ingredientsList.filter(ingredient =>
ingredient.toLowerCase().includes(input.toLowerCase())
);
if (filteredIngredients.length === 0) {
suggestionsContainer.style.display = 'none';
return;
}
filteredIngredients.forEach(ingredient => {
const suggestion = document.createElement('div');
suggestion.classList.add('suggestion-item');
suggestion.textContent = ingredient;
suggestion.addEventListener('click', () => {
const textarea = document.getElementById('custom-dish-description');
const currentText = textarea.value;
const lastCommaIndex = currentText.lastIndexOf(',');
const baseText = lastCommaIndex === -1 ? '' : currentText.substring(0, lastCommaIndex + 1);
textarea.value = baseText ? `${baseText} ${ingredient}` : ingredient;
suggestionsContainer.style.display = 'none';
});
suggestionsContainer.appendChild(suggestion);
});
suggestionsContainer.style.display = 'block';
}
const descriptionInput = document.getElementById('custom-dish-description');
if (descriptionInput) {
descriptionInput.addEventListener('input', function () {
const input = this.value;
const lastCommaIndex = input.lastIndexOf(',');
const currentWord = input.substring(lastCommaIndex + 1).trim();
updateDescriptionSuggestions(currentWord);
});
document.addEventListener('click', function (event) {
const suggestionsContainer = document.getElementById('descriptionSuggestions');
if (!descriptionInput.contains(event.target) && !suggestionsContainer.contains(event.target)) {
suggestionsContainer.style.display = 'none';
}
});
}
updateCartUI(getCartLocalStorage());
});
</script>
</body>
</html>