|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<meta http-equiv="x-ua-compatible" content="ie=edge"> |
|
<title>Order Summary</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<style> |
|
|
|
@keyframes fadeIn { |
|
from { opacity: 0; transform: translateY(10px); } |
|
to { opacity: 1; transform: translateY(0); } |
|
} |
|
@keyframes lightMoveUp { |
|
0% { background-position: 0 100%; } |
|
100% { background-position: 0 0%; } |
|
} |
|
@keyframes shine { |
|
from { transform: rotate(0deg) translateX(-100%); } |
|
to { transform: rotate(25deg) translateX(100%); } |
|
} |
|
@keyframes pulse { |
|
0% { box-shadow: 0 0 0 0 rgba(255, 179, 71, 0.7); } |
|
70% { box-shadow: 0 0 0 10px rgba(255, 179, 71, 0); } |
|
100% { box-shadow: 0 0 0 0 rgba(255, 179, 71, 0); } |
|
} |
|
@keyframes slideDown { |
|
from { max-height: 0; opacity: 0; } |
|
to { max-height: 1000px; opacity: 1; } |
|
} |
|
.modal, .popup { |
|
animation: fadeIn 0.3s ease-in-out; |
|
} |
|
.progress-bar { |
|
transition: width 0.6s ease-in-out, background 0.3s ease-in-out; |
|
} |
|
|
|
.progress-bar.range-0-100 { |
|
background: linear-gradient(90deg, #2DD4BF, #5EEAD4); |
|
} |
|
.progress-bar.range-100-200 { |
|
background: linear-gradient(90deg, #10B981, #34D399); |
|
} |
|
.progress-bar.range-200-plus { |
|
background: linear-gradient(90deg, #F59E0B, #FBBF24); |
|
} |
|
.ingredient-button:hover .ingredient-image { |
|
transform: scale(1.1); |
|
border-color: #10B981; |
|
} |
|
.tier-badge { |
|
position: relative; |
|
overflow: hidden; |
|
background-color: #FFB347; |
|
animation: pulse 2s infinite; |
|
will-change: box-shadow; |
|
} |
|
.tier-badge::after { |
|
content: ''; |
|
position: absolute; |
|
top: -50%; |
|
left: -50%; |
|
width: 200%; |
|
height: 200%; |
|
background: linear-gradient(45deg, transparent 0%, rgba(255, 255, 255, 0.3) 50%, transparent 100%); |
|
animation: shine 3s infinite; |
|
} |
|
|
|
.custom-class { |
|
text-align: center; |
|
border-radius: 12px; |
|
border-width: 1px; |
|
border-color: #E5E7EB; |
|
padding: 24px !important; |
|
margin-bottom: 16px; |
|
background-color: #FFFFFF; |
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; |
|
width: 100%; |
|
max-width: clamp(288px, 100%, 488px); |
|
margin-left: auto; |
|
margin-right: auto; |
|
} |
|
.custom-class:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
.order-image-wrapper { |
|
position: relative; |
|
display: block; |
|
margin-bottom: 16px; |
|
} |
|
|
|
.order-image { |
|
max-width: 100%; |
|
max-height: 330px; |
|
width: auto; |
|
height: auto; |
|
aspect-ratio: 4/3; |
|
object-fit: contain; |
|
border-radius: 10px; |
|
border: 3px solid #D1D5DB; |
|
box-sizing: border-box; |
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); |
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; |
|
will-change: transform, box-shadow; |
|
display: block; |
|
margin: 0 auto 20px; |
|
} |
|
.order-image:hover { |
|
transform: scale(1.04); |
|
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); |
|
} |
|
|
|
.order-image[src$="placeholder.jpg"] { |
|
background: linear-gradient(135deg, #F9FAFB, #E5E7EB); |
|
object-fit: contain; |
|
} |
|
|
|
.order-item-name { |
|
display: block; |
|
text-align: center; |
|
color: #000000; |
|
font-size: 1.5rem; |
|
font-weight: 600; |
|
margin-top: 12px; |
|
padding: 8px 16px; |
|
background: #FFFFFF; |
|
border-radius: 8px; |
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); |
|
white-space: nowrap; |
|
overflow: hidden; |
|
text-overflow: ellipsis; |
|
max-width: 100%; |
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; |
|
} |
|
.order-image-wrapper:hover .order-item-name { |
|
transform: translateY(-2px); |
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); |
|
} |
|
.history { |
|
display: flex; |
|
justify-content: center; |
|
font-size: 1.75rem; |
|
font-weight: 700; |
|
padding: 1.5rem; |
|
background: linear-gradient(45deg, #FFF7ED, #FFE4D6); |
|
border-radius: 8px; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.sector-images-container { |
|
position: relative; |
|
display: flex; |
|
flex-wrap: nowrap; |
|
overflow-x: auto; |
|
overflow-y: hidden; |
|
padding: 0 10px; |
|
gap: 20px; |
|
width: 100%; |
|
max-width: none; |
|
scroll-behavior: smooth; |
|
scrollbar-width: thin; |
|
scrollbar-color: #FFB347 #E5E7EB; |
|
} |
|
.sector-images-container::-webkit-scrollbar { |
|
height: 8px; |
|
} |
|
.sector-images-container::-webkit-scrollbar-track { |
|
background: #E5E7EB; |
|
} |
|
.sector-images-container::-webkit-scrollbar-thumb { |
|
background: #FFB347; |
|
border-radius: 4px; |
|
} |
|
.sector-item { |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
margin: 0 auto; |
|
flex-shrink: 0; |
|
background: #FFF7ED; |
|
border-radius: 8px; |
|
padding: 8px; |
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); |
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; |
|
} |
|
.sector-item:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); |
|
} |
|
.sector-image { |
|
max-width: 150px; |
|
max-height: 100px; |
|
width: auto; |
|
height: auto; |
|
aspect-ratio: 3/2; |
|
object-fit: contain; |
|
cursor: pointer; |
|
border-radius: 8px; |
|
border: 1px solid #D1D5DB; |
|
box-sizing: border-box; |
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); |
|
transition: transform 0.15s ease-in-out; |
|
will-change: transform; |
|
} |
|
.sector-image:hover { |
|
transform: scale(1.08); |
|
} |
|
.sector-name { |
|
text-align: center; |
|
font-size: 0.75rem; |
|
font-weight: 600; |
|
margin-top: 6px; |
|
max-width: 150px; |
|
color: #1F2937; |
|
} |
|
|
|
.scroll-button { |
|
position: absolute; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
background: #FFB347; |
|
color: #FFFFFF; |
|
width: 40px; |
|
height: 40px; |
|
border-radius: 50%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
font-size: 20px; |
|
cursor: pointer; |
|
opacity: 0; |
|
transition: opacity 0.3s ease-in-out, transform 0.2s ease-in-out; |
|
z-index: 10; |
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
} |
|
.scroll-button:hover { |
|
background: #FF9E2C; |
|
transform: translateY(-50%) scale(1.1); |
|
} |
|
.sector-images-container:hover .scroll-button { |
|
opacity: 1; |
|
} |
|
.scroll-button.left { |
|
left: 0; |
|
} |
|
.scroll-button.right { |
|
right: 0; |
|
} |
|
|
|
.back-to-menu { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
display: flex; |
|
align-items: center; |
|
padding: 14px 24px; |
|
background: linear-gradient(45deg, #FFA07A, #FFB347); |
|
color: #FFFFFF; |
|
font-size: 1.125rem; |
|
font-weight: 600; |
|
text-decoration: none; |
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
|
z-index: 9999; |
|
transition: background-color 0.3s ease, transform 0.2s ease; |
|
} |
|
.back-to-menu:hover { |
|
background: linear-gradient(45deg, #FF8C61, #FF9E2C); |
|
transform: translateY(-1px); |
|
} |
|
|
|
.container { |
|
margin-top: 90px; |
|
max-width: 100%; |
|
padding: 20px; |
|
} |
|
|
|
#sector-popup { |
|
display: none; |
|
position: fixed; |
|
inset: 0; |
|
background: rgba(17, 24, 39, 0.6); |
|
justify-content: center; |
|
align-items: center; |
|
z-index: 10000; |
|
animation: fadeIn 0.3s ease-in-out; |
|
} |
|
#popup-content { |
|
background: linear-gradient(135deg, #FFFFFF 0%, #F9FAFB 100%); |
|
padding: 24px; |
|
border-radius: 12px; |
|
width: 90%; |
|
max-width: 550px; |
|
max-height: 85vh; |
|
overflow-y: auto; |
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); |
|
border: 1px solid #E5E7EB; |
|
position: relative; |
|
contain: layout; |
|
} |
|
.popup-header { |
|
position: relative; |
|
padding-bottom: 12px; |
|
margin-bottom: 16px; |
|
border-bottom: 2px solid #FFB347; |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
} |
|
.popup-close { |
|
background: #FFB347; |
|
color: #FFFFFF; |
|
border-radius: 50%; |
|
width: 40px; |
|
height: 40px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
font-size: 24px; |
|
font-weight: bold; |
|
border: none; |
|
cursor: pointer; |
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
line-height: 1; |
|
padding: 0; |
|
position: relative; |
|
overflow: hidden; |
|
will-change: transform, background; |
|
} |
|
.popup-close::before { |
|
content: ''; |
|
position: absolute; |
|
top: 100%; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background: linear-gradient(to top, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%); |
|
animation: lightMoveUp 1.5s infinite linear; |
|
z-index: 0; |
|
} |
|
.popup-close:hover { |
|
background: #FF9E2C; |
|
transform: scale(1.1); |
|
} |
|
.popup-close span { |
|
position: relative; |
|
z-index: 1; |
|
} |
|
|
|
.ingredient-modal-container { |
|
display: none; |
|
position: fixed; |
|
inset: 0; |
|
background: rgba(0, 0, 0, 0.6); |
|
justify-content: center; |
|
align-items: center; |
|
z-index: 10000; |
|
animation: fadeIn 0.3s ease-in-out; |
|
} |
|
.ingredient-modal { |
|
background: linear-gradient(135deg, #FFFFFF 0%, #F9FAFB 100%); |
|
border-radius: 12px; |
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); |
|
border: 1px solid #E5E7EB; |
|
width: 90%; |
|
max-width: 500px; |
|
max-height: 90vh; |
|
overflow-y: auto; |
|
position: relative; |
|
contain: layout; |
|
} |
|
.modal-section { |
|
padding: 16px; |
|
border-left: 4px solid #2DD4BF; |
|
margin-bottom: 16px; |
|
background: #F9FAFB; |
|
border-radius: 6px; |
|
} |
|
|
|
.ingredient-image { |
|
max-width: 100%; |
|
max-height: 100px; |
|
width: 100%; |
|
height: 100px; |
|
aspect-ratio: 1/1; |
|
object-fit: cover; |
|
border-radius: 6px; |
|
border: 1px solid #D1D5DB; |
|
transition: transform 0.3s ease-in-out, border-color 0.3s ease-in-out; |
|
} |
|
|
|
.ingredient-button:hover .ingredient-image { |
|
transform: scale(1.1); |
|
border-color: #10B981; |
|
} |
|
|
|
.ingredients выполнение-section:not(.hidden) .ingredient-image { |
|
border: 2px solid #10B981; |
|
} |
|
|
|
.ingredients-section { |
|
transition: opacity 0.3s ease-in-out, max-height 0.3s ease-in-out; |
|
max-height: 0; |
|
opacity: 0; |
|
overflow: hidden; |
|
} |
|
.ingredients-section:not(.hidden) { |
|
max-height: 1000px; |
|
opacity: 1; |
|
} |
|
|
|
body.modal-open { |
|
overflow: hidden; |
|
} |
|
|
|
.no-data { |
|
text-align: center; |
|
color: #6B7280; |
|
font-size: 1.125rem; |
|
padding: 20px; |
|
background: #F9FAFB; |
|
border-radius: 8px; |
|
margin-bottom: 20px; |
|
} |
|
|
|
.order-confirmed { |
|
background: linear-gradient(135deg, #FFF7ED 0%, #FFE4D6 100%); |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
.order-confirmed::before { |
|
content: '✔'; |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
font-size: 120px; |
|
color: rgba(16, 185, 129, 0.1); |
|
z-index: 0; |
|
} |
|
.order-confirmed h1 { |
|
font-size: 2.25rem; |
|
z-index: 1; |
|
position: relative; |
|
} |
|
|
|
.tier-details { |
|
overflow: hidden; |
|
transition: max-height 0.5s ease-in-out, opacity 0.3s ease-in-out; |
|
max-height: 0; |
|
opacity: 0; |
|
} |
|
.tier-details:not(.hidden) { |
|
max-height: 1000px; |
|
opacity: 1; |
|
animation: slideDown 0.5s ease-in-out; |
|
} |
|
|
|
.price-badge { |
|
display: inline-block; |
|
background: #FFE4D6; |
|
padding: 6px 14px; |
|
border-radius: 14px; |
|
font-weight: 600; |
|
color: #C2410C; |
|
} |
|
|
|
.ingredients-toggle-button:focus { |
|
outline: none; |
|
transform: scale(1.05); |
|
} |
|
|
|
@media (max-width: 768px) { |
|
.custom-class { |
|
padding: 20px !important; |
|
max-width: 400px; |
|
} |
|
.order-image { |
|
max-height: 270px; |
|
} |
|
.order-item-name { |
|
font-size: 1.25rem; |
|
padding: 6px 12px; |
|
} |
|
.grid { |
|
grid-template-columns: repeat(2, 1fr); |
|
} |
|
} |
|
@media (max-width: 480px) { |
|
.custom-class { |
|
max-width: 336px; |
|
} |
|
.order-image { |
|
max-height: 225px; |
|
} |
|
.order-item-name { |
|
font-size: 1.125rem; |
|
} |
|
} |
|
@media (max-width: 360px) { |
|
.custom-class { |
|
max-width: 296px; |
|
} |
|
.order-image { |
|
max-height: 195px; |
|
} |
|
.order-item-name { |
|
font-size: 1rem; |
|
padding: 4px 10px; |
|
} |
|
} |
|
@media (max-width: 640px) { |
|
.back-to-menu { |
|
padding: 12px 16px; |
|
font-size: 1rem; |
|
} |
|
.container { |
|
margin-top: 70px; |
|
padding: 16px; |
|
} |
|
.history { |
|
font-size: 1.5rem; |
|
padding: 1rem; |
|
} |
|
.sector-image { |
|
max-width: 120px; |
|
max-height: 80px; |
|
} |
|
.sector-name { |
|
max-width: 120px; |
|
} |
|
.sector-item { |
|
padding: 6px; |
|
} |
|
.order-confirmed h1 { |
|
font-size: 1.75rem; |
|
} |
|
.scroll-button { |
|
width: 32px; |
|
height: 32px; |
|
font-size: 16px; |
|
} |
|
#popup-content { |
|
width: 95%; |
|
padding: 16px; |
|
max-height: 80vh; |
|
} |
|
.ingredient-modal { |
|
width: 95%; |
|
max-height: 80vh; |
|
} |
|
.popup-close { |
|
width: 40px; |
|
height: 40px; |
|
font-size: 24px; |
|
} |
|
.popup-close::before { |
|
animation: lightMoveUp 1.2s infinite linear; |
|
} |
|
.ingredient-image { |
|
max-height: 80px; |
|
height: 80px; |
|
} |
|
.grid { |
|
grid-template-columns: repeat(2, 1fr); |
|
} |
|
} |
|
@media (min-width: 768px) { |
|
.grid { |
|
grid-template-columns: repeat(3, 1fr); |
|
} |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-50"> |
|
<a href="{{ url_for('menu.menu') }}" class="back-to-menu" aria-label="Go back to menu"> |
|
<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"> |
|
<path d="M15 18l-6-6 6-6"></path> |
|
</svg> |
|
Back to Menu |
|
</a> |
|
|
|
<div class="container mx-auto p-6 pt-2"> |
|
|
|
<div class="section bg-white shadow-sm rounded-xl p-6 mb-6 order-confirmed" role="alert"> |
|
<h1 class="text-center text-2xl font-bold text-orange-500">Order Confirmed!</h1> |
|
<p class="text-center text-gray-600 mt-2">Estimated delivery time: {{ delivery_time }} minutes</p> |
|
</div> |
|
|
|
|
|
<div class="section bg-white rounded-xl shadow-lg p-6 mb-6"> |
|
<div class="flex items-center justify-between mb-4 cursor-pointer" onclick="toggleTierDetails()" aria-expanded="false" aria-controls="tierDetails"> |
|
<div id="tierBadge" class="w-8 h-8 p-1 rounded-full flex items-center justify-center tier-badge"> |
|
<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"> |
|
<path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"></path> |
|
<path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"></path> |
|
<path d="M4 22h16"></path> |
|
<path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"></path> |
|
<path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"></path> |
|
<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> |
|
<path d="M18 9H6a4 4 0 0 1 0-8h12a4 4 0 0 1 0 8Z"></path> |
|
</svg> |
|
</div> |
|
<span class="ml-2 text-xl font-bold text-orange-500" id="currentTier">{{ current_tier }} Tier</span> |
|
<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"> |
|
<path id="arrowPath" d="M19 9l-7 7-7-7"></path> |
|
</svg> |
|
</div> |
|
|
|
|
|
<div id="tierDetails" class="tier-details hidden"> |
|
<div class="text-center mb-6"> |
|
<p class="text-gray-600">Valid through December {{ validity_year }}</p> |
|
<p class="text-lg font-semibold mt-2 text-yellow-600" id="pointsDisplay">{{ user_points }} points</p> |
|
</div> |
|
|
|
|
|
<div class="relative h-4 bg-gray-200 rounded-full overflow-hidden mb-4"> |
|
<div id="progressBar" class="absolute left-0 top-0 h-full progress-bar" style="width: {{ progress_percentage }}%"></div> |
|
</div> |
|
|
|
<div class="flex justify-between text-sm text-gray-600 mb-4"> |
|
<span id="startPoint">{{ start_point }}</span> |
|
<span id="endPoint">{{ end_point }}</span> |
|
</div> |
|
|
|
<p class="text-center text-gray-700"> |
|
You need <span class="font-semibold text-gray-800" id="pointsNeeded">{{ points_needed_for_next_tier }}</span> more |
|
points to reach |
|
<span class="font-semibold text-orange-500" id="nextTier">{{ next_tier }}</span> |
|
</p> |
|
|
|
|
|
<div class="mt-6 bg-gray-50 rounded-xl p-4"> |
|
<h3 class="text-lg font-semibold mb-4 text-gray-800" id="benefitsTitle"> |
|
Benefits of Reaching {{ next_tier }} Tier |
|
</h3> |
|
<ul class="space-y-3" id="benefitsList"> |
|
{% if next_tier == "Silver" %} |
|
<li class="flex items-center"> |
|
<span class="text-2xl mr-3">🏷️</span> |
|
<span class="text-gray-700">10% discount on next purchase</span> |
|
</li> |
|
<li class="flex items-center"> |
|
<span class="text-2xl mr-3">🍹</span> |
|
<span class="text-gray-700">Free soft drink with your next order</span> |
|
</li> |
|
{% elif next_tier == "Gold" %} |
|
<li class="flex items-center"> |
|
<span class="text-2xl mr-3">🏷️</span> |
|
<span class="text-gray-700">15% discount on next purchase</span> |
|
</li> |
|
<li class="flex items-center"> |
|
<span class="text-2xl mr-3">🍰</span> |
|
<span class="text-gray-700">Free dessert on next order</span> |
|
</li> |
|
{% elif next_tier == "Platinum" %} |
|
<li class="flex items-center"> |
|
<span class="text-2xl mr-3">🏷️</span> |
|
<span class="text-gray-700">20% discount on next purchase</span> |
|
</li> |
|
<li class="flex items-center"> |
|
<span class="text-2xl mr-3">🍴</span> |
|
<span class="text-gray-700">Free entrée with your next order</span> |
|
</li> |
|
{% else %} |
|
<li class="text-gray-700">You've reached the highest tier! Enjoy exclusive benefits.</li> |
|
{% endif %} |
|
</ul> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="history"> |
|
<h1 class="text-center text-2xl font-bold text-orange-500">Ingredient History</h1> |
|
</div> |
|
{% if sector_details %} |
|
<div class="sector-images-container" role="region" aria-label="Ingredient History Carousel"> |
|
<button class="scroll-button left" onclick="scrollContainer('left')" aria-label="Scroll left"> |
|
<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"> |
|
<path d="M15 18l-6-6 6-6"></path> |
|
</svg> |
|
</button> |
|
{% for sector_name, sector in sector_details.items() %} |
|
<div class="sector-item"> |
|
<img |
|
src="{{ sector.image_url | default('/static/placeholder.jpg') }}" |
|
alt="{{ sector_name }}" |
|
class="sector-image lazyload" |
|
loading="lazy" |
|
onclick="showSectorDescription('{{ sector.description | escape }}')" |
|
role="img" |
|
aria-describedby="sector-name-{{ loop.index }}" |
|
onerror="this.src='/static/placeholder.jpg'; this.alt='Placeholder image'" |
|
> |
|
<h3 id="sector-name-{{ loop.index }}" class="sector-name">{{ sector_name }}</h3> |
|
</div> |
|
{% endfor %} |
|
<button class="scroll-button right" onclick="scrollContainer('right')" aria-label="Scroll right"> |
|
<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"> |
|
<path d="M9 18l6-6-6-6"></path> |
|
</svg> |
|
</button> |
|
</div> |
|
{% else %} |
|
<div class="no-data">No sector details available.</div> |
|
{% endif %} |
|
|
|
|
|
<div id="sector-popup" class="popup" style="display:none;" role="dialog" aria-modal="true" aria-labelledby="sector-popup-title"> |
|
<div id="popup-content"> |
|
<div class="popup-header flex justify-between items-center"> |
|
<h3 id="sector-popup-title" class="text-xl font-semibold text-gray-800">Origin History</h3> |
|
<button onclick="closePopup()" class="popup-close" aria-label="Close sector description popup"><span>×</span></button> |
|
</div> |
|
<p id="sector-description" class="text-gray-700 leading-relaxed"></p> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="text-center text-2xl font-bold text-orange-500 mb-6">Previous Orders</div> |
|
{% if order_items %} |
|
{% for item in order_items %} |
|
<div class="custom-class"> |
|
<div class="order-image-wrapper"> |
|
<img |
|
src="{{ item.image_url | default('/static/placeholder.jpg') }}" |
|
alt="{{ item.name | escape }}" |
|
class="order-image lazyload" |
|
loading="lazy" |
|
decoding="async" |
|
role="img" |
|
aria-label="Image of {{ item.name | escape }}" |
|
aria-describedby="order-price-{{ loop.index }}" |
|
onerror="this.src='/static/placeholder.jpg'; this.alt='Placeholder image'" |
|
/> |
|
<h3 class="order-item-name" id="order-name-{{ loop.index }}">{{ item.name | escape }}</h3> |
|
</div> |
|
<p id="order-price-{{ loop.index }}" class="text-gray-600 mb-2 price-badge">${{ "%.2f"|format(item.price | default(0)) }}</p> |
|
|
|
{% if item.category != 'Soft Drink' %} |
|
<button |
|
id="ingredientsToggleButton{{ loop.index }}" |
|
class="ingredients-toggle-button 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 }}" |
|
data-index="{{ loop.index }}" |
|
> |
|
Show Ingredients |
|
</button> |
|
|
|
<div id="ingredientsSection{{ loop.index }}" class="ingredients-section hidden mt-4" aria-hidden="true"> |
|
{% if item.ingredients and item.ingredients|length > 0 %} |
|
<div class="grid grid-cols-2 gap-4 sm:grid-cols-3"> |
|
{% for ingredient in item.ingredients %} |
|
<button |
|
class="relative group ingredient-button focus:outline-none focus:ring-2 focus:ring-green-500" |
|
aria-label="View details for {{ ingredient.name | escape }}" |
|
data-ingredient='{ |
|
"index": "{{ loop.index }}", |
|
"name": "{{ ingredient.name | escape }}", |
|
"image": "{{ ingredient.image | default('/static/placeholder.jpg') | escape }}", |
|
"health_benefits": "{{ ingredient.health_benefits | escape }}", |
|
"fun_facts": "{{ ingredient.fun_facts | escape }}" |
|
}' |
|
onclick="showIngredientDetails(this)" |
|
> |
|
<div class="overflow-hidden rounded-lg"> |
|
<img |
|
src="{{ ingredient.image | default('/static/placeholder.jpg') }}" |
|
alt="{{ ingredient.name | escape }}" |
|
class="ingredient-image lazyload" |
|
loading="lazy" |
|
decoding="async" |
|
onerror="this.src='/static/placeholder.jpg'; this.alt='Placeholder image'" |
|
/> |
|
</div> |
|
<p class="mt-2 text-center text-sm font-medium text-gray-800">{{ ingredient.name | escape }}</p> |
|
</button> |
|
{% endfor %} |
|
</div> |
|
{% else %} |
|
<p class="text-gray-600 text-center">No ingredients available for this item.</p> |
|
{% endif %} |
|
</div> |
|
{% endif %} |
|
</div> |
|
|
|
|
|
{% if item.category != 'Soft Drink' %} |
|
<div id="ingredientModal{{ loop.index }}" class="ingredient-modal-container hidden modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle{{ loop.index }}"> |
|
<div class="ingredient-modal"> |
|
<div class="p-6"> |
|
<div class="popup-header flex justify-between items-center mb-4"> |
|
<h3 id="modalTitle{{ loop.index }}" class="text-xl font-semibold text-gray-800"></h3> |
|
<button onclick="closeModal({{ loop.index }})" class="popup-close" aria-label="Close ingredient details modal"><span>×</span></button> |
|
</div> |
|
|
|
<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" /> |
|
|
|
<div class="space-y-4"> |
|
<div class="modal-section"> |
|
<h4 class="font-semibold mb-2 text-gray-800 flex items-center"> |
|
<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"> |
|
<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> |
|
</svg> |
|
Health Benefits |
|
</h4> |
|
<ul id="healthBenefits{{ loop.index }}" class="list-disc list-inside text-gray-700"></ul> |
|
</div> |
|
|
|
<div class="modal-section"> |
|
<h4 class="font-semibold mb-2 text-gray-800 flex items-center"> |
|
<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"> |
|
<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> |
|
</svg> |
|
Fun Facts |
|
</h4> |
|
<ul id="funFacts{{ loop.index }}" class="list-disc list-inside text-gray-700"></ul> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
{% endif %} |
|
{% endfor %} |
|
{% else %} |
|
<div class="no-data">No previous orders found.</div> |
|
{% endif %} |
|
</div> |
|
|
|
<script> |
|
|
|
function debounce(func, wait) { |
|
let timeout; |
|
return function executedFunction(...args) { |
|
const later = () => { |
|
clearTimeout(timeout); |
|
func(...args); |
|
}; |
|
clearTimeout(timeout); |
|
timeout = setTimeout(later, wait); |
|
}; |
|
} |
|
|
|
|
|
function scrollContainer(direction) { |
|
try { |
|
const container = document.querySelector('.sector-images-container'); |
|
const scrollAmount = 200; |
|
if (direction === 'left') { |
|
container.scrollLeft -= scrollAmount; |
|
} else { |
|
container.scrollLeft += scrollAmount; |
|
} |
|
} catch (e) { |
|
console.error('Error scrolling container:', e); |
|
} |
|
} |
|
|
|
|
|
function showSectorDescription(description) { |
|
try { |
|
document.getElementById('sector-description').innerText = description || 'No description available.'; |
|
document.getElementById('sector-popup').style.display = 'flex'; |
|
document.body.classList.add('modal-open'); |
|
} catch (e) { |
|
console.error('Error showing sector description:', e); |
|
} |
|
} |
|
|
|
|
|
function closePopup() { |
|
try { |
|
document.getElementById('sector-popup').style.display = 'none'; |
|
document.body.classList.remove('modal-open'); |
|
} catch (e) { |
|
console.error('Error closing popup:', e); |
|
} |
|
} |
|
|
|
|
|
function toggleTierDetails() { |
|
try { |
|
const tierDetails = document.getElementById('tierDetails'); |
|
const arrowPath = document.getElementById('arrowPath'); |
|
const toggleButton = tierDetails.parentElement.querySelector('[aria-controls="tierDetails"]'); |
|
const isExpanded = !tierDetails.classList.contains('hidden'); |
|
tierDetails.classList.toggle('hidden'); |
|
arrowPath.setAttribute('d', tierDetails.classList.contains('hidden') ? 'M19 9l-7 7-7-7' : 'M19 15l-7-7-7 7'); |
|
toggleButton.setAttribute('aria-expanded', !isExpanded); |
|
} catch (e) { |
|
console.error('Error toggling tier details:', e); |
|
} |
|
} |
|
|
|
|
|
function toggleIngredients(index) { |
|
try { |
|
const section = document.getElementById(`ingredientsSection${index}`); |
|
const button = document.getElementById(`ingredientsToggleButton${index}`); |
|
|
|
if (!section || !button) { |
|
console.error(`Elements not found for index ${index}`); |
|
return; |
|
} |
|
|
|
const isHidden = section.classList.contains('hidden'); |
|
|
|
|
|
document.querySelectorAll('.ingredients-section').forEach(s => { |
|
s.classList.add('hidden'); |
|
s.setAttribute('aria-hidden', 'true'); |
|
}); |
|
document.querySelectorAll('[id^="ingredientsToggleButton"]').forEach(b => { |
|
b.textContent = 'Show Ingredients'; |
|
b.setAttribute('aria-expanded', 'false'); |
|
}); |
|
|
|
|
|
if (isHidden) { |
|
section.classList.remove('hidden'); |
|
section.setAttribute('aria-hidden', 'false'); |
|
button.textContent = 'Hide Ingredients'; |
|
button.setAttribute('aria-expanded', 'true'); |
|
} else { |
|
section.classList.add('hidden'); |
|
section.setAttribute('aria-hidden', 'true'); |
|
button.textContent = 'Show Ingredients'; |
|
button.setAttribute('aria-expanded', 'false'); |
|
} |
|
} catch (e) { |
|
console.error('Error toggling ingredients:', e); |
|
} |
|
} |
|
|
|
|
|
function showIngredientDetails(button) { |
|
try { |
|
const data = JSON.parse(button.getAttribute('data-ingredient')); |
|
const { index, name, image, health_benefits, fun_facts } = data; |
|
|
|
const healthBenefitsList = (health_benefits || '').split(',').filter(item => item.trim()); |
|
const funFactsList = (fun_facts || '').split(',').filter(item => item.trim()); |
|
|
|
const modal = document.getElementById(`ingredientModal${index}`); |
|
if (!modal) { |
|
console.error(`Modal not found for index ${index}`); |
|
return; |
|
} |
|
|
|
document.getElementById(`modalTitle${index}`).textContent = name || 'Unknown Ingredient'; |
|
const modalImage = document.getElementById(`modalImage${index}`); |
|
modalImage.src = image || '/static/placeholder.jpg'; |
|
modalImage.alt = name || 'Ingredient image'; |
|
|
|
const healthBenefitsUl = document.getElementById(`healthBenefits${index}`); |
|
const funFactsUl = document.getElementById(`funFacts${index}`); |
|
healthBenefitsUl.innerHTML = healthBenefitsList.length |
|
? healthBenefitsList.map(item => `<li>${item.trim()}</li>`).join('') |
|
: '<li>No health benefits available.</li>'; |
|
funFactsUl.innerHTML = funFactsList.length |
|
? funFactsList.map(item => `<li>${item.trim()}</li>`).join('') |
|
: '<li>No fun facts available.</li>'; |
|
|
|
modal.style.display = 'flex'; |
|
document.body.classList.add('modal-open'); |
|
} catch (e) { |
|
console.error('Error showing ingredient details:', e); |
|
} |
|
} |
|
|
|
|
|
function closeModal(index) { |
|
try { |
|
const modal = document.getElementById(`ingredientModal${index}`); |
|
if (modal) { |
|
modal.style.display = 'none'; |
|
document.body.classList.remove('modal-open'); |
|
} |
|
} catch (e) { |
|
console.error('Error closing modal:', e); |
|
} |
|
} |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
try { |
|
const progressBar = document.getElementById('progressBar'); |
|
const pointsDisplay = document.getElementById('pointsDisplay'); |
|
const points = parseInt(pointsDisplay.textContent, 10) || 0; |
|
|
|
if (points <= 100) { |
|
progressBar.classList.add('range-0-100'); |
|
} else if (points <= 200) { |
|
progressBar.classList.add('range-100-200'); |
|
} else { |
|
progressBar.classList.add('range-200-plus'); |
|
} |
|
} catch (e) { |
|
console.error('Error setting progress bar color:', e); |
|
} |
|
|
|
|
|
const images = document.querySelectorAll('img.lazyload'); |
|
if ('IntersectionObserver' in window) { |
|
const observer = new IntersectionObserver((entries, observer) => { |
|
entries.forEach(entry => { |
|
if (entry.isIntersecting) { |
|
const img = entry.target; |
|
img.src = img.src || '/static/placeholder.jpg'; |
|
img.classList.remove('lazyload'); |
|
observer.unobserve(img); |
|
} |
|
}); |
|
}); |
|
images.forEach(img => observer.observe(img)); |
|
} else { |
|
images.forEach(img => { |
|
img.src = img.src || '/static/placeholder.jpg'; |
|
img.classList.remove('lazyload'); |
|
}); |
|
} |
|
}); |
|
|
|
|
|
document.addEventListener('click', (e) => { |
|
try { |
|
if (e.target.id === 'sector-popup') { |
|
closePopup(); |
|
} |
|
document.querySelectorAll('.ingredient-modal-container').forEach(modal => { |
|
if (e.target === modal) { |
|
const index = modal.id.replace('ingredientModal', ''); |
|
closeModal(index); |
|
} |
|
}); |
|
} catch (e) { |
|
console.error('Error handling outside click:', e); |
|
} |
|
}); |
|
|
|
|
|
document.querySelectorAll('.scroll-button').forEach(button => { |
|
button.addEventListener('keydown', function(e) { |
|
if (e.key === 'Enter' || e.key === ' ') { |
|
e.preventDefault(); |
|
scrollContainer(button.classList.contains('left') ? 'left' : 'right'); |
|
} |
|
}); |
|
}); |
|
|
|
|
|
document.querySelectorAll('[id^="ingredientsToggleButton"]').forEach(button => { |
|
button.addEventListener('keydown', (e) => { |
|
if (e.key === 'Enter' || e.key === ' ') { |
|
e.preventDefault(); |
|
const index = button.getAttribute('data-index'); |
|
toggleIngredients(index); |
|
} |
|
}); |
|
}); |
|
</script> |
|
</body> |
|
</html> |