geethareddy commited on
Commit
5977d7a
·
verified ·
1 Parent(s): 480cb3f

Update templates/menu.html

Browse files
Files changed (1) hide show
  1. templates/menu.html +728 -724
templates/menu.html CHANGED
@@ -7,478 +7,482 @@
7
  <!-- Bootstrap CSS -->
8
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
9
  <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
10
- <style>
11
- body {
12
- font-family: Arial, sans-serif;
13
- background-color: #fdf4e3; /* Updated background color */
14
- margin: 0;
15
- padding: 0;
16
- display: flex;
17
- flex-direction: column;
18
- }
19
- .container {
20
- max-width: 900px;
21
- }
22
- .menu-card {
23
- max-width: 350px;
24
- border-radius: 15px;
25
- overflow: hidden;
26
- background-color: #fff;
27
- margin: auto;
28
- display: flex;
29
- flex-direction: column;
30
- }
31
- .menu-image {
32
- height: 200px; /* Fixed height */
33
- width: 100%; /* Full width of the card */
34
- object-fit: fill; /* Ensure the image covers the area and maintains the aspect ratio */
35
- border-radius: 15px 15px 0 0; /* Rounded top corners */
36
- }
37
- .card-title {
38
- font-size: 1.2rem;
39
- font-weight: bold;
40
- margin: 10px 0;
41
- }
42
- .card-text {
43
- font-size: 1rem;
44
- color: #6c757d;
45
- }
46
- .btn-primary {
47
- font-size: 13px;
48
- font-weight: bold;
49
- border-radius: 5px;
50
- width: 100px;
51
- background-color: #0FAA39; /* Updated button background color */
52
- border-color: #0FAA39;
53
- }
54
- .btn-primary:hover {
55
- background-color: #0FAA39;
56
- border-color: #0FAA39;
57
- }
58
- .btn-primary:active,
59
- .btn-primary:focus {
60
- background-color: #0FAA39;
61
- border-color: #ffffff;
62
- box-shadow: none;
63
- }
64
- .view-cart-container {
65
- position: fixed;
66
- bottom: 20px;
67
- right: 20px;
68
- z-index: 999;
69
- }
70
- .view-cart-button {
71
- background-color: #0FAA39; /* Updated View Cart button background color */
72
- color: #fff;
73
- padding: 10px 20px;
74
- border-radius: 30px;
75
- font-size: 1rem;
76
- font-weight: bold;
77
- text-decoration: none;
78
- box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
79
- display: flex;
80
- align-items: center;
81
- justify-content: center;
82
- }
83
- .view-cart-button:hover {
84
- background-color: #109835; /* Slightly darker shade for hover effect */
85
- text-decoration: none;
86
- }
87
- .avatar-dropdown-container {
88
- position: relative;
89
- }
90
- .avatar-icon {
91
- width: 40px;
92
- height: 40px;
93
- border-radius: 50%;
94
- background-color: #5bbfc1;
95
- cursor: pointer;
96
- display: flex;
97
- align-items: center;
98
- justify-content: center;
99
- color: white;
100
- font-size: 20px;
101
- font-weight: bold;
102
- }
103
- .dropdown-menu {
104
- position: absolute;
105
- right: 0;
106
- top: 100%;
107
- background-color: #fff;
108
- border-radius: 5px;
109
- width: 200px; /* Adjust width as needed */
110
- box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
111
- display: none;
112
- }
113
- .avatar-dropdown-container:hover .dropdown-menu {
114
- display: block;
115
- }
116
- .avatar-dropdown-container {
117
- position: absolute;
118
- right: 20px; /* Adjust the value as needed to position it properly */
119
- top: 50%; /* Adjust top to place it within the header */
120
- transform: translateY(-50%); /* Correct the alignment to be perfectly centered */
121
- display: flex;
122
- align-items: right;
123
- justify-content: center;
124
- }
125
-
126
- .dropdown-menu .dropdown-item {
127
- padding: 10px 15px;
128
- text-decoration: none;
129
- color: #333;
130
- border-bottom: 1px solid #ddd;
131
- display: block; /* Make each item stack vertically */
132
- }
133
- .dropdown-menu .dropdown-item:last-child {
134
- border-bottom: none; /* Remove the bottom border from the last item */
135
- }
136
- .dropdown-menu .dropdown-item:hover {
137
- background-color: #f1f1f1;
138
- }
139
- .fixed-search-container {
140
- position: absolute;
141
- top: 90px; /* Move it slightly lower */
142
- left: 50%;
143
- transform: translateX(-50%);
144
- width: 80%;
145
- max-width: 600px;
146
- z-index: 999; /* Keep it above content */
147
- background-color: white;
148
- padding: 10px;
149
- border-radius: 25px;
150
- box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
151
- }
152
- /* Ensure the category filter dropdown does not overlap */
153
- form.text-center.mb-4 {
154
- margin-top: 10px; /* No margin at the top */
155
- margin-bottom: 0px; /* Small space at the bottom */
156
- }
157
- /* Ensure the container has enough margin so nothing is overlapped */
158
- .container {
159
- margin-top: 10px; /* Adjust spacing based on navbar and search bar */
160
- padding-top: 0 !important; /* Ensure no padding is added by default */
161
- }
162
- h1.text-center {
163
- margin-top: 10px; /* Reduced space above */
164
- padding-top: 0 !important; /* Removed padding */
165
- font-weight: semi-bold; /* Make the "Menu" text bold */
166
- }
167
- .fixed-top-bar {
168
- /* Remove the fixed positioning */
169
- position: relative; /* Change from fixed to relative */
170
- top: 0;
171
- left: 0;
172
- width: 100%;
173
- height: 54px;
174
- background-color: #FF6B35;
175
- color: white;
176
- padding: 15px;
177
- display: flex;
178
- justify-content: space-between;
179
- align-items: center; /* Vertically align items */
180
- z-index: 1000; /* Make sure it's still above other content */
181
- }
182
- .search-bar-container {
183
- padding: 10px;
184
- position: absolute;
185
- left: 20px;
186
- top: 50%;
187
- transform: translateY(-50%);
188
- display: flex;
189
- justify-content: flex-start;
190
- align-items: center;
191
- width: 300px; /* Adjust width as needed */
192
- }
193
- .search-bar-container input {
194
- width: 85%;
195
- padding: 8px 10px 8px 30px; /* Add padding for the icon */
196
- font-size: 16px;
197
- border-radius: 10px;
198
- border: none;
199
- }
200
- .search-icon {
201
- position: absolute;
202
- left: 15px; /* Position the icon inside the input box */
203
- font-size: 20px;
204
- color: #888; /* Icon color */
205
- }
206
- /* Style for customization sections */
207
- .addon-section {
208
- background-color: #fff; /* Light gray background */
209
- border: 2px solid #6c757d; /* Border color */
210
- border-radius: 8px;
211
- padding: 12px;
212
- margin-bottom: 10px; /* Spacing between sections */
213
- }
214
- /* Customization section title */
215
- .addon-section h6 {
216
- margin-bottom: 10px;
217
- font-size: 1.1rem;
218
- font-weight: bold;
219
- color: #343a40; /* Darker title text */
220
- }
221
- /* Style for add-on checkboxes */
222
- .addon-section .form-check {
223
- display: inline-flex; /* Display checkboxes horizontally */
224
- align-items: center; /* Align checkboxes and labels */
225
- margin-left: 10px; /* Space between checkboxes */
226
- color: #343a40; /* Darker text color */
227
- }
228
- /* Customize the default checkbox */
229
- .addon-section .form-check-input {
230
- -webkit-appearance: none; /* Remove default checkbox styling in Webkit browsers (e.g. Chrome, Safari) */
231
- -moz-appearance: none; /* Remove default checkbox styling in Firefox */
232
- appearance: none; /* Remove default checkbox styling in all browsers */
233
- width: 20px;
234
- height: 20px;
235
- border: 2px solid #343a40; /* Darker border color */
236
- border-radius: 5px; /* Rounded corners */
237
- background-color: #f0f0f0; /* Lighter gray background when unchecked */
238
- position: relative;
239
- margin-right: 10px; /* Add space between the checkbox and label */
240
- }
241
-
242
- /* Checked state for the custom checkbox */
243
- .addon-section .form-check-input:checked {
244
- background-color: #006400; /* Dark green background when checked */
245
- border-color: #006400; /* Dark green border when checked */
246
- }
247
- /* Add the check mark when checkbox is checked */
248
- .addon-section .form-check-input:checked::before {
249
- content: ''; /* Unicode check mark */
250
- font-size: 14px;
251
- position: absolute;
252
- top: 3px;
253
- left: 4px;
254
- color: white; /* White color for the check mark */
255
- }
256
- /* Hover effect for the checkboxes */
257
- .addon-section .form-check-input:hover {
258
- /* background-color: #006400; /* Slightly darker background on hover */
259
- }
260
- /* Focus effect on custom checkbox */
261
- .addon-section .form-check-input:focus {
262
- outline: none;
263
- box-shadow: 0 0 0 2px #006400; /* Green focus outline */
264
- }
265
- /* Custom checkbox label styles */
266
- .addon-section .form-check-label {
267
- font-size: 16px;
268
- margin-left: 5px;
269
- cursor: pointer;
270
- display: inline-block; /* Ensure label aligns correctly with checkbox */
271
- vertical-align: middle; /* Align text vertically with the checkbox */
272
- }
273
- /* Fix alignment of text and checkbox */
274
- .addon-section .form-check input[type="checkbox"],
275
- .addon-section .form-check label {
276
- display: inline-block;
277
- /* vertical-align: middle; /* Align text and checkboxes vertically */
278
- }
279
- /* Category Filter with Custom Radio Buttons */
280
- form.text-center.mb-4 {
281
- display: flex;
282
- flex-direction: column;
283
- align-items: center;
284
- justify-content: center;
285
- margin-bottom: 5px; /* Reduce bottom margin */
286
- }
287
- .form-check {
288
- display: inline-block;
289
- margin-right: 5px; /* Reduced space between radio button and label */
290
- margin-bottom: 0; /* Remove bottom margin */
291
- margin-top: 10px; /* Adds space between categories and Customized Dish */
292
- vertical-align: middle; /* Align radio buttons vertically */
293
- }
294
- .form-check-inline {
295
- display: inline-block;
296
- margin-right: 5px; /* Decrease space between each radio button */
297
- }
298
- .form-check-label {
299
- display: inline-block;
300
- font-size: 16px;
301
- margin-left: 5px; /* Spacing between radio button and label */
302
- vertical-align: middle; /* Align label vertically */
303
- }
304
- form-check-input addon-option{
305
- color: #333d47;
306
- }
307
- .custom-radio {
308
- appearance: none;
309
- -webkit-appearance: none;
310
- -moz-appearance: none;
311
- width: 20px;
312
- height: 20px;
313
- border: 3px solid #4CAF50; /* Green border */
314
- border-radius: 50%;
315
- margin-right: -5px; /* Reduced spacing between button and label */
316
- outline: none;
317
- cursor: pointer;
318
- position: relative;
319
- display: inline-block;
320
- vertical-align: middle; /* Align vertically with text */
321
- }
322
- .custom-radio:checked {
323
- background-color: #4CAF50; /* Green color when checked */
324
- border-color: #4CAF50; /* Matching border color */
325
- }
326
- .custom-radio:checked::after {
327
- content: '';
328
- position: relative;
329
- top: 5px;
330
- left: 5px;
331
- border-radius: 50%;
332
- }
333
- .custom-radio:hover {
334
- border-color: #388E3C;
335
- }
336
- /* Optional: Style the labels */
337
- .form-check-label {
338
- font-size: 16px;
339
- margin-left: 8px; /* Space between the radio button and the label */
340
- }
341
- .cart-container {
342
- display: flex;
343
- align-items: center;
344
- gap: 10px;
345
- }
346
- .modal-footer {
347
- display: flex;
348
- align-items: center;
349
- justify-content: space-between; /* Space between quantity and Add to Cart button */
350
- padding: 10px;
351
- }
352
- .modal-footer .d-flex {
353
- display: flex;
354
- align-items: center;
355
- gap: 10px; /* Space between quantity buttons */
356
- }
357
- .modal-footer .btn {
358
- height: 40px; /* Set consistent button height */
359
- padding: 0 15px; /* Adjust padding to fit inside the buttons */
360
- }
361
- .modal-footer .form-control {
362
- width: 50px; /* Fixed width for quantity input */
363
- height: 40px; /* Match the height of buttons */
364
- text-align: center; /* Center the value inside the input */
365
- }
366
- .modal-footer .btn-primary {
367
- background-color: #0FAA39; /* Green background for Add to Cart button */
368
- border-color: #0FAA39; /* Border color to match button background */
369
- font-weight: bold; /* Bold text */
370
- padding: 10px 20px; /* Adjust padding to make the button look better */
371
- height: 40px; /* Match the height with quantity buttons */
372
- display: flex;
373
- justify-content: center;
374
- align-items: center;
375
- width: auto; /* Auto width to adjust to button text */
376
- }
377
- .modal-footer .btn-outline-secondary {
378
- height: 40px; /* Ensure quantity buttons are the same size */
379
- width: 40px; /* Make sure the buttons are square */
380
- }
381
- @media (max-width: 576px) {
382
- /* Responsive adjustments for smaller screens */
383
- .modal-dialog {
384
- max-width: 98%; /* Adjust modal width for smaller screens */
385
- }
386
- .modal-footer .btn {
387
- height: 35px; /* Smaller buttons for small screens */
388
- }
389
- .modal-footer .form-control {
390
- width: 40px; /* Adjust input size for smaller screens */
391
- height: 35px;
392
- }
393
- }
394
- </style>
 
 
 
 
395
  </head>
396
  <body>
397
 
398
- <div class="fixed-top-bar">
399
- <!-- Avatar and Dropdown -->
400
- <div class="avatar-dropdown-container">
401
- <div class="avatar-icon">
402
- <span>{{ first_letter }}</span> <!-- Display the first letter of the customer's name -->
403
- </div>
404
- <div class="dropdown-menu">
405
- <a href="{{ url_for('customer_details') }}" class="dropdown-item">View Profile</a>
406
- <a href="{{ url_for('order_history') }}" class="dropdown-item">Order History</a>
407
- <a href="{{ url_for('logout') }}" class="dropdown-item">Logout</a>
 
408
  </div>
409
- </div>
410
 
411
- <!-- Search Bar Section -->
412
- <div class="search-bar-container">
413
- <input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." onkeyup="filterMenu()">
414
- <i class="bi bi-search search-icon"></i> <!-- Search icon inside the input -->
 
415
  </div>
416
- </div>
417
 
418
- <!-- Category Filter with Custom Radio Buttons -->
419
- <form method="get" action="/menu" class="text-center mb-4">
420
- <label class="form-label fw-bold">Select a Category:</label>
421
- <div class="form-check form-check-inline">
422
- {% for category in categories %}
423
- <input type="radio" id="category-{{ category }}" name="category" value="{{ category }}" class="custom-radio"
424
- {% if selected_category == category %}checked{% endif %} onchange="this.form.submit()">
425
- <label class="form-check-label" for="category-{{ category }}">{{ category }}</label>
426
- {% endfor %}
427
- </div>
428
- <!-- Separate Customized Dish radio button in a new div to align it properly -->
429
- <div class="form-check">
430
- <input type="radio" id="category-CustomizedDish" name="category" value="Customized Dish" class="custom-radio"
431
- {% if selected_category == "Customized Dish" %}checked{% endif %} onchange="this.form.submit()">
432
- <label class="form-check-label" for="category-CustomizedDish">Customized Dish</label>
433
- </div>
434
- </form>
435
 
436
- <!-- Show menu items only when Customized Dish is not selected -->
437
  <div class="container mt-4">
438
  <h1 class="text-center">Menu</h1>
439
 
440
- <!-- Display text boxes for Customized Dish -->
441
- {% if selected_category == "Customized Dish" %}
442
- <div id="custom-dish-form" class="mt-4">
443
- <h3>Create Your Custom Dish</h3>
444
- <form method="POST" action="/generate_custom_dish">
445
- <div class="mb-3">
446
- <label for="custom-dish-name" class="form-label">Dish Name</label>
447
- <input type="text" class="form-control" id="custom-dish-name" name="name" required>
448
- </div>
449
- <div class="mb-3">
450
- <label for="custom-dish-description" class="form-label">Dish Description</label>
451
- <textarea class="form-control" id="custom-dish-description" name="description" required></textarea>
 
 
 
452
  </div>
453
- <button type="submit" class="btn btn-primary">Submit</button>
454
- </form>
455
- </div>
456
- {% else %}
457
 
458
- <!-- Menu Sections -->
459
- {% for section, items in ordered_menu.items() %}
460
- <h3>{{ section }}</h3>
461
- <div class="row">
462
- {% for item in items %}
463
- <div class="col-md-6 mb-4">
464
- <div class="card menu-card">
465
- <img src="{{ item.Image1__c }}" class="card-img-top menu-image" alt="{{ item.Name }}" onerror="this.src='/static/placeholder.jpg';">
466
- <div class="card-body">
467
- <h5 class="card-title">{{ item.Name }}</h5>
468
- <p class="card-text">${{ item.Price__c }}</p>
469
- <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#itemModal"
470
- onclick="showItemDetails('{{ item.Name }}', '{{ item.Price__c }}', '{{ item.Image2__c }}', '{{ item.Description__c }}', '{{ item.Section__c }}','{{ selected_category }}')">
471
- Add
472
- </button>
 
 
473
  </div>
474
  </div>
475
- </div>
476
- {% endfor %}
477
- </div>
478
- {% endfor %}
479
- </div>
480
- {% endif %}
481
-
482
  </div>
483
 
484
  <!-- View Cart Button -->
@@ -488,316 +492,316 @@ form-check-input addon-option{
488
  </a>
489
  </div>
490
 
491
- <!-- Modal for Item Details -->
492
- <div class="modal fade" id="itemModal" tabindex="-1" aria-labelledby="itemModalLabel" aria-hidden="true">
493
- <div class="modal-dialog modal-dialog-centered">
494
- <div class="modal-content">
495
- <div class="modal-header">
496
- <h5 class="modal-title" id="itemModalLabel">Item Details</h5>
497
- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
498
- </div>
499
- <div class="modal-body">
500
- <!-- Item Image -->
501
- <img id="modal-img" class="img-fluid rounded mb-3 d-block mx-auto" alt="Item Image" style="max-height: 200px; object-fit: cover;">
502
- <!-- Item Name -->
503
- <h5 id="modal-name" class="fw-bold text-center"></h5>
504
- <!-- Item Price -->
505
- <p id="modal-price" class="text-muted text-center"></p>
506
- <!-- Item Description -->
507
- <p id="modal-description" class="text-secondary"></p>
508
- <!-- Add-ons -->
509
- <div id="modal-addons" class="modal-addons mt-4">
510
- <h6>Customization Options</h6>
511
- <div id="addons-list" class="addons-container">Loading customization options...</div>
512
  </div>
513
- <div class="mt-4">
514
- <h6>Custom Request</h6>
515
- <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
516
  </div>
517
- <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
518
- </div>
519
- <!-- Quantity Controls and Add to Cart Button -->
520
- <div class="modal-footer d-flex align-items-center justify-content-between">
521
- <!-- Quantity Controls -->
522
- <div class="d-flex align-items-center gap-2">
523
- <button type="button" class="btn btn-outline-secondary" id="decreaseQuantity">-</button>
524
- <input type="text" class="form-control text-center" id="quantityInput" value="1" readonly style="width: 50px;"/>
525
- <button type="button" class="btn btn-outline-secondary" id="increaseQuantity">+</button>
 
526
  </div>
527
- <!-- Add to Cart Button -->
528
- <button type="button" class="btn btn-primary" onclick="addToCartFromModal()">Add to Cart</button>
529
  </div>
530
  </div>
531
  </div>
532
- </div>
533
 
534
- <!-- JavaScript -->
535
- <script>
536
- // Show item details and fetch customization options
537
- function showItemDetails(name, price, image, description, section, selectedCategory) {
538
- document.getElementById('modal-name').innerText = name;
539
- document.getElementById('modal-price').innerText = `$${price}`;
540
- document.getElementById('modal-img').src = image || '/static/placeholder.jpg';
541
- document.getElementById('modal-description').innerText = description || 'No description available.';
542
- document.getElementById('addons-list').innerHTML = 'Loading customization options...';
543
- document.getElementById('modal-instructions').value = '';
544
 
545
- const modalSectionEl = document.getElementById('modal-section');
546
- modalSectionEl.setAttribute('data-section', section);
547
- modalSectionEl.setAttribute('data-category', selectedCategory);
548
 
549
- // Set the default quantity to 1
550
- document.getElementById('quantityInput').value = 1;
551
 
552
- // Fetch customization options based on the section
553
- fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
554
- .then(response => response.json())
555
- .then(data => {
556
- const addonsList = document.getElementById('addons-list');
557
- addonsList.innerHTML = ''; // Clear previous content
558
 
559
- if (!data.success || !data.addons || data.addons.length === 0) {
560
- addonsList.innerHTML = '<p>No customization options available.</p>';
561
- return;
562
- }
563
 
564
- // Display customization options inside styled divs
565
- data.addons.forEach(addon => {
566
- const sectionDiv = document.createElement('div');
567
- sectionDiv.classList.add('addon-section'); // Add styling class
568
 
569
- // Add section title
570
- const title = document.createElement('h6');
571
- title.innerText = addon.name;
572
- sectionDiv.appendChild(title);
573
 
574
- // Create options list
575
- const optionsContainer = document.createElement('div');
576
- addon.options.forEach((option, index) => {
577
- const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
578
- const listItem = document.createElement('div');
579
- listItem.classList.add('form-check');
580
- listItem.innerHTML = `
581
- <input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
582
- data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}">
583
- <label class="form-check-label" for="${optionId}">
584
- ${option} ${addon.extra_charge ? `($${addon.extra_charge_amount})` : ''}
585
- </label>
586
- `;
587
- optionsContainer.appendChild(listItem);
 
 
 
588
  });
589
- sectionDiv.appendChild(optionsContainer);
590
- addonsList.appendChild(sectionDiv);
 
 
591
  });
592
- })
593
- .catch(err => {
594
- console.error('Error fetching add-ons:', err);
595
- document.getElementById('addons-list').innerHTML = '<p>Error loading customization options.</p>';
596
- });
597
- }
598
 
599
- // Handle single-select/deselect logic for checkbox groups in all modals
600
- document.addEventListener('click', function(event) {
601
- if (event.target.classList.contains('addon-option')) {
602
- handleAddonClick(event.target);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  }
604
- });
605
 
606
- // Handle checkbox selection logic
607
- function handleAddonClick(checkbox) {
608
- const groupName = checkbox.getAttribute('data-group');
609
- const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides","Select Dip/Sauce","Extra Add-ons","Make it a Combo"].includes(groupName);
 
 
 
 
 
 
610
 
611
- // If it's not multi-select, uncheck all other checkboxes in the same group
612
- if (!isMultiSelectGroup) {
613
- const checkboxes = document.querySelectorAll(`.addon-option[data-group="${groupName}"]`);
614
- checkboxes.forEach(otherCheckbox => {
615
- if (otherCheckbox !== checkbox) {
616
- otherCheckbox.checked = false;
617
  }
618
  });
619
- }
620
- }
621
- function filterMenu() {
622
- let input = document.getElementById('searchBar').value.toLowerCase(); // Get the value from search bar
623
- let sections = document.querySelectorAll('h3'); // Select section headers
624
- let items = document.querySelectorAll('.menu-card'); // Select all items
625
- let matchedSections = new Set(); // Store matched sections
626
-
627
- // Hide all items initially
628
- items.forEach(item => {
629
- let itemName = item.querySelector('.card-title').innerText.toLowerCase(); // Get item name
630
- let itemSection = item.closest('.row').previousElementSibling.innerText.toLowerCase(); // Get section name
631
 
632
- // If the search matches item name or section, show the item
633
- if (itemName.includes(input) || (itemSection && itemSection.includes(input))) {
634
- item.style.display = 'block'; // Show item if it matches search
635
- matchedSections.add(item.closest('.row')); // Add section to matched list
636
- } else {
637
- item.style.display = 'none'; // Hide item if not matched
638
- }
639
- });
640
-
641
- // Show or hide sections based on matched items
642
- sections.forEach(section => {
643
- let sectionRow = section.nextElementSibling; // The row containing items
644
- if (matchedSections.has(sectionRow)) {
645
- section.style.display = 'block'; // Show section header
646
- sectionRow.style.display = 'flex'; // Show section items
647
- } else {
648
- section.style.display = 'none'; // Hide section header
649
- sectionRow.style.display = 'none'; // Hide section items
650
- }
651
- });
652
- }
653
 
654
- function addToCartFromModal() {
655
- const itemName = document.getElementById('modal-name').innerText;
656
- let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
657
 
658
- // Validate item price
659
- if (isNaN(itemPrice)) {
660
- alert('Invalid price for the item. Please check the item details.');
661
- return;
662
- }
663
 
664
- const itemImage = document.getElementById('modal-img').src;
665
- console.log(itemName, itemPrice, itemImage); // Log values for debugging
666
- const modalSectionEl = document.getElementById('modal-section');
667
- const section = modalSectionEl.getAttribute('data-section');
668
- const selectedCategory = modalSectionEl.getAttribute('data-category');
669
- if (!itemName || !itemPrice || !section || !itemImage) {
670
- console.error('Missing data for cart item:', { itemName, itemPrice, section, itemImage});
671
- return;
672
- }
673
 
674
- // Collect selected add-ons
675
- let selectedAddOns = Array.from(
676
- document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
677
- ).map(addon => ({
678
- name: addon.getAttribute('data-name') || 'Default Name', // Fallback Name
679
- price: parseFloat(addon.getAttribute('data-price') || 0)
680
- }));
681
 
682
- // Get the selected quantity
683
- const quantity = parseInt(document.getElementById('quantityInput').value) || 1; // Default to 1 if invalid
684
 
685
- const instructions = document.getElementById('modal-instructions').value;
686
 
687
- // Prepare data for the cart
688
- const cartPayload = {
689
- itemName: itemName,
690
- itemPrice: itemPrice,
691
- itemImage: itemImage,
692
- section: section,
693
- category: selectedCategory,
694
- addons: selectedAddOns,
695
- instructions: instructions,
696
- quantity: quantity // Include the quantity
697
- };
698
 
699
- // Send the cart data to the server
700
- fetch('/cart/add', {
701
- method: 'POST',
702
- headers: {
703
- 'Content-Type': 'application/json',
704
- },
705
- body: JSON.stringify(cartPayload)
706
- })
707
- .then(response => response.json())
708
- .then(data => {
709
- if (data.success) {
710
- alert('Item added to cart successfully!');
711
- updateCartUI(data.cart); // Update cart UI after adding an item
712
- const modal = document.getElementById('itemModal');
713
- const modalInstance = bootstrap.Modal.getInstance(modal);
714
- modalInstance.hide();
715
- } else {
716
- alert(data.error || 'Failed to add item to cart.');
717
- }
718
- })
719
- .catch(err => {
720
- console.error('Error adding item to cart:', err);
721
- alert('An error occurred while adding the item to the cart.');
722
- });
723
- }
724
 
725
- function updateCartUI(cart) {
726
- if (!Array.isArray(cart)) {
727
- console.error('Invalid cart data:', cart);
728
- return;
729
- }
730
- const cartIcon = document.getElementById('cart-icon');
731
- cartIcon.innerText = cart.length; // Assuming cart is an array of items
732
- }
733
 
734
- function updateCartDisplay(cart) {
735
- if (!Array.isArray(cart)) {
736
- console.error('Invalid cart data:', cart);
737
- return;
738
- }
739
- // Optional: Update quantity on the cart page
740
- const cartCountElement = document.getElementById('cart-count');
741
- cartCountElement.innerText = cart.reduce((total, item)=> total+item.quantity,0); // Update cart item count //Sum of all quantities
742
 
743
- // Optionally, show a small success notification that the item was added
744
- const successNotification = document.createElement('div');
745
- successNotification.classList.add('success-notification');
746
- successNotification.innerText = 'Item added to cart!';
747
- document.body.appendChild(successNotification);
748
- setTimeout(() => {
749
- successNotification.remove(); // Remove success notification after a few seconds
750
- }, 2000);
751
- }
752
 
753
- document.addEventListener('DOMContentLoaded', function () {
754
- // Get references to the quantity buttons and the input field
755
- const decreaseBtn = document.getElementById('decreaseQuantity');
756
- const increaseBtn = document.getElementById('increaseQuantity');
757
- const quantityInput = document.getElementById('quantityInput');
758
 
759
- // Add event listener to decrease button
760
- decreaseBtn.addEventListener('click', function () {
761
- let currentQuantity = parseInt(quantityInput.value);
762
- if (currentQuantity > 1) {
763
- currentQuantity--;
764
- quantityInput.value = currentQuantity;
765
- }
766
- });
767
 
768
- // Add event listener to increase button
769
- increaseBtn.addEventListener('click', function () {
770
- let currentQuantity = parseInt(quantityInput.value);
771
- currentQuantity++;
772
- quantityInput.value = currentQuantity;
773
- });
774
- });
775
 
776
- // Function to round reward points to a single digit
777
- function roundRewardPoints() {
778
- // Get the reward points element
779
- let rewardPointsElement = document.getElementById('reward-points');
780
 
781
- // Check if the element exists in the DOM
782
- if (rewardPointsElement) {
783
- let rewardPointsText = rewardPointsElement.innerText.trim(); // Get and trim the value to remove any extra spaces
784
 
785
- // Check if the innerText is a valid number
786
- let rewardPoints = parseFloat(rewardPointsText);
787
 
788
- // If it's a valid number, round it to 1 decimal place
789
- if (!isNaN(rewardPoints)) {
790
- rewardPointsElement.innerText = rewardPoints.toFixed(1); // Round to 1 decimal place
791
- } else {
792
- console.error("Reward points value is not a valid number:", rewardPointsText);
793
- }
794
- } else {
795
- console.error("Reward points element is missing.");
796
- }
797
- }
798
  // Run the function when the page loads
799
  window.onload = roundRewardPoints;
800
-
801
  </script>
802
 
803
  <!-- Bootstrap JS -->
 
7
  <!-- Bootstrap CSS -->
8
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
9
  <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
10
+ <style>
11
+ body {
12
+ font-family: Arial, sans-serif;
13
+ background-color: #fdf4e3; /* Updated background color */
14
+ margin: 0;
15
+ padding: 0;
16
+ display: flex;
17
+ flex-direction: column;
18
+ }
19
+ .container {
20
+ max-width: 900px;
21
+ }
22
+ .menu-card {
23
+ max-width: 350px;
24
+ border-radius: 15px;
25
+ overflow: hidden;
26
+ background-color: #fff;
27
+ margin: auto;
28
+ display: flex;
29
+ flex-direction: column;
30
+ }
31
+ .menu-image {
32
+ height: 200px; /* Fixed height */
33
+ width: 100%; /* Full width of the card */
34
+ object-fit: fill; /* Ensure the image covers the area and maintains the aspect ratio */
35
+ border-radius: 15px 15px 0 0; /* Rounded top corners */
36
+ }
37
+ .card-title {
38
+ font-size: 1.2rem;
39
+ font-weight: bold;
40
+ margin: 10px 0;
41
+ }
42
+ .card-text {
43
+ font-size: 1rem;
44
+ color: #6c757d;
45
+ }
46
+ .customisable-text {
47
+ font-size: 0.8rem; /* Smaller font size to match the first image */
48
+ color: #6c757d; /* Gray color to match the first image */
49
+ text-align: center; /* Center the text */
50
+ margin-top: 5px; /* Small space above the text */
51
+ }
52
+ .btn-primary {
53
+ font-size: 13px;
54
+ font-weight: bold;
55
+ border-radius: 5px;
56
+ width: 100px;
57
+ background-color: #0FAA39; /* Updated button background color */
58
+ border-color: #0FAA39;
59
+ }
60
+ .btn-primary:hover {
61
+ background-color: #0FAA39;
62
+ border-color: #0FAA39;
63
+ }
64
+ .btn-primary:active,
65
+ .btn-primary:focus {
66
+ background-color: #0FAA39;
67
+ border-color: #ffffff;
68
+ box-shadow: none;
69
+ }
70
+ .view-cart-container {
71
+ position: fixed;
72
+ bottom: 20px;
73
+ right: 20px;
74
+ z-index: 999;
75
+ }
76
+ .view-cart-button {
77
+ background-color: #0FAA39; /* Updated View Cart button background color */
78
+ color: #fff;
79
+ padding: 10px 20px;
80
+ border-radius: 30px;
81
+ font-size: 1rem;
82
+ font-weight: bold;
83
+ text-decoration: none;
84
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ }
89
+ .view-cart-button:hover {
90
+ background-color: #109835; /* Slightly darker shade for hover effect */
91
+ text-decoration: none;
92
+ }
93
+ .avatar-dropdown-container {
94
+ position: relative;
95
+ }
96
+ .avatar-icon {
97
+ width: 40px;
98
+ height: 40px;
99
+ border-radius: 50%;
100
+ background-color: #5bbfc1;
101
+ cursor: pointer;
102
+ display: flex;
103
+ align-items: center;
104
+ justify-content: center;
105
+ color: white;
106
+ font-size: 20px;
107
+ font-weight: bold;
108
+ }
109
+ .dropdown-menu {
110
+ position: absolute;
111
+ right: 0;
112
+ top: 100%;
113
+ background-color: #fff;
114
+ border-radius: 5px;
115
+ width: 200px; /* Adjust width as needed */
116
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
117
+ display: none;
118
+ }
119
+ .avatar-dropdown-container:hover .dropdown-menu {
120
+ display: block;
121
+ }
122
+ .avatar-dropdown-container {
123
+ position: absolute;
124
+ right: 20px; /* Adjust the value as needed to position it properly */
125
+ top: 50%; /* Adjust top to place it within the header */
126
+ transform: translateY(-50%); /* Correct the alignment to be perfectly centered */
127
+ display: flex;
128
+ align-items: right;
129
+ justify-content: center;
130
+ }
131
+ .dropdown-menu .dropdown-item {
132
+ padding: 10px 15px;
133
+ text-decoration: none;
134
+ color: #333;
135
+ border-bottom: 1px solid #ddd;
136
+ display: block; /* Make each item stack vertically */
137
+ }
138
+ .dropdown-menu .dropdown-item:last-child {
139
+ border-bottom: none; /* Remove the bottom border from the last item */
140
+ }
141
+ .dropdown-menu .dropdown-item:hover {
142
+ background-color: #f1f1f1;
143
+ }
144
+ .fixed-search-container {
145
+ position: absolute;
146
+ top: 90px; /* Move it slightly lower */
147
+ left: 50%;
148
+ transform: translateX(-50%);
149
+ width: 80%;
150
+ max-width: 600px;
151
+ z-index: 999; /* Keep it above content */
152
+ background-color: white;
153
+ padding: 10px;
154
+ border-radius: 25px;
155
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
156
+ }
157
+ /* Ensure the category filter dropdown does not overlap */
158
+ form.text-center.mb-4 {
159
+ margin-top: 10px; /* No margin at the top */
160
+ margin-bottom: 0px; /* Small space at the bottom */
161
+ }
162
+ /* Ensure the container has enough margin so nothing is overlapped */
163
+ .container {
164
+ margin-top: 10px; /* Adjust spacing based on navbar and search bar */
165
+ padding-top: 0 !important; /* Ensure no padding is added by default */
166
+ }
167
+ h1.text-center {
168
+ margin-top: 10px; /* Reduced space above */
169
+ padding-top: 0 !important; /* Removed padding */
170
+ font-weight: semi-bold; /* Make the "Menu" text bold */
171
+ }
172
+ .fixed-top-bar {
173
+ /* Remove the fixed positioning */
174
+ position: relative; /* Change from fixed to relative */
175
+ top: 0;
176
+ left: 0;
177
+ width: 100%;
178
+ height: 54px;
179
+ background-color: #FF6B35;
180
+ color: white;
181
+ padding: 15px;
182
+ display: flex;
183
+ justify-content: space-between;
184
+ align-items: center; /* Vertically align items */
185
+ z-index: 1000; /* Make sure it's still above other content */
186
+ }
187
+ .search-bar-container {
188
+ padding: 10px;
189
+ position: absolute;
190
+ left: 20px;
191
+ top: 50%;
192
+ transform: translateY(-50%);
193
+ display: flex;
194
+ justify-content: flex-start;
195
+ align-items: center;
196
+ width: 300px; /* Adjust width as needed */
197
+ }
198
+ .search-bar-container input {
199
+ width: 85%;
200
+ padding: 8px 10px 8px 30px; /* Add padding for the icon */
201
+ font-size: 16px;
202
+ border-radius: 10px;
203
+ border: none;
204
+ }
205
+ .search-icon {
206
+ position: absolute;
207
+ left: 15px; /* Position the icon inside the input box */
208
+ font-size: 20px;
209
+ color: #888; /* Icon color */
210
+ }
211
+ /* Style for customization sections */
212
+ .addon-section {
213
+ background-color: #fff; /* Light gray background */
214
+ border: 2px solid #6c757d; /* Border color */
215
+ border-radius: 8px;
216
+ padding: 12px;
217
+ margin-bottom: 10px; /* Spacing between sections */
218
+ }
219
+ /* Customization section title */
220
+ .addon-section h6 {
221
+ margin-bottom: 10px;
222
+ font-size: 1.1rem;
223
+ font-weight: bold;
224
+ color: #343a40; /* Darker title text */
225
+ }
226
+ /* Style for add-on checkboxes */
227
+ .addon-section .form-check {
228
+ display: inline-flex; /* Display checkboxes horizontally */
229
+ align-items: center; /* Align checkboxes and labels */
230
+ margin-left: 10px; /* Space between checkboxes */
231
+ color: #343a40; /* Darker text color */
232
+ }
233
+ /* Customize the default checkbox */
234
+ .addon-section .form-check-input {
235
+ -webkit-appearance: none; /* Remove default checkbox styling in Webkit browsers (e.g. Chrome, Safari) */
236
+ -moz-appearance: none; /* Remove default checkbox styling in Firefox */
237
+ appearance: none; /* Remove default checkbox styling in all browsers */
238
+ width: 20px;
239
+ height: 20px;
240
+ border: 2px solid #343a40; /* Darker border color */
241
+ border-radius: 5px; /* Rounded corners */
242
+ background-color: #f0f0f0; /* Lighter gray background when unchecked */
243
+ position: relative;
244
+ margin-right: 10px; /* Add space between the checkbox and label */
245
+ }
246
+ /* Checked state for the custom checkbox */
247
+ .addon-section .form-check-input:checked {
248
+ background-color: #006400; /* Dark green background when checked */
249
+ border-color: #006400; /* Dark green border when checked */
250
+ }
251
+ /* Add the check mark when checkbox is checked */
252
+ .addon-section .form-check-input:checked::before {
253
+ content: ''; /* Unicode check mark */
254
+ font-size: 14px;
255
+ position: absolute;
256
+ top: 3px;
257
+ left: 4px;
258
+ color: white; /* White color for the check mark */
259
+ }
260
+ /* Hover effect for the checkboxes */
261
+ .addon-section .form-check-input:hover {
262
+ /* background-color: #006400; /* Slightly darker background on hover */
263
+ }
264
+ /* Focus effect on custom checkbox */
265
+ .addon-section .form-check-input:focus {
266
+ outline: none;
267
+ box-shadow: 0 0 0 2px #006400; /* Green focus outline */
268
+ }
269
+ /* Custom checkbox label styles */
270
+ .addon-section .form-check-label {
271
+ font-size: 16px;
272
+ margin-left: 5px;
273
+ cursor: pointer;
274
+ display: inline-block; /* Ensure label aligns correctly with checkbox */
275
+ vertical-align: middle; /* Align text vertically with the checkbox */
276
+ }
277
+ /* Fix alignment of text and checkbox */
278
+ .addon-section .form-check input[type="checkbox"],
279
+ .addon-section .form-check label {
280
+ display: inline-block;
281
+ /* vertical-align: middle; /* Align text and checkboxes vertically */
282
+ }
283
+ /* Category Filter with Custom Radio Buttons */
284
+ form.text-center.mb-4 {
285
+ display: flex;
286
+ flex-direction: column;
287
+ align-items: center;
288
+ justify-content: center;
289
+ margin-bottom: 5px; /* Reduce bottom margin */
290
+ }
291
+ .form-check {
292
+ display: inline-block;
293
+ margin-right: 5px; /* Reduced space between radio button and label */
294
+ margin-bottom: 0; /* Remove bottom margin */
295
+ margin-top: 10px; /* Adds space between categories and Customized Dish */
296
+ vertical-align: middle; /* Align radio buttons vertically */
297
+ }
298
+ .form-check-inline {
299
+ display: inline-block;
300
+ margin-right: 5px; /* Decrease space between each radio button */
301
+ }
302
+ .form-check-label {
303
+ display: inline-block;
304
+ font-size: 16px;
305
+ margin-left: 5px; /* Spacing between radio button and label */
306
+ vertical-align: middle; /* Align label vertically */
307
+ }
308
+ form-check-input addon-option {
309
+ color: #333d47;
310
+ }
311
+ .custom-radio {
312
+ appearance: none;
313
+ -webkit-appearance: none;
314
+ -moz-appearance: none;
315
+ width: 20px;
316
+ height: 20px;
317
+ border: 3px solid #4CAF50; /* Green border */
318
+ border-radius: 50%;
319
+ margin-right: -5px; /* Reduced spacing between button and label */
320
+ outline: none;
321
+ cursor: pointer;
322
+ position: relative;
323
+ display: inline-block;
324
+ vertical-align: middle; /* Align vertically with text */
325
+ }
326
+ .custom-radio:checked {
327
+ background-color: #4CAF50; /* Green color when checked */
328
+ border-color: #4CAF50; /* Matching border color */
329
+ }
330
+ .custom-radio:checked::after {
331
+ content: '';
332
+ position: relative;
333
+ top: 5px;
334
+ left: 5px;
335
+ border-radius: 50%;
336
+ }
337
+ .custom-radio:hover {
338
+ border-color: #388E3C;
339
+ }
340
+ /* Optional: Style the labels */
341
+ .form-check-label {
342
+ font-size: 16px;
343
+ margin-left: 8px; /* Space between the radio button and the label */
344
+ }
345
+ .cart-container {
346
+ display: flex;
347
+ align-items: center;
348
+ gap: 10px;
349
+ }
350
+ .modal-footer {
351
+ display: flex;
352
+ align-items: center;
353
+ justify-content: space-between; /* Space between quantity and Add to Cart button */
354
+ padding: 10px;
355
+ }
356
+ .modal-footer .d-flex {
357
+ display: flex;
358
+ align-items: center;
359
+ gap: 10px; /* Space between quantity buttons */
360
+ }
361
+ .modal-footer .btn {
362
+ height: 40px; /* Set consistent button height */
363
+ padding: 0 15px; /* Adjust padding to fit inside the buttons */
364
+ }
365
+ .modal-footer .form-control {
366
+ width: 50px; /* Fixed width for quantity input */
367
+ height: 40px; /* Match the height of buttons */
368
+ text-align: center; /* Center the value inside the input */
369
+ }
370
+ .modal-footer .btn-primary {
371
+ background-color: #0FAA39; /* Green background for Add to Cart button */
372
+ border-color: #0FAA39; /* Border color to match button background */
373
+ font-weight: bold; /* Bold text */
374
+ padding: 10px 20px; /* Adjust padding to make the button look better */
375
+ height: 40px; /* Match the height with quantity buttons */
376
+ display: flex;
377
+ justify-content: center;
378
+ align-items: center;
379
+ width: auto; /* Auto width to adjust to button text */
380
+ }
381
+ .modal-footer .btn-outline-secondary {
382
+ height: 40px; /* Ensure quantity buttons are the same size */
383
+ width: 40px; /* Make sure the buttons are square */
384
+ }
385
+ @media (max-width: 576px) {
386
+ /* Responsive adjustments for smaller screens */
387
+ .modal-dialog {
388
+ max-width: 98%; /* Adjust modal width for smaller screens */
389
+ }
390
+ .modal-footer .btn {
391
+ height: 35px; /* Smaller buttons for small screens */
392
+ }
393
+ .modal-footer .form-control {
394
+ width: 40px; /* Adjust input size for smaller screens */
395
+ height: 35px;
396
+ }
397
+ }
398
+ </style>
399
  </head>
400
  <body>
401
 
402
+ <div class="fixed-top-bar">
403
+ <!-- Avatar and Dropdown -->
404
+ <div class="avatar-dropdown-container">
405
+ <div class="avatar-icon">
406
+ <span>{{ first_letter }}</span> <!-- Display the first letter of the customer's name -->
407
+ </div>
408
+ <div class="dropdown-menu">
409
+ <a href="{{ url_for('customer_details') }}" class="dropdown-item">View Profile</a>
410
+ <a href="{{ url_for('order_history') }}" class="dropdown-item">Order History</a>
411
+ <a href="{{ url_for('logout') }}" class="dropdown-item">Logout</a>
412
+ </div>
413
  </div>
 
414
 
415
+ <!-- Search Bar Section -->
416
+ <div class="search-bar-container">
417
+ <input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." onkeyup="filterMenu()">
418
+ <i class="bi bi-search search-icon"></i> <!-- Search icon inside the input -->
419
+ </div>
420
  </div>
 
421
 
422
+ <!-- Category Filter with Custom Radio Buttons -->
423
+ <form method="get" action="/menu" class="text-center mb-4">
424
+ <label class="form-label fw-bold">Select a Category:</label>
425
+ <div class="form-check form-check-inline">
426
+ {% for category in categories %}
427
+ <input type="radio" id="category-{{ category }}" name="category" value="{{ category }}" class="custom-radio"
428
+ {% if selected_category == category %}checked{% endif %} onchange="this.form.submit()">
429
+ <label class="form-check-label" for="category-{{ category }}">{{ category }}</label>
430
+ {% endfor %}
431
+ </div>
432
+ <!-- Separate Customized Dish radio button in a new div to align it properly -->
433
+ <div class="form-check">
434
+ <input type="radio" id="category-CustomizedDish" name="category" value="Customized Dish" class="custom-radio"
435
+ {% if selected_category == "Customized Dish" %}checked{% endif %} onchange="this.form.submit()">
436
+ <label class="form-check-label" for="category-CustomizedDish">Customized Dish</label>
437
+ </div>
438
+ </form>
439
 
440
+ <!-- Show menu items only when Customized Dish is not selected -->
441
  <div class="container mt-4">
442
  <h1 class="text-center">Menu</h1>
443
 
444
+ <!-- Display text boxes for Customized Dish -->
445
+ {% if selected_category == "Customized Dish" %}
446
+ <div id="custom-dish-form" class="mt-4">
447
+ <h3>Create Your Custom Dish</h3>
448
+ <form method="POST" action="/generate_custom_dish">
449
+ <div class="mb-3">
450
+ <label for="custom-dish-name" class="form-label">Dish Name</label>
451
+ <input type="text" class="form-control" id="custom-dish-name" name="name" required>
452
+ </div>
453
+ <div class="mb-3">
454
+ <label for="custom-dish-description" class="form-label">Dish Description</label>
455
+ <textarea class="form-control" id="custom-dish-description" name="description" required></textarea>
456
+ </div>
457
+ <button type="submit" class="btn btn-primary">Submit</button>
458
+ </form>
459
  </div>
460
+ {% else %}
 
 
 
461
 
462
+ <!-- Menu Sections -->
463
+ {% for section, items in ordered_menu.items() %}
464
+ <h3>{{ section }}</h3>
465
+ <div class="row">
466
+ {% for item in items %}
467
+ <div class="col-md-6 mb-4">
468
+ <div class="card menu-card">
469
+ <img src="{{ item.Image1__c }}" class="card-img-top menu-image" alt="{{ item.Name }}" onerror="this.src='/static/placeholder.jpg';">
470
+ <div class="card-body">
471
+ <h5 class="card-title">{{ item.Name }}</h5>
472
+ <p class="card-text">${{ item.Price__c }}</p>
473
+ <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#itemModal"
474
+ onclick="showItemDetails('{{ item.Name }}', '{{ item.Price__c }}', '{{ item.Image2__c }}', '{{ item.Description__c }}', '{{ item.Section__c }}','{{ selected_category }}')">
475
+ Add
476
+ </button>
477
+ <div class="customisable-text">Customisable</div> <!-- Added Customisable text -->
478
+ </div>
479
  </div>
480
  </div>
481
+ {% endfor %}
482
+ </div>
483
+ {% endfor %}
484
+ </div>
485
+ {% endif %}
 
 
486
  </div>
487
 
488
  <!-- View Cart Button -->
 
492
  </a>
493
  </div>
494
 
495
+ <!-- Modal for Item Details -->
496
+ <div class="modal fade" id="itemModal" tabindex="-1" aria-labelledby="itemModalLabel" aria-hidden="true">
497
+ <div class="modal-dialog modal-dialog-centered">
498
+ <div class="modal-content">
499
+ <div class="modal-header">
500
+ <h5 class="modal-title" id="itemModalLabel">Item Details</h5>
501
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  </div>
503
+ <div class="modal-body">
504
+ <!-- Item Image -->
505
+ <img id="modal-img" class="img-fluid rounded mb-3 d-block mx-auto" alt="Item Image" style="max-height: 200px; object-fit: cover;">
506
+ <!-- Item Name -->
507
+ <h5 id="modal-name" class="fw-bold text-center"></h5>
508
+ <!-- Item Price -->
509
+ <p id="modal-price" class="text-muted text-center"></p>
510
+ <!-- Item Description -->
511
+ <p id="modal-description" class="text-secondary"></p>
512
+ <!-- Add-ons -->
513
+ <div id="modal-addons" class="modal-addons mt-4">
514
+ <h6>Customization Options</h6>
515
+ <div id="addons-list" class="addons-container">Loading customization options...</div>
516
+ </div>
517
+ <div class="mt-4">
518
+ <h6>Custom Request</h6>
519
+ <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
520
+ </div>
521
+ <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
522
  </div>
523
+ <!-- Quantity Controls and Add to Cart Button -->
524
+ <div class="modal-footer d-flex align-items-center justify-content-between">
525
+ <!-- Quantity Controls -->
526
+ <div class="d-flex align-items-center gap-2">
527
+ <button type="button" class="btn btn-outline-secondary" id="decreaseQuantity">-</button>
528
+ <input type="text" class="form-control text-center" id="quantityInput" value="1" readonly style="width: 50px;"/>
529
+ <button type="button" class="btn btn-outline-secondary" id="increaseQuantity">+</button>
530
+ </div>
531
+ <!-- Add to Cart Button -->
532
+ <button type="button" class="btn btn-primary" onclick="addToCartFromModal()">Add to Cart</button>
533
  </div>
 
 
534
  </div>
535
  </div>
536
  </div>
 
537
 
538
+ <!-- JavaScript -->
539
+ <script>
540
+ // Show item details and fetch customization options
541
+ function showItemDetails(name, price, image, description, section, selectedCategory) {
542
+ document.getElementById('modal-name').innerText = name;
543
+ document.getElementById('modal-price').innerText = `$${price}`;
544
+ document.getElementById('modal-img').src = image || '/static/placeholder.jpg';
545
+ document.getElementById('modal-description').innerText = description || 'No description available.';
546
+ document.getElementById('addons-list').innerHTML = 'Loading customization options...';
547
+ document.getElementById('modal-instructions').value = '';
548
 
549
+ const modalSectionEl = document.getElementById('modal-section');
550
+ modalSectionEl.setAttribute('data-section', section);
551
+ modalSectionEl.setAttribute('data-category', selectedCategory);
552
 
553
+ // Set the default quantity to 1
554
+ document.getElementById('quantityInput').value = 1;
555
 
556
+ // Fetch customization options based on the section
557
+ fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
558
+ .then(response => response.json())
559
+ .then(data => {
560
+ const addonsList = document.getElementById('addons-list');
561
+ addonsList.innerHTML = ''; // Clear previous content
562
 
563
+ if (!data.success || !data.addons || data.addons.length === 0) {
564
+ addonsList.innerHTML = '<p>No customization options available.</p>';
565
+ return;
566
+ }
567
 
568
+ // Display customization options inside styled divs
569
+ data.addons.forEach(addon => {
570
+ const sectionDiv = document.createElement('div');
571
+ sectionDiv.classList.add('addon-section'); // Add styling class
572
 
573
+ // Add section title
574
+ const title = document.createElement('h6');
575
+ title.innerText = addon.name;
576
+ sectionDiv.appendChild(title);
577
 
578
+ // Create options list
579
+ const optionsContainer = document.createElement('div');
580
+ addon.options.forEach((option, index) => {
581
+ const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
582
+ const listItem = document.createElement('div');
583
+ listItem.classList.add('form-check');
584
+ listItem.innerHTML = `
585
+ <input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
586
+ data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}">
587
+ <label class="form-check-label" for="${optionId}">
588
+ ${option} ${addon.extra_charge ? `($${addon.extra_charge_amount})` : ''}
589
+ </label>
590
+ `;
591
+ optionsContainer.appendChild(listItem);
592
+ });
593
+ sectionDiv.appendChild(optionsContainer);
594
+ addonsList.appendChild(sectionDiv);
595
  });
596
+ })
597
+ .catch(err => {
598
+ console.error('Error fetching add-ons:', err);
599
+ document.getElementById('addons-list').innerHTML = '<p>Error loading customization options.</p>';
600
  });
601
+ }
 
 
 
 
 
602
 
603
+ // Handle single-select/deselect logic for checkbox groups in all modals
604
+ document.addEventListener('click', function(event) {
605
+ if (event.target.classList.contains('addon-option')) {
606
+ handleAddonClick(event.target);
607
+ }
608
+ });
609
+
610
+ // Handle checkbox selection logic
611
+ function handleAddonClick(checkbox) {
612
+ const groupName = checkbox.getAttribute('data-group');
613
+ const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides","Select Dip/Sauce","Extra Add-ons","Make it a Combo"].includes(groupName);
614
+
615
+ // If it's not multi-select, uncheck all other checkboxes in the same group
616
+ if (!isMultiSelectGroup) {
617
+ const checkboxes = document.querySelectorAll(`.addon-option[data-group="${groupName}"]`);
618
+ checkboxes.forEach(otherCheckbox => {
619
+ if (otherCheckbox !== checkbox) {
620
+ otherCheckbox.checked = false;
621
+ }
622
+ });
623
+ }
624
  }
 
625
 
626
+ function filterMenu() {
627
+ let input = document.getElementById('searchBar').value.toLowerCase(); // Get the value from search bar
628
+ let sections = document.querySelectorAll('h3'); // Select section headers
629
+ let items = document.querySelectorAll('.menu-card'); // Select all items
630
+ let matchedSections = new Set(); // Store matched sections
631
+
632
+ // Hide all items initially
633
+ items.forEach(item => {
634
+ let itemName = item.querySelector('.card-title').innerText.toLowerCase(); // Get item name
635
+ let itemSection = item.closest('.row').previousElementSibling.innerText.toLowerCase(); // Get section name
636
 
637
+ // If the search matches item name or section, show the item
638
+ if (itemName.includes(input) || (itemSection && itemSection.includes(input))) {
639
+ item.style.display = 'block'; // Show item if it matches search
640
+ matchedSections.add(item.closest('.row')); // Add section to matched list
641
+ } else {
642
+ item.style.display = 'none'; // Hide item if not matched
643
  }
644
  });
 
 
 
 
 
 
 
 
 
 
 
 
645
 
646
+ // Show or hide sections based on matched items
647
+ sections.forEach(section => {
648
+ let sectionRow = section.nextElementSibling; // The row containing items
649
+ if (matchedSections.has(sectionRow)) {
650
+ section.style.display = 'block'; // Show section header
651
+ sectionRow.style.display = 'flex'; // Show section items
652
+ } else {
653
+ section.style.display = 'none'; // Hide section header
654
+ sectionRow.style.display = 'none'; // Hide section items
655
+ }
656
+ });
657
+ }
 
 
 
 
 
 
 
 
 
658
 
659
+ function addToCartFromModal() {
660
+ const itemName = document.getElementById('modal-name').innerText;
661
+ let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
662
 
663
+ // Validate item price
664
+ if (isNaN(itemPrice)) {
665
+ alert('Invalid price for the item. Please check the item details.');
666
+ return;
667
+ }
668
 
669
+ const itemImage = document.getElementById('modal-img').src;
670
+ console.log(itemName, itemPrice, itemImage); // Log values for debugging
671
+ const modalSectionEl = document.getElementById('modal-section');
672
+ const section = modalSectionEl.getAttribute('data-section');
673
+ const selectedCategory = modalSectionEl.getAttribute('data-category');
674
+ if (!itemName || !itemPrice || !section || !itemImage) {
675
+ console.error('Missing data for cart item:', { itemName, itemPrice, section, itemImage});
676
+ return;
677
+ }
678
 
679
+ // Collect selected add-ons
680
+ let selectedAddOns = Array.from(
681
+ document.querySelectorAll('#addons-list input[type="checkbox"]:checked')
682
+ ).map(addon => ({
683
+ name: addon.getAttribute('data-name') || 'Default Name', // Fallback Name
684
+ price: parseFloat(addon.getAttribute('data-price') || 0)
685
+ }));
686
 
687
+ // Get the selected quantity
688
+ const quantity = parseInt(document.getElementById('quantityInput').value) || 1; // Default to 1 if invalid
689
 
690
+ const instructions = document.getElementById('modal-instructions').value;
691
 
692
+ // Prepare data for the cart
693
+ const cartPayload = {
694
+ itemName: itemName,
695
+ itemPrice: itemPrice,
696
+ itemImage: itemImage,
697
+ section: section,
698
+ category: selectedCategory,
699
+ addons: selectedAddOns,
700
+ instructions: instructions,
701
+ quantity: quantity // Include the quantity
702
+ };
703
 
704
+ // Send the cart data to the server
705
+ fetch('/cart/add', {
706
+ method: 'POST',
707
+ headers: {
708
+ 'Content-Type': 'application/json',
709
+ },
710
+ body: JSON.stringify(cartPayload)
711
+ })
712
+ .then(response => response.json())
713
+ .then(data => {
714
+ if (data.success) {
715
+ alert('Item added to cart successfully!');
716
+ updateCartUI(data.cart); // Update cart UI after adding an item
717
+ const modal = document.getElementById('itemModal');
718
+ const modalInstance = bootstrap.Modal.getInstance(modal);
719
+ modalInstance.hide();
720
+ } else {
721
+ alert(data.error || 'Failed to add item to cart.');
722
+ }
723
+ })
724
+ .catch(err => {
725
+ console.error('Error adding item to cart:', err);
726
+ alert('An error occurred while adding the item to the cart.');
727
+ });
728
+ }
729
 
730
+ function updateCartUI(cart) {
731
+ if (!Array.isArray(cart)) {
732
+ console.error('Invalid cart data:', cart);
733
+ return;
734
+ }
735
+ const cartIcon = document.getElementById('cart-icon');
736
+ cartIcon.innerText = cart.length; // Assuming cart is an array of items
737
+ }
738
 
739
+ function updateCartDisplay(cart) {
740
+ if (!Array.isArray(cart)) {
741
+ console.error('Invalid cart data:', cart);
742
+ return;
743
+ }
744
+ // Optional: Update quantity on the cart page
745
+ const cartCountElement = document.getElementById('cart-count');
746
+ cartCountElement.innerText = cart.reduce((total, item)=> total+item.quantity,0); // Update cart item count //Sum of all quantities
747
 
748
+ // Optionally, show a small success notification that the item was added
749
+ const successNotification = document.createElement('div');
750
+ successNotification.classList.add('success-notification');
751
+ successNotification.innerText = 'Item added to cart!';
752
+ document.body.appendChild(successNotification);
753
+ setTimeout(() => {
754
+ successNotification.remove(); // Remove success notification after a few seconds
755
+ }, 2000);
756
+ }
757
 
758
+ document.addEventListener('DOMContentLoaded', function () {
759
+ // Get references to the quantity buttons and the input field
760
+ const decreaseBtn = document.getElementById('decreaseQuantity');
761
+ const increaseBtn = document.getElementById('increaseQuantity');
762
+ const quantityInput = document.getElementById('quantityInput');
763
 
764
+ // Add event listener to decrease button
765
+ decreaseBtn.addEventListener('click', function () {
766
+ let currentQuantity = parseInt(quantityInput.value);
767
+ if (currentQuantity > 1) {
768
+ currentQuantity--;
769
+ quantityInput.value = currentQuantity;
770
+ }
771
+ });
772
 
773
+ // Add event listener to increase button
774
+ increaseBtn.addEventListener('click', function () {
775
+ let currentQuantity = parseInt(quantityInput.value);
776
+ currentQuantity++;
777
+ quantityInput.value = currentQuantity;
778
+ });
779
+ });
780
 
781
+ // Function to round reward points to a single digit
782
+ function roundRewardPoints() {
783
+ // Get the reward points element
784
+ let rewardPointsElement = document.getElementById('reward-points');
785
 
786
+ // Check if the element exists in the DOM
787
+ if (rewardPointsElement) {
788
+ let rewardPointsText = rewardPointsElement.innerText.trim(); // Get and trim the value to remove any extra spaces
789
 
790
+ // Check if the innerText is a valid number
791
+ let rewardPoints = parseFloat(rewardPointsText);
792
 
793
+ // If it's a valid number, round it to 1 decimal place
794
+ if (!isNaN(rewardPoints)) {
795
+ rewardPointsElement.innerText = rewardPoints.toFixed(1); // Round to 1 decimal place
796
+ } else {
797
+ console.error("Reward points value is not a valid number:", rewardPointsText);
798
+ }
799
+ } else {
800
+ console.error("Reward points element is missing.");
801
+ }
802
+ }
803
  // Run the function when the page loads
804
  window.onload = roundRewardPoints;
 
805
  </script>
806
 
807
  <!-- Bootstrap JS -->