lokeshloki143 commited on
Commit
83701f1
·
verified ·
1 Parent(s): c307077

Update templates/combined_summary.html

Browse files
Files changed (1) hide show
  1. templates/combined_summary.html +656 -991
templates/combined_summary.html CHANGED
@@ -3,1155 +3,820 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta http-equiv="x-ua-compatible" content="ie=edge">
7
- <title>Order Summary</title>
8
- <script src="https://cdn.tailwindcss.com"></script>
 
 
 
9
  <style>
10
- /* Custom animations */
11
- @keyframes fadeIn {
12
- from { opacity: 0; transform: translateY(10px); }
13
- to { opacity: 1; transform: translateY(0); }
14
- }
15
- @keyframes lightMoveUp {
16
- 0% { background-position: 0 100%; }
17
- 100% { background-position: 0 0%; }
18
- }
19
- @keyframes shine {
20
- from { transform: rotate(0deg) translateX(-100%); }
21
- to { transform: rotate(25deg) translateX(100%); }
22
- }
23
- @keyframes pulse {
24
- 0% { box-shadow: 0 0 0 0 rgba(255, 179, 71, 0.7); }
25
- 70% { box-shadow: 0 0 0 10px rgba(255, 179, 71, 0); }
26
- 100% { box-shadow: 0 0 0 0 rgba(255, 179, 71, 0); }
27
- }
28
- @keyframes slideDown {
29
- from { max-height: 0; opacity: 0; }
30
- to { max-height: 1000px; opacity: 1; }
31
- }
32
- .modal, .popup {
33
- animation: fadeIn 0.3s ease-in-out;
34
- }
35
- .progress-bar {
36
- transition: width 0.6s ease-in-out, background 0.3s ease-in-out;
37
- }
38
- /* Progress bar color ranges */
39
- .progress-bar.range-0-100 {
40
- background: linear-gradient(90deg, #2DD4BF, #5EEAD4);
41
- }
42
- .progress-bar.range-100-200 {
43
- background: linear-gradient(90deg, #10B981, #34D399);
44
- }
45
- .progress-bar.range-200-plus {
46
- background: linear-gradient(90deg, #F59E0B, #FBBF24);
47
- }
48
- .ingredient-button:hover .ingredient-image {
49
- transform: scale(1.1);
50
- border-color: #10B981;
51
- }
52
- .tier-badge {
53
- position: relative;
54
- overflow: hidden;
55
- background-color: #FFB347;
56
- animation: pulse 2s infinite;
57
- will-change: box-shadow;
58
  }
59
- .tier-badge::after {
60
- content: '';
61
- position: absolute;
62
- top: -50%;
63
- left: -50%;
64
- width: 200%;
65
- height: 200%;
66
- background: linear-gradient(45deg, transparent 0%, rgba(255, 255, 255, 0.3) 50%, transparent 100%);
67
- animation: shine 3s infinite;
68
  }
69
- /* Custom class for order items */
70
- .custom-class {
 
 
71
  text-align: center;
72
- border-radius: 12px;
73
- border-width: 1px;
74
- border-color: #E5E7EB;
75
- padding: 24px !important;
76
- margin-bottom: 16px;
77
- background-color: #FFFFFF;
78
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
79
- transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
80
  width: 100%;
81
- max-width: clamp(288px, 100%, 488px);
82
  margin-left: auto;
83
  margin-right: auto;
84
  }
85
- .custom-class:hover {
86
- transform: translateY(-2px);
87
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
 
 
 
 
 
 
 
88
  }
89
- /* Order image wrapper for positioning text */
90
- .order-image-wrapper {
91
  position: relative;
92
- display: block;
93
- margin-bottom: 16px;
94
  }
95
- /* Order image styles */
96
- .order-image {
97
- max-width: 100%;
98
- max-height: 330px;
99
- width: auto;
100
- height: auto;
101
- aspect-ratio: 4/3;
102
- object-fit: contain;
103
- border-radius: 10px;
104
- border: 3px solid #D1D5DB;
105
- box-sizing: border-box;
106
- box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
107
- transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
108
- will-change: transform, box-shadow;
109
  display: block;
110
- margin: 0 auto 20px;
111
- }
112
- .order-image:hover {
113
- transform: scale(1.04);
114
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
115
- }
116
- /* Fallback for placeholder images */
117
- .order-image[src$="placeholder.jpg"] {
118
- background: linear-gradient(135deg, #F9FAFB, #E5E7EB);
119
- object-fit: contain;
120
  }
121
- /* Item name below image */
122
- .order-item-name {
123
- display: block;
124
- text-align: center;
125
- color: #000000;
126
- font-size: 1.5rem;
127
  font-weight: 600;
128
- margin-top: 12px;
129
- padding: 8px 16px;
130
- background: #FFFFFF;
131
- border-radius: 8px;
132
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
 
 
133
  white-space: nowrap;
134
  overflow: hidden;
135
  text-overflow: ellipsis;
136
- max-width: 100%;
137
- transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
138
- }
139
- .order-image-wrapper:hover .order-item-name {
140
- transform: translateY(-2px);
141
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
142
- }
143
- .history {
144
- display: flex;
145
- justify-content: center;
146
- font-size: 1.75rem;
147
- font-weight: 700;
148
- padding: 1.5rem;
149
- background: linear-gradient(45deg, #FFF7ED, #FFE4D6);
150
- border-radius: 8px;
151
- margin-bottom: 1rem;
152
- }
153
- /* Scrollable sector images */
154
- .sector-images-container {
155
- position: relative;
156
- display: flex;
157
- flex-wrap: nowrap;
158
- overflow-x: auto;
159
- overflow-y: hidden;
160
- padding: 0 10px;
161
- gap: 20px;
162
- width: 100%;
163
- max-width: none;
164
- scroll-behavior: smooth;
165
- scrollbar-width: thin;
166
- scrollbar-color: #FFB347 #E5E7EB;
167
- }
168
- .sector-images-container::-webkit-scrollbar {
169
- height: 8px;
170
- }
171
- .sector-images-container::-webkit-scrollbar-track {
172
- background: #E5E7EB;
173
- }
174
- .sector-images-container::-webkit-scrollbar-thumb {
175
- background: #FFB347;
176
- border-radius: 4px;
177
- }
178
- .sector-item {
179
- display: flex;
180
- flex-direction: column;
181
- align-items: center;
182
- margin: 0 auto;
183
- flex-shrink: 0;
184
- background: #FFF7ED;
185
- border-radius: 8px;
186
- padding: 8px;
187
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
188
- transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
189
- }
190
- .sector-item:hover {
191
- transform: translateY(-2px);
192
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
193
- }
194
- .sector-image {
195
- max-width: 150px;
196
- max-height: 100px;
197
- width: auto;
198
- height: auto;
199
- aspect-ratio: 3/2;
200
- object-fit: contain;
201
- cursor: pointer;
202
- border-radius: 8px;
203
- border: 1px solid #D1D5DB;
204
- box-sizing: border-box;
205
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
206
- transition: transform 0.15s ease-in-out;
207
- will-change: transform;
208
  }
209
- .sector-image:hover {
210
- transform: scale(1.08);
 
211
  }
212
- .sector-name {
 
 
213
  text-align: center;
214
- font-size: 0.75rem;
215
- font-weight: 600;
216
- margin-top: 6px;
217
- max-width: 150px;
218
- color: #1F2937;
219
  }
220
- /* Scroll buttons */
221
- .scroll-button {
222
  position: absolute;
 
223
  top: 50%;
224
  transform: translateY(-50%);
225
- background: #FFB347;
226
- color: #FFFFFF;
 
 
 
227
  width: 40px;
228
  height: 40px;
229
  border-radius: 50%;
 
 
230
  display: flex;
231
  align-items: center;
232
  justify-content: center;
 
233
  font-size: 20px;
234
- cursor: pointer;
235
- opacity: 0;
236
- transition: opacity 0.3s ease-in-out, transform 0.2s ease-in-out;
237
- z-index: 10;
238
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
239
- }
240
- .scroll-button:hover {
241
- background: #FF9E2C;
242
- transform: translateY(-50%) scale(1.1);
243
- }
244
- .sector-images-container:hover .scroll-button {
245
- opacity: 1;
246
- }
247
- .scroll-button.left {
248
- left: 0;
249
  }
250
- .scroll-button.right {
 
251
  right: 0;
 
 
 
 
 
 
 
 
252
  }
253
- /* Full-width gradient header */
254
- .back-to-menu {
255
- position: fixed;
256
- top: 0;
257
- left: 0;
258
- right: 0;
259
  display: flex;
260
  align-items: center;
261
- padding: 14px 24px;
262
- background: linear-gradient(45deg, #FFA07A, #FFB347);
263
- color: #FFFFFF;
264
- font-size: 1.125rem;
265
- font-weight: 600;
266
- text-decoration: none;
267
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
268
- z-index: 9999;
269
- transition: background-color 0.3s ease, transform 0.2s ease;
270
  }
271
- .back-to-menu:hover {
272
- background: linear-gradient(45deg, #FF8C61, #FF9E2C);
273
- transform: translateY(-1px);
274
- }
275
- /* Content spacing */
276
- .container {
277
- margin-top: 90px;
278
- max-width: 100%;
279
- padding: 20px;
280
  }
281
- /* Sector popup */
282
- #sector-popup {
283
- display: none;
284
- position: fixed;
285
- inset: 0;
286
- background: rgba(17, 24, 39, 0.6);
287
- justify-content: center;
288
- align-items: center;
289
- z-index: 10000;
290
- animation: fadeIn 0.3s ease-in-out;
291
  }
292
- #popup-content {
293
- background: linear-gradient(135deg, #FFFFFF 0%, #F9FAFB 100%);
294
- padding: 24px;
295
- border-radius: 12px;
296
- width: 90%;
297
- max-width: 550px;
298
- max-height: 85vh;
299
- overflow-y: auto;
300
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
301
- border: 1px solid #E5E7EB;
302
- position: relative;
303
- contain: layout;
304
  }
305
- .popup-header {
306
  position: relative;
307
- padding-bottom: 12px;
308
- margin-bottom: 16px;
309
- border-bottom: 2px solid #FFB347;
 
 
 
 
310
  display: flex;
311
  justify-content: space-between;
312
  align-items: center;
 
 
 
 
 
 
 
 
 
 
313
  }
314
- .popup-close {
315
- background: #FFB347;
316
- color: #FFFFFF;
317
  border-radius: 50%;
318
- width: 40px;
319
- height: 40px;
320
  display: flex;
321
  align-items: center;
322
  justify-content: center;
323
- font-size: 24px;
324
- font-weight: bold;
325
- border: none;
326
  cursor: pointer;
327
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
328
- line-height: 1;
329
- padding: 0;
330
- position: relative;
331
- overflow: hidden;
332
- will-change: transform, background;
333
- }
334
- .popup-close::before {
335
- content: '';
336
- position: absolute;
337
- top: 100%;
338
- left: 0;
339
- width: 100%;
340
- height: 100%;
341
- background: linear-gradient(to top, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%);
342
- animation: lightMoveUp 1.5s infinite linear;
343
- z-index: 0;
344
  }
345
- .popup-close:hover {
346
- background: #FF9E2C;
347
  transform: scale(1.1);
348
  }
349
- .popup-close span {
350
- position: relative;
351
- z-index: 1;
352
  }
353
- /* Ingredient modal */
354
- .ingredient-modal-container {
355
- display: none;
356
- position: fixed;
357
- inset: 0;
358
- background: rgba(0, 0, 0, 0.6);
359
- justify-content: center;
360
  align-items: center;
361
- z-index: 10000;
362
- animation: fadeIn 0.3s ease-in-out;
363
- }
364
- .ingredient-modal {
365
- background: linear-gradient(135deg, #FFFFFF 0%, #F9FAFB 100%);
366
- border-radius: 12px;
367
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
368
- border: 1px solid #E5E7EB;
369
- width: 90%;
370
- max-width: 500px;
371
- max-height: 90vh;
372
- overflow-y: auto;
373
  position: relative;
374
- contain: layout;
375
- }
376
- .modal-section {
377
- padding: 16px;
378
- border-left: 4px solid #2DD4BF;
379
- margin-bottom: 16px;
380
- background: #F9FAFB;
381
- border-radius: 6px;
382
  }
383
- /* Ingredient images */
384
- .ingredient-image {
385
- max-width: 100%;
386
- max-height: 100px;
387
  width: 100%;
388
- height: 100px;
389
- aspect-ratio: 1/1;
390
- object-fit: cover;
391
- border-radius: 6px;
392
- border: 1px solid #D1D5DB;
393
- transition: transform 0.3s ease-in-out, border-color 0.3s ease-in-out;
 
 
394
  }
395
- /* Hover effect for ingredient buttons */
396
- .ingredient-button:hover .ingredient-image {
397
- transform: scale(1.1);
398
- border-color: #10B981;
399
  }
400
- /* Green border when section is visible */
401
- .ingredients-section:not(.hidden) .ingredient-image {
402
- border: 2px solid #10B981;
403
  }
404
- /* Ensure ingredient section is smooth */
405
- .ingredients-section {
406
- transition: opacity 0.3s ease-in-out, max-height 0.3s ease-in-out;
407
- max-height: 0;
408
- opacity: 0;
409
- overflow: hidden;
410
  }
411
- .ingredients-section:not(.hidden) {
412
- max-height: 1000px;
413
- opacity: 1;
 
 
 
 
414
  }
415
- /* Prevent body scroll when modal is open */
416
- body.modal-open {
417
- overflow: hidden;
418
  }
419
- /* Fallback messages */
420
- .no-data {
421
- text-align: center;
422
- color: #6B7280;
423
- font-size: 1.125rem;
424
- padding: 20px;
425
- background: #F9FAFB;
426
- border-radius: 8px;
427
- margin-bottom: 20px;
 
 
 
 
428
  }
429
- /* Order confirmed section */
430
- .order-confirmed {
431
- background: linear-gradient(135deg, #FFF7ED 0%, #FFE4D6 100%);
432
- position: relative;
433
- overflow: hidden;
 
 
434
  }
435
- .order-confirmed::before {
436
- content: '✔';
437
- position: absolute;
438
- top: 50%;
439
- left: 50%;
440
- transform: translate(-50%, -50%);
441
- font-size: 120px;
442
- color: rgba(16, 185, 129, 0.1);
443
- z-index: 0;
444
  }
445
- .order-confirmed h1 {
446
- font-size: 2.25rem;
447
- z-index: 1;
448
- position: relative;
 
 
449
  }
450
- /* Success message styling */
451
- .success-message {
452
- text-align: center;
453
- color: #10B981;
454
- font-size: 1.5rem;
455
- font-weight: 600;
456
- margin-top: 1rem;
457
- animation: fadeIn 0.5s ease-in-out;
458
  }
459
- /* Timer styling */
460
- #deliveryTimer {
461
- display: inline-block;
462
- font-weight: 600;
463
- color: #10B981;
464
- background: #ECFDF5;
465
- padding: 4px 12px;
466
- border-radius: 6px;
467
- min-width: 80px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  text-align: center;
 
 
469
  }
470
- /* Tier details animation */
471
- .tier-details {
472
- overflow: hidden;
473
- transition: max-height 0.5s ease-in-out, opacity 0.3s ease-in-out;
474
- max-height: 0;
475
- opacity: 0;
476
  }
477
- .tier-details:not(.hidden) {
478
- max-height: 1000px;
479
- opacity: 1;
480
- animation: slideDown 0.5s ease-in-out;
481
  }
482
- /* Price badge */
483
- .price-badge {
484
- display: inline-block;
485
- background: #FFE4D6;
486
- padding: 6px 14px;
487
- border-radius: 14px;
488
- font-weight: 600;
489
- color: #C2410C;
490
  }
491
- /* Show Ingredients button focus style */
492
- .ingredients-toggle-button:focus {
493
- outline: none;
494
- transform: scale(1.05);
 
 
 
 
 
 
 
 
 
 
 
495
  }
496
- /* Responsive adjustments */
497
- @media (max-width: 768px) {
498
- .custom-class {
499
- padding: 20px !important;
500
- max-width: 400px;
 
 
 
 
 
501
  }
502
- .order-image {
503
- max-height: 270px;
504
  }
505
- .order-item-name {
506
- font-size: 1.25rem;
507
- padding: 6px 12px;
 
508
  }
509
- .grid {
510
- grid-template-columns: repeat(2, 1fr);
 
 
511
  }
512
- }
513
- @media (max-width: 480px) {
514
- .custom-class {
515
- max-width: 336px;
516
  }
517
- .order-image {
518
- max-height: 225px;
 
519
  }
520
- .order-item-name {
521
- font-size: 1.125rem;
 
522
  }
523
- }
524
- @media (max-width: 360px) {
525
- .custom-class {
526
- max-width: 296px;
527
  }
528
- .order-image {
529
- max-height: 195px;
 
 
530
  }
531
- .order-item-name {
532
- font-size: 1rem;
533
- padding: 4px 10px;
534
  }
535
- }
536
- @media (max-width: 640px) {
537
- .back-to-menu {
538
  padding: 12px 16px;
539
- font-size: 1rem;
540
  }
541
- .container {
542
- margin-top: 70px;
543
- padding: 16px;
544
- }
545
- .history {
546
  font-size: 1.5rem;
547
- padding: 1rem;
 
 
 
 
548
  }
549
- .sector-image {
550
- max-width: 120px;
551
- max-height: 80px;
552
  }
553
- .sector-name {
554
- max-width: 120px;
 
 
555
  }
556
- .sector-item {
557
- padding: 6px;
558
  }
559
- .order-confirmed h1 {
560
- font-size: 1.75rem;
561
  }
562
- .scroll-button {
563
- width: 32px;
564
- height: 32px;
565
- font-size: 16px;
566
  }
567
- #popup-content {
568
- width: 95%;
569
- padding: 16px;
570
- max-height: 80vh;
 
571
  }
572
- .ingredient-modal {
573
- width: 95%;
574
- max-height: 80vh;
575
  }
576
- .popup-close {
577
  width: 40px;
578
  height: 40px;
579
- font-size: 24px;
580
- }
581
- .popup-close::before {
582
- animation: lightMoveUp 1.2s infinite linear;
583
  }
584
- .ingredient-image {
585
- max-height: 80px;
586
- height: 80px;
587
- }
588
- .grid {
589
- grid-template-columns: repeat(2, 1fr);
590
- }
591
- .success-message {
592
- font-size: 1.25rem;
593
- }
594
- }
595
- @media (min-width: 768px) {
596
- .grid {
597
- grid-template-columns: repeat(3, 1fr);
598
  }
599
  }
600
  </style>
601
  </head>
602
- <body class="bg-gray-50">
603
- <a href="{{ url_for('menu.menu') }}" class="back-to-menu" aria-label="Go back to menu">
604
- <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
605
- <path d="M15 18l-6-6 6-6"></path>
606
- </svg>
607
- Back to Menu
608
- </a>
609
-
610
- <div class="container mx-auto p-6 pt-2">
611
- <!-- Order Confirmation -->
612
- <div class="section bg-white shadow-sm rounded-xl p-6 mb-6 order-confirmed" role="alert">
613
- <h1 class="text-center text-2xl font-bold text-orange-500">Order Confirmed!</h1>
614
- <p class="text-center text-gray-600 mt-2">
615
- Estimated delivery time: <span id="deliveryTimer" aria-live="polite">{{ delivery_time }}:00</span>
616
- </p>
617
- <p id="successMessage" class="success-message hidden">Successfully Delivered!</p>
618
  </div>
619
-
620
- <!-- Reward Status Section -->
621
- <div class="section bg-white rounded-xl shadow-lg p-6 mb-6">
622
- <div class="flex items-center justify-between mb-4 cursor-pointer" onclick="toggleTierDetails()" aria-expanded="false" aria-controls="tierDetails">
623
- <div id="tierBadge" class="w-8 h-8 p-1 rounded-full flex items-center justify-center tier-badge">
624
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-white">
625
- <path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"></path>
626
- <path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"></path>
627
- <path d="M4 22h16"></path>
628
- <path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"></path>
629
- <path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"></path>
630
- <path d="M9 9c0 .97.64 1.79 1.5 2.05A2 2 0 0 1 12 13c.82 0 1.54-.39 2-1"></path>
631
- <path d="M18 9H6a4 4 0 0 1 0-8h12a4 4 0 0 1 0 8Z"></path>
632
- </svg>
633
- </div>
634
- <span class="ml-2 text-xl font-bold text-orange-500" id="currentTier">{{ current_tier }} Tier</span>
635
- <svg id="arrowIcon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-gray-600">
636
- <path id="arrowPath" d="M19 9l-7 7-7-7"></path>
637
- </svg>
638
- </div>
639
-
640
- <!-- Collapsible Content Section -->
641
- <div id="tierDetails" class="tier-details hidden">
642
- <div class="text-center mb-6">
643
- <p class="text-gray-600">Valid through December {{ validity_year }}</p>
644
- <p class="text-lg font-semibold mt-2 text-yellow-600" id="pointsDisplay">{{ user_points }} points</p>
645
- </div>
646
-
647
- <!-- Progress Bar -->
648
- <div class="relative h-4 bg-gray-200 rounded-full overflow-hidden mb-4">
649
- <div id="progressBar" class="absolute left-0 top-0 h-full progress-bar" style="width: {{ progress_percentage }}%"></div>
650
- </div>
651
-
652
- <div class="flex justify-between text-sm text-gray-600 mb-4">
653
- <span id="startPoint">{{ start_point }}</span>
654
- <span id="endPoint">{{ end_point }}</span>
655
- </div>
656
-
657
- <p class="text-center text-gray-700">
658
- You need <span class="font-semibold text-gray-800" id="pointsNeeded">{{ points_needed_for_next_tier }}</span> more
659
- points to reach
660
- <span class="font-semibold text-orange-500" id="nextTier">{{ next_tier }}</span>
661
- </p>
662
-
663
- <!-- Tier Benefits -->
664
- <div class="mt-6 bg-gray-50 rounded-xl p-4">
665
- <h3 class="text-lg font-semibold mb-4 text-gray-800" id="benefitsTitle">
666
- Benefits of Reaching {{ next_tier }} Tier
667
- </h3>
668
- <ul class="space-y-3" id="benefitsList">
669
- {% if next_tier == "Silver" %}
670
- <li class="flex items-center">
671
- <span class="text-2xl mr-3">🏷️</span>
672
- <span class="text-gray-700">10% discount on next purchase</span>
673
- </li>
674
- <li class="flex items-center">
675
- <span class="text-2xl mr-3">🍹</span>
676
- <span class="text-gray-700">Free soft drink with your next order</span>
677
- </li>
678
- {% elif next_tier == "Gold" %}
679
- <li class="flex items-center">
680
- <span class="text-2xl mr-3">🏷️</span>
681
- <span class="text-gray-700">15% discount on next purchase</span>
682
- </li>
683
- <li class="flex items-center">
684
- <span class="text-2xl mr-3">🍰</span>
685
- <span class="text-gray-700">Free dessert on next order</span>
686
- </li>
687
- {% elif next_tier == "Platinum" %}
688
- <li class="flex items-center">
689
- <span class="text-2xl mr-3">🏷️</span>
690
- <span class="text-gray-700">20% discount on next purchase</span>
691
- </li>
692
- <li class="flex items-center">
693
- <span class="text-2xl mr-3">🍴</span>
694
- <span class="text-gray-700">Free entrée with your next order</span>
695
- </li>
696
- {% else %}
697
- <li class="text-gray-700">You've reached the highest tier! Enjoy exclusive benefits.</li>
698
- {% endif %}
699
- </ul>
700
- </div>
701
- </div>
702
- </div>
703
-
704
- <!-- Ingredient History -->
705
- <div class="history">
706
- <h1 class="text-center text-2xl font-bold text-orange-500">Ingredient History</h1>
707
- </div>
708
- {% if sector_details %}
709
- <div class="sector-images-container" role="region" aria-label="Ingredient History Carousel">
710
- <button class="scroll-button left" onclick="scrollContainer('left')" aria-label="Scroll left">
711
- <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
712
- <path d="M15 18l-6-6 6-6"></path>
713
- </svg>
714
- </button>
715
- {% for sector_name, sector in sector_details.items() %}
716
- <div class="sector-item">
717
- <img
718
- src="{{ sector.image_url | default('/static/placeholder.jpg') }}"
719
- alt="{{ sector_name }}"
720
- class="sector-image lazyload"
721
- loading="lazy"
722
- onclick="showSectorDescription('{{ sector.description | escape }}')"
723
- role="img"
724
- aria-describedby="sector-name-{{ loop.index }}"
725
- onerror="this.src='/static/placeholder.jpg'; this.alt='Placeholder image'"
726
- >
727
- <h3 id="sector-name-{{ loop.index }}" class="sector-name">{{ sector_name }}</h3>
728
  </div>
729
- {% endfor %}
730
- <button class="scroll-button right" onclick="scrollContainer('right')" aria-label="Scroll right">
731
- <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
732
- <path d="M9 18l6-6-6-6"></path>
733
- </svg>
734
- </button>
735
- </div>
736
- {% else %}
737
- <div class="no-data">No sector details available.</div>
738
- {% endif %}
739
-
740
- <!-- Popup for Sector Description -->
741
- <div id="sector-popup" class="popup" style="display:none;" role="dialog" aria-modal="true" aria-labelledby="sector-popup-title">
742
- <div id="popup-content">
743
- <div class="popup-header flex justify-between items-center">
744
- <h3 id="sector-popup-title" class="text-xl font-semibold text-gray-800">Origin History</h3>
745
- <button onclick="closePopup()" class="popup-close" aria-label="Close sector description popup"><span>×</span></button>
746
- </div>
747
- <p id="sector-description" class="text-gray-700 leading-relaxed"></p>
748
  </div>
749
  </div>
750
-
751
- <!-- Order Items Section -->
752
- <div class="text-center text-2xl font-bold text-orange-500 mb-6">Previous Orders</div>
753
- {% if order_items %}
754
- {% for item in order_items %}
755
- <div class="custom-class">
756
- <div class="order-image-wrapper">
757
- <img
758
- src="{{ item.image_url | default('/static/placeholder.jpg') }}"
759
- alt="{{ item.name | escape }}"
760
- class="order-image lazyload"
761
- loading="lazy"
762
- decoding="async"
763
- role="img"
764
- aria-label="Image of {{ item.name | escape }}"
765
- aria-describedby="order-price-{{ loop.index }}"
766
- onerror="this.src='/static/placeholder.jpg'; this.alt='Placeholder image'"
767
- />
768
- <h3 class="order-item-name" id="order-name-{{ loop.index }}">{{ item.name | escape }}</h3>
769
- </div>
770
- <p id="order-price-{{ loop.index }}" class="text-gray-600 mb-2 price-badge">${{ "%.2f"|format(item.price | default(0)) }}</p>
771
-
772
- {% if item.category != 'Soft Drink' %}
773
- <button
774
- id="ingredientsToggleButton{{ loop.index }}"
775
- class="ingredients-toggle-button text-green-600 text-sm font-semibold mt-2 ml-2 text-left pb-4 hover:text-green-700"
776
- onclick="toggleIngredients({{ loop.index }})"
777
- aria-expanded="false"
778
- aria-controls="ingredientsSection{{ loop.index }}"
779
- data-index="{{ loop.index }}"
780
- >
781
- Show Ingredients
782
- </button>
783
-
784
- <div id="ingredientsSection{{ loop.index }}" class="ingredients-section hidden mt-4" aria-hidden="true">
785
- {% if item.ingredients and item.ingredients|length > 0 %}
786
- <div class="grid grid-cols-2 gap-4 sm:grid-cols-3">
787
- {% for ingredient in item.ingredients %}
788
- <button
789
- class="relative group ingredient-button focus:outline-none focus:ring-2 focus:ring-green-500"
790
- aria-label="View details for {{ ingredient.name | escape }}"
791
- data-ingredient='{
792
- "index": "{{ loop.index }}",
793
- "name": "{{ ingredient.name | escape }}",
794
- "image": "{{ ingredient.image | default('/static/placeholder.jpg') | escape }}",
795
- "health_benefits": "{{ ingredient.health_benefits | escape }}",
796
- "fun_facts": "{{ ingredient.fun_facts | escape }}"
797
- }'
798
- onclick="showIngredientDetails(this)"
799
- >
800
- <div class="overflow-hidden rounded-lg">
801
- <img
802
- src="{{ ingredient.image | default('/static/placeholder.jpg') }}"
803
- alt="{{ ingredient.name | escape }}"
804
- class="ingredient-image lazyload"
805
- loading="lazy"
806
- decoding="async"
807
- onerror="this.src='/static/placeholder.jpg'; this.alt='Placeholder image'"
808
- />
809
- </div>
810
- <p class="mt-2 text-center text-sm font-medium text-gray-800">{{ ingredient.name | escape }}</p>
811
- </button>
812
- {% endfor %}
813
- </div>
814
- {% else %}
815
- <p class="text-gray-600 text-center">No ingredients available for this item.</p>
816
- {% endif %}
817
- </div>
818
- {% endif %}
819
  </div>
 
820
 
821
- <!-- Modal for Ingredients -->
822
- {% if item.category != 'Soft Drink' %}
823
- <div id="ingredientModal{{ loop.index }}" class="ingredient-modal-container hidden modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle{{ loop.index }}">
824
- <div class="ingredient-modal">
825
- <div class="p-6">
826
- <div class="popup-header flex justify-between items-center mb-4">
827
- <h3 id="modalTitle{{ loop.index }}" class="text-xl font-semibold text-gray-800"></h3>
828
- <button onclick="closeModal({{ loop.index }})" class="popup-close" aria-label="Close ingredient details modal"><span>×</span></button>
829
- </div>
830
-
831
- <img id="modalImage{{ loop.index }}" src="" alt="" class="w-full max-h-48 object-contain rounded-xl mb-4 border border-gray-200 lazyload" loading="lazy" decoding="async" />
832
-
833
- <div class="space-y-4">
834
- <div class="modal-section">
835
- <h4 class="font-semibold mb-2 text-gray-800 flex items-center">
836
- <svg class="w-5 h-5 mr-2 text-teal-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
837
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
838
- </svg>
839
- Health Benefits
840
- </h4>
841
- <ul id="healthBenefits{{ loop.index }}" class="list-disc list-inside text-gray-700"></ul>
842
- </div>
843
 
844
- <div class="modal-section">
845
- <h4 class="font-semibold mb-2 text-gray-800 flex items-center">
846
- <svg class="w-5 h-5 mr-2 text-orange-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
847
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
848
- </svg>
849
- Fun Facts
850
- </h4>
851
- <ul id="funFacts{{ loop.index }}" class="list-disc list-inside text-gray-700"></ul>
 
 
 
 
 
 
852
  </div>
853
  </div>
854
- </div>
855
- </div>
 
 
 
856
  </div>
857
- {% endif %}
858
- {% endfor %}
859
- {% else %}
860
- <div class="no-data">No previous orders found.</div>
861
- {% endif %}
862
  </div>
863
 
 
 
 
 
 
 
 
 
 
 
 
864
  <script>
865
- // Debounce function for performance
866
- function debounce(func, wait) {
867
- let timeout;
868
- return function executedFunction(...args) {
869
- const later = () => {
870
- clearTimeout(timeout);
871
- func(...args);
872
- };
873
- clearTimeout(timeout);
874
- timeout = setTimeout(later, wait);
875
- };
876
- }
877
 
878
- // Scroll container function
879
- function scrollContainer(direction) {
880
- try {
881
- const container = document.querySelector('.sector-images-container');
882
- const scrollAmount = 200;
883
- if (direction === 'left') {
884
- container.scrollLeft -= scrollAmount;
885
- } else {
886
- container.scrollLeft += scrollAmount;
887
- }
888
- } catch (e) {
889
- console.error('Error scrolling container:', e);
890
  }
891
- }
892
-
893
- // Show sector description popup
894
- function showSectorDescription(description) {
895
- try {
896
- document.getElementById('sector-description').innerText = description || 'No description available.';
897
- document.getElementById('sector-popup').style.display = 'flex';
898
- document.body.classList.add('modal-open');
899
- } catch (e) {
900
- console.error('Error showing sector description:', e);
901
  }
902
  }
903
 
904
- // Close sector popup
905
- function closePopup() {
906
- try {
907
- document.getElementById('sector-popup').style.display = 'none';
908
- document.body.classList.remove('modal-open');
909
- } catch (e) {
910
- console.error('Error closing popup:', e);
911
- }
912
  }
913
 
914
- // Toggle tier details with animation
915
- function toggleTierDetails() {
916
- try {
917
- const tierDetails = document.getElementById('tierDetails');
918
- const arrowPath = document.getElementById('arrowPath');
919
- const toggleButton = tierDetails.parentElement.querySelector('[aria-controls="tierDetails"]');
920
- const isExpanded = !tierDetails.classList.contains('hidden');
921
- tierDetails.classList.toggle('hidden');
922
- arrowPath.setAttribute('d', tierDetails.classList.contains('hidden') ? 'M19 9l-7 7-7-7' : 'M19 15l-7-7-7 7');
923
- toggleButton.setAttribute('aria-expanded', !isExpanded);
924
- } catch (e) {
925
- console.error('Error toggling tier details:', e);
926
- }
927
  }
928
 
929
- // Toggle ingredients section
930
- function toggleIngredients(index) {
931
- try {
932
- const section = document.getElementById(`ingredientsSection${index}`);
933
- const button = document.getElementById(`ingredientsToggleButton${index}`);
934
 
935
- if (!section || !button) {
936
- console.error(`Elements not found for index ${index}`);
937
- return;
938
- }
939
-
940
- const isHidden = section.classList.contains('hidden');
941
-
942
- // Close all other ingredient sections
943
- document.querySelectorAll('.ingredients-section').forEach(s => {
944
- s.classList.add('hidden');
945
- s.setAttribute('aria-hidden', 'true');
946
- });
947
- document.querySelectorAll('[id^="ingredientsToggleButton"]').forEach(b => {
948
- b.textContent = 'Show Ingredients';
949
- b.setAttribute('aria-expanded', 'false');
950
- });
951
 
952
- // Toggle the current section
953
- if (isHidden) {
954
- section.classList.remove('hidden');
955
- section.setAttribute('aria-hidden', 'false');
956
- button.textContent = 'Hide Ingredients';
957
- button.setAttribute('aria-expanded', 'true');
958
- } else {
959
- section.classList.add('hidden');
960
- section.setAttribute('aria-hidden', 'true');
961
- button.textContent = 'Show Ingredients';
962
- button.setAttribute('aria-expanded', 'false');
963
- }
964
- } catch (e) {
965
- console.error('Error toggling ingredients:', e);
966
- }
967
  }
968
 
969
- // Show ingredient details modal
970
- function showIngredientDetails(button) {
971
- try {
972
- const data = JSON.parse(button.getAttribute('data-ingredient'));
973
- const { index, name, image, health_benefits, fun_facts } = data;
974
-
975
- const healthBenefitsList = (health_benefits || '').split(',').filter(item => item.trim());
976
- const funFactsList = (fun_facts || '').split(',').filter(item => item.trim());
977
 
978
- const modal = document.getElementById(`ingredientModal${index}`);
979
- if (!modal) {
980
- console.error(`Modal not found for index ${index}`);
981
- return;
982
- }
983
 
984
- document.getElementById(`modalTitle${index}`).textContent = name || 'Unknown Ingredient';
985
- const modalImage = document.getElementById(`modalImage${index}`);
986
- modalImage.src = image || '/static/placeholder.jpg';
987
- modalImage.alt = name || 'Ingredient image';
988
 
989
- const healthBenefitsUl = document.getElementById(`healthBenefits${index}`);
990
- const funFactsUl = document.getElementById(`funFacts${index}`);
991
- healthBenefitsUl.innerHTML = healthBenefitsList.length
992
- ? healthBenefitsList.map(item => `<li>${item.trim()}</li>`).join('')
993
- : '<li>No health benefits available.</li>';
994
- funFactsUl.innerHTML = funFactsList.length
995
- ? funFactsList.map(item => `<li>${item.trim()}</li>`).join('')
996
- : '<li>No fun facts available.</li>';
 
 
 
 
997
 
998
- modal.style.display = 'flex';
999
- document.body.classList.add('modal-open');
1000
- } catch (e) {
1001
- console.error('Error showing ingredient details:', e);
1002
- }
1003
  }
1004
 
1005
- // Close ingredient modal
1006
- function closeModal(index) {
1007
- try {
1008
- const modal = document.getElementById(`ingredientModal${index}`);
1009
- if (modal) {
1010
- modal.style.display = 'none';
1011
- document.body.classList.remove('modal-open');
1012
- }
1013
- } catch (e) {
1014
- console.error('Error closing modal:', e);
1015
- }
1016
- }
1017
 
1018
- // Delivery timer function
1019
- function startDeliveryTimer() {
1020
- try {
1021
- const timerElement = document.getElementById('deliveryTimer');
1022
- const successMessage = document.getElementById('successMessage');
1023
- const deliveryText = document.querySelector('.order-confirmed p.text-center.text-gray-600');
1024
- const storageKey = 'orderDeliveryTimer';
1025
- const now = Date.now();
1026
 
1027
- // Get delivery time from template (in minutes)
1028
- const initialDeliveryTime = {{ delivery_time | default(15) }};
1029
- const totalDuration = initialDeliveryTime * 60 * 1000; // Convert to milliseconds
1030
 
1031
- // Check if timer data exists in localStorage
1032
- let timerData = JSON.parse(localStorage.getItem(storageKey));
1033
- let startTime;
 
1034
 
1035
- if (timerData && timerData.startTime && timerData.totalDuration === totalDuration) {
1036
- // Resume existing timer
1037
- startTime = timerData.startTime;
1038
- } else {
1039
- // Start new timer
1040
- startTime = now;
1041
- localStorage.setItem(storageKey, JSON.stringify({
1042
- startTime: startTime,
1043
- totalDuration: totalDuration
1044
- }));
1045
- }
1046
 
1047
- // Update timer every second
1048
- const timerInterval = setInterval(() => {
1049
- const elapsedTime = Date.now() - startTime;
1050
- const remainingTime = totalDuration - elapsedTime;
1051
 
1052
- if (remainingTime <= 0) {
1053
- clearInterval(timerInterval);
1054
- deliveryText.classList.add('hidden');
1055
- successMessage.classList.remove('hidden');
1056
- timerElement.textContent = 'Order is ready!';
1057
- timerElement.setAttribute('aria-label', 'Order is ready for delivery');
1058
- localStorage.removeItem(storageKey);
1059
- return;
1060
- }
1061
 
1062
- const remainingSeconds = Math.floor(remainingTime / 1000);
1063
- const minutes = Math.floor(remainingSeconds / 60);
1064
- const seconds = remainingSeconds % 60;
1065
- const formattedTime = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
1066
- timerElement.textContent = formattedTime;
1067
- timerElement.setAttribute('aria-label', `Estimated delivery time: ${minutes} minutes and ${seconds} seconds`);
1068
- }, 1000);
1069
- } catch (e) {
1070
- console.error('Error running delivery timer:', e);
1071
- document.getElementById('deliveryTimer').textContent = 'Time unavailable';
1072
  }
1073
- }
1074
 
1075
- // Set progress bar color based on points and start delivery timer
1076
- document.addEventListener('DOMContentLoaded', () => {
1077
- try {
1078
- // Progress bar color
1079
- const progressBar = document.getElementById('progressBar');
1080
- const pointsDisplay = document.getElementById('pointsDisplay');
1081
- const points = parseInt(pointsDisplay.textContent, 10) || 0;
1082
 
1083
- if (points <= 100) {
1084
- progressBar.classList.add('range-0-100');
1085
- } else if (points <= 200) {
1086
- progressBar.classList.add('range-100-200');
 
 
 
 
 
 
 
 
1087
  } else {
1088
- progressBar.classList.add('range-200-plus');
1089
  }
 
 
1090
 
1091
- // Start delivery timer
1092
- startDeliveryTimer();
 
 
 
 
 
1093
 
1094
- // Lazy load images with IntersectionObserver
1095
- const images = document.querySelectorAll('img.lazyload');
1096
- if ('IntersectionObserver' in window) {
1097
- const observer = new IntersectionObserver((entries, observer) => {
1098
- entries.forEach(entry => {
1099
- if (entry.isIntersecting) {
1100
- const img = entry.target;
1101
- img.src = img.src || '/static/placeholder.jpg';
1102
- img.classList.remove('lazyload');
1103
- observer.unobserve(img);
1104
- }
1105
- });
1106
- });
1107
- images.forEach(img => observer.observe(img));
1108
- } else {
1109
- images.forEach(img => {
1110
- img.src = img.src || '/static/placeholder.jpg';
1111
- img.classList.remove('lazyload');
1112
- });
1113
- }
1114
- } catch (e) {
1115
- console.error('Error in DOMContentLoaded:', e);
1116
- }
1117
- });
1118
 
1119
- // Close modals on outside click
1120
- document.addEventListener('click', (e) => {
1121
- try {
1122
- if (e.target.id === 'sector-popup') {
1123
- closePopup();
 
 
 
 
 
 
1124
  }
1125
- document.querySelectorAll('.ingredient-modal-container').forEach(modal => {
1126
- if (e.target === modal) {
1127
- const index = modal.id.replace('ingredientModal', '');
1128
- closeModal(index);
1129
- }
 
 
 
 
 
 
 
 
1130
  });
1131
- } catch (e) {
1132
- console.error('Error handling outside click:', e);
1133
  }
1134
- });
1135
 
1136
- // Keyboard navigation for scroll buttons
1137
- document.querySelectorAll('.scroll-button').forEach(button => {
1138
- button.addEventListener('keydown', function(e) {
1139
- if (e.key === 'Enter' || e.key === ' ') {
1140
- e.preventDefault();
1141
- scrollContainer(button.classList.contains('left') ? 'left' : 'right');
 
 
 
 
 
 
 
 
 
 
 
 
1142
  }
1143
  });
1144
- });
1145
 
1146
- // Keyboard navigation for toggle buttons
1147
- document.querySelectorAll('[id^="ingredientsToggleButton"]').forEach(button => {
1148
- button.addEventListener('keydown', (e) => {
1149
- if (e.key === 'Enter' || e.key === ' ') {
1150
- e.preventDefault();
1151
- const index = button.getAttribute('data-index');
1152
- toggleIngredients(index);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1153
  }
1154
- });
 
 
 
 
 
 
1155
  });
1156
  </script>
1157
  </body>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Search Menu</title>
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
+ <!-- Preload Placeholder Image -->
11
+ <link rel="preload" href="/static/placeholder.jpg" as="image">
12
  <style>
13
+ body {
14
+ font-family: Arial, sans-serif;
15
+ background-color: #fdf4e3;
16
+ margin: 0;
17
+ padding: 0;
18
+ display: flex;
19
+ flex-direction: column;
20
+ padding-bottom: 70px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
+ .container {
23
+ max-width: 900px;
 
 
 
 
 
 
 
24
  }
25
+ .menu-heading {
26
+ font-size: 2rem;
27
+ font-weight: 700;
28
+ color: #fff;
29
  text-align: center;
30
+ padding: 15px 20px;
31
+ margin: 20px 0;
32
+ background: linear-gradient(45deg, #FFA07A, #FFB347);
33
+ border-radius: 10px;
34
+ box-shadow: 0 4px 8px rgba(0,0,0,0.2);
 
 
 
35
  width: 100%;
36
+ max-width: 900px;
37
  margin-left: auto;
38
  margin-right: auto;
39
  }
40
+ .menu-card {
41
+ max-width: 350px;
42
+ border-radius: 15px;
43
+ overflow: hidden;
44
+ background-color: #fff;
45
+ margin: auto;
46
+ display: flex;
47
+ flex-direction: column;
48
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
49
+ cursor: pointer;
50
  }
51
+ .card-img-container {
 
52
  position: relative;
53
+ width: 100%;
54
+ height: 200px;
55
  }
56
+ .card-img {
57
+ height: 100%;
58
+ width: 100%;
59
+ object-fit: cover;
60
+ border-radius: 15px 15px 0 0;
 
 
 
 
 
 
 
 
 
61
  display: block;
 
 
 
 
 
 
 
 
 
 
62
  }
63
+ .card-title {
64
+ position: absolute;
65
+ top: 10px;
66
+ left: 50%;
67
+ transform: translateX(-50%);
68
+ font-size: 1.2rem;
69
  font-weight: 600;
70
+ color: #fff;
71
+ text-align: center;
72
+ margin: 0;
73
+ padding: 5px 10px;
74
+ background-color: rgba(0, 0, 0, 0.5);
75
+ border-radius: 5px;
76
+ width: 90%;
77
  white-space: nowrap;
78
  overflow: hidden;
79
  text-overflow: ellipsis;
80
+ z-index: 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  }
82
+ .menu-card .card-body {
83
+ padding: 10px;
84
+ text-align: center;
85
  }
86
+ .menu-card .card-body .card-text.section {
87
+ font-size: 0.9rem;
88
+ color: #6c757d;
89
  text-align: center;
90
+ margin-bottom: 10px;
 
 
 
 
91
  }
92
+ .avatar-dropdown-container {
 
93
  position: absolute;
94
+ right: 10px;
95
  top: 50%;
96
  transform: translateY(-50%);
97
+ display: flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ }
101
+ .avatar-icon {
102
  width: 40px;
103
  height: 40px;
104
  border-radius: 50%;
105
+ background: linear-gradient(45deg, #FF4500, #000000, #1E90FF);
106
+ cursor: pointer;
107
  display: flex;
108
  align-items: center;
109
  justify-content: center;
110
+ color: white;
111
  font-size: 20px;
112
+ font-weight: bold;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
+ .dropdown-menu {
115
+ position: absolute;
116
  right: 0;
117
+ top: 100%;
118
+ background-color: #fff8f0;
119
+ border-radius: 5px;
120
+ width: 220px;
121
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
122
+ display: none;
123
+ border: 1px solid #ffd8b1;
124
+ z-index: 1000;
125
  }
126
+ .dropdown-menu .dropdown-item {
127
+ padding: 12px 16px;
128
+ text-decoration: none;
129
+ color: #333;
130
+ border-bottom: 1px solid #ffd8b1;
 
131
  display: flex;
132
  align-items: center;
133
+ font-size: 15px;
134
+ transition: background-color 0.2s ease;
135
+ background: linear-gradient(45deg, #FF4500, #000000, #1E90FF);
136
+ -webkit-background-clip: text;
137
+ -webkit-text-fill-color: transparent;
 
 
 
 
138
  }
139
+ .dropdown-menu .dropdown-item i {
140
+ margin-right: 10px;
141
+ font-size: 16px;
 
 
 
 
 
 
142
  }
143
+ .dropdown-menu .dropdown-item:last-child {
144
+ border-bottom: none;
 
 
 
 
 
 
 
 
145
  }
146
+ .dropdown-menu .dropdown-item:hover {
147
+ background-color: #ffe4c4;
148
+ color: #333;
149
+ -webkit-text-fill-color: #333;
 
 
 
 
 
 
 
 
150
  }
151
+ .fixed-top-bar {
152
  position: relative;
153
+ top: 0;
154
+ left: 0;
155
+ width: 100%;
156
+ height: 54px;
157
+ background: linear-gradient(45deg, #FFA07A, #FFB347);
158
+ color: white;
159
+ padding: 15px;
160
  display: flex;
161
  justify-content: space-between;
162
  align-items: center;
163
+ z-index: 1000;
164
+ }
165
+ .back-arrow-container {
166
+ position: absolute;
167
+ left: 10px;
168
+ top: 50%;
169
+ transform: translateY(-50%);
170
+ display: flex;
171
+ align-items: center;
172
+ justify-content: center;
173
  }
174
+ .back-arrow {
175
+ width: 36px;
176
+ height: 36px;
177
  border-radius: 50%;
178
+ background: linear-gradient(45deg, #FFA07A, #FFB347);
 
179
  display: flex;
180
  align-items: center;
181
  justify-content: center;
182
+ color: white;
183
+ font-size: 20px;
 
184
  cursor: pointer;
185
+ transition: transform 0.2s ease, background-color 0.2s ease;
186
+ text-decoration: none;
187
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  }
189
+ .back-arrow:hover {
190
+ background: linear-gradient(45deg, #FF8C61, #FF9E2C);
191
  transform: scale(1.1);
192
  }
193
+ .back-arrow:active {
194
+ transform: scale(0.95);
 
195
  }
196
+ .search-bar-container {
197
+ position: absolute;
198
+ left: 60px;
199
+ top: 50%;
200
+ transform: translateY(-50%);
201
+ display: flex;
 
202
  align-items: center;
203
+ width: 300px;
204
+ max-width: calc(90% - 60px);
 
 
 
 
 
 
 
 
 
 
205
  position: relative;
 
 
 
 
 
 
 
 
206
  }
207
+ .search-bar-container input {
 
 
 
208
  width: 100%;
209
+ padding: 8px 40px 8px 40px;
210
+ font-size: 16px;
211
+ border-radius: 25px;
212
+ border: none;
213
+ background-color: #fff;
214
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
215
+ outline: none;
216
+ transition: border-bottom 0.3s ease;
217
  }
218
+ .search-bar-container input:focus {
219
+ border-bottom: 2px solid #FFA07A;
 
 
220
  }
221
+ .search-bar-container input::placeholder {
222
+ color: #888;
 
223
  }
224
+ .search-icon {
225
+ position: absolute;
226
+ left: 15px;
227
+ font-size: 18px;
228
+ color: #888;
 
229
  }
230
+ .mic-icon {
231
+ position: absolute;
232
+ right: 15px;
233
+ font-size: 18px;
234
+ color: #888;
235
+ cursor: pointer;
236
+ transition: color 0.3s ease;
237
  }
238
+ .mic-icon.active {
239
+ color: #007bff;
 
240
  }
241
+ .search-popup {
242
+ position: absolute;
243
+ top: 100%;
244
+ left: 0;
245
+ right: 0;
246
+ background-color: #fff;
247
+ border-radius: 5px;
248
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
249
+ max-height: 300px;
250
+ overflow-y: auto;
251
+ z-index: 1000;
252
+ display: none;
253
+ margin-top: 5px;
254
  }
255
+ .search-popup-item {
256
+ display: flex;
257
+ align-items: center;
258
+ padding: 10px;
259
+ border-bottom: 1px solid #eee;
260
+ cursor: pointer;
261
+ transition: background-color 0.2s ease;
262
  }
263
+ .search-popup-item:hover {
264
+ background-color: #f8f9fa;
 
 
 
 
 
 
 
265
  }
266
+ .search-popup-item img {
267
+ width: 50px;
268
+ height: 50px;
269
+ object-fit: cover;
270
+ border-radius: 5px;
271
+ margin-right: 10px;
272
  }
273
+ .search-popup-item span {
274
+ font-size: 14px;
275
+ color: #333;
 
 
 
 
 
276
  }
277
+ .bottom-action-bar {
278
+ position: fixed;
279
+ bottom: 0;
280
+ left: 0;
281
+ right: 0;
282
+ background-color: white;
283
+ padding: 10px 20px;
284
+ display: flex;
285
+ justify-content: space-between;
286
+ align-items: center;
287
+ box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
288
+ z-index: 1000;
289
+ max-width: 900px;
290
+ margin: 0 auto;
291
+ }
292
+ .bottom-action-bar .btn {
293
+ flex: 1;
294
+ margin: 0 5px;
295
+ padding: 10px 15px;
296
+ border-radius: 8px;
297
+ font-weight: bold;
298
+ font-size: 16px;
299
+ color: white;
300
+ display: flex;
301
+ align-items: center;
302
+ justify-content: center;
303
  text-align: center;
304
+ min-width: 0;
305
+ white-space: nowrap;
306
  }
307
+ .bottom-action-bar .btn-order-history {
308
+ background-color: #FFA07A;
309
+ border-color: #FFA07A;
 
 
 
310
  }
311
+ .bottom-action-bar .btn-order-history:hover {
312
+ background-color: #FF8C61;
313
+ border-color: #FF8C61;
 
314
  }
315
+ .bottom-action-bar .btn-view-cart {
316
+ background-color: #0FAA39;
317
+ border-color: #0FAA39;
 
 
 
 
 
318
  }
319
+ .bottom-action-bar .btn-view-cart:hover {
320
+ background-color: #0D9232;
321
+ border-color: #0D9232;
322
+ }
323
+ .cart-icon-badge {
324
+ background-color: white;
325
+ color: #0FAA39;
326
+ border-radius: 50%;
327
+ width: 20px;
328
+ height: 20px;
329
+ display: inline-flex;
330
+ align-items: center;
331
+ justify-content: center;
332
+ font-size: 12px;
333
+ margin-left: 8px;
334
  }
335
+ .no-results {
336
+ text-align: center;
337
+ font-size: 1.2rem;
338
+ color: #6c757d;
339
+ margin-top: 20px;
340
+ }
341
+ @media (max-width: 576px) {
342
+ .fixed-top-bar {
343
+ height: 60px;
344
+ padding: 10px;
345
  }
346
+ .back-arrow-container {
347
+ left: 8px;
348
  }
349
+ .back-arrow {
350
+ width: 32px;
351
+ height: 32px;
352
+ font-size: 18px;
353
  }
354
+ .search-bar-container {
355
+ width: calc(80% - 50px);
356
+ max-width: calc(100% - 50px);
357
+ left: 50px;
358
  }
359
+ .search-bar-container input {
360
+ padding: 6px 35px 6px 35px;
361
+ font-size: 14px;
362
+ border-radius: 20px;
363
  }
364
+ .search-icon {
365
+ left: 12px;
366
+ font-size: 16px;
367
  }
368
+ .mic-icon {
369
+ right: 12px;
370
+ font-size: 16px;
371
  }
372
+ .avatar-dropdown-container {
373
+ right: 10px;
 
 
374
  }
375
+ .avatar-icon {
376
+ width: 40px;
377
+ height: 40px;
378
+ font-size: 20px;
379
  }
380
+ .dropdown-menu {
381
+ width: 220px;
 
382
  }
383
+ .dropdown-menu .dropdown-item {
 
 
384
  padding: 12px 16px;
385
+ font-size: 15px;
386
  }
387
+ .menu-heading {
 
 
 
 
388
  font-size: 1.5rem;
389
+ padding: 10px 15px;
390
+ margin: 15px 0;
391
+ }
392
+ .menu-card {
393
+ max-width: 100%;
394
  }
395
+ .card-img-container {
396
+ height: 150px;
 
397
  }
398
+ .card-title {
399
+ font-size: 1rem;
400
+ top: 8px;
401
+ padding: 4px 8px;
402
  }
403
+ .menu-card .card-body .card-text.section {
404
+ font-size: 0.8rem;
405
  }
406
+ .bottom-action-bar {
407
+ padding: 8px 10px;
408
  }
409
+ .bottom-action-bar .btn {
410
+ padding: 8px 10px;
411
+ font-size: 14px;
 
412
  }
413
+ .cart-icon-badge {
414
+ width: 18px;
415
+ height: 18px;
416
+ font-size: 10px;
417
+ margin-left: 5px;
418
  }
419
+ .search-popup {
420
+ width: 100%;
 
421
  }
422
+ .search-popup-item img {
423
  width: 40px;
424
  height: 40px;
 
 
 
 
425
  }
426
+ .search-popup-item span {
427
+ font-size: 12px;
 
 
 
 
 
 
 
 
 
 
 
 
428
  }
429
  }
430
  </style>
431
  </head>
432
+ <body>
433
+ <div class="fixed-top-bar">
434
+ <div class="back-arrow-container">
435
+ <a href="{{ url_for('menu.menu') }}" class="back-arrow" aria-label="Back to Menu">
436
+ <i class="bi bi-arrow-left"></i>
437
+ </a>
 
 
 
 
 
 
 
 
 
 
438
  </div>
439
+ <div class="avatar-dropdown-container">
440
+ <div class="avatar-icon">
441
+ <span>{{ first_letter }}</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
  </div>
443
+ <div class="dropdown-menu">
444
+ <a href="{{ url_for('user_details.customer_details') }}" class="dropdown-item"><i class="bi bi-person"></i> View Profile</a>
445
+ <a href="{{ url_for('orderhistory.order_history') }}" class="dropdown-item"><i class="bi bi-clock-history"></i> Order History</a>
446
+ <a href="{{ url_for('combined_summary.combined_summary') }}" class="dropdown-item"><i class="bi bi-file-earmark-text"></i> MY Summary</a>
447
+ <a href="{{ url_for('logout') }}" class="dropdown-item" id="logoutLink"><i class="bi bi-box-arrow-right"></i> Logout</a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  </div>
449
  </div>
450
+ <div class="search-bar-container">
451
+ <input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off">
452
+ <i class="bi bi-search search-icon"></i>
453
+ <i class="bi bi-mic mic-icon" id="micIcon"></i>
454
+ <div class="search-popup" id="searchPopup"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
  </div>
456
+ </div>
457
 
458
+ <!-- Timer and Success Message Container -->
459
+ <div id="orderTimerContainer" style="display: none; text-align: center; margin-top: 20px;">
460
+ <div id="orderTimer" style="font-size: 1.5rem; font-weight: bold; color: #FFA07A;"></div>
461
+ <div id="orderSuccessMessage" style="font-size: 1.5rem; font-weight: bold; color: #0FAA39; display: none;">Order Successfully Placed!</div>
462
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
 
464
+ <div class="container mt-4">
465
+ <h1 class="menu-heading">Search Menu Items</h1>
466
+ <div class="row" id="menuItems">
467
+ {% for section, items in ordered_menu.items() %}
468
+ {% for item in items %}
469
+ <div class="col-md-6 mb-4 menu-item" data-name="{{ item.Name | default('Unnamed Item') }}" data-section="{{ item.Section__c | default(section) }}">
470
+ <div class="card menu-card" onclick="selectItem('{{ item.Name | default('Unnamed Item') }}', '{{ item.Section__c | default(section) }}')">
471
+ <div class="card-img-container">
472
+ <img src="{{ item.Image1__c | default('/static/placeholder.jpg') }}" alt="{{ item.Name | default('Unnamed Item') }}" class="card-img" loading="eager" decoding="async" width="350" height="200">
473
+ <h5 class="card-title">{{ item.Name | default('Unnamed Item') }}</h5>
474
+ </div>
475
+ <div class="card-body">
476
+ <p class="card-text section">{{ item.Section__c | default(section) }}</p>
477
+ </div>
478
  </div>
479
  </div>
480
+ {% endfor %}
481
+ {% endfor %}
482
+ </div>
483
+ <div class="no-results" id="noResults" style="display: none;">
484
+ No items found matching your search.
485
  </div>
 
 
 
 
 
486
  </div>
487
 
488
+ <div class="bottom-action-bar">
489
+ <a href="{{ url_for('orderhistory.order_history') }}" class="btn btn-order-history">
490
+ <i class="bi bi-clock-history"></i> Order History
491
+ </a>
492
+ <a href="{{ url_for('cart.cart') }}" class="btn btn-view-cart">
493
+ <i class="bi bi-cart"></i> View Cart
494
+ <span id="cart-item-count" class="cart-icon-badge" style="display: none;">0</span>
495
+ </a>
496
+ </div>
497
+
498
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
499
  <script>
500
+ const menuItems = [
501
+ {% for section, items in ordered_menu.items() %}
502
+ {% for item in items %}
503
+ {
504
+ name: "{{ item.Name | default('Unnamed Item') }}",
505
+ section: "{{ item.Section__c | default(section) }}",
506
+ image: "{{ item.Image1__c | default('/static/placeholder.jpg') }}"
507
+ },
508
+ {% endfor %}
509
+ {% endfor %}
510
+ ];
 
511
 
512
+ function updateCartUI(cart) {
513
+ if (!Array.isArray(cart)) {
514
+ console.error('Invalid cart data:', cart);
515
+ return;
 
 
 
 
 
 
 
 
516
  }
517
+ let totalQuantity = 0;
518
+ cart.forEach(item => {
519
+ totalQuantity += item.quantity;
520
+ });
521
+ const cartItemCount = document.getElementById('cart-item-count');
522
+ if (cartItemCount) {
523
+ cartItemCount.innerText = totalQuantity;
524
+ cartItemCount.style.display = totalQuantity > 0 ? 'inline-flex' : 'none';
 
 
525
  }
526
  }
527
 
528
+ function getCartLocalStorage() {
529
+ return JSON.parse(localStorage.getItem('cart')) || [];
 
 
 
 
 
 
530
  }
531
 
532
+ function selectItem(itemName, section) {
533
+ localStorage.setItem('selectedItem', JSON.stringify({ name: itemName, section: section }));
534
+ window.location.href = '/menu';
 
 
 
 
 
 
 
 
 
 
535
  }
536
 
537
+ function filterMenuItems(query) {
538
+ const menuItemElements = document.querySelectorAll('.menu-item');
539
+ const noResults = document.getElementById('noResults');
540
+ let hasResults = false;
 
541
 
542
+ menuItemElements.forEach(item => {
543
+ const name = item.getAttribute('data-name').toLowerCase();
544
+ const section = item.getAttribute('data-section').toLowerCase();
545
+ const matches = name.includes(query.toLowerCase()) || section.includes(query.toLowerCase());
546
+ item.style.display = matches ? '' : 'none';
547
+ if (matches) hasResults = true;
548
+ });
 
 
 
 
 
 
 
 
 
549
 
550
+ noResults.style.display = hasResults ? 'none' : 'block';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
  }
552
 
553
+ function showSearchPopup(query) {
554
+ const searchPopup = document.getElementById('searchPopup');
555
+ searchPopup.innerHTML = '';
556
+ if (!query) {
557
+ searchPopup.style.display = 'none';
558
+ return;
559
+ }
 
560
 
561
+ const filteredItems = menuItems.filter(item =>
562
+ item.name.toLowerCase().includes(query.toLowerCase()) ||
563
+ item.section.toLowerCase().includes(query.toLowerCase())
564
+ );
 
565
 
566
+ if (filteredItems.length === 0) {
567
+ searchPopup.style.display = 'none';
568
+ return;
569
+ }
570
 
571
+ filteredItems.forEach(item => {
572
+ const popupItem = document.createElement('div');
573
+ popupItem.className = 'search-popup-item';
574
+ popupItem.innerHTML = `
575
+ <img src="${item.image}" alt="${item.name}">
576
+ <span>${item.name}</span>
577
+ `;
578
+ popupItem.addEventListener('click', () => {
579
+ selectItem(item.name, item.section);
580
+ });
581
+ searchPopup.appendChild(popupItem);
582
+ });
583
 
584
+ searchPopup.style.display = 'block';
 
 
 
 
585
  }
586
 
587
+ // Timer and Success Message Functions
588
+ let orderTimerInterval;
589
+ let orderDurationInSeconds = 0;
590
+ let orderStartTime = null; // To store the start time for persistence
 
 
 
 
 
 
 
 
591
 
592
+ function startOrderTimer(durationInSeconds) {
593
+ orderDurationInSeconds = durationInSeconds;
594
+ orderStartTime = Date.now(); // Record the start time
595
+ localStorage.setItem('orderTimer', JSON.stringify({
596
+ startTime: orderStartTime,
597
+ duration: orderDurationInSeconds
598
+ }));
 
599
 
600
+ const timerElement = document.getElementById('orderTimer');
601
+ const successMessageElement = document.getElementById('orderSuccessMessage');
602
+ const timerContainer = document.getElementById('orderTimerContainer');
603
 
604
+ if (!timerElement || !successMessageElement || !timerContainer) {
605
+ console.error("Timer elements not found.");
606
+ return;
607
+ }
608
 
609
+ timerContainer.style.display = 'block';
610
+ successMessageElement.style.display = 'none';
611
+ timerElement.style.display = 'block'; // Ensure timer is visible
 
 
 
 
 
 
 
 
612
 
613
+ let secondsRemaining = orderDurationInSeconds;
 
 
 
614
 
615
+ timerElement.innerText = formatTime(secondsRemaining);
 
 
 
 
 
 
 
 
616
 
617
+ // Clear any existing interval before starting a new one
618
+ if (orderTimerInterval) {
619
+ clearInterval(orderTimerInterval);
 
 
 
 
 
 
 
620
  }
 
621
 
622
+ orderTimerInterval = setInterval(() => {
623
+ secondsRemaining--;
 
 
 
 
 
624
 
625
+ if (secondsRemaining <= 0) {
626
+ clearInterval(orderTimerInterval);
627
+ timerElement.style.display = 'none';
628
+ successMessageElement.style.display = 'block';
629
+ // Hide the success message and container after a few seconds
630
+ setTimeout(() => {
631
+ timerContainer.style.display = 'none';
632
+ successMessageElement.style.display = 'none';
633
+ // We don't reset timerElement.style.display to 'block' here
634
+ // because a new timer should only start with a new order.
635
+ }, 5000); // Hide after 5 seconds
636
+ localStorage.removeItem('orderTimer'); // Clear finished timer data
637
  } else {
638
+ timerElement.innerText = formatTime(secondsRemaining);
639
  }
640
+ }, 1000);
641
+ }
642
 
643
+ function formatTime(seconds) {
644
+ const minutes = Math.floor(seconds / 60);
645
+ const remainingSeconds = seconds % 60;
646
+ const formattedMinutes = String(minutes).padStart(2, '0');
647
+ const formattedSeconds = String(remainingSeconds).padStart(2, '0');
648
+ return `${formattedMinutes}:${formattedSeconds}`;
649
+ }
650
 
651
+ // Function to handle a new order being successfully placed
652
+ // This is the function you will call from your order placement logic.
653
+ function handleNewOrderPlaced(estimatedCompletionTimeInSeconds) {
654
+ console.log("New order successful, starting timer...");
655
+ startOrderTimer(estimatedCompletionTimeInSeconds);
656
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
657
 
658
+ document.addEventListener('DOMContentLoaded', function () {
659
+ // Avatar Dropdown
660
+ const avatarContainer = document.querySelector('.avatar-dropdown-container');
661
+ const dropdownMenu = document.querySelector('.dropdown-menu');
662
+ avatarContainer.addEventListener('click', function (event) {
663
+ event.stopPropagation();
664
+ dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
665
+ });
666
+ document.addEventListener('click', function (event) {
667
+ if (!avatarContainer.contains(event.target)) {
668
+ dropdownMenu.style.display = 'none';
669
  }
670
+ });
671
+ const dropdownItems = document.querySelectorAll('.dropdown-item');
672
+ dropdownItems.forEach(item => {
673
+ item.addEventListener('click', function () {
674
+ dropdownMenu.style.display = 'none';
675
+ });
676
+ });
677
+
678
+ // Logout Link - Clear timer on logout
679
+ const logoutLink = document.getElementById('logoutLink');
680
+ if (logoutLink) {
681
+ logoutLink.addEventListener('click', function() {
682
+ localStorage.removeItem('orderTimer'); // Clear timer on logout
683
  });
 
 
684
  }
 
685
 
686
+
687
+ // Search Bar Functionality
688
+ const searchBar = document.getElementById('searchBar');
689
+ const searchPopup = document.getElementById('searchPopup');
690
+ const searchQuery = localStorage.getItem('searchQuery');
691
+ if (searchQuery) {
692
+ searchBar.value = searchQuery;
693
+ filterMenuItems(searchQuery);
694
+ showSearchPopup(searchQuery);
695
+ localStorage.removeItem('searchQuery');
696
+ }
697
+ searchBar.addEventListener('input', function () {
698
+ filterMenuItems(this.value);
699
+ showSearchPopup(this.value);
700
+ });
701
+ document.addEventListener('click', function (event) {
702
+ if (!searchBar.contains(event.target) && !searchPopup.contains(event.target)) {
703
+ searchPopup.style.display = 'none';
704
  }
705
  });
 
706
 
707
+ // Voice Recognition
708
+ const micIcon = document.getElementById('micIcon');
709
+ if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
710
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
711
+ const recognition = new SpeechRecognition();
712
+ recognition.lang = 'en-US';
713
+ recognition.onstart = () => micIcon.classList.add('active');
714
+ recognition.onresult = (event) => {
715
+ const query = event.results[0][0].transcript.trim();
716
+ searchBar.value = query;
717
+ filterMenuItems(query);
718
+ showSearchPopup(query);
719
+ };
720
+ recognition.onend = () => micIcon.classList.remove('active');
721
+ recognition.onerror = (event) => {
722
+ micIcon.classList.remove('active');
723
+ console.error('Speech error:', event.error);
724
+ };
725
+ micIcon.addEventListener('click', () => {
726
+ recognition.start();
727
+ });
728
+ } else {
729
+ micIcon.style.display = 'none';
730
+ }
731
+
732
+ // Fetch Cart
733
+ fetch('/cart/get')
734
+ .then(response => {
735
+ if (!response.ok) {
736
+ throw new Error(`HTTP error! Status: ${response.status}`);
737
+ }
738
+ return response.json();
739
+ })
740
+ .then(data => {
741
+ if (data.success) {
742
+ updateCartUI(data.cart);
743
+ } else {
744
+ console.error('Failed to fetch cart:', data.error);
745
+ const cart = getCartLocalStorage();
746
+ updateCartUI(cart);
747
+ }
748
+ })
749
+ .catch(err => {
750
+ console.error('Error fetching cart:', err);
751
+ const cart = getCartLocalStorage();
752
+ updateCartUI(cart);
753
+ });
754
+
755
+ // --- Timer Logic Integration ---
756
+ // Check local storage for an existing timer when the page loads.
757
+ const savedOrderTimer = localStorage.getItem('orderTimer');
758
+ if (savedOrderTimer) {
759
+ const timerData = JSON.parse(savedOrderTimer);
760
+ const now = Date.now();
761
+ const elapsed = Math.floor((now - timerData.startTime) / 1000);
762
+ const remaining = timerData.duration - elapsed;
763
+
764
+ const timerElement = document.getElementById('orderTimer');
765
+ const successMessageElement = document.getElementById('orderSuccessMessage');
766
+ const timerContainer = document.getElementById('orderTimerContainer');
767
+
768
+ if (remaining > 0) {
769
+ // Resume the timer
770
+ orderDurationInSeconds = timerData.duration; // Load duration
771
+ orderStartTime = timerData.startTime; // Load start time
772
+ timerContainer.style.display = 'block';
773
+ successMessageElement.style.display = 'none';
774
+ timerElement.style.display = 'block';
775
+ let secondsRemaining = remaining;
776
+ timerElement.innerText = formatTime(secondsRemaining);
777
+
778
+ // Clear any existing interval before resuming
779
+ if (orderTimerInterval) {
780
+ clearInterval(orderTimerInterval);
781
+ }
782
+
783
+ orderTimerInterval = setInterval(() => {
784
+ secondsRemaining--;
785
+
786
+ if (secondsRemaining <= 0) {
787
+ clearInterval(orderTimerInterval);
788
+ timerElement.style.display = 'none';
789
+ successMessageElement.style.display = 'block';
790
+ setTimeout(() => {
791
+ timerContainer.style.display = 'none';
792
+ successMessageElement.style.display = 'none';
793
+ }, 5000); // Hide success after 5 seconds
794
+ localStorage.removeItem('orderTimer'); // Clear finished timer data
795
+ } else {
796
+ timerElement.innerText = formatTime(secondsRemaining);
797
+ }
798
+ }, 1000);
799
+
800
+ } else {
801
+ // Timer has already finished, show success message briefly
802
+ if (timerContainer && successMessageElement && timerElement) {
803
+ timerContainer.style.display = 'block';
804
+ timerElement.style.display = 'none'; // Timer is finished
805
+ successMessageElement.style.display = 'block';
806
+ setTimeout(() => {
807
+ timerContainer.style.display = 'none';
808
+ successMessageElement.style.display = 'none';
809
+ }, 3000); // Show success for 3 seconds
810
+ localStorage.removeItem('orderTimer'); // Clear finished timer data
811
+ }
812
  }
813
+ }
814
+
815
+ // --- Example of how you would trigger the timer (replace with your actual logic) ---
816
+ // This is for demonstration only. You should call handleNewOrderPlaced()
817
+ // from your code that handles a successful order submission.
818
+ // For example, after a successful API call to create an order.
819
+ // handleNewOrderPlaced(45); // Simulate a new order with a 45-second timer
820
  });
821
  </script>
822
  </body>