nagasurendra commited on
Commit
d295a56
·
verified ·
1 Parent(s): e0e0b32

Update templates/combined_summary.html

Browse files
Files changed (1) hide show
  1. templates/combined_summary.html +562 -97
templates/combined_summary.html CHANGED
@@ -20,22 +20,41 @@
20
  from { transform: rotate(0deg) translateX(-100%); }
21
  to { transform: rotate(25deg) translateX(100%); }
22
  }
 
 
 
 
 
 
 
 
 
23
  .modal, .popup {
24
- animation: fadeIn 0.2s ease-in-out;
25
  }
26
  .progress-bar {
27
- transition: width 0.6s ease-in-out;
28
  }
29
- .ingredient-image {
30
- transition: transform 0.3s ease-in-out;
 
 
 
 
 
 
 
31
  }
32
  .ingredient-button:hover .ingredient-image {
33
  transform: scale(1.1);
 
34
  }
35
  .tier-badge {
36
  position: relative;
37
  overflow: hidden;
38
  background-color: #FFB347;
 
 
39
  }
40
  .tier-badge::after {
41
  content: '';
@@ -44,19 +63,82 @@
44
  left: -50%;
45
  width: 200%;
46
  height: 200%;
47
- background: linear-gradient(45deg, transparent 0%, rgba(255, 255, 255, 0.2) 50%, transparent 100%);
48
  animation: shine 3s infinite;
49
  }
50
  /* Custom class for order items */
51
  .custom-class {
52
  text-align: center;
53
- border-radius: 8px;
54
  border-width: 1px;
55
  border-color: #E5E7EB;
56
- padding: 20px !important;
57
- margin-bottom: 12px;
58
  background-color: #FFFFFF;
59
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
  .history {
62
  display: flex;
@@ -64,29 +146,110 @@
64
  font-size: 1.75rem;
65
  font-weight: 700;
66
  padding: 1.5rem;
 
 
 
67
  }
68
  /* Scrollable sector images */
69
  .sector-images-container {
 
70
  display: flex;
 
71
  overflow-x: auto;
72
- padding: 10px 0;
73
- gap: 15px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  }
75
  .sector-image {
76
  max-width: 150px;
77
- height: 100px;
78
- object-fit: cover;
 
 
 
79
  cursor: pointer;
80
- border-radius: 6px;
 
 
 
 
 
 
 
 
81
  }
82
  .sector-name {
83
  text-align: center;
84
  font-size: 0.75rem;
85
  font-weight: 600;
86
  margin-top: 6px;
87
- max-width: 100px;
88
  color: #1F2937;
89
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  /* Full-width gradient header */
91
  .back-to-menu {
92
  position: fixed;
@@ -112,6 +275,8 @@
112
  /* Content spacing */
113
  .container {
114
  margin-top: 90px;
 
 
115
  }
116
  /* Sector popup */
117
  #sector-popup {
@@ -122,7 +287,7 @@
122
  justify-content: center;
123
  align-items: center;
124
  z-index: 10000;
125
- animation: fadeIn 0.2s ease-in-out;
126
  }
127
  #popup-content {
128
  background: linear-gradient(135deg, #FFFFFF 0%, #F9FAFB 100%);
@@ -194,7 +359,7 @@
194
  justify-content: center;
195
  align-items: center;
196
  z-index: 10000;
197
- animation: fadeIn 0.2s ease-in-out;
198
  }
199
  .ingredient-modal {
200
  background: linear-gradient(135deg, #FFFFFF 0%, #F9FAFB 100%);
@@ -215,10 +380,37 @@
215
  background: #F9FAFB;
216
  border-radius: 6px;
217
  }
218
- /* Green border for ingredient images when section is visible */
219
- .ingredients-section:not(.hidden) .ingredient-image {
220
- border: 2px solid #10B981;
 
 
 
 
 
221
  border-radius: 6px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  }
223
  /* Prevent body scroll when modal is open */
224
  body.modal-open {
@@ -234,7 +426,93 @@
234
  border-radius: 8px;
235
  margin-bottom: 20px;
236
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  /* Responsive adjustments */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  @media (max-width: 640px) {
239
  .back-to-menu {
240
  padding: 12px 16px;
@@ -242,17 +520,29 @@
242
  }
243
  .container {
244
  margin-top: 70px;
 
245
  }
246
  .history {
247
  font-size: 1.5rem;
248
  padding: 1rem;
249
  }
250
- .custom-class {
251
- padding: 16px !important;
252
- }
253
  .sector-image {
254
  max-width: 120px;
255
- height: 80px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  }
257
  #popup-content {
258
  width: 95%;
@@ -271,6 +561,18 @@
271
  .popup-close::before {
272
  animation: lightMoveUp 1.2s infinite linear;
273
  }
 
 
 
 
 
 
 
 
 
 
 
 
274
  }
275
  </style>
276
  </head>
@@ -284,7 +586,7 @@
284
 
285
  <div class="container mx-auto p-6 pt-2">
286
  <!-- Order Confirmation -->
287
- <div class="section bg-white shadow-sm rounded-xl p-6 mb-6">
288
  <h1 class="text-center text-2xl font-bold text-orange-500">Order Confirmed!</h1>
289
  <p class="text-center text-gray-600 mt-2">Estimated delivery time: {{ delivery_time }} minutes</p>
290
  </div>
@@ -318,7 +620,7 @@
318
 
319
  <!-- Progress Bar -->
320
  <div class="relative h-4 bg-gray-200 rounded-full overflow-hidden mb-4">
321
- <div id="progressBar" class="absolute left-0 top-0 h-full progress-bar bg-teal-400" style="width: {{ progress_percentage }}%"></div>
322
  </div>
323
 
324
  <div class="flex justify-between text-sm text-gray-600 mb-4">
@@ -378,13 +680,32 @@
378
  <h1 class="text-center text-2xl font-bold text-orange-500">Ingredient History</h1>
379
  </div>
380
  {% if sector_details %}
381
- <div class="sector-images-container">
 
 
 
 
 
382
  {% for sector_name, sector in sector_details.items() %}
383
  <div class="sector-item">
384
- <img src="{{ sector.image_url | default('/static/placeholder.jpg') }}" alt="{{ sector_name }}" class="sector-image lazyload" loading="lazy" onclick="showSectorDescription('{{ sector.description | escape }}')">
385
- <h3 class="sector-name">{{ sector_name }}</h3>
 
 
 
 
 
 
 
 
 
386
  </div>
387
  {% endfor %}
 
 
 
 
 
388
  </div>
389
  {% else %}
390
  <div class="no-data">No sector details available.</div>
@@ -406,46 +727,73 @@
406
  {% if order_items %}
407
  {% for item in order_items %}
408
  <div class="custom-class">
409
- <img src="{{ item.image_url | default('/static/placeholder.jpg') }}" alt="{{ item.name | escape }}" class="w-full h-48 object-cover rounded-xl mb-4 lazyload" loading="lazy" />
410
- <h3 class="text-lg font-semibold text-gray-800">{{ item.name | escape }}</h3>
411
- <p class="text-gray-600 mb-2">${{ "%.2f"|format(item.price | default(0)) }}</p>
 
 
 
 
 
 
 
 
 
 
 
 
412
 
413
- {% if item.ingredients %}
414
- <button id="ingredientsToggleButton{{ loop.index }}" class="text-green-600 text-sm font-semibold mt-2 ml-2 text-left pb-4 hover:text-green-700" onclick="toggleIngredients({{ loop.index }})" aria-expanded="false" aria-controls="ingredientsSection{{ loop.index }}">
 
 
 
 
 
 
 
415
  Show Ingredients
416
  </button>
417
 
418
- <div id="ingredientsSection{{ loop.index }}" class="ingredients-section hidden mt-4">
419
- <div class="grid grid-cols-2 gap-4">
 
420
  {% for ingredient in item.ingredients %}
421
  <button
422
- onclick="showIngredientDetails(
423
- '{{ loop.index }}',
424
- '{{ ingredient.name | escape }}',
425
- '{{ ingredient.image | default('/static/placeholder.jpg') | escape }}',
426
- '{{ ingredient.health_benefits | escape }}',
427
- '{{ ingredient.fun_facts | escape }}'
428
- )"
429
- class="relative group ingredient-button"
430
- aria-label="View details for {{ ingredient.name }}"
 
431
  >
432
  <div class="overflow-hidden rounded-lg">
433
  <img
434
  src="{{ ingredient.image | default('/static/placeholder.jpg') }}"
435
  alt="{{ ingredient.name | escape }}"
436
- class="w-full h-32 object-cover ingredient-image lazyload"
437
  loading="lazy"
 
 
438
  />
439
  </div>
440
  <p class="mt-2 text-center text-sm font-medium text-gray-800">{{ ingredient.name | escape }}</p>
441
  </button>
442
  {% endfor %}
443
  </div>
 
 
 
444
  </div>
445
  {% endif %}
446
  </div>
447
 
448
  <!-- Modal for Ingredients -->
 
449
  <div id="ingredientModal{{ loop.index }}" class="ingredient-modal-container hidden modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle{{ loop.index }}">
450
  <div class="ingredient-modal">
451
  <div class="p-6">
@@ -454,7 +802,7 @@
454
  <button onclick="closeModal({{ loop.index }})" class="popup-close" aria-label="Close ingredient details modal"><span>×</span></button>
455
  </div>
456
 
457
- <img id="modalImage{{ loop.index }}" src="" alt="" class="w-full h-48 object-cover rounded-xl mb-4 border border-gray-200 lazyload" loading="lazy" />
458
 
459
  <div class="space-y-4">
460
  <div class="modal-section">
@@ -480,6 +828,7 @@
480
  </div>
481
  </div>
482
  </div>
 
483
  {% endfor %}
484
  {% else %}
485
  <div class="no-data">No previous orders found.</div>
@@ -500,6 +849,21 @@
500
  };
501
  }
502
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
  // Show sector description popup
504
  function showSectorDescription(description) {
505
  try {
@@ -513,38 +877,63 @@
513
 
514
  // Close sector popup
515
  function closePopup() {
516
- document.getElementById('sector-popup').style.display = 'none';
517
- document.body.classList.remove('modal-open');
 
 
 
 
518
  }
519
 
520
- // Toggle tier details
521
  function toggleTierDetails() {
522
- const tierDetails = document.getElementById('tierDetails');
523
- const arrowPath = document.getElementById('arrowPath');
524
- const toggleButton = tierDetails.parentElement.querySelector('[aria-controls="tierDetails"]');
525
- const isExpanded = !tierDetails.classList.contains('hidden');
526
- tierDetails.classList.toggle('hidden');
527
- arrowPath.setAttribute('d', tierDetails.classList.contains('hidden') ? 'M19 9l-7 7-7-7' : 'M19 15l-7-7-7 7');
528
- toggleButton.setAttribute('aria-expanded', !isExpanded);
 
 
 
 
529
  }
530
 
531
  // Toggle ingredients section
532
  function toggleIngredients(index) {
533
  try {
534
- const currentSection = document.getElementById('ingredientsSection' + index);
535
- const currentButton = document.getElementById('ingredientsToggleButton' + index);
536
- const isCurrentlyVisible = !currentSection.classList.contains('hidden');
537
 
538
- document.querySelectorAll('[id^="ingredientsSection"]').forEach(section => section.classList.add('hidden'));
539
- document.querySelectorAll('[id^="ingredientsToggleButton"]').forEach(button => {
540
- button.textContent = 'Show Ingredients';
541
- button.setAttribute('aria-expanded', 'false');
 
 
 
 
 
 
 
 
 
 
 
542
  });
543
 
544
- if (!isCurrentlyVisible) {
545
- currentSection.classList.remove('hidden');
546
- currentButton.textContent = 'Hide Ingredients';
547
- currentButton.setAttribute('aria-expanded', 'true');
 
 
 
 
 
 
 
548
  }
549
  } catch (e) {
550
  console.error('Error toggling ingredients:', e);
@@ -552,27 +941,35 @@
552
  }
553
 
554
  // Show ingredient details modal
555
- function showIngredientDetails(index, name, image, healthBenefits, funFacts) {
556
  try {
557
- const healthBenefitsList = (healthBenefits || '').split(',').filter(item => item.trim());
558
- const funFactsList = (funFacts || '').split(',').filter(item => item.trim());
559
- document.getElementById("modalTitle" + index).textContent = name || 'Unknown Ingredient';
560
- document.getElementById("modalImage" + index).src = image || '/static/placeholder.jpg';
561
- const healthBenefitsUl = document.getElementById("healthBenefits" + index);
562
- const funFactsUl = document.getElementById("funFacts" + index);
563
- healthBenefitsUl.innerHTML = '';
564
- funFactsUl.innerHTML = '';
565
- healthBenefitsList.length ? healthBenefitsList.forEach(item => {
566
- const li = document.createElement("li");
567
- li.textContent = item.trim();
568
- healthBenefitsUl.appendChild(li);
569
- }) : healthBenefitsUl.innerHTML = '<li>No health benefits available.</li>';
570
- funFactsList.length ? funFactsList.forEach(item => {
571
- const li = document.createElement("li");
572
- li.textContent = item.trim();
573
- funFactsUl.appendChild(li);
574
- }) : funFactsUl.innerHTML = '<li>No fun facts available.</li>';
575
- document.getElementById("ingredientModal" + index).style.display = "flex";
 
 
 
 
 
 
 
 
576
  document.body.classList.add('modal-open');
577
  } catch (e) {
578
  console.error('Error showing ingredient details:', e);
@@ -582,22 +979,90 @@
582
  // Close ingredient modal
583
  function closeModal(index) {
584
  try {
585
- document.getElementById("ingredientModal" + index).style.display = "none";
586
- document.body.classList.remove('modal-open');
 
 
 
587
  } catch (e) {
588
  console.error('Error closing modal:', e);
589
  }
590
  }
591
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
  // Close modals on outside click
593
- document.addEventListener('click', function(e) {
594
- if (e.target.id === 'sector-popup') {
595
- closePopup();
596
- }
597
- document.querySelectorAll('.ingredient-modal-container').forEach(modal => {
598
- if (e.target === modal) {
599
- const index = modal.id.replace('ingredientModal', '');
600
- closeModal(index);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
601
  }
602
  });
603
  });
 
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: '';
 
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;
 
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;
 
275
  /* Content spacing */
276
  .container {
277
  margin-top: 90px;
278
+ max-width: 100%;
279
+ padding: 20px;
280
  }
281
  /* Sector popup */
282
  #sector-popup {
 
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%);
 
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%);
 
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 {
 
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
+ /* Tier details animation */
451
+ .tier-details {
452
+ overflow: hidden;
453
+ transition: max-height 0.5s ease-in-out, opacity 0.3s ease-in-out;
454
+ max-height: 0;
455
+ opacity: 0;
456
+ }
457
+ .tier-details:not(.hidden) {
458
+ max-height: 1000px;
459
+ opacity: 1;
460
+ animation: slideDown 0.5s ease-in-out;
461
+ }
462
+ /* Price badge */
463
+ .price-badge {
464
+ display: inline-block;
465
+ background: #FFE4D6;
466
+ padding: 6px 14px;
467
+ border-radius: 14px;
468
+ font-weight: 600;
469
+ color: #C2410C;
470
+ }
471
+ /* Show Ingredients button focus style */
472
+ .ingredients-toggle-button:focus {
473
+ outline: none;
474
+ transform: scale(1.05);
475
+ }
476
  /* Responsive adjustments */
477
+ @media (max-width: 768px) {
478
+ .custom-class {
479
+ padding: 20px !important;
480
+ max-width: 400px;
481
+ }
482
+ .order-image {
483
+ max-height: 270px;
484
+ }
485
+ .order-item-name {
486
+ font-size: 1.25rem;
487
+ padding: 6px 12px;
488
+ }
489
+ .grid {
490
+ grid-template-columns: repeat(2, 1fr);
491
+ }
492
+ }
493
+ @media (max-width: 480px) {
494
+ .custom-class {
495
+ max-width: 336px;
496
+ }
497
+ .order-image {
498
+ max-height: 225px;
499
+ }
500
+ .order-item-name {
501
+ font-size: 1.125rem;
502
+ }
503
+ }
504
+ @media (max-width: 360px) {
505
+ .custom-class {
506
+ max-width: 296px;
507
+ }
508
+ .order-image {
509
+ max-height: 195px;
510
+ }
511
+ .order-item-name {
512
+ font-size: 1rem;
513
+ padding: 4px 10px;
514
+ }
515
+ }
516
  @media (max-width: 640px) {
517
  .back-to-menu {
518
  padding: 12px 16px;
 
520
  }
521
  .container {
522
  margin-top: 70px;
523
+ padding: 16px;
524
  }
525
  .history {
526
  font-size: 1.5rem;
527
  padding: 1rem;
528
  }
 
 
 
529
  .sector-image {
530
  max-width: 120px;
531
+ max-height: 80px;
532
+ }
533
+ .sector-name {
534
+ max-width: 120px;
535
+ }
536
+ .sector-item {
537
+ padding: 6px;
538
+ }
539
+ .order-confirmed h1 {
540
+ font-size: 1.75rem;
541
+ }
542
+ .scroll-button {
543
+ width: 32px;
544
+ height: 32px;
545
+ font-size: 16px;
546
  }
547
  #popup-content {
548
  width: 95%;
 
561
  .popup-close::before {
562
  animation: lightMoveUp 1.2s infinite linear;
563
  }
564
+ .ingredient-image {
565
+ max-height: 80px;
566
+ height: 80px;
567
+ }
568
+ .grid {
569
+ grid-template-columns: repeat(2, 1fr);
570
+ }
571
+ }
572
+ @media (min-width: 768px) {
573
+ .grid {
574
+ grid-template-columns: repeat(3, 1fr);
575
+ }
576
  }
577
  </style>
578
  </head>
 
586
 
587
  <div class="container mx-auto p-6 pt-2">
588
  <!-- Order Confirmation -->
589
+ <div class="section bg-white shadow-sm rounded-xl p-6 mb-6 order-confirmed" role="alert">
590
  <h1 class="text-center text-2xl font-bold text-orange-500">Order Confirmed!</h1>
591
  <p class="text-center text-gray-600 mt-2">Estimated delivery time: {{ delivery_time }} minutes</p>
592
  </div>
 
620
 
621
  <!-- Progress Bar -->
622
  <div class="relative h-4 bg-gray-200 rounded-full overflow-hidden mb-4">
623
+ <div id="progressBar" class="absolute left-0 top-0 h-full progress-bar" style="width: {{ progress_percentage }}%"></div>
624
  </div>
625
 
626
  <div class="flex justify-between text-sm text-gray-600 mb-4">
 
680
  <h1 class="text-center text-2xl font-bold text-orange-500">Ingredient History</h1>
681
  </div>
682
  {% if sector_details %}
683
+ <div class="sector-images-container" role="region" aria-label="Ingredient History Carousel">
684
+ <button class="scroll-button left" onclick="scrollContainer('left')" aria-label="Scroll left">
685
+ <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">
686
+ <path d="M15 18l-6-6 6-6"></path>
687
+ </svg>
688
+ </button>
689
  {% for sector_name, sector in sector_details.items() %}
690
  <div class="sector-item">
691
+ <img
692
+ src="{{ sector.image_url | default('/static/placeholder.jpg') }}"
693
+ alt="{{ sector_name }}"
694
+ class="sector-image lazyload"
695
+ loading="lazy"
696
+ onclick="showSectorDescription('{{ sector.description | escape }}')"
697
+ role="img"
698
+ aria-describedby="sector-name-{{ loop.index }}"
699
+ onerror="this.src='/static/placeholder.jpg'; this.alt='Placeholder image'"
700
+ >
701
+ <h3 id="sector-name-{{ loop.index }}" class="sector-name">{{ sector_name }}</h3>
702
  </div>
703
  {% endfor %}
704
+ <button class="scroll-button right" onclick="scrollContainer('right')" aria-label="Scroll right">
705
+ <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">
706
+ <path d="M9 18l6-6-6-6"></path>
707
+ </svg>
708
+ </button>
709
  </div>
710
  {% else %}
711
  <div class="no-data">No sector details available.</div>
 
727
  {% if order_items %}
728
  {% for item in order_items %}
729
  <div class="custom-class">
730
+ <div class="order-image-wrapper">
731
+ <img
732
+ src="{{ item.image_url | default('/static/placeholder.jpg') }}"
733
+ alt="{{ item.name | escape }}"
734
+ class="order-image lazyload"
735
+ loading="lazy"
736
+ decoding="async"
737
+ role="img"
738
+ aria-label="Image of {{ item.name | escape }}"
739
+ aria-describedby="order-price-{{ loop.index }}"
740
+ onerror="this.src='/static/placeholder.jpg'; this.alt='Placeholder image'"
741
+ />
742
+ <h3 class="order-item-name" id="order-name-{{ loop.index }}">{{ item.name | escape }}</h3>
743
+ </div>
744
+ <p id="order-price-{{ loop.index }}" class="text-gray-600 mb-2 price-badge">${{ "%.2f"|format(item.price | default(0)) }}</p>
745
 
746
+ {% if item.category != 'Soft Drink' %}
747
+ <button
748
+ id="ingredientsToggleButton{{ loop.index }}"
749
+ class="ingredients-toggle-button text-green-600 text-sm font-semibold mt-2 ml-2 text-left pb-4 hover:text-green-700"
750
+ onclick="toggleIngredients({{ loop.index }})"
751
+ aria-expanded="false"
752
+ aria-controls="ingredientsSection{{ loop.index }}"
753
+ data-index="{{ loop.index }}"
754
+ >
755
  Show Ingredients
756
  </button>
757
 
758
+ <div id="ingredientsSection{{ loop.index }}" class="ingredients-section hidden mt-4" aria-hidden="true">
759
+ {% if item.ingredients and item.ingredients|length > 0 %}
760
+ <div class="grid grid-cols-2 gap-4 sm:grid-cols-3">
761
  {% for ingredient in item.ingredients %}
762
  <button
763
+ class="relative group ingredient-button focus:outline-none focus:ring-2 focus:ring-green-500"
764
+ aria-label="View details for {{ ingredient.name | escape }}"
765
+ data-ingredient='{
766
+ "index": "{{ loop.index }}",
767
+ "name": "{{ ingredient.name | escape }}",
768
+ "image": "{{ ingredient.image | default('/static/placeholder.jpg') | escape }}",
769
+ "health_benefits": "{{ ingredient.health_benefits | escape }}",
770
+ "fun_facts": "{{ ingredient.fun_facts | escape }}"
771
+ }'
772
+ onclick="showIngredientDetails(this)"
773
  >
774
  <div class="overflow-hidden rounded-lg">
775
  <img
776
  src="{{ ingredient.image | default('/static/placeholder.jpg') }}"
777
  alt="{{ ingredient.name | escape }}"
778
+ class="ingredient-image lazyload"
779
  loading="lazy"
780
+ decoding="async"
781
+ onerror="this.src='/static/placeholder.jpg'; this.alt='Placeholder image'"
782
  />
783
  </div>
784
  <p class="mt-2 text-center text-sm font-medium text-gray-800">{{ ingredient.name | escape }}</p>
785
  </button>
786
  {% endfor %}
787
  </div>
788
+ {% else %}
789
+ <p class="text-gray-600 text-center">No ingredients available for this item.</p>
790
+ {% endif %}
791
  </div>
792
  {% endif %}
793
  </div>
794
 
795
  <!-- Modal for Ingredients -->
796
+ {% if item.category != 'Soft Drink' %}
797
  <div id="ingredientModal{{ loop.index }}" class="ingredient-modal-container hidden modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle{{ loop.index }}">
798
  <div class="ingredient-modal">
799
  <div class="p-6">
 
802
  <button onclick="closeModal({{ loop.index }})" class="popup-close" aria-label="Close ingredient details modal"><span>×</span></button>
803
  </div>
804
 
805
+ <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" />
806
 
807
  <div class="space-y-4">
808
  <div class="modal-section">
 
828
  </div>
829
  </div>
830
  </div>
831
+ {% endif %}
832
  {% endfor %}
833
  {% else %}
834
  <div class="no-data">No previous orders found.</div>
 
849
  };
850
  }
851
 
852
+ // Scroll container function
853
+ function scrollContainer(direction) {
854
+ try {
855
+ const container = document.querySelector('.sector-images-container');
856
+ const scrollAmount = 200;
857
+ if (direction === 'left') {
858
+ container.scrollLeft -= scrollAmount;
859
+ } else {
860
+ container.scrollLeft += scrollAmount;
861
+ }
862
+ } catch (e) {
863
+ console.error('Error scrolling container:', e);
864
+ }
865
+ }
866
+
867
  // Show sector description popup
868
  function showSectorDescription(description) {
869
  try {
 
877
 
878
  // Close sector popup
879
  function closePopup() {
880
+ try {
881
+ document.getElementById('sector-popup').style.display = 'none';
882
+ document.body.classList.remove('modal-open');
883
+ } catch (e) {
884
+ console.error('Error closing popup:', e);
885
+ }
886
  }
887
 
888
+ // Toggle tier details with animation
889
  function toggleTierDetails() {
890
+ try {
891
+ const tierDetails = document.getElementById('tierDetails');
892
+ const arrowPath = document.getElementById('arrowPath');
893
+ const toggleButton = tierDetails.parentElement.querySelector('[aria-controls="tierDetails"]');
894
+ const isExpanded = !tierDetails.classList.contains('hidden');
895
+ tierDetails.classList.toggle('hidden');
896
+ arrowPath.setAttribute('d', tierDetails.classList.contains('hidden') ? 'M19 9l-7 7-7-7' : 'M19 15l-7-7-7 7');
897
+ toggleButton.setAttribute('aria-expanded', !isExpanded);
898
+ } catch (e) {
899
+ console.error('Error toggling tier details:', e);
900
+ }
901
  }
902
 
903
  // Toggle ingredients section
904
  function toggleIngredients(index) {
905
  try {
906
+ const section = document.getElementById(`ingredientsSection${index}`);
907
+ const button = document.getElementById(`ingredientsToggleButton${index}`);
 
908
 
909
+ if (!section || !button) {
910
+ console.error(`Elements not found for index ${index}`);
911
+ return;
912
+ }
913
+
914
+ const isHidden = section.classList.contains('hidden');
915
+
916
+ // Close all other ingredient sections
917
+ document.querySelectorAll('.ingredients-section').forEach(s => {
918
+ s.classList.add('hidden');
919
+ s.setAttribute('aria-hidden', 'true');
920
+ });
921
+ document.querySelectorAll('[id^="ingredientsToggleButton"]').forEach(b => {
922
+ b.textContent = 'Show Ingredients';
923
+ b.setAttribute('aria-expanded', 'false');
924
  });
925
 
926
+ // Toggle the current section
927
+ if (isHidden) {
928
+ section.classList.remove('hidden');
929
+ section.setAttribute('aria-hidden', 'false');
930
+ button.textContent = 'Hide Ingredients';
931
+ button.setAttribute('aria-expanded', 'true');
932
+ } else {
933
+ section.classList.add('hidden');
934
+ section.setAttribute('aria-hidden', 'true');
935
+ button.textContent = 'Show Ingredients';
936
+ button.setAttribute('aria-expanded', 'false');
937
  }
938
  } catch (e) {
939
  console.error('Error toggling ingredients:', e);
 
941
  }
942
 
943
  // Show ingredient details modal
944
+ function showIngredientDetails(button) {
945
  try {
946
+ const data = JSON.parse(button.getAttribute('data-ingredient'));
947
+ const { index, name, image, health_benefits, fun_facts } = data;
948
+
949
+ const healthBenefitsList = (health_benefits || '').split(',').filter(item => item.trim());
950
+ const funFactsList = (fun_facts || '').split(',').filter(item => item.trim());
951
+
952
+ const modal = document.getElementById(`ingredientModal${index}`);
953
+ if (!modal) {
954
+ console.error(`Modal not found for index ${index}`);
955
+ return;
956
+ }
957
+
958
+ document.getElementById(`modalTitle${index}`).textContent = name || 'Unknown Ingredient';
959
+ const modalImage = document.getElementById(`modalImage${index}`);
960
+ modalImage.src = image || '/static/placeholder.jpg';
961
+ modalImage.alt = name || 'Ingredient image';
962
+
963
+ const healthBenefitsUl = document.getElementById(`healthBenefits${index}`);
964
+ const funFactsUl = document.getElementById(`funFacts${index}`);
965
+ healthBenefitsUl.innerHTML = healthBenefitsList.length
966
+ ? healthBenefitsList.map(item => `<li>${item.trim()}</li>`).join('')
967
+ : '<li>No health benefits available.</li>';
968
+ funFactsUl.innerHTML = funFactsList.length
969
+ ? funFactsList.map(item => `<li>${item.trim()}</li>`).join('')
970
+ : '<li>No fun facts available.</li>';
971
+
972
+ modal.style.display = 'flex';
973
  document.body.classList.add('modal-open');
974
  } catch (e) {
975
  console.error('Error showing ingredient details:', e);
 
979
  // Close ingredient modal
980
  function closeModal(index) {
981
  try {
982
+ const modal = document.getElementById(`ingredientModal${index}`);
983
+ if (modal) {
984
+ modal.style.display = 'none';
985
+ document.body.classList.remove('modal-open');
986
+ }
987
  } catch (e) {
988
  console.error('Error closing modal:', e);
989
  }
990
  }
991
 
992
+ // Set progress bar color based on points
993
+ document.addEventListener('DOMContentLoaded', () => {
994
+ try {
995
+ const progressBar = document.getElementById('progressBar');
996
+ const pointsDisplay = document.getElementById('pointsDisplay');
997
+ const points = parseInt(pointsDisplay.textContent, 10) || 0;
998
+
999
+ if (points <= 100) {
1000
+ progressBar.classList.add('range-0-100');
1001
+ } else if (points <= 200) {
1002
+ progressBar.classList.add('range-100-200');
1003
+ } else {
1004
+ progressBar.classList.add('range-200-plus');
1005
+ }
1006
+ } catch (e) {
1007
+ console.error('Error setting progress bar color:', e);
1008
+ }
1009
+
1010
+ // Lazy load images with IntersectionObserver
1011
+ const images = document.querySelectorAll('img.lazyload');
1012
+ if ('IntersectionObserver' in window) {
1013
+ const observer = new IntersectionObserver((entries, observer) => {
1014
+ entries.forEach(entry => {
1015
+ if (entry.isIntersecting) {
1016
+ const img = entry.target;
1017
+ img.src = img.src || '/static/placeholder.jpg';
1018
+ img.classList.remove('lazyload');
1019
+ observer.unobserve(img);
1020
+ }
1021
+ });
1022
+ });
1023
+ images.forEach(img => observer.observe(img));
1024
+ } else {
1025
+ images.forEach(img => {
1026
+ img.src = img.src || '/static/placeholder.jpg';
1027
+ img.classList.remove('lazyload');
1028
+ });
1029
+ }
1030
+ });
1031
+
1032
  // Close modals on outside click
1033
+ document.addEventListener('click', (e) => {
1034
+ try {
1035
+ if (e.target.id === 'sector-popup') {
1036
+ closePopup();
1037
+ }
1038
+ document.querySelectorAll('.ingredient-modal-container').forEach(modal => {
1039
+ if (e.target === modal) {
1040
+ const index = modal.id.replace('ingredientModal', '');
1041
+ closeModal(index);
1042
+ }
1043
+ });
1044
+ } catch (e) {
1045
+ console.error('Error handling outside click:', e);
1046
+ }
1047
+ });
1048
+
1049
+ // Keyboard navigation for scroll buttons
1050
+ document.querySelectorAll('.scroll-button').forEach(button => {
1051
+ button.addEventListener('keydown', function(e) {
1052
+ if (e.key === 'Enter' || e.key === ' ') {
1053
+ e.preventDefault();
1054
+ scrollContainer(button.classList.contains('left') ? 'left' : 'right');
1055
+ }
1056
+ });
1057
+ });
1058
+
1059
+ // Keyboard navigation for toggle buttons
1060
+ document.querySelectorAll('[id^="ingredientsToggleButton"]').forEach(button => {
1061
+ button.addEventListener('keydown', (e) => {
1062
+ if (e.key === 'Enter' || e.key === ' ') {
1063
+ e.preventDefault();
1064
+ const index = button.getAttribute('data-index');
1065
+ toggleIngredients(index);
1066
  }
1067
  });
1068
  });