lokesh341 commited on
Commit
54a3c48
·
verified ·
1 Parent(s): 8d0fd70

Update menu.py

Browse files
Files changed (1) hide show
  1. menu.py +2034 -178
menu.py CHANGED
@@ -1,180 +1,2036 @@
1
- from flask import Blueprint, render_template, request, session, jsonify, redirect, url_for
2
- from salesforce import get_salesforce_connection
3
- import os
4
-
5
- menu_blueprint = Blueprint('menu', __name__)
6
-
7
- # Initialize Salesforce connection
8
- sf = get_salesforce_connection()
9
-
10
- # Constants for video handling
11
- STATIC_DIR = os.path.join(os.path.dirname(__file__), 'static')
12
- PLACEHOLDER_VIDEO = 'placeholder.mp4'
13
- PLACEHOLDER_PATH = os.path.join(STATIC_DIR, PLACEHOLDER_VIDEO)
14
- SECTION_ORDER = ["Best Sellers", "Starters", "Biryanis", "Curries", "Breads", "Customized dish", "Apetizer", "Desserts", "Soft Drinks"]
15
-
16
- # Create placeholder video at startup if it doesn't exist
17
- if not os.path.exists(PLACEHOLDER_PATH):
18
- open(PLACEHOLDER_PATH, 'wb').close()
19
- print(f"Created placeholder video at {PLACEHOLDER_PATH}")
20
-
21
- def get_valid_video_path(item_name, video_url=None):
22
- """
23
- Get valid video path for item with placeholder fallback
24
- Priority: 1. Video1__c from Salesforce 2. placeholder.mp4
25
- """
26
- # First try: Video1__c from Salesforce if provided
27
- if video_url:
28
- # If it's a complete URL (http/https)
29
- if video_url.startswith(('http://', 'https://')):
30
- return video_url
31
- # If it's a relative path (/videos/xxx.mp4)
32
- elif video_url.startswith('/'):
33
- return video_url
34
- # If it's a Salesforce File ID (starts with '069')
35
- elif video_url.startswith('069'):
36
- return f"https://yourdomain.my.salesforce.com/sfc/servlet.shepherd/version/download/{video_url}"
37
-
38
- # Final fallback: placeholder.mp4
39
- if not os.path.exists(PLACEHOLDER_PATH):
40
- open(PLACEHOLDER_PATH, 'wb').close()
41
- print(f"Created missing placeholder video at {PLACEHOLDER_PATH}")
42
-
43
- return f"/static/{PLACEHOLDER_VIDEO}"
44
-
45
- @menu_blueprint.route("/menu", methods=["GET", "POST"])
46
- def menu():
47
- selected_category = request.args.get("category", "All")
48
- user_email = session.get('user_email')
49
-
50
- if not user_email:
51
- user_email = request.args.get("email")
52
- user_name = request.args.get("name")
53
-
54
- if user_email:
55
- session['user_email'] = user_email
56
- session['user_name'] = user_name
57
- else:
58
- return redirect(url_for("login"))
59
- else:
60
- user_name = session.get('user_name')
61
-
62
- first_letter = user_name[0].upper() if user_name else "A"
63
-
64
- try:
65
- # Fetch user referral and reward points
66
- user_query = f"SELECT Referral__c, Reward_Points__c FROM Customer_Login__c WHERE Email__c = '{user_email}'"
67
- user_result = sf.query(user_query)
68
-
69
- if not user_result['records']:
70
- return redirect(url_for('login'))
71
-
72
- referral_code = user_result['records'][0].get('Referral__c', 'N/A')
73
- reward_points = user_result['records'][0].get('Reward_Points__c', 0)
74
-
75
- # Get cart item count
76
- cart_query = f"SELECT COUNT() FROM Cart_Item__c WHERE Customer_Email__c = '{user_email}'"
77
- cart_count_result = sf.query(cart_query)
78
- cart_item_count = cart_count_result['totalSize']
79
-
80
- # Query to fetch Menu_Item__c records including Video1__c
81
- menu_query = """
82
- SELECT Name, Price__c, Description__c, Image1__c, Image2__c,
83
- Veg_NonVeg__c, Section__c, Total_Ordered__c, Video1__c
84
- FROM Menu_Item__c
85
- """
86
- result = sf.query(menu_query)
87
- food_items = result['records'] if 'records' in result else []
88
-
89
- # Process items and add video paths
90
- for item in food_items:
91
- if 'Total_Ordered__c' not in item or item['Total_Ordered__c'] is None:
92
- item['Total_Ordered__c'] = 0
93
- item['Video1__c'] = get_valid_video_path(item['Name'], item.get('Video1__c'))
94
-
95
- # Query to fetch Custom_Dish__c records
96
- custom_dish_query = """
97
- SELECT Name, Price__c, Description__c, Image1__c, Image2__c,
98
- Veg_NonVeg__c, Section__c, Total_Ordered__c
99
- FROM Custom_Dish__c
100
- WHERE CreatedDate >= LAST_N_DAYS:7
101
- """
102
- custom_dish_result = sf.query(custom_dish_query)
103
- custom_dishes = custom_dish_result.get('records', [])
104
-
105
- # Process custom dishes and add video paths
106
- for item in custom_dishes:
107
- if 'Total_Ordered__c' not in item or item['Total_Ordered__c'] is None:
108
- item['Total_Ordered__c'] = 0
109
- item['Video1__c'] = get_valid_video_path(item['Name'])
110
-
111
- # Merge both Menu_Item__c and Custom_Dish__c records
112
- all_items = food_items + custom_dishes
113
- ordered_menu = {section: [] for section in SECTION_ORDER}
114
-
115
- # Process best sellers
116
- best_sellers = sorted(all_items, key=lambda x: x.get("Total_Ordered__c", 0), reverse=True)
117
 
118
- if selected_category == "Veg":
119
- best_sellers = [item for item in best_sellers if item.get("Veg_NonVeg__c") in ["Veg", "both"]]
120
- elif selected_category == "Non veg":
121
- best_sellers = [item for item in best_sellers if item.get("Veg_NonVeg__c") in ["Non veg", "both"]]
122
-
123
- best_sellers = best_sellers[:4]
124
- if best_sellers:
125
- ordered_menu["Best Sellers"] = best_sellers
126
-
127
- # Organize other sections
128
- added_item_names = set()
129
- for item in all_items:
130
- section = item.get("Section__c", "Others")
131
- if section not in ordered_menu:
132
- ordered_menu[section] = []
133
-
134
- if item['Name'] in added_item_names:
135
- continue
136
-
137
- if selected_category == "Veg" and item.get("Veg_NonVeg__c") not in ["Veg", "both"]:
138
- continue
139
- if selected_category == "Non veg" and item.get("Veg_NonVeg__c") not in ["Non veg", "both"]:
140
- continue
141
-
142
- ordered_menu[section].append(item)
143
- added_item_names.add(item['Name'])
144
-
145
- ordered_menu = {section: items for section, items in ordered_menu.items() if items}
146
- categories = ["All", "Veg", "Non veg"]
147
-
148
- except Exception as e:
149
- print(f"Error fetching menu data: {str(e)}")
150
- # Fallback data with video support
151
- ordered_menu = {section: [] for section in SECTION_ORDER}
152
- best_sellers = ["Chicken Biryani", "Paneer Butter Masala", "Veg Manchurian", "Prawn Fry"]
153
- ordered_menu["Best Sellers"] = [{
154
- "Name": name,
155
- "Price__c": "12.99",
156
- "Description__c": f"Popular {name}",
157
- "Image1__c": "/static/placeholder.jpg",
158
- "Video1__c": get_valid_video_path(name),
159
- "Total_Ordered__c": 100,
160
- "Veg_NonVeg__c": "Veg" if "Paneer" in name or "Veg" in name else "Non veg"
161
- } for name in best_sellers]
162
 
163
- categories = ["All", "Veg", "Non veg"]
164
- referral_code = 'N/A'
165
- reward_points = 0
166
- cart_item_count = 0
167
-
168
- return render_template(
169
- "menu.html",
170
- ordered_menu=ordered_menu,
171
- categories=categories,
172
- selected_category=selected_category,
173
- referral_code=referral_code,
174
- reward_points=reward_points,
175
- user_name=user_name,
176
- first_letter=first_letter,
177
- cart_item_count=cart_item_count
178
- )
179
-
180
- # [Rest of your existing routes...]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- templates/menu.html -->
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Menu</title>
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
+ <link rel="preload" href="/static/placeholder.jpg" as="image">
11
+ {% for section, items in ordered_menu.items() %}
12
+ {% for item in items[:1] %}
13
+ <link rel="preload" href="{{ item.Image1__c }}" as="image" fetchpriority="high">
14
+ {% endfor %}
15
+ {% endfor %}
16
+ <style>
17
+ body {
18
+ font-family: Arial, sans-serif;
19
+ background-color: #fdf4e3;
20
+ margin: 0;
21
+ padding: 0;
22
+ display: flex;
23
+ flex-direction: column;
24
+ }
25
+ .container {
26
+ max-width: 900px;
27
+ }
28
+ .menu-card {
29
+ max-width: 350px;
30
+ border-radius: 15px;
31
+ overflow: hidden;
32
+ background-color: #fff;
33
+ margin: auto;
34
+ display: flex;
35
+ flex-direction: column;
36
+ opacity: 0;
37
+ transition: opacity 0.3s ease-in-out;
38
+ }
39
+ .menu-card.visible {
40
+ opacity: 1;
41
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
+ .video-container {
44
+ position: relative;
45
+ width: 100%;
46
+ height: 200px;
47
+ overflow: hidden;
48
+ border-radius: 15px 15px 0 0;
49
+ background-color: #000;
50
+ touch-action: manipulation;
51
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
+ .video-container video {
54
+ width: 100%;
55
+ height: 100%;
56
+ object-fit: cover;
57
+ transition: opacity 0.5s ease;
58
+ -webkit-user-select: none;
59
+ user-select: none;
60
+ }
61
+
62
+ .video-container .video-placeholder {
63
+ position: absolute;
64
+ top: 0;
65
+ left: 0;
66
+ width: 100%;
67
+ height: 100%;
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ background-color: #f0f0f0;
72
+ color: #666;
73
+ font-size: 14px;
74
+ }
75
+
76
+ .video-container .play-button {
77
+ position: absolute;
78
+ top: 50%;
79
+ left: 50%;
80
+ transform: translate(-50%, -50%);
81
+ width: 50px;
82
+ height: 50px;
83
+ background-color: rgba(0, 0, 0, 0.7);
84
+ border-radius: 50%;
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ cursor: pointer;
89
+ z-index: 10;
90
+ opacity: 0;
91
+ transition: opacity 0.3s ease;
92
+ }
93
+
94
+ .video-container:hover .play-button {
95
+ opacity: 1;
96
+ }
97
+
98
+ .video-container .play-button i {
99
+ color: white;
100
+ font-size: 20px;
101
+ margin-left: 3px;
102
+ }
103
+
104
+ @media (max-width: 768px) {
105
+ .video-container .play-button {
106
+ opacity: 1;
107
+ }
108
+ .video-container:hover .play-button {
109
+ opacity: 1;
110
+ }
111
+ .video-container {
112
+ height: 150px;
113
+ }
114
+ }
115
+
116
+ .card-title {
117
+ font-size: 1.2rem;
118
+ font-weight: bold;
119
+ margin: 10px 0;
120
+ }
121
+ .card-text {
122
+ font-size: 1rem;
123
+ color: #6c757d;
124
+ }
125
+ .addbutton .btn {
126
+ background-color: #28a745;
127
+ color: white;
128
+ padding: 10px 20px;
129
+ font-size: 16px;
130
+ font-weight: bold;
131
+ border-radius: 5px;
132
+ border: none;
133
+ transition: background-color 0.3s ease;
134
+ margin-left: 13px;
135
+ }
136
+ .addbutton .btn:hover {
137
+ background-color: #218838;
138
+ }
139
+ .button-container {
140
+ display: flex;
141
+ flex-direction: column;
142
+ align-items: center;
143
+ justify-content: center;
144
+ gap: 6px;
145
+ }
146
+ .customisable-text {
147
+ color: #0FAA39;
148
+ font-size: 10px;
149
+ font-weight: 500;
150
+ margin: 0;
151
+ text-align: center;
152
+ line-height: 1;
153
+ }
154
+ .btn-primary {
155
+ font-size: 12px;
156
+ font-weight: bold;
157
+ border-radius: 8px;
158
+ width: 70px;
159
+ height: 35px;
160
+ background-color: #0FAA39;
161
+ border-color: #0FAA39;
162
+ display: flex;
163
+ align-items: center;
164
+ justify-content: center;
165
+ padding: 0;
166
+ transition: background-color 0.3s ease, transform 0.1s ease;
167
+ }
168
+ .btn-primary:hover {
169
+ background-color: #0D9232;
170
+ border-color: #0D9232;
171
+ transform: scale(1.05);
172
+ }
173
+ .btn-primary:active,
174
+ .btn-primary:focus {
175
+ background-color: #0B7A29;
176
+ border-color: #0B7A29;
177
+ box-shadow: none;
178
+ transform: scale(0.98);
179
+ }
180
+ .view-cart-container {
181
+ position: fixed;
182
+ bottom: 20px;
183
+ right: 20px;
184
+ z-index: 999;
185
+ display: flex;
186
+ align-items: center;
187
+ }
188
+ .view-cart-button {
189
+ background-color: #0FAA39;
190
+ color: #fff;
191
+ padding: 10px 20px;
192
+ border-radius: 30px;
193
+ font-size: 1rem;
194
+ font-weight: bold;
195
+ text-decoration: none;
196
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
197
+ display: flex;
198
+ align-items: center;
199
+ justify-content: center;
200
+ gap: 8px;
201
+ transition: background-color 0.3s ease, transform 0.2s ease;
202
+ }
203
+ .view-cart-button:hover {
204
+ background-color: #109835;
205
+ text-decoration: none;
206
+ color: #fff;
207
+ transform: scale(1.05);
208
+ }
209
+ .cart-icon-badge {
210
+ background-color: #fff;
211
+ color: #0FAA39;
212
+ border-radius: 50%;
213
+ width: 24px;
214
+ height: 24px;
215
+ display: flex;
216
+ align-items: center;
217
+ justify-content: center;
218
+ font-size: 12px;
219
+ font-weight: bold;
220
+ margin-left: 5px;
221
+ transition: background-color 0.3s ease, color 0.3s ease;
222
+ }
223
+ .cart-icon-badge.active {
224
+ background-color: #ffcc00;
225
+ color: #0FAA39;
226
+ }
227
+ .avatar-dropdown-container {
228
+ position: absolute;
229
+ right: 10px;
230
+ top: 50%;
231
+ transform: translateY(-50%);
232
+ display: flex;
233
+ align-items: right;
234
+ justify-content: center;
235
+ }
236
+ .avatar-icon {
237
+ width: 40px;
238
+ height: 40px;
239
+ border-radius: 50%;
240
+ background-color: #5bbfc1;
241
+ cursor: pointer;
242
+ display: flex;
243
+ align-items: center;
244
+ justify-content: center;
245
+ color: white;
246
+ font-size: 20px;
247
+ font-weight: bold;
248
+ }
249
+ .dropdown-menu {
250
+ position: absolute;
251
+ right: 0;
252
+ top: 100%;
253
+ background-color: #fff;
254
+ border-radius: 5px;
255
+ width: 220px;
256
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
257
+ display: none;
258
+ }
259
+ .dropdown-menu .dropdown-item {
260
+ padding: 12px 16px;
261
+ text-decoration: none;
262
+ color: #333;
263
+ border-bottom: 1px solid #ddd;
264
+ display: block;
265
+ font-size: 15px;
266
+ }
267
+ .dropdown-menu .dropdown-item:last-child {
268
+ border-bottom: none;
269
+ }
270
+ .dropdown-menu .dropdown-item:hover {
271
+ background-color: #f1f1f1;
272
+ }
273
+ .fixed-top-bar {
274
+ position: relative;
275
+ top: 0;
276
+ left: 0;
277
+ width: 100%;
278
+ height: 54px;
279
+ background: linear-gradient(45deg, #FFA07A, #FFB347);
280
+ color: white;
281
+ padding: 15px;
282
+ display: flex;
283
+ justify-content: space-between;
284
+ align-items: center;
285
+ z-index: 1000;
286
+ }
287
+ .search-bar-container {
288
+ position: absolute;
289
+ left: 20px;
290
+ top: 50%;
291
+ transform: translateY(-50%);
292
+ display: flex;
293
+ align-items: center;
294
+ width: 300px;
295
+ max-width: 90%;
296
+ }
297
+ .search-bar-container input {
298
+ width: 100%;
299
+ padding: 8px 15px 8px 40px;
300
+ font-size: 16px;
301
+ border-radius: 25px;
302
+ border: none;
303
+ background-color: #fff;
304
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
305
+ outline: none;
306
+ }
307
+ .search-bar-container input::placeholder {
308
+ color: #888;
309
+ }
310
+ .search-icon {
311
+ position: absolute;
312
+ left: 15px;
313
+ font-size: 18px;
314
+ color: #888;
315
+ }
316
+ .autocomplete-suggestions {
317
+ position: absolute;
318
+ top: 100%;
319
+ left: 0;
320
+ width: 100%;
321
+ max-height: 200px;
322
+ overflow-y: auto;
323
+ background-color: #fff;
324
+ border: 1px solid #ddd;
325
+ border-radius: 5px;
326
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
327
+ z-index: 1000;
328
+ display: none;
329
+ }
330
+ .autocomplete-suggestions .suggestion-item {
331
+ padding: 8px 15px;
332
+ cursor: pointer;
333
+ font-size: 14px;
334
+ color: #333;
335
+ }
336
+ .autocomplete-suggestions .suggestion-item:hover {
337
+ background-color: #f1f1f1;
338
+ }
339
+ .addon-section {
340
+ background-color: #fff;
341
+ border: 2px solid #6c757d;
342
+ border-radius: 8px;
343
+ padding: 12px;
344
+ margin-bottom: 10px;
345
+ }
346
+ .addon-section h6 {
347
+ margin-bottom: 10px;
348
+ font-size: 1.1rem;
349
+ font-weight: bold;
350
+ color: #343a40;
351
+ }
352
+ .addon-section .form-check {
353
+ display: inline-flex;
354
+ align-items: center;
355
+ margin-left: 10px;
356
+ color: #343a40;
357
+ }
358
+ .addon-section .form-check-input {
359
+ -webkit-appearance: none;
360
+ -moz-appearance: none;
361
+ appearance: none;
362
+ width: 20px;
363
+ height: 20px;
364
+ border: 2px solid #343a40;
365
+ border-radius: 5px;
366
+ background-color: #f0f0f0;
367
+ position: relative;
368
+ margin-right: 10px;
369
+ }
370
+ .addon-section .form-check-input:checked {
371
+ background-color: #006400;
372
+ border-color: #006400;
373
+ }
374
+ .addon-section .form-check-input:checked::before {
375
+ content: '\2713';
376
+ font-size: 14px;
377
+ position: absolute;
378
+ top: 3px;
379
+ left: 4px;
380
+ color: white;
381
+ }
382
+ .addon-section .form-check-label {
383
+ font-size: 16px;
384
+ margin-left: 5px;
385
+ margin-right: 15px;
386
+ cursor: pointer;
387
+ display: inline-block;
388
+ vertical-align: middle;
389
+ }
390
+ form.text-center.mb-4 {
391
+ display: flex;
392
+ flex-direction: column;
393
+ align-items: center;
394
+ justify-content: center;
395
+ margin-bottom: 5px;
396
+ }
397
+ .modal-header {
398
+ padding: 10px 15px;
399
+ }
400
+ .modal-title {
401
+ font-size: 16px;
402
+ font-weight: bold;
403
+ }
404
+ .modal-body {
405
+ max-height: 60vh;
406
+ overflow-y: auto;
407
+ padding: 15px;
408
+ }
409
+ .modal-body #modal-img {
410
+ max-height: 200px;
411
+ width: 100%;
412
+ object-fit: cover;
413
+ border-radius: 8px;
414
+ margin-bottom: 10px;
415
+ }
416
+ .modal-body #modal-name {
417
+ font-size: 20px;
418
+ font-weight: bold;
419
+ text-align: center;
420
+ margin-bottom: 5px;
421
+ }
422
+ .modal-body #modal-price {
423
+ font-size: 16px;
424
+ font-weight: bold;
425
+ color: #6c757d;
426
+ text-align: center;
427
+ margin-bottom: 10px;
428
+ }
429
+ .modal-body #modal-description {
430
+ font-size: 14px;
431
+ color: #6c757d;
432
+ margin-bottom: 10px;
433
+ }
434
+ .modal-body .nutritional-info {
435
+ font-size: 12px;
436
+ color: #6c757d;
437
+ margin-bottom: 10px;
438
+ }
439
+ .modal-body #modal-addons h6,
440
+ .modal-body #first-row h6 {
441
+ font-size: 14px;
442
+ font-weight: bold;
443
+ margin-bottom: 10px;
444
+ }
445
+ .modal-footer {
446
+ display: flex;
447
+ align-items: center;
448
+ justify-content: space-between;
449
+ padding: 10px;
450
+ }
451
+ .modal-footer .d-flex {
452
+ display: flex;
453
+ align-items: center;
454
+ gap: 10px;
455
+ }
456
+ .modal-footer .btn {
457
+ height: 40px;
458
+ padding: 0 15px;
459
+ }
460
+ .modal-footer .form-control {
461
+ width: 50px;
462
+ height: 40px;
463
+ text-align: center;
464
+ }
465
+ .modal-footer .btn-primary {
466
+ background-color: #0FAA39;
467
+ border-color: #0FAA39;
468
+ font-weight: bold;
469
+ padding: 10px 20px;
470
+ height: 40px;
471
+ display: flex;
472
+ justify-content: center;
473
+ align-items: center;
474
+ width: auto;
475
+ }
476
+ .modal-footer .btn-outline-secondary {
477
+ height: 40px;
478
+ width: 40px;
479
+ }
480
+ .item-details {
481
+ background-color: #f8f9fa;
482
+ border-radius: 8px;
483
+ padding: 10px;
484
+ margin: 10px 15px;
485
+ display: none;
486
+ }
487
+ .item-details.show {
488
+ display: block;
489
+ }
490
+ .item-details h6 {
491
+ font-size: 0.9rem;
492
+ font-weight: bold;
493
+ margin-bottom: 5px;
494
+ }
495
+ .item-details p {
496
+ font-size: 0.85rem;
497
+ margin-bottom: 5px;
498
+ color: #333;
499
+ }
500
+ .item-details .nutritional-info {
501
+ display: grid;
502
+ grid-template-columns: 1fr 1fr;
503
+ gap: 10px;
504
+ background-color: #e9ecef;
505
+ padding: 10px;
506
+ border-radius: 5px;
507
+ font-size: 0.85rem;
508
+ line-height: 1.5;
509
+ }
510
+ .toggle-details {
511
+ cursor: pointer;
512
+ color: #0FAA39;
513
+ font-size: 0.9rem;
514
+ margin-left: 15px;
515
+ margin-bottom: 10px;
516
+ display: inline-block;
517
+ }
518
+ .toggle-details:hover {
519
+ text-decoration: underline;
520
+ }
521
+ .category-buttons {
522
+ display: flex;
523
+ flex-wrap: wrap;
524
+ gap: 10px;
525
+ justify-content: center;
526
+ margin-top: 10px;
527
+ }
528
+ .category-button {
529
+ background-color: #fff;
530
+ border: 2px solid #0FAA39;
531
+ color: #0FAA39;
532
+ padding: 5px 15px;
533
+ border-radius: 20px;
534
+ font-size: 0.9rem;
535
+ cursor: pointer;
536
+ transition: background-color 0.3s, color 0.3s;
537
+ }
538
+ .category-button.selected {
539
+ background-color: #0FAA39;
540
+ color: #fff;
541
+ border-color: #0FAA39;
542
+ }
543
+ .category-button:hover {
544
+ background-color: #e6f4ea;
545
+ }
546
+ .quantity-selector {
547
+ display: flex;
548
+ align-items: center;
549
+ gap: 5px;
550
+ }
551
+ .quantity-selector .btn {
552
+ width: 25px;
553
+ height: 25px;
554
+ padding: 0;
555
+ font-size: 12px;
556
+ line-height: 25px;
557
+ text-align: center;
558
+ }
559
+ .quantity-selector .quantity-display {
560
+ width: 25px;
561
+ text-align: center;
562
+ font-size: 12px;
563
+ font-weight: bold;
564
+ line-height: 25px;
565
+ }
566
+ .quantity-selector .quantity-to-add,
567
+ .quantity-selector .quantity-to-remove {
568
+ width: 45px;
569
+ height: 25px;
570
+ font-size: 12px;
571
+ padding: 0 5px;
572
+ }
573
+ .modal-dialog {
574
+ max-height: 90vh;
575
+ }
576
+ .modal-body::-webkit-scrollbar {
577
+ width: 8px;
578
+ }
579
+ .modal-body::-webkit-scrollbar-track {
580
+ background: #f1f1f1;
581
+ border-radius: 10px;
582
+ }
583
+ .modal-body::-webkit-scrollbar-thumb {
584
+ background: #0FAA39;
585
+ border-radius: 10px;
586
+ }
587
+ .modal-body::-webkit-scrollbar-thumb:hover {
588
+ background: #0D9232;
589
+ }
590
+ @media (max-width: 576px) {
591
+ .fixed-top-bar {
592
+ height: 60px;
593
+ padding: 10px;
594
+ }
595
+ .search-bar-container {
596
+ width: 80%;
597
+ max-width: 100%;
598
+ left: 10px;
599
+ top: 50%;
600
+ transform: translateY(-50%);
601
+ }
602
+ .search-bar-container input {
603
+ padding: 6px 12px 6px 35px;
604
+ font-size: 14px;
605
+ border-radius: 20px;
606
+ }
607
+ .search-icon {
608
+ left: 12px;
609
+ font-size: 16px;
610
+ }
611
+ .avatar-dropdown-container {
612
+ right: 10px;
613
+ }
614
+ .avatar-icon {
615
+ width: 40px;
616
+ height: 40px;
617
+ font-size: 20px;
618
+ }
619
+ .dropdown-menu {
620
+ width: 220px;
621
+ }
622
+ .dropdown-menu .dropdown-item {
623
+ padding: 12px 16px;
624
+ font-size: 15px;
625
+ }
626
+ .category-buttons {
627
+ gap: 8px;
628
+ }
629
+ .category-button {
630
+ padding: 4px 12px;
631
+ font-size: 0.85rem;
632
+ }
633
+ .modal-dialog {
634
+ max-width: 96%;
635
+ margin: 5px auto;
636
+ }
637
+ .modal-header {
638
+ padding: 5px 10px;
639
+ }
640
+ .modal-title {
641
+ font-size: 14px;
642
+ }
643
+ .modal-body {
644
+ max-height: 50vh;
645
+ padding: 8px;
646
+ }
647
+ .modal-body #modal-img {
648
+ max-height: 150px;
649
+ width: 100%;
650
+ max-width: 150px;
651
+ margin: 0 auto 5px;
652
+ display: block;
653
+ }
654
+ .modal-body #modal-name {
655
+ font-size: 18px;
656
+ margin-bottom: 3px;
657
+ }
658
+ .modal-body #modal-price {
659
+ font-size: 14px;
660
+ margin-bottom: 5px;
661
+ }
662
+ .modal-body #modal-description {
663
+ font-size: 12px;
664
+ margin-bottom: 5px;
665
+ }
666
+ .modal-body .nutritional-info {
667
+ font-size: 10px;
668
+ margin-bottom: 5px;
669
+ }
670
+ .modal-body #modal-addons h6,
671
+ .modal-body #first-row h6 {
672
+ font-size: 12px;
673
+ margin-bottom: 5px;
674
+ }
675
+ .modal-footer {
676
+ padding: 5px;
677
+ }
678
+ .modal-footer .btn {
679
+ height: 30px;
680
+ padding: 0 10px;
681
+ }
682
+ .modal-footer .form-control {
683
+ width: 30px;
684
+ height: 30px;
685
+ font-size: 12px;
686
+ font-weight: bold;
687
+ }
688
+ .modal-footer .btn-outline-secondary {
689
+ width: 25px;
690
+ height: 25px;
691
+ font-size: 12px;
692
+ line-height: 25px;
693
+ }
694
+ .modal-footer .btn-primary {
695
+ font-size: 12px;
696
+ height: 30px;
697
+ padding: 0 15px;
698
+ border-radius: 5px;
699
+ }
700
+ .btn-primary {
701
+ font-size: 10px;
702
+ width: 50px;
703
+ height: 25px;
704
+ }
705
+ .customisable-text {
706
+ font-size: 8px;
707
+ }
708
+ .button-container {
709
+ gap: 3px;
710
+ }
711
+ .quantity-selector .btn {
712
+ width: 18px;
713
+ height: 18px;
714
+ font-size: 9px;
715
+ line-height: 18px;
716
+ }
717
+ .quantity-selector .quantity-display {
718
+ width: 18px;
719
+ font-size: 9px;
720
+ line-height: 18px;
721
+ }
722
+ .quantity-selector .quantity-to-add,
723
+ .quantity-selector .quantity-to-remove {
724
+ width: 35px;
725
+ height: 18px;
726
+ font-size: 9px;
727
+ }
728
+ .view-cart-button {
729
+ padding: 8px 16px;
730
+ font-size: 14px;
731
+ }
732
+ .cart-icon-badge {
733
+ width: 20px;
734
+ height: 20px;
735
+ font-size: 10px;
736
+ }
737
+ }
738
+ </style>
739
+ </head>
740
+ <body>
741
+
742
+ <div class="fixed-top-bar">
743
+ <div class="avatar-dropdown-container">
744
+ <div class="avatar-icon">
745
+ <span>{{ first_letter }}</span>
746
+ </div>
747
+ <div class="dropdown-menu">
748
+ <a href="{{ url_for('user_details.customer_details') }}" class="dropdown-item">View Profile</a>
749
+ <a href="{{ url_for('orderhistory.order_history') }}" class="dropdown-item">Order History</a>
750
+ <a href="{{ url_for('logout') }}" class="dropdown-item">Logout</a>
751
+ </div>
752
+ </div>
753
+ <div class="search-bar-container">
754
+ <input type="text" id="searchBar" class="form-control" placeholder="Search items or sections..." autocomplete="off">
755
+ <i class="bi bi-search search-icon"></i>
756
+ <div id="autocompleteSuggestions" class="autocomplete-suggestions"></div>
757
+ </div>
758
+ </div>
759
+
760
+ <form method="get" action="/menu" class="text-center mb-4" id="categoryForm">
761
+ <label class="form-label fw-bold">Select a Category:</label>
762
+ <div class="category-buttons">
763
+ {% for category in categories %}
764
+ <button type="button" class="category-button {% if selected_category == category %}selected{% endif %}" data-category="{{ category }}">{{ category }}</button>
765
+ {% endfor %}
766
+ <button type="button" class="category-button {% if selected_category == 'Customized Dish' %}selected{% endif %}" data-category="Customized Dish">Customized Dish</button>
767
+ </div>
768
+ <input type="hidden" name="category" id="selectedCategoryInput" value="{{ selected_category }}">
769
+ </form>
770
+
771
+ <div class="container mt-4">
772
+ {% if selected_category == "Customized Dish" %}
773
+ <div id="custom-dish-form" class="mt-4">
774
+ <h3>Create Your Custom Dish</h3>
775
+ <form method="POST" action="/customdish/generate_custom_dish">
776
+ <div class="mb-3">
777
+ <label for="custom-dish-name" class="form-label">Dish Name</label>
778
+ <input type="text" class="form-control" id="custom-dish-name" name="name" required>
779
+ </div>
780
+ <div class="mb-3 position-relative">
781
+ <label for="custom-dish-description" class="form-label">Dish Description</label>
782
+ <textarea class="form-control" id="custom-dish-description" name="description" required></textarea>
783
+ <div id="descriptionSuggestions" class="autocomplete-suggestions"></div>
784
+ </div>
785
+ <button type="submit" class="btn btn-primary">Submit</button>
786
+ </form>
787
+ </div>
788
+ {% else %}
789
+ {% for section, items in ordered_menu.items() %}
790
+ <h3>{{ section }}</h3>
791
+ <div class="row">
792
+ {% for item in items %}
793
+ <div class="col-md-6 mb-4">
794
+ <div class="card menu-card">
795
+ <div class="video-container">
796
+ <video
797
+ id="video-{{ loop.index }}"
798
+ preload="metadata"
799
+ poster="{{ item.Image1__c if item.Image1__c else '/static/placeholder.jpg' }}"
800
+ data-src="{{ item.Video1__c }}"
801
+ muted
802
+ loop
803
+ >
804
+ <source src="{{ item.Video1__c }}" type="video/mp4">
805
+ Your browser does not support the video tag.
806
+ </video>
807
+ {% if not item.Video1__c %}
808
+ <div class="video-placeholder">
809
+ No video available
810
+ </div>
811
+ {% endif %}
812
+ <div class="play-button" onclick="togglePlay(this)">
813
+ <i class="bi bi-play-fill"></i>
814
+ </div>
815
+ </div>
816
+
817
+ <div class="addbutton">
818
+ <div class="card-body d-flex align-items-center justify-content-between">
819
+ <div>
820
+ <h5 class="card-title">{{ item.Name }}</h5>
821
+ <p class="card-text">${{ item.Price__c }}</p>
822
+ </div>
823
+ <div class="d-flex flex-column align-item-center justify-content-center">
824
+ <div class="button-container" data-item-name="{{ item.Name }}" data-item-price="{{ item.Price__c }}" data-item-image="{{ item.Image1__c }}" data-item-section="{{ item.Section__c }}" data-item-category="{{ selected_category }}">
825
+ {% if item.Section__c == 'Soft Drinks' %}
826
+ <button class="btn btn-primary add-to-cart-btn" onclick="handleSoftDrinkAdd(this)">ADD</button>
827
+ <div class="quantity-selector" style="display: none;">
828
+ <button class="btn btn-outline-secondary decrease-btn" onclick="decreaseQuantity(this)">-</button>
829
+ <select class="quantity-to-remove">
830
+ {% for i in range(1, 21) %}
831
+ <option value="{{ i }}">{{ i }}</option>
832
+ {% endfor %}
833
+ </select>
834
+ <span class="quantity-display">0</span>
835
+ <button class="btn btn-outline-secondary increase-btn" onclick="increaseQuantity(this)">+</button>
836
+ <select class="quantity-to-add">
837
+ {% for i in range(1, 21) %}
838
+ <option value="{{ i }}">{{ i }}</option>
839
+ {% endfor %}
840
+ </select>
841
+ </div>
842
+ {% else %}
843
+ <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#itemModal"
844
+ onclick="showItemDetails('{{ item.Name }}', '{{ item.Price__c }}', '{{ item.Image2__c }}', '{{ item.Description__c }}', '{{ item.Section__c }}','{{ selected_category }}')">
845
+ ADD
846
+ </button>
847
+ {% endif %}
848
+ {% if item.Section__c != 'Apetizer' and item.Section__c != 'Customized dish' and item.Section__c !='Soft Drinks' %}
849
+ <span class="customisable-text">Customisable</span>
850
+ {% endif %}
851
+ </div>
852
+ </div>
853
+ </div>
854
+ </div>
855
+ <div class="toggle-details" data-item-name="{{ item.Name }}">Show Details</div>
856
+ <div class="item-details" id="details-{{ item.Name | replace(' ', '-') }}"></div>
857
+ </div>
858
+ </div>
859
+ {% endfor %}
860
+ </div>
861
+ {% endfor %}
862
+ {% endif %}
863
+ </div>
864
+
865
+ <div class="view-cart-container">
866
+ <a href="{{ url_for('cart.cart') }}" class="view-cart-button">
867
+ <i class="bi bi-cart"></i>
868
+ view Cart
869
+ <span id="cart-item-count" class="cart-icon-badge {% if cart_item_count > 0 %}active{% endif %}">
870
+ {{ cart_item_count if cart_item_count > 0 else '' }}
871
+ </span>
872
+ </a>
873
+ </div>
874
+
875
+ <div class="modal fade" id="itemModal" tabindex="-1" aria-labelledby="itemModalLabel" aria-hidden="true">
876
+ <div class="modal-dialog modal-dialog-centered">
877
+ <div class="modal-content">
878
+ <div class="modal-header">
879
+ <h5 class="modal-title" id="itemModalLabel">Item Details</h5>
880
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
881
+ </div>
882
+ <div class="modal-body">
883
+ <img id="modal-img" class="img-fluid rounded mb-3 d-block mx-auto" alt="Item Image">
884
+ <h5 id="modal-name" class="fw-bold text-center"></h5>
885
+ <p id="modal-price" class="text-muted text-center"></p>
886
+ <p id="modal-description" class="text-secondary"></p>
887
+ <p class="nutritional-info" id="modal-nutritional-info"></p>
888
+
889
+ <div id="first-row">
890
+ <h6 id="first-row-title" style="display: none;">Customization Options</h6>
891
+ <div class="addon-section">
892
+ <h6>Choose Preparation Style</h6>
893
+ <div id="prep-style-options"></div>
894
+ </div>
895
+ <div class="addon-section">
896
+ <h6>Type</h6>
897
+ <div id="type-options"></div>
898
+ </div>
899
+ <div class="addon-section">
900
+ <h6>Spice Level</h6>
901
+ <div id="spice-level-options"></div>
902
+ </div>
903
+ </div>
904
+
905
+ <div id="modal-addons" class="modal-addons mt-4">
906
+ <h6 id="addons-title">Customization Options</h6>
907
+ <div id="addons-list" class="addons-container">Loading customization options...</div>
908
+ </div>
909
+
910
+ <div class="mt-4">
911
+ <h6>Custom Request</h6>
912
+ <textarea id="modal-instructions" class="form-control" placeholder="Enter any special instructions here..."></textarea>
913
+ </div>
914
+ <span id="modal-section" data-section="" data-category="" style="display: none;"></span>
915
+ </div>
916
+ <div class="modal-footer d-flex align-items-center justify-content-between">
917
+ <div class="d-flex align-items-center gap-2">
918
+ <button type="button" class="btn btn-outline-secondary" id="decreaseQuantity">-</button>
919
+ <input type="text" class="form-control text-center" id="quantityInput" value="1" readonly style="width: 50px;"/>
920
+ <button type="button" class="btn btn-outline-secondary" id="increaseQuantity">+</button>
921
+ </div>
922
+ <button type="button" class="btn btn-primary" onclick="addToCartFromModal()">Add to Cart</button>
923
+ </div>
924
+ </div>
925
+ </div>
926
+ </div>
927
+
928
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
929
+ <script>
930
+ function togglePlay(button) {
931
+ const videoContainer = button.closest('.video-container');
932
+ const video = videoContainer.querySelector('video');
933
+
934
+ if (video.paused) {
935
+ if (!video.src && video.dataset.src) {
936
+ video.src = video.dataset.src;
937
+ }
938
+ video.play()
939
+ .then(() => {
940
+ button.innerHTML = '<i class="bi bi-pause-fill"></i>';
941
+ })
942
+ .catch(e => console.log('Video play error:', e));
943
+ } else {
944
+ video.pause();
945
+ button.innerHTML = '<i class="bi bi-play-fill"></i>';
946
+ }
947
+ }
948
+
949
+ const menuItems = [
950
+ {% for section, items in ordered_menu.items() %}
951
+ {% for item in items %}
952
+ "{{ item.Name }}",
953
+ {% endfor %}
954
+ {% endfor %}
955
+ ];
956
+
957
+ const ingredientsList = [
958
+ "Basmati Rice", "Bell Pepper", "Biryani Masala", "Butter", "Capsicum", "Cauliflower",
959
+ "Chickpea Flour (Besan)", "Chickpea Flour (for batter)", "Chickpeas (Channa)", "Chili Powder",
960
+ "Chili Sauce", "Coconut Milk", "Coriander Powder", "Cornflour", "Cream", "Cumin Powder",
961
+ "Cumin Seeds", "Curd (Yogurt)", "Curry Leaves", "Fish (e.g., King Fish or Salmon)",
962
+ "Fresh Coriander Leaves", "Garam Masala", "Garlic", "Ghee (Clarified Butter)", "Ginger",
963
+ "Ginger-Garlic Paste", "Goat Meat (Mutton)", "Green Chilies", "Honey",
964
+ "Kasuri Methi (dried fenugreek leaves)", "Lemon Juice", "Mango Puree", "Mint Leaves",
965
+ "Mixed Vegetables (Carrot, Peas, Potato, Cauliflower)", "Mixed Vegetables (Carrot, Peas, Potato)",
966
+ "Mustard Seeds", "Mutton (Goat Meat)", "Oil", "Oil (for frying)", "Onion",
967
+ "Paneer (Indian Cottage Cheese)", "Peas", "Potatoes", "Prawns", "Red Chili Powder",
968
+ "Rice Flour", "Saffron", "Salt", "Soy Sauce", "Spring Onion", "Tamarind (for sourness)",
969
+ "Tomato Ketchup", "Tomatoes", "Turmeric Powder", "Vinegar", "Water", "Wheat Flour (for dough)",
970
+ "Whole Wheat Flour", "Yogurt (Curd)"
971
+ ];
972
+
973
+ const menuItemDetails = {
974
+ "Veg Manchurian": {
975
+ ingredients: "Cauliflower, Onion, Ginger, Garlic, Soy Sauce, Cornflour, Green Chilies, Capsicum, Spring Onion",
976
+ nutritionalInfo: { calories: 250, protein: 5, carbs: 35, fats: 12, fiber: 3, sugar: 2 },
977
+ allergens: "Soy, Gluten"
978
+ },
979
+ "Veg Biryani": {
980
+ ingredients: "Basmati Rice, Mixed Vegetables (Carrot, Peas, Potato, Cauliflower), Ginger, Garlic, Biryani Masala, Mint Leaves, Curd, Onion, Ghee",
981
+ nutritionalInfo: { calories: 300, protein: 6, carbs: 50, fats: 12, fiber: 5, sugar: 3 },
982
+ allergens: "Dairy"
983
+ },
984
+ "Sukka Gosht (Goat)": {
985
+ ingredients: "Goat Meat, Ginger-Garlic Paste, Green Chilies, Onion, Tomatoes, Garam Masala, Coriander Powder, Cumin Powder, Fresh Coriander",
986
+ nutritionalInfo: { calories: 450, protein: 35, carbs: 10, fats: 30, fiber: 2, sugar: 1 },
987
+ allergens: "None"
988
+ },
989
+ "Samosa": {
990
+ ingredients: "Potatoes, Peas, Onion, Ginger, Cumin Seeds, Garam Masala, Wheat Flour (for dough), Oil (for frying)",
991
+ nutritionalInfo: { calories: 150, protein: 3, carbs: 25, fats: 7, fiber: 2, sugar: 1 },
992
+ allergens: "Gluten"
993
+ },
994
+ "Roti": {
995
+ ingredients: "Whole Wheat Flour, Water, Salt",
996
+ nutritionalInfo: { calories: 150, protein: 4, carbs: 30, fats: 1, fiber: 3, sugar: 0 },
997
+ allergens: "Gluten"
998
+ },
999
+ "Prawn Fry": {
1000
+ ingredients: "Prawns, Garlic, Ginger, Chili Powder, Coriander Powder, Cumin Powder, Lemon Juice, Oil",
1001
+ nutritionalInfo: { calories: 350, protein: 25, carbs: 10, fats: 20, fiber: 1, sugar: 1 },
1002
+ allergens: "Shellfish"
1003
+ },
1004
+ "Paneer Butter Masala": {
1005
+ ingredients: "Paneer, Butter, Cream, Tomato Puree, Onion, Ginger, Garlic, Garam Masala",
1006
+ nutritionalInfo: { calories: 400, protein: 15, carbs: 20, fats: 25, fiber: 2, sugar: 3 },
1007
+ allergens: "Dairy"
1008
+ },
1009
+ "Paneer Biryani": {
1010
+ ingredients: "Paneer, Basmati Rice, Mixed Vegetables (Carrot, Peas, Potato), Onion, Tomatoes, Biryani Masala, Mint Leaves, Curd",
1011
+ nutritionalInfo: { calories: 350, protein: 12, carbs: 55, fats: 15, fiber: 4, sugar: 3 },
1012
+ allergens: "Dairy"
1013
+ },
1014
+ "Onion Pakoda": {
1015
+ ingredients: "Onion, Chickpea Flour (Besan), Rice Flour, Green Chilies, Cumin Seeds, Ginger, Turmeric Powder, Oil (for frying)",
1016
+ nutritionalInfo: { calories: 200, protein: 5, carbs: 30, fats: 8, fiber: 3, sugar: 2 },
1017
+ allergens: "Gluten (if cross-contamination)"
1018
+ },
1019
+ "Mutton Biryani": {
1020
+ ingredients: "Mutton, Basmati Rice, Onion, Tomatoes, Ginger-Garlic Paste, Biryani Masala, Mint Leaves, Yogurt, Ghee",
1021
+ nutritionalInfo: { calories: 500, protein: 30, carbs: 50, fats: 25, fiber: 4, sugar: 3 },
1022
+ allergens: "Dairy"
1023
+ },
1024
+ "Fish Curry": {
1025
+ ingredients: "Fish (any firm fish like Salmon or King Fish), Onion, Tomato, Ginger-Garlic Paste, Curry Leaves, Coconut Milk, Tamarind, Mustard Seeds",
1026
+ nutritionalInfo: { calories: 300, protein: 25, carbs: 10, fats: 20, fiber: 2, sugar: 1 },
1027
+ allergens: "Fish"
1028
+ },
1029
+ "Fiery Mango Glaze Chicken": {
1030
+ ingredients: "Chicken, Mango Puree, Chili Sauce, Soy Sauce, Honey, Garlic, Ginger, Lemon Juice",
1031
+ nutritionalInfo: { calories: 350, protein: 30, carbs: 15, fats: 18, fiber: 1, sugar: 5 },
1032
+ allergens: "Soy"
1033
+ },
1034
+ "Chilli Gobi": {
1035
+ ingredients: "Cauliflower, Onion, Green Chilies, Soy Sauce, Cornflour, Garlic, Ginger, Cumin Powder",
1036
+ nutritionalInfo: { calories: 250, protein: 6, carbs: 35, fats: 12, fiber: 3, sugar: 2 },
1037
+ allergens: "Soy, Gluten"
1038
+ },
1039
+ "Chilli Chicken": {
1040
+ ingredients: "Chicken, Bell Pepper, Onion, Green Chilies, Soy Sauce, Cornflour, Garlic, Ginger",
1041
+ nutritionalInfo: { calories: 400, protein: 35, carbs: 20, fats: 18, fiber: 2, sugar: 2 },
1042
+ allergens: "Soy, Gluten"
1043
+ },
1044
+ "Chicken Manchurian": {
1045
+ ingredients: "Chicken, Onion, Garlic, Ginger, Soy Sauce, Cornflour, Green Chilies, Capsicum",
1046
+ nutritionalInfo: { calories: 350, protein: 25, carbs: 20, fats: 18, fiber: 2, sugar: 2 },
1047
+ allergens: "Soy, Gluten"
1048
+ },
1049
+ "Chicken Curry": {
1050
+ ingredients: "Chicken, Onion, Tomatoes, Ginger-Garlic Paste, Garam Masala, Coconut Milk, Coriander Leaves",
1051
+ nutritionalInfo: { calories: 350, protein: 28, carbs: 15, fats: 12, fiber: 4, sugar: 2 },
1052
+ allergens: "None"
1053
+ },
1054
+ "Chicken Biryani": {
1055
+ ingredients: "Chicken, Basmati Rice, Onion, Tomatoes, Ginger-Garlic Paste, Biryani Masala, Mint Leaves, Curd",
1056
+ nutritionalInfo: { calories: 500, protein: 35, carbs: 60, fats: 20, fiber: 5, sugar: 3 },
1057
+ allergens: "Dairy"
1058
+ },
1059
+ "Channa Masala": {
1060
+ ingredients: "Chickpeas, Onion, Tomatoes, Ginger-Garlic Paste, Garam Masala, Coriander Powder, Cumin Seeds, Lemon Juice",
1061
+ nutritionalInfo: { calories: 250, protein: 10, carbs: 45, fats: 5, fiber: 6, sugar: 2 },
1062
+ allergens: "None"
1063
+ }
1064
+ };
1065
+
1066
+ function addToCartLocalStorage(payload) {
1067
+ let cart = JSON.parse(localStorage.getItem('cart')) || [];
1068
+ const existingItem = cart.find(item =>
1069
+ item.itemName === payload.itemName &&
1070
+ item.instructions === payload.instructions &&
1071
+ JSON.stringify(item.addons) === JSON.stringify(payload.addons)
1072
+ );
1073
+ if (existingItem) {
1074
+ existingItem.quantity += payload.quantity;
1075
+ } else {
1076
+ cart.push(payload);
1077
+ }
1078
+ localStorage.setItem('cart', JSON.stringify(cart));
1079
+ return cart;
1080
+ }
1081
+
1082
+ function removeFromCartLocalStorage(itemName, quantityToRemove, instructions, addons) {
1083
+ let cart = JSON.parse(localStorage.getItem('cart')) || [];
1084
+ const itemIndex = cart.findIndex(item =>
1085
+ item.itemName === itemName &&
1086
+ item.instructions === instructions &&
1087
+ JSON.stringify(item.addons) === JSON.stringify(addons)
1088
+ );
1089
+ if (itemIndex !== -1) {
1090
+ if (quantityToRemove >= cart[itemIndex].quantity) {
1091
+ cart.splice(itemIndex, 1);
1092
+ } else {
1093
+ cart[itemIndex].quantity -= quantityToRemove;
1094
+ }
1095
+ }
1096
+ localStorage.setItem('cart', JSON.stringify(cart));
1097
+ return cart;
1098
+ }
1099
+
1100
+ function getCartLocalStorage() {
1101
+ return JSON.parse(localStorage.getItem('cart')) || [];
1102
+ }
1103
+
1104
+ document.addEventListener('DOMContentLoaded', function () {
1105
+ const videoContainers = document.querySelectorAll('.video-container');
1106
+
1107
+ videoContainers.forEach(container => {
1108
+ const video = container.querySelector('video');
1109
+ const playButton = container.querySelector('.play-button');
1110
+
1111
+ const observer = new IntersectionObserver((entries) => {
1112
+ entries.forEach(entry => {
1113
+ if (entry.isIntersecting && video.dataset.src && !video.src) {
1114
+ video.src = video.dataset.src;
1115
+ observer.unobserve(entry.target);
1116
+ }
1117
+ });
1118
+ }, {
1119
+ rootMargin: '200px',
1120
+ threshold: 0.1
1121
+ });
1122
+
1123
+ observer.observe(container);
1124
+
1125
+ container.addEventListener('mouseenter', () => {
1126
+ if (window.innerWidth > 768) {
1127
+ if (video.src || video.dataset.src) {
1128
+ if (!video.src) video.src = video.dataset.src;
1129
+ video.play().catch(e => console.log('Autoplay prevented:', e));
1130
+ }
1131
+ }
1132
+ });
1133
+
1134
+ container.addEventListener('mouseleave', () => {
1135
+ if (window.innerWidth > 768) {
1136
+ if (!video.paused) {
1137
+ video.pause();
1138
+ if (playButton) {
1139
+ playButton.innerHTML = '<i class="bi bi-play-fill"></i>';
1140
+ }
1141
+ }
1142
+ }
1143
+ });
1144
+
1145
+ container.addEventListener('touchstart', (e) => {
1146
+ e.preventDefault();
1147
+ if (window.innerWidth <= 768) {
1148
+ if (video.src || video.dataset.src) {
1149
+ if (!video.src) video.src = video.dataset.src;
1150
+ if (video.paused) {
1151
+ video.play()
1152
+ .then(() => {
1153
+ if (playButton) {
1154
+ playButton.innerHTML = '<i class="bi bi-pause-fill"></i>';
1155
+ }
1156
+ })
1157
+ .catch(e => console.log('Video play error:', e));
1158
+ } else {
1159
+ video.pause();
1160
+ if (playButton) {
1161
+ playButton.innerHTML = '<i class="bi bi-play-fill"></i>';
1162
+ }
1163
+ }
1164
+ }
1165
+ }
1166
+ }, { passive: false });
1167
+ });
1168
+
1169
+ const avatarContainer = document.querySelector('.avatar-dropdown-container');
1170
+ const dropdownMenu = document.querySelector('.dropdown-menu');
1171
+
1172
+ avatarContainer.addEventListener('click', function (event) {
1173
+ event.stopPropagation();
1174
+ dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
1175
+ });
1176
+
1177
+ document.addEventListener('click', function (event) {
1178
+ if (!avatarContainer.contains(event.target)) {
1179
+ dropdownMenu.style.display = 'none';
1180
+ }
1181
+ });
1182
+
1183
+ const dropdownItems = document.querySelectorAll('.dropdown-item');
1184
+ dropdownItems.forEach(item => {
1185
+ item.addEventListener('click', function () {
1186
+ dropdownMenu.style.display = 'none';
1187
+ });
1188
+ });
1189
+
1190
+ const menuCards = document.querySelectorAll('.menu-card');
1191
+ menuCards.forEach(card => {
1192
+ const itemName = card.querySelector('.card-title').innerText;
1193
+ const detailsDiv = card.querySelector('.item-details');
1194
+ const detailsData = menuItemDetails[itemName];
1195
+
1196
+ if (detailsData) {
1197
+ detailsDiv.innerHTML = `
1198
+ <h6>Ingredients</h6>
1199
+ <p>${detailsData.ingredients}</p>
1200
+ <h6>Nutritional Info</h6>
1201
+ <div class="nutritional-info">
1202
+ <span>Calories: ${detailsData.nutritionalInfo.calories} kcal</span>
1203
+ <span>Carbs: ${detailsData.nutritionalInfo.carbs}g</span>
1204
+ <span>Protein: ${detailsData.nutritionalInfo.protein}g</span>
1205
+ <span>Fats: ${detailsData.nutritionalInfo.fats}g</span>
1206
+ </div>
1207
+ <h6>Allergens</h6>
1208
+ <p>${detailsData.allergens}</p>
1209
+ `;
1210
+ } else {
1211
+ detailsDiv.innerHTML = '<p>No details available for this item.</p>';
1212
+ }
1213
+ });
1214
+
1215
+ const cardObserver = new IntersectionObserver((entries, observer) => {
1216
+ entries.forEach(entry => {
1217
+ if (entry.isIntersecting) {
1218
+ entry.target.classList.add('visible');
1219
+ observer.unobserve(entry.target);
1220
+ }
1221
+ });
1222
+ }, {
1223
+ root: null,
1224
+ rootMargin: '0px',
1225
+ threshold: 0.1
1226
+ });
1227
+
1228
+ menuCards.forEach(card => cardObserver.observe(card));
1229
+
1230
+ const toggleLinks = document.querySelectorAll('.toggle-details');
1231
+ toggleLinks.forEach(link => {
1232
+ link.addEventListener('click', function () {
1233
+ const itemName = this.getAttribute('data-item-name').replace(/ /g, '-');
1234
+ const detailsDiv = document.getElementById(`details-${itemName}`);
1235
+ detailsDiv.classList.toggle('show');
1236
+ this.innerText = detailsDiv.classList.contains('show') ? 'Hide Details' : 'Show Details';
1237
+ });
1238
+ });
1239
+
1240
+ const categoryButtons = document.querySelectorAll('.category-button');
1241
+ const categoryForm = document.getElementById('categoryForm');
1242
+ const selectedCategoryInput = document.getElementById('selectedCategoryInput');
1243
+
1244
+ if (!selectedCategoryInput.value) {
1245
+ selectedCategoryInput.value = "All";
1246
+ document.querySelector('.category-button[data-category="All"]').classList.add('selected');
1247
+ }
1248
+
1249
+ categoryButtons.forEach(button => {
1250
+ button.addEventListener('click', function () {
1251
+ categoryButtons.forEach(btn => btn.classList.remove('selected'));
1252
+ this.classList.add('selected');
1253
+ selectedCategoryInput.value = this.getAttribute('data-category');
1254
+ categoryForm.submit();
1255
+ });
1256
+ });
1257
+
1258
+ const searchBar = document.getElementById('searchBar');
1259
+ const suggestionsContainer = document.getElementById('autocompleteSuggestions');
1260
+
1261
+ searchBar.addEventListener('input', function () {
1262
+ const input = this.value.trim().toLowerCase();
1263
+ suggestionsContainer.innerHTML = '';
1264
+ suggestionsContainer.style.display = 'none';
1265
+
1266
+ if (input) {
1267
+ const filteredItems = menuItems.filter(item =>
1268
+ item.toLowerCase().includes(input)
1269
+ );
1270
+ if (filteredItems.length > 0) {
1271
+ filteredItems.forEach(item => {
1272
+ const suggestionDiv = document.createElement('div');
1273
+ suggestionDiv.classList.add('suggestion-item');
1274
+ suggestionDiv.innerText = item;
1275
+ suggestionDiv.addEventListener('click', function () {
1276
+ searchBar.value = item;
1277
+ suggestionsContainer.style.display = 'none';
1278
+ filterMenu();
1279
+ });
1280
+ suggestionsContainer.appendChild(suggestionDiv);
1281
+ });
1282
+ suggestionsContainer.style.display = 'block';
1283
+ }
1284
+ }
1285
+ filterMenu();
1286
+ });
1287
+
1288
+ document.addEventListener('click', function (event) {
1289
+ if (!searchBar.contains(event.target) && !suggestionsContainer.contains(event.target)) {
1290
+ suggestionsContainer.style.display = 'none';
1291
+ }
1292
+ });
1293
+
1294
+ const descriptionTextarea = document.getElementById('custom-dish-description');
1295
+ const descriptionSuggestions = document.getElementById('descriptionSuggestions');
1296
+
1297
+ if (descriptionTextarea && descriptionSuggestions) {
1298
+ let usedIngredients = new Set();
1299
+
1300
+ function updateUsedIngredients() {
1301
+ const inputText = descriptionTextarea.value.trim();
1302
+ usedIngredients.clear();
1303
+ if (inputText) {
1304
+ const words = inputText.split(/,\s*/).map(word => word.trim());
1305
+ words.forEach(word => {
1306
+ if (word && ingredientsList.includes(word)) {
1307
+ usedIngredients.add(word);
1308
+ }
1309
+ });
1310
+ }
1311
+ }
1312
+
1313
+ descriptionTextarea.addEventListener('input', function () {
1314
+ const inputText = this.value.trim();
1315
+ const words = inputText.split(/,\s*/);
1316
+ const lastWord = words[words.length - 1].trim().toLowerCase();
1317
+ descriptionSuggestions.innerHTML = '';
1318
+ descriptionSuggestions.style.display = 'none';
1319
+
1320
+ updateUsedIngredients();
1321
+
1322
+ if (lastWord) {
1323
+ const filteredIngredients = ingredientsList.filter(ingredient =>
1324
+ ingredient.toLowerCase().includes(lastWord) && !usedIngredients.has(ingredient)
1325
+ );
1326
+ if (filteredIngredients.length > 0) {
1327
+ filteredIngredients.forEach(ingredient => {
1328
+ const suggestionDiv = document.createElement('div');
1329
+ suggestionDiv.classList.add('suggestion-item');
1330
+ suggestionDiv.innerText = ingredient;
1331
+ suggestionDiv.addEventListener('click', function () {
1332
+ const currentValue = descriptionTextarea.value;
1333
+ const lastCommaIndex = currentValue.lastIndexOf(',');
1334
+ const baseText = lastCommaIndex !== -1 ? currentValue.substring(0, lastCommaIndex + 1) : '';
1335
+ descriptionTextarea.value = baseText + (baseText ? ' ' : '') + ingredient + ', ';
1336
+ descriptionSuggestions.style.display = 'none';
1337
+ descriptionTextarea.focus();
1338
+ updateUsedIngredients();
1339
+ });
1340
+ descriptionSuggestions.appendChild(suggestionDiv);
1341
+ });
1342
+ descriptionSuggestions.style.display = 'block';
1343
+ }
1344
+ }
1345
+ });
1346
+
1347
+ document.addEventListener('click', function (event) {
1348
+ if (!descriptionTextarea.contains(event.target) && !descriptionSuggestions.contains(event.target)) {
1349
+ descriptionSuggestions.style.display = 'none';
1350
+ }
1351
+ });
1352
+ }
1353
+
1354
+ fetch('/cart/get')
1355
+ .then(response => {
1356
+ if (!response.ok) {
1357
+ throw new Error(`HTTP error! Status: ${response.status}`);
1358
+ }
1359
+ return response.json();
1360
+ })
1361
+ .then(data => {
1362
+ if (data.success) {
1363
+ updateCartUI(data.cart);
1364
+ } else {
1365
+ console.error('Failed to fetch cart:', data.error);
1366
+ const cart = getCartLocalStorage();
1367
+ updateCartUI(cart);
1368
+ }
1369
+ })
1370
+ .catch(err => {
1371
+ console.error('Error fetching cart:', err);
1372
+ const cart = getCartLocalStorage();
1373
+ updateCartUI(cart);
1374
+ });
1375
+
1376
+ const preloadedImages = document.querySelectorAll('link[rel="preload"]');
1377
+ preloadedImages.forEach(link => {
1378
+ const img = new Image();
1379
+ img.src = link.href;
1380
+ });
1381
+
1382
+ const decreaseBtn = document.getElementById('decreaseQuantity');
1383
+ const increaseBtn = document.getElementById('increaseQuantity');
1384
+ const quantityInput = document.getElementById('quantityInput');
1385
+
1386
+ decreaseBtn.addEventListener('click', function () {
1387
+ let currentQuantity = parseInt(quantityInput.value);
1388
+ if (currentQuantity > 1) {
1389
+ currentQuantity--;
1390
+ quantityInput.value = currentQuantity;
1391
+ }
1392
+ });
1393
+
1394
+ increaseBtn.addEventListener('click', function () {
1395
+ let currentQuantity = parseInt(quantityInput.value);
1396
+ currentQuantity++;
1397
+ quantityInput.value = currentQuantity;
1398
+ });
1399
+ });
1400
+
1401
+ function debounce(func, wait) {
1402
+ let timeout;
1403
+ return function (...args) {
1404
+ clearTimeout(timeout);
1405
+ timeout = setTimeout(() => func.apply(this, args), wait);
1406
+ };
1407
+ }
1408
+
1409
+ function filterMenu() {
1410
+ const input = document.getElementById('searchBar').value.trim().toLowerCase();
1411
+ const sections = document.querySelectorAll('h3');
1412
+ const items = document.querySelectorAll('.menu-card');
1413
+ let matchedSections = new Set();
1414
+
1415
+ items.forEach(item => {
1416
+ const itemName = item.querySelector('.card-title').innerText.toLowerCase();
1417
+ const itemSection = item.closest('.row').previousElementSibling.innerText.toLowerCase();
1418
+
1419
+ if (itemName.includes(input) || (itemSection && itemSection.includes(input))) {
1420
+ item.style.display = 'block';
1421
+ item.classList.add('visible');
1422
+ matchedSections.add(item.closest('.row'));
1423
+ } else {
1424
+ item.style.display = 'none';
1425
+ }
1426
+ });
1427
+
1428
+ sections.forEach(section => {
1429
+ const sectionRow = section.nextElementSibling;
1430
+ if (matchedSections.has(sectionRow)) {
1431
+ section.style.display = 'block';
1432
+ sectionRow.style.display = 'flex';
1433
+ } else {
1434
+ section.style.display = 'none';
1435
+ sectionRow.style.display = 'none';
1436
+ }
1437
+ });
1438
+
1439
+ if (!input) {
1440
+ sections.forEach(section => {
1441
+ section.style.display = 'block';
1442
+ section.nextElementSibling.style.display = 'flex';
1443
+ });
1444
+ items.forEach(item => {
1445
+ item.style.display = 'block';
1446
+ item.classList.add('visible');
1447
+ });
1448
+ }
1449
+ }
1450
+
1451
+ function showItemDetails(name, price, image, description, section, selectedCategory) {
1452
+ document.getElementById('modal-name').innerText = name;
1453
+ document.getElementById('modal-price').innerText = `$${price}`;
1454
+ const modalImg = document.getElementById('modal-img');
1455
+ if (section.toLowerCase() === 'soft drinks') {
1456
+ modalImg.style.display = 'none';
1457
+ } else {
1458
+ modalImg.style.display = 'block';
1459
+ modalImg.src = image || '/static/placeholder.jpg';
1460
+ }
1461
+ document.getElementById('modal-description').innerText = description || 'No description available.';
1462
+ const nutritionalInfoEl = document.getElementById('modal-nutritional-info');
1463
+ const itemDetails = menuItemDetails[name];
1464
+ if (itemDetails && itemDetails.nutritionalInfo) {
1465
+ const { calories, protein, carbs, fats, fiber, sugar } = itemDetails.nutritionalInfo;
1466
+ nutritionalInfoEl.innerText = `[Energy: ${calories} kcal, Protein: ${protein}g, Carbohydrates: ${carbs}g, Fiber: ${fiber}g, Fat: ${fats}g, Sugar: ${sugar}g]`;
1467
+ } else {
1468
+ nutritionalInfoEl.innerText = '[No nutritional info available.]';
1469
+ }
1470
+
1471
+ document.getElementById('addons-list').innerHTML = 'Loading customization options...';
1472
+ document.getElementById('modal-instructions').value = '';
1473
+ const modalSectionEl = document.getElementById('modal-section');
1474
+ modalSectionEl.setAttribute('data-section', section);
1475
+ modalSectionEl.setAttribute('data-category', selectedCategory);
1476
+ document.getElementById('quantityInput').value = 1;
1477
+
1478
+ const prepStyleOptions = document.getElementById('prep-style-options');
1479
+ const typeOptions = document.getElementById('type-options');
1480
+ const spiceLevelOptions = document.getElementById('spice-level-options');
1481
+ const firstRow = document.getElementById('first-row');
1482
+ const firstRowTitle = document.getElementById('first-row-title');
1483
+ const addonsTitle = document.getElementById('addons-title');
1484
+
1485
+ prepStyleOptions.innerHTML = '';
1486
+ typeOptions.innerHTML = '';
1487
+ spiceLevelOptions.innerHTML = '';
1488
+
1489
+ if (section.toLowerCase() === 'starters') {
1490
+ firstRow.style.display = 'block';
1491
+ firstRowTitle.style.display = 'block';
1492
+ addonsTitle.style.display = 'none';
1493
+ } else {
1494
+ firstRow.style.display = 'none';
1495
+ firstRowTitle.style.display = 'none';
1496
+ addonsTitle.style.display = 'block';
1497
+ }
1498
+
1499
+ const addonsList = document.getElementById('addons-list');
1500
+ addonsList.innerHTML = '';
1501
+ const dummySections = [
1502
+ { name: "Beverages", options: ["Sprite ($3)", "Thums Up ($3)", "Virgin Mojito ($3)", "Lemonade ($3)", "Blue Lagoon Mocktail ($3)"] },
1503
+ { name: "Sauces", options: ["Mint Chutney", "Tomato Sauce"] },
1504
+ { name: "Extra Toppings", options: ["Cheese ($2)", "Olives ($1)", "Jalapenos ($1)", "Mushrooms ($2)", "Peppers ($1)"] },
1505
+ { name: "Sides", options: ["Fries ($3)", "Salad ($2)", "Garlic Bread ($3)", "Onion Rings ($2)", "Coleslaw ($2)"] },
1506
+ { name: "Desserts", options: ["Ice Cream ($3)", "Brownie ($3)", "Cheesecake ($4)", "Gulab Jamun ($3)", "Rasmalai ($4)"] }
1507
+ ];
1508
+
1509
+ dummySections.forEach(addon => {
1510
+ const sectionDiv = document.createElement('div');
1511
+ sectionDiv.classList.add('addon-section');
1512
+ sectionDiv.setAttribute('data-addon-name', addon.name);
1513
+
1514
+ const title = document.createElement('h6');
1515
+ title.innerText = addon.name;
1516
+ sectionDiv.appendChild(title);
1517
+
1518
+ const optionsContainer = document.createElement('div');
1519
+ addon.options.forEach((option, index) => {
1520
+ const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
1521
+ const listItem = document.createElement('div');
1522
+ listItem.classList.add('form-check');
1523
+
1524
+ listItem.innerHTML = `
1525
+ <input type="checkbox" class="form-check-input addon-option" id="${optionId}" value="${option}"
1526
+ data-name="${option}" data-group="${addon.name}" data-price="0">
1527
+ <label class="form-check-label" for="${optionId}">
1528
+ ${option}
1529
+ </label>
1530
+ `;
1531
+ optionsContainer.appendChild(listItem);
1532
+ });
1533
+ sectionDiv.appendChild(optionsContainer);
1534
+ addonsList.appendChild(sectionDiv);
1535
+ });
1536
+
1537
+ fetch(`/api/addons?item_name=${encodeURIComponent(name)}&item_section=${encodeURIComponent(section)}`)
1538
+ .then(response => response.json())
1539
+ .then(data => {
1540
+ const addonsList = document.getElementById('addons-list');
1541
+ addonsList.innerHTML = '';
1542
+
1543
+ if (!data.success || !data.addons || data.addons.length === 0) {
1544
+ addonsList.innerHTML = '<p>No customization options available.</p>';
1545
+ addonsTitle.style.display = 'none';
1546
+ return;
1547
+ }
1548
+
1549
+ if (section.toLowerCase() === 'starters') {
1550
+ data.addons.forEach(addon => {
1551
+ if (addon.name.toLowerCase() === "choose preparation style") {
1552
+ addon.options.forEach(option => {
1553
+ const optionId = `addon-prep-style-${option}`;
1554
+ const optionHTML = `
1555
+ <div class="form-check">
1556
+ <input type="checkbox" class="form-check-input" id="${optionId}" value="${option}" data-name="${option}" data-group="Choose Preparation Style">
1557
+ <label class="form-check-label" for="${optionId}">
1558
+ ${option}
1559
+ </label>
1560
+ </div>
1561
+ `;
1562
+ prepStyleOptions.innerHTML += optionHTML;
1563
+ });
1564
+ }
1565
+ if (addon.name.toLowerCase() === "type") {
1566
+ addon.options.forEach(option => {
1567
+ const optionId = `addon-type-${option}`;
1568
+ const optionHTML = `
1569
+ <div class="form-check">
1570
+ <input type="checkbox" class="form-check-input" id="${optionId}" value="${option}" data-name="${option}" data-group="Type">
1571
+ <label class="form-check-label" for="${optionId}">
1572
+ ${option}
1573
+ </label>
1574
+ </div>
1575
+ `;
1576
+ typeOptions.innerHTML += optionHTML;
1577
+ });
1578
+ }
1579
+ if (addon.name.toLowerCase() === "spice level") {
1580
+ addon.options.forEach(option => {
1581
+ const optionId = `addon-spice-level-${option}`;
1582
+ const optionHTML = `
1583
+ <div class="form-check">
1584
+ <input type="checkbox" class="form-check-input spice-level-option" id="${optionId}" value="${option}" data-name="${option}" data-group="Spice Level">
1585
+ <label class="form-check-label" for="${optionId}">
1586
+ ${option}
1587
+ </label>
1588
+ </div>
1589
+ `;
1590
+ spiceLevelOptions.innerHTML += optionHTML;
1591
+ });
1592
+ }
1593
+ });
1594
+ }
1595
+
1596
+ data.addons.forEach(addon => {
1597
+ if (section.toLowerCase() === 'starters' &&
1598
+ (addon.name.toLowerCase() === "type" ||
1599
+ addon.name.toLowerCase() === "spice level" ||
1600
+ addon.name.toLowerCase() === "choose preparation style")) {
1601
+ return;
1602
+ }
1603
+
1604
+ const sectionDiv = document.createElement('div');
1605
+ sectionDiv.classList.add('addon-section');
1606
+ sectionDiv.setAttribute('data-addon-name', addon.name);
1607
+
1608
+ const title = document.createElement('h6');
1609
+ title.innerText = addon.name;
1610
+ sectionDiv.appendChild(title);
1611
+
1612
+ const optionsContainer = document.createElement('div');
1613
+ addon.options.forEach((option, index) => {
1614
+ const optionId = `addon-${addon.name.replace(/\s+/g, '')}-${index}`;
1615
+ const listItem = document.createElement('div');
1616
+ listItem.classList.add('form-check');
1617
+
1618
+ listItem.innerHTML = `
1619
+ <input type="checkbox" class="form-check-input ${addon.name.toLowerCase() === 'spice level' ? 'spice-level-option' : 'addon-option'}" id="${optionId}" value="${option}"
1620
+ data-name="${option}" data-group="${addon.name}" data-price="${addon.extra_charge ? addon.extra_charge_amount : 0}">
1621
+ <label class="form-check-label" for="${optionId}">
1622
+ ${option} ${addon.extra_charge ? `($${addon.extra_charge_amount})` : ''}
1623
+ </label>
1624
+ `;
1625
+ optionsContainer.appendChild(listItem);
1626
+ });
1627
+ sectionDiv.appendChild(optionsContainer);
1628
+ addonsList.appendChild(sectionDiv);
1629
+ });
1630
+
1631
+ const startersOrder = [
1632
+ "Select Dip/Sauce",
1633
+ "Extra Add-ons",
1634
+ "Make it a Combo"
1635
+ ];
1636
+
1637
+ const desiredOrder = [
1638
+ "Spice Level",
1639
+ "Choose Preparation Style",
1640
+ "Select Dip/Sauce",
1641
+ "Extra Add-ons",
1642
+ "Make it a Combo",
1643
+ "Type"
1644
+ ];
1645
+
1646
+ const orderToUse = section.toLowerCase() === 'starters' ? startersOrder : desiredOrder;
1647
+
1648
+ const sections = Array.from(addonsList.children);
1649
+ addonsList.innerHTML = '';
1650
+
1651
+ orderToUse.forEach(sectionName => {
1652
+ const section = sections.find(s => s.getAttribute('data-addon-name') === sectionName);
1653
+ if (section) {
1654
+ addonsList.appendChild(section);
1655
+ }
1656
+ });
1657
+
1658
+ sections.forEach(section => {
1659
+ if (!orderToUse.includes(section.getAttribute('data-addon-name'))) {
1660
+ addonsList.appendChild(section);
1661
+ }
1662
+ });
1663
+ })
1664
+ .catch(err => {
1665
+ console.error('Error fetching add-ons:', err);
1666
+ document.getElementById('addons-list').innerHTML = '<p>Error loading customization options.</p>';
1667
+ addonsTitle.style.display = 'none';
1668
+ });
1669
+ }
1670
+
1671
+ document.addEventListener('click', function(event) {
1672
+ if (event.target.classList.contains('spice-level-option') || event.target.classList.contains('addon-option')) {
1673
+ handleAddonClick(event.target);
1674
+ }
1675
+ });
1676
+
1677
+ function handleAddonClick(checkbox) {
1678
+ const groupName = checkbox.getAttribute('data-group');
1679
+ const isMultiSelectGroup = ["Extra Toppings", "Choose Raita/Sides", "Select Dip/Sauce", "Extra Add-ons", "Make it a Combo", "Beverages", "Sauces"].includes(groupName);
1680
+
1681
+ if (groupName.toLowerCase() === "spice level") {
1682
+ const allSpiceLevelCheckboxes = document.querySelectorAll('.spice-level-option');
1683
+ allSpiceLevelCheckboxes.forEach(otherCheckbox => {
1684
+ if (otherCheckbox !== checkbox) {
1685
+ otherCheckbox.checked = false;
1686
+ }
1687
+ });
1688
+ }
1689
+ else if (!isMultiSelectGroup) {
1690
+ const checkboxes = document.querySelectorAll(`.addon-option[data-group="${groupName}"]`);
1691
+ checkboxes.forEach(otherCheckbox => {
1692
+ if (otherCheckbox !== checkbox) {
1693
+ otherCheckbox.checked = false;
1694
+ }
1695
+ });
1696
+ }
1697
+ }
1698
+
1699
+ function addToCartFromModal() {
1700
+ const itemName = document.getElementById('modal-name').innerText;
1701
+ let itemPrice = parseFloat(document.getElementById('modal-price').innerText.replace('$', ''));
1702
+ if (isNaN(itemPrice)) {
1703
+ alert('Invalid price for the item. Please check the item details.');
1704
+ return;
1705
+ }
1706
+ const itemImage = document.getElementById('modal-img').src;
1707
+ const modalSectionEl = document.getElementById('modal-section');
1708
+ const section = modalSectionEl.getAttribute('data-section');
1709
+ const selectedCategory = modalSectionEl.getAttribute('data-category');
1710
+ if (!itemName || !itemPrice || !section || !itemImage) {
1711
+ console.error('Missing data for cart item:', { itemName, itemPrice, section, itemImage});
1712
+ return;
1713
+ }
1714
+
1715
+ let selectedAddOns = [];
1716
+ const addonsListOptions = document.querySelectorAll('#addons-list .addon-option');
1717
+ addonsListOptions.forEach(option => {
1718
+ if (option.checked) {
1719
+ selectedAddOns.push({
1720
+ name: option.getAttribute('data-name') || 'Default Name',
1721
+ price: parseFloat(option.getAttribute('data-price') || 0)
1722
+ });
1723
+ }
1724
+ });
1725
+
1726
+ if (section.toLowerCase() === 'starters') {
1727
+ const prepStyleOptions = Array.from(
1728
+ document.querySelectorAll('#prep-style-options input[type="checkbox"]:checked')
1729
+ ).map(option => ({
1730
+ name: option.getAttribute('data-name') || 'Default Prep Style',
1731
+ price: 0
1732
+ }));
1733
+ const typeOptions = Array.from(
1734
+ document.querySelectorAll('#type-options input[type="checkbox"]:checked')
1735
+ ).map(option => ({
1736
+ name: option.getAttribute('data-name') || 'Default Type',
1737
+ price: 0
1738
+ }));
1739
+ const spiceLevelOption = document.querySelector('#spice-level-options input[type="checkbox"].spice-level-option:checked');
1740
+ const spiceLevelOptions = spiceLevelOption ? [{
1741
+ name: spiceLevelOption.getAttribute('data-name') || 'Default Spice Level',
1742
+ price: 0
1743
+ }] : [];
1744
+ selectedAddOns = [...selectedAddOns, ...prepStyleOptions, ...typeOptions, ...spiceLevelOptions];
1745
+ }
1746
+
1747
+
1748
+
1749
+ const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
1750
+ const instructions = document.getElementById('modal-instructions').value;
1751
+ const cartPayload = {
1752
+ itemName: itemName,
1753
+ itemPrice: itemPrice,
1754
+ itemImage: itemImage,
1755
+ section: section,
1756
+ category: selectedCategory,
1757
+ addons: selectedAddOns,
1758
+ instructions: instructions,
1759
+ quantity: quantity
1760
+ };
1761
+ fetch('/cart/add', {
1762
+ method: 'POST',
1763
+ headers: {
1764
+ 'Content-Type': 'application/json',
1765
+ },
1766
+ body: JSON.stringify(cartPayload)
1767
+ })
1768
+ .then(response => {
1769
+ if (!response.ok) {
1770
+ throw new Error(`HTTP error! Status: ${response.status}`);
1771
+ }
1772
+ return response.json();
1773
+ })
1774
+ .then(data => {
1775
+ if (data.success) {
1776
+ alert('Item added to cart successfully!');
1777
+ updateCartUI(data.cart);
1778
+ const modal = document.getElementById('itemModal');
1779
+ const modalInstance = bootstrap.Modal.getInstance(modal);
1780
+ modalInstance.hide();
1781
+ } else {
1782
+ console.error('Failed to add item to cart:', data.error);
1783
+ alert(data.error || 'Failed to add item to cart.');
1784
+ }
1785
+ })
1786
+ .catch(err => {
1787
+ console.error('Error adding item to cart:', err);
1788
+ alert('An error occurred while adding the item to the cart: ' + err.message);
1789
+ const cart = addToCartLocalStorage(cartPayload);
1790
+ updateCartUI(cart);
1791
+ const modal = document.getElementById('itemModal');
1792
+ const modalInstance = bootstrap.Modal.getInstance(modal);
1793
+ modalInstance.hide();
1794
+ });
1795
+ }
1796
+ function handleSoftDrinkAdd(button) {
1797
+ const buttonContainer = button.closest('.button-container');
1798
+ const quantitySelector = buttonContainer.querySelector('.quantity-selector');
1799
+ const addButton = buttonContainer.querySelector('.add-to-cart-btn');
1800
+ const quantityDisplay = quantitySelector.querySelector('.quantity-display');
1801
+ const quantityToAddSelect = quantitySelector.querySelector('.quantity-to-add');
1802
+ const quantityToAdd = parseInt(quantityToAddSelect.value);
1803
+ const itemName = buttonContainer.getAttribute('data-item-name');
1804
+ const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
1805
+ const itemImage = buttonContainer.getAttribute('data-item-image');
1806
+ const section = buttonContainer.getAttribute('data-item-section');
1807
+ const selectedCategory = buttonContainer.getAttribute('data-item-category');
1808
+ addButton.style.display = 'none';
1809
+ quantitySelector.style.display = 'flex';
1810
+ let currentQuantity = parseInt(quantityDisplay.innerText) || 0;
1811
+ currentQuantity += quantityToAdd;
1812
+ quantityDisplay.innerText = currentQuantity;
1813
+ const cartPayload = {
1814
+ itemName: itemName,
1815
+ itemPrice: itemPrice,
1816
+ itemImage: itemImage,
1817
+ section: section,
1818
+ category: selectedCategory,
1819
+ addons: [],
1820
+ instructions: '',
1821
+ quantity: quantityToAdd
1822
+ };
1823
+ button.disabled = true;
1824
+ fetch('/cart/add', {
1825
+ method: 'POST',
1826
+ headers: {
1827
+ 'Content-Type': 'application/json',
1828
+ },
1829
+ body: JSON.stringify(cartPayload)
1830
+ })
1831
+ .then(response => {
1832
+ if (!response.ok) {
1833
+ throw new Error(`HTTP error! Status: ${response.status}`);
1834
+ }
1835
+ return response.json();
1836
+ })
1837
+ .then(data => {
1838
+ if (data.success) {
1839
+ alert(`Added ${quantityToAdd} item(s) to cart successfully!`);
1840
+ updateCartUI(data.cart);
1841
+ } else {
1842
+ console.error('Failed to add item to cart:', data.error);
1843
+ alert(data.error || 'Failed to add item to cart.');
1844
+ currentQuantity -= quantityToAdd;
1845
+ quantityDisplay.innerText = currentQuantity;
1846
+ }
1847
+ })
1848
+ .catch(err => {
1849
+ console.error('Error adding item to cart:', err);
1850
+ alert('An error occurred while adding the item to the cart: ' + err.message);
1851
+ const cart = addToCartLocalStorage(cartPayload);
1852
+ updateCartUI(cart);
1853
+ })
1854
+ .finally(() => {
1855
+ button.disabled = false;
1856
+ });
1857
+ }
1858
+ function increaseQuantity(button) {
1859
+ const buttonContainer = button.closest('.button-container');
1860
+ const quantityDisplay = buttonContainer.querySelector('.quantity-display');
1861
+ const quantityToAddSelect = buttonContainer.querySelector('.quantity-to-add');
1862
+ const quantityToAdd = parseInt(quantityToAddSelect.value);
1863
+ const itemName = buttonContainer.getAttribute('data-item-name');
1864
+ const itemPrice = parseFloat(buttonContainer.getAttribute('data-item-price'));
1865
+ const itemImage = buttonContainer.getAttribute('data-item-image');
1866
+ const section = buttonContainer.getAttribute('data-item-section');
1867
+ const selectedCategory = buttonContainer.getAttribute('data-item-category');
1868
+ let currentQuantity = parseInt(quantityDisplay.innerText) || 0;
1869
+ currentQuantity += quantityToAdd;
1870
+ quantityDisplay.innerText = currentQuantity;
1871
+ const cartPayload = {
1872
+ itemName: itemName,
1873
+ itemPrice: itemPrice,
1874
+ itemImage: itemImage,
1875
+ section: section,
1876
+ category: selectedCategory,
1877
+ addons: [],
1878
+ instructions: '',
1879
+ quantity: quantityToAdd
1880
+ };
1881
+ fetch('/cart/add', {
1882
+ method: 'POST',
1883
+ headers: {
1884
+ 'Content-Type': 'application/json',
1885
+ },
1886
+ body: JSON.stringify(cartPayload)
1887
+ })
1888
+ .then(response => {
1889
+ if (!response.ok) {
1890
+ throw new Error(`HTTP error! Status: ${response.status}`);
1891
+ }
1892
+ return response.json();
1893
+ })
1894
+ .then(data => {
1895
+ if (data.success) {
1896
+ alert(`Added ${quantityToAdd} item(s) to cart successfully!`);
1897
+ updateCartUI(data.cart);
1898
+ } else {
1899
+ console.error('Failed to add item to cart:', data.error);
1900
+ alert(data.error || 'Failed to add item to cart.');
1901
+ currentQuantity -= quantityToAdd;
1902
+ quantityDisplay.innerText = currentQuantity;
1903
+ }
1904
+ })
1905
+ .catch(err => {
1906
+ console.error('Error adding item to cart:', err);
1907
+ alert('An error occurred while adding the item to the cart: ' + err.message);
1908
+ const cart = addToCartLocalStorage(cartPayload);
1909
+ updateCartUI(cart);
1910
+ });
1911
+ }
1912
+ function decreaseQuantity(button) {
1913
+ const buttonContainer = button.closest('.button-container');
1914
+ const quantityDisplay = buttonContainer.querySelector('.quantity-display');
1915
+ const quantityToRemoveSelect = buttonContainer.querySelector('.quantity-to-remove');
1916
+ const quantityToRemove = parseInt(quantityToRemoveSelect.value);
1917
+ const addButton = buttonContainer.querySelector('.add-to-cart-btn');
1918
+ const quantitySelector = buttonContainer.querySelector('.quantity-selector');
1919
+ let currentQuantity = parseInt(quantityDisplay.innerText);
1920
+ if (currentQuantity <= quantityToRemove) {
1921
+ const itemName = buttonContainer.getAttribute('data-item-name');
1922
+ fetch(`/cart/remove?item_name=${encodeURIComponent(itemName)}&quantity=${currentQuantity}&instructions=&addons=[]`, {
1923
+ method: 'POST',
1924
+ headers: {
1925
+ 'Content-Type': 'application/json',
1926
+ }
1927
+ })
1928
+ .then(response => {
1929
+ if (!response.ok) {
1930
+ throw new Error(`HTTP error! Status: ${response.status}`);
1931
+ }
1932
+ return response.json();
1933
+ })
1934
+ .then(data => {
1935
+ if (data.success) {
1936
+ updateCartUI(data.cart);
1937
+ addButton.style.display = 'block';
1938
+ quantitySelector.style.display = 'none';
1939
+ quantityDisplay.innerText = 0;
1940
+ } else {
1941
+ console.error('Failed to remove item from cart:', data.error);
1942
+ alert(data.error || 'Failed to remove item from cart.');
1943
+ }
1944
+ })
1945
+ .catch(err => {
1946
+ console.error('Error removing item from cart:', err);
1947
+ alert('An error occurred while removing the item from the cart: ' + err.message);
1948
+ const cart = removeFromCartLocalStorage(itemName, currentQuantity, '', []);
1949
+ updateCartUI(cart);
1950
+ addButton.style.display = 'block';
1951
+ quantitySelector.style.display = 'none';
1952
+ quantityDisplay.innerText = 0;
1953
+ });
1954
+ } else {
1955
+ currentQuantity -= quantityToRemove;
1956
+ quantityDisplay.innerText = currentQuantity;
1957
+ const itemName = buttonContainer.getAttribute('data-item-name');
1958
+ fetch(`/cart/remove?item_name=${encodeURIComponent(itemName)}&quantity=${quantityToRemove}&instructions=&addons=[]`, {
1959
+ method: 'POST',
1960
+ headers: {
1961
+ 'Content-Type': 'application/json',
1962
+ }
1963
+ })
1964
+ .then(response => {
1965
+ if (!response.ok) {
1966
+ throw new Error(`HTTP error! Status: ${response.status}`);
1967
+ }
1968
+ return response.json();
1969
+ })
1970
+ .then(data => {
1971
+ if (data.success) {
1972
+ alert(`Removed ${quantityToRemove} item(s) from cart successfully!`);
1973
+ updateCartUI(data.cart);
1974
+ } else {
1975
+ console.error('Failed to remove item from cart:', data.error);
1976
+ alert(data.error || 'Failed to remove item from cart.');
1977
+ currentQuantity += quantityToRemove;
1978
+ quantityDisplay.innerText = currentQuantity;
1979
+ }
1980
+ })
1981
+ .catch(err => {
1982
+ console.error('Error removing item from cart:', err);
1983
+ alert('An error occurred while removing the item from the cart: ' + err.message);
1984
+ const cart = removeFromCartLocalStorage(itemName, quantityToRemove, '', []);
1985
+ updateCartUI(cart);
1986
+ });
1987
+ }
1988
+ }
1989
+ function updateCartUI(cart) {
1990
+ if (!Array.isArray(cart)) {
1991
+ console.error('Invalid cart data:', cart);
1992
+ return;
1993
+ }
1994
+
1995
+ // Calculate total quantity of items in cart
1996
+ let totalQuantity = 0;
1997
+ cart.forEach(item => {
1998
+ totalQuantity += item.quantity;
1999
+ });
2000
+
2001
+ // Update cart item count badge
2002
+ const cartItemCount = document.getElementById('cart-item-count');
2003
+ if (cartItemCount) {
2004
+ cartItemCount.innerText = totalQuantity;
2005
+ if (totalQuantity > 0) {
2006
+ cartItemCount.classList.add('active');
2007
+ } else {
2008
+ cartItemCount.classList.remove('active');
2009
+ }
2010
+ }
2011
+ // Update quantity displays for soft drinks
2012
+ const buttonContainers = document.querySelectorAll('.button-container');
2013
+ buttonContainers.forEach(container => {
2014
+ const itemName = container.getAttribute('data-item-name');
2015
+ const quantityDisplay = container.querySelector('.quantity-display');
2016
+ const addButton = container.querySelector('.add-to-cart-btn');
2017
+ const quantitySelector = container.querySelector('.quantity-selector');
2018
+ const cartItem = cart.find(item =>
2019
+ item.itemName === itemName &&
2020
+ item.instructions === '' &&
2021
+ JSON.stringify(item.addons) === JSON.stringify([])
2022
+ );
2023
+ if (cartItem && cartItem.quantity > 0) {
2024
+ quantityDisplay.innerText = cartItem.quantity;
2025
+ addButton.style.display = 'none';
2026
+ quantitySelector.style.display = 'flex';
2027
+ } else {
2028
+ quantityDisplay.innerText = 0;
2029
+ addButton.style.display = 'block';
2030
+ quantitySelector.style.display = 'none';
2031
+ }
2032
+ });
2033
+ }
2034
+ </script>
2035
+ </body>
2036
+ </html>