Spaces:
Sleeping
Sleeping
Upload 8 files
Browse files- app.py +73 -41
- static/WhatsApp Image 2025-09-18 at 18.33.55_105edc80.jpg +0 -0
- templates/base.html +1 -0
- templates/certificate.html +278 -0
- templates/landing.html +1 -0
- templates/quiz.html +114 -16
app.py
CHANGED
|
@@ -10,10 +10,10 @@ app.secret_key = 'supersecretkey_for_session_management' # Required for flash me
|
|
| 10 |
# Renamed to RAW as we'll augment it with position and path data
|
| 11 |
VIDEOS_RAW = [
|
| 12 |
{"id": "v1", "title": "A Beginner's Guide to Rainwater Collection", "url": "https://www.youtube.com/embed/uPS3GT1DC_Q?si=OYkUG-tuJeZquIkv", "length": "10:51", "base_points": 50},
|
| 13 |
-
{"id": "v2", "title": "Introduction to Rainwater Harvesting", "url": "https://www.youtube.com/embed/
|
| 14 |
{"id": "v3", "title": "First Flush Diverter Explained", "url": "https://www.youtube.com/embed/zO09yau1lCo?si=g-EJqsLU3PNiWjRD", "length": "8:16", "base_points": 60},
|
| 15 |
{"id": "v4", "title": "Is Rainwater Safe to Drink?", "url": "https://www.youtube.com/embed/nLphSEiHroU?si=PJ49EHuKVxeYRt_H", "length": "7:00", "base_points": 70}, # Adjusted length for the new video
|
| 16 |
-
{"id": "v5", "title": "First Flush Installation", "url": "https://www.youtube.com/embed/
|
| 17 |
{"id": "v6", "title": "DIY Home System Tour", "url": "https://www.youtube.com/embed/J2t_ZZGmBoo?si=LpSyztIH8xtF_Z_3", "length": "10:27", "base_points": 80},
|
| 18 |
{"id": "v7", "title": "Upgrading a Large System", "url": "https://www.youtube.com/embed/-NJ8aS4_WDA?si=2C0vCgr2O2hiMJx6", "length": "9:01", "base_points": 75},
|
| 19 |
{"id": "v8", "title": "Living on Rainwater in a Desert Environment", "url": "https://www.youtube.com/embed/rxmspcSjjKM?si=TerHbg_Ny_ZjbEy3", "length": "10:43", "base_points": 90},
|
|
@@ -88,57 +88,57 @@ for i, video_data in enumerate(VIDEOS_RAW):
|
|
| 88 |
|
| 89 |
|
| 90 |
# Quizzes (Video ID -> List of Questions)
|
| 91 |
-
# Each question: 'question', 'options' (list), 'correct_answer_index' (0-indexed), 'points'
|
| 92 |
QUIZZES = {
|
| 93 |
"v1": [
|
| 94 |
-
{"question": "What is the primary benefit of rainwater collection?", "options": ["Reduced water bills", "Increased garden pests", "More cloudy days", "Better internet speed"], "correct_answer_index": 0, "points": 20},
|
| 95 |
-
{"question": "What is a common component of a basic rainwater system?", "options": ["Solar panels", "Downspout", "Microwave", "Treadmill"], "correct_answer_index": 1, "points": 20},
|
| 96 |
-
{"question": "Why is rainwater harvesting considered sustainable?", "options": ["It uses more energy", "It depletes groundwater", "It utilizes a renewable resource", "It requires constant human intervention"], "correct_answer_index": 2, "points": 20},
|
| 97 |
],
|
| 98 |
"v2": [
|
| 99 |
-
{"question": "What is the first step in harvesting rainwater?", "options": ["Filtering", "Collecting from a surface", "Storing in a tank", "Drinking it"], "correct_answer_index": 1, "points": 20},
|
| 100 |
-
{"question": "Which of these is NOT typically part of an introduction to rainwater harvesting?", "options": ["System sizing", "Components overview", "Basic benefits", "Advanced purification techniques"], "correct_answer_index": 3, "points": 20},
|
| 101 |
-
{"question": "What is a common use for harvested rainwater in a household?", "options": ["Cooking", "Showering", "Toilet flushing", "Drinking without treatment"], "correct_answer_index": 2, "points": 20},
|
| 102 |
],
|
| 103 |
"v3": [
|
| 104 |
-
{"question": "What is the main purpose of a first flush diverter?", "options": ["To increase water pressure", "To divert initial dirty rainwater", "To cool the water", "To attract insects"], "correct_answer_index": 1, "points": 20},
|
| 105 |
-
{"question": "When does the first flush occur?", "options": ["During the middle of a storm", "After a prolonged dry spell", "At the very beginning of a rain event", "When the tank is full"], "correct_answer_index": 2, "points": 20},
|
| 106 |
-
{"question": "Why is it important to divert the first flush?", "options": ["To save space in the tank", "To improve water quality", "To reduce the amount of collected water", "To make the system more complex"], "correct_answer_index": 1, "points": 20},
|
| 107 |
],
|
| 108 |
"v4": [
|
| 109 |
-
{"question": "What is crucial for making rainwater safe to drink?", "options": ["No filtration at all", "Only basic screening", "Proper filtration and purification", "Adding sugar"], "correct_answer_index": 2, "points": 20},
|
| 110 |
-
{"question": "What contaminants might be found in raw rainwater?", "options": ["Pure oxygen", "Roof debris, dust, bird droppings", "Salt", "Distilled water"], "correct_answer_index": 1, "points": 20},
|
| 111 |
-
{"question": "Which method is commonly used for purifying drinking water from rainwater?", "options": ["Boiling", "Freezing", "Microwaving", "Shaking vigorously"], "correct_answer_index": 0, "points": 20},
|
| 112 |
],
|
| 113 |
"v5": [
|
| 114 |
-
{"question": "What type of pipe is often used for first flush diverters?", "options": ["Electrical conduit", "PVC pipe", "Garden hose", "Metal rebar"], "correct_answer_index": 1, "points": 20},
|
| 115 |
-
{"question": "Where is a first flush diverter typically installed?", "options": ["Inside the storage tank", "At the very top of the roof", "Between the gutter downspout and the storage tank", "Underground, far from the house"], "correct_answer_index": 2, "points": 20},
|
| 116 |
-
{"question": "What is a common safety measure during installation?", "options": ["Working alone", "Wearing a blindfold", "Using proper tools and fall protection", "Installing during a thunderstorm"], "correct_answer_index": 2, "points": 20},
|
| 117 |
],
|
| 118 |
"v6": [
|
| 119 |
-
{"question": "What does a 'DIY Home System Tour' typically showcase?", "options": ["Professional installation only", "Pre-built commercial systems", "Custom-built, homeowner-installed systems", "Fantasy systems"], "correct_answer_index": 2, "points": 20},
|
| 120 |
-
{"question": "What is a common component highlighted in a home tour?", "options": ["An electric car charger", "A storage tank", "A swimming pool heater", "A satellite dish"], "correct_answer_index": 1, "points": 20},
|
| 121 |
-
{"question": "What can be learned from a DIY system tour?", "options": ["How to break the system", "Specific design choices and challenges", "The history of plumbing", "Advanced quantum physics"], "correct_answer_index": 1, "points": 20},
|
| 122 |
],
|
| 123 |
"v7": [
|
| 124 |
-
{"question": "What might an upgrade to a large system involve?", "options": ["Reducing tank capacity", "Adding more collection surfaces or storage", "Removing all filters", "Switching to bottled water"], "correct_answer_index": 1, "points": 20},
|
| 125 |
-
{"question": "Why would someone upgrade a large rainwater harvesting system?", "options": ["To collect less water", "To improve efficiency or meet higher demand", "To make it less reliable", "To attract more birds"], "correct_answer_index": 1, "points": 20},
|
| 126 |
-
{"question": "What should be considered when planning a system upgrade?", "options": ["Ignoring existing infrastructure", "Only focusing on aesthetics", "Budget, demand, and integration with current setup", "Completely random additions"], "correct_answer_index": 2, "points": 20},
|
| 127 |
],
|
| 128 |
"v8": [
|
| 129 |
-
{"question": "What is a primary challenge of living on rainwater in a desert?", "options": ["Too much rain", "Limited rainfall and high evaporation", "No need for water", "Excessive humidity"], "correct_answer_index": 1, "points": 20},
|
| 130 |
-
{"question": "What strategy is crucial for rainwater harvesting in arid climates?", "options": ["Using tiny collection areas", "Maximizing collection surfaces and storage", "Wasting water frequently", "Ignoring forecasts"], "correct_answer_index": 1, "points": 20},
|
| 131 |
-
{"question": "Why is careful management important in a desert environment?", "options": ["Water is abundant", "Water is a scarce and precious resource", "It's a fun hobby", "To prove a point"], "correct_answer_index": 1, "points": 20},
|
| 132 |
],
|
| 133 |
"v9": [
|
| 134 |
-
{"question": "What material are many water storage tanks made from?", "options": ["Glass", "Wood", "Polyethylene", "Cardboard"], "correct_answer_index": 2, "points": 20},
|
| 135 |
-
{"question": "What tool might be used to prepare a cracked polyethylene tank for repair?", "options": ["A hammer", "A heat gun or plastic welder", "A spoon", "A paperclip"], "correct_answer_index": 1, "points": 20},
|
| 136 |
-
{"question": "What is a key step in ensuring a successful tank repair?", "options": ["Leaving the crack dirty", "Cleaning and drying the area thoroughly", "Applying repair material blindly", "Ignoring manufacturer instructions"], "correct_answer_index": 1, "points": 20},
|
| 137 |
],
|
| 138 |
"v10": [
|
| 139 |
-
{"question": "What is the main function of a pump in a rainwater system?", "options": ["To filter the water", "To add chemicals to the water", "To pressurize and distribute water", "To cool the water"], "correct_answer_index": 2, "points": 20},
|
| 140 |
-
{"question": "What kind of power source do most rainwater pumps use?", "options": ["Manual hand crank", "Electricity", "Solar power only", "Wind power"], "correct_answer_index": 1, "points": 20},
|
| 141 |
-
{"question": "What needs to be considered when selecting a pump?", "options": ["Its color", "Flow rate and pressure requirements", "The brand of your car", "Its weight"], "correct_answer_index": 1, "points": 20},
|
| 142 |
],
|
| 143 |
}
|
| 144 |
|
|
@@ -289,32 +289,64 @@ def quiz(video_id):
|
|
| 289 |
flash("Please complete the video before taking the quiz.", 'warning')
|
| 290 |
return redirect(url_for('dashboard'))
|
| 291 |
|
| 292 |
-
|
|
|
|
|
|
|
| 293 |
flash(f"You already completed the quiz for '{video['title']}'. Your score: {user_progress['video_quiz_scores'][video_id]} points.", 'info')
|
| 294 |
return redirect(url_for('dashboard'))
|
| 295 |
|
| 296 |
if request.method == 'POST':
|
| 297 |
user_score = 0
|
| 298 |
correct_answers_count = 0
|
|
|
|
|
|
|
| 299 |
for i, question_data in enumerate(quiz_questions):
|
| 300 |
-
|
| 301 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
try:
|
| 303 |
-
user_answer_index = int(
|
|
|
|
| 304 |
if user_answer_index == question_data['correct_answer_index']:
|
| 305 |
-
|
|
|
|
|
|
|
| 306 |
correct_answers_count += 1
|
| 307 |
except ValueError:
|
| 308 |
-
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
|
| 310 |
user_progress['points'] += user_score
|
| 311 |
user_progress['video_quiz_scores'][video_id] = user_score
|
| 312 |
flash(f"Quiz completed for '{video['title']}': You scored {user_score} points ({correct_answers_count}/{len(quiz_questions)} correct)!", 'success')
|
| 313 |
session['user_progress'] = user_progress # Update session after modification
|
| 314 |
evaluate_badges()
|
| 315 |
-
return redirect(url_for('dashboard'))
|
| 316 |
|
| 317 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
|
| 319 |
@app.route('/set_username', methods=['POST'])
|
| 320 |
def set_username():
|
|
|
|
| 10 |
# Renamed to RAW as we'll augment it with position and path data
|
| 11 |
VIDEOS_RAW = [
|
| 12 |
{"id": "v1", "title": "A Beginner's Guide to Rainwater Collection", "url": "https://www.youtube.com/embed/uPS3GT1DC_Q?si=OYkUG-tuJeZquIkv", "length": "10:51", "base_points": 50},
|
| 13 |
+
{"id": "v2", "title": "Introduction to Rainwater Harvesting", "url": "https://www.youtube.com/embed/72CVryFbv5I?si=oKWZ5Ep1Z3kcLI-g", "length": "6:44", "base_points": 40},
|
| 14 |
{"id": "v3", "title": "First Flush Diverter Explained", "url": "https://www.youtube.com/embed/zO09yau1lCo?si=g-EJqsLU3PNiWjRD", "length": "8:16", "base_points": 60},
|
| 15 |
{"id": "v4", "title": "Is Rainwater Safe to Drink?", "url": "https://www.youtube.com/embed/nLphSEiHroU?si=PJ49EHuKVxeYRt_H", "length": "7:00", "base_points": 70}, # Adjusted length for the new video
|
| 16 |
+
{"id": "v5", "title": "First Flush Installation", "url": "https://www.youtube.com/embed/bbYJvTj8uiw?si=nClbPzN9L2buoilz", "length": "9:34", "base_points": 65},
|
| 17 |
{"id": "v6", "title": "DIY Home System Tour", "url": "https://www.youtube.com/embed/J2t_ZZGmBoo?si=LpSyztIH8xtF_Z_3", "length": "10:27", "base_points": 80},
|
| 18 |
{"id": "v7", "title": "Upgrading a Large System", "url": "https://www.youtube.com/embed/-NJ8aS4_WDA?si=2C0vCgr2O2hiMJx6", "length": "9:01", "base_points": 75},
|
| 19 |
{"id": "v8", "title": "Living on Rainwater in a Desert Environment", "url": "https://www.youtube.com/embed/rxmspcSjjKM?si=TerHbg_Ny_ZjbEy3", "length": "10:43", "base_points": 90},
|
|
|
|
| 88 |
|
| 89 |
|
| 90 |
# Quizzes (Video ID -> List of Questions)
|
| 91 |
+
# Each question: 'question', 'options' (list), 'correct_answer_index' (0-indexed), 'points', 'reason'
|
| 92 |
QUIZZES = {
|
| 93 |
"v1": [
|
| 94 |
+
{"question": "What is the primary benefit of rainwater collection?", "options": ["Reduced water bills", "Increased garden pests", "More cloudy days", "Better internet speed"], "correct_answer_index": 0, "points": 20, "reason": "Rainwater collection significantly reduces the need for municipal or well water, directly lowering utility costs."},
|
| 95 |
+
{"question": "What is a common component of a basic rainwater system?", "options": ["Solar panels", "Downspout", "Microwave", "Treadmill"], "correct_answer_index": 1, "points": 20, "reason": "A downspout is crucial for directing water from the roof (collection surface) to the storage system."},
|
| 96 |
+
{"question": "Why is rainwater harvesting considered sustainable?", "options": ["It uses more energy", "It depletes groundwater", "It utilizes a renewable resource", "It requires constant human intervention"], "correct_answer_index": 2, "points": 20, "reason": "Rainwater is a naturally replenished resource, making its use sustainable as it doesn't deplete finite resources."},
|
| 97 |
],
|
| 98 |
"v2": [
|
| 99 |
+
{"question": "What is the first step in harvesting rainwater?", "options": ["Filtering", "Collecting from a surface", "Storing in a tank", "Drinking it"], "correct_answer_index": 1, "points": 20, "reason": "The initial step is always to collect water, typically from a roof or other suitable surface."},
|
| 100 |
+
{"question": "Which of these is NOT typically part of an introduction to rainwater harvesting?", "options": ["System sizing", "Components overview", "Basic benefits", "Advanced purification techniques"], "correct_answer_index": 3, "points": 20, "reason": "Advanced purification techniques are usually covered in more in-depth or specialized modules, not basic introductions."},
|
| 101 |
+
{"question": "What is a common use for harvested rainwater in a household?", "options": ["Cooking", "Showering", "Toilet flushing", "Drinking without treatment"], "correct_answer_index": 2, "points": 20, "reason": "Toilet flushing is a common and excellent use for untreated or minimally treated rainwater, reducing potable water consumption."},
|
| 102 |
],
|
| 103 |
"v3": [
|
| 104 |
+
{"question": "What is the main purpose of a first flush diverter?", "options": ["To increase water pressure", "To divert initial dirty rainwater", "To cool the water", "To attract insects"], "correct_answer_index": 1, "points": 20, "reason": "A first flush diverter prevents the initial, most contaminated rainwater (carrying debris from the roof) from entering the main storage tank."},
|
| 105 |
+
{"question": "When does the first flush occur?", "options": ["During the middle of a storm", "After a prolonged dry spell", "At the very beginning of a rain event", "When the tank is full"], "correct_answer_index": 2, "points": 20, "reason": "The 'first flush' refers to the first few minutes of a rainfall event, when the most impurities are washed off collection surfaces."},
|
| 106 |
+
{"question": "Why is it important to divert the first flush?", "options": ["To save space in the tank", "To improve water quality", "To reduce the amount of collected water", "To make the system more complex"], "correct_answer_index": 1, "points": 20, "reason": "Diverting the first flush significantly improves the overall quality of the water collected in the storage tank."},
|
| 107 |
],
|
| 108 |
"v4": [
|
| 109 |
+
{"question": "What is crucial for making rainwater safe to drink?", "options": ["No filtration at all", "Only basic screening", "Proper filtration and purification", "Adding sugar"], "correct_answer_index": 2, "points": 20, "reason": "For drinking, rainwater requires thorough filtration to remove particulates and purification (like boiling or UV) to eliminate pathogens."},
|
| 110 |
+
{"question": "What contaminants might be found in raw rainwater?", "options": ["Pure oxygen", "Roof debris, dust, bird droppings", "Salt", "Distilled water"], "correct_answer_index": 1, "points": 20, "reason": "Raw rainwater can pick up various contaminants from the atmosphere and collection surfaces, including organic matter, dust, and animal waste."},
|
| 111 |
+
{"question": "Which method is commonly used for purifying drinking water from rainwater?", "options": ["Boiling", "Freezing", "Microwaving", "Shaking vigorously"], "correct_answer_index": 0, "points": 20, "reason": "Boiling water for at least one minute is a reliable method to kill most bacteria and viruses, making it safe for consumption."},
|
| 112 |
],
|
| 113 |
"v5": [
|
| 114 |
+
{"question": "What type of pipe is often used for first flush diverters?", "options": ["Electrical conduit", "PVC pipe", "Garden hose", "Metal rebar"], "correct_answer_index": 1, "points": 20, "reason": "PVC (Polyvinyl Chloride) pipes are commonly used due to their durability, cost-effectiveness, and ease of installation for water systems."},
|
| 115 |
+
{"question": "Where is a first flush diverter typically installed?", "options": ["Inside the storage tank", "At the very top of the roof", "Between the gutter downspout and the storage tank", "Underground, far from the house"], "correct_answer_index": 2, "points": 20, "reason": "It's installed in the downspout system before the water enters the main storage, allowing the initial flow to be diverted."},
|
| 116 |
+
{"question": "What is a common safety measure during installation?", "options": ["Working alone", "Wearing a blindfold", "Using proper tools and fall protection", "Installing during a thunderstorm"], "correct_answer_index": 2, "points": 20, "reason": "Safety precautions like using correct tools and fall protection are essential, especially when working on roofs or with heavy equipment."},
|
| 117 |
],
|
| 118 |
"v6": [
|
| 119 |
+
{"question": "What does a 'DIY Home System Tour' typically showcase?", "options": ["Professional installation only", "Pre-built commercial systems", "Custom-built, homeowner-installed systems", "Fantasy systems"], "correct_answer_index": 2, "points": 20, "reason": "DIY tours focus on practical, often budget-friendly systems built and managed by homeowners themselves."},
|
| 120 |
+
{"question": "What is a common component highlighted in a home tour?", "options": ["An electric car charger", "A storage tank", "A swimming pool heater", "A satellite dish"], "correct_answer_index": 1, "points": 20, "reason": "The storage tank is a central and visually significant component of any rainwater harvesting system, often a key focus in tours."},
|
| 121 |
+
{"question": "What can be learned from a DIY system tour?", "options": ["How to break the system", "Specific design choices and challenges", "The history of plumbing", "Advanced quantum physics"], "correct_answer_index": 1, "points": 20, "reason": "DIY tours offer insights into practical design considerations, modifications, and solutions to common challenges faced by homeowners."},
|
| 122 |
],
|
| 123 |
"v7": [
|
| 124 |
+
{"question": "What might an upgrade to a large system involve?", "options": ["Reducing tank capacity", "Adding more collection surfaces or storage", "Removing all filters", "Switching to bottled water"], "correct_answer_index": 1, "points": 20, "reason": "Upgrading often means expanding capacity to collect more water or increasing storage to meet higher demand."},
|
| 125 |
+
{"question": "Why would someone upgrade a large rainwater harvesting system?", "options": ["To collect less water", "To improve efficiency or meet higher demand", "To make it less reliable", "To attract more birds"], "correct_answer_index": 1, "points": 20, "reason": "Upgrades are typically motivated by a need for more water, better performance, or adapting to changing water demands."},
|
| 126 |
+
{"question": "What should be considered when planning a system upgrade?", "options": ["Ignoring existing infrastructure", "Only focusing on aesthetics", "Budget, demand, and integration with current setup", "Completely random additions"], "correct_answer_index": 2, "points": 20, "reason": "Effective planning requires assessing financial resources, water needs, and how new components will fit with existing infrastructure."},
|
| 127 |
],
|
| 128 |
"v8": [
|
| 129 |
+
{"question": "What is a primary challenge of living on rainwater in a desert?", "options": ["Too much rain", "Limited rainfall and high evaporation", "No need for water", "Excessive humidity"], "correct_answer_index": 1, "points": 20, "reason": "Deserts are characterized by scarce rainfall and high temperatures, leading to significant water loss through evaporation, making collection challenging."},
|
| 130 |
+
{"question": "What strategy is crucial for rainwater harvesting in arid climates?", "options": ["Using tiny collection areas", "Maximizing collection surfaces and storage", "Wasting water frequently", "Ignoring forecasts"], "correct_answer_index": 1, "points": 20, "reason": "In arid regions, it's vital to capture as much rainfall as possible from large surfaces and store it effectively to last through dry periods."},
|
| 131 |
+
{"question": "Why is careful management important in a desert environment?", "options": ["Water is abundant", "Water is a scarce and precious resource", "It's a fun hobby", "To prove a point"], "correct_answer_index": 1, "points": 20, "reason": "Water is extremely limited in deserts, so every drop must be managed wisely to ensure survival and sustainability."},
|
| 132 |
],
|
| 133 |
"v9": [
|
| 134 |
+
{"question": "What material are many water storage tanks made from?", "options": ["Glass", "Wood", "Polyethylene", "Cardboard"], "correct_answer_index": 2, "points": 20, "reason": "Polyethylene is a common material for water tanks due to its durability, resistance to corrosion, and food-grade safety for water storage."},
|
| 135 |
+
{"question": "What tool might be used to prepare a cracked polyethylene tank for repair?", "options": ["A hammer", "A heat gun or plastic welder", "A spoon", "A paperclip"], "correct_answer_index": 1, "points": 20, "reason": "Plastic welding or using a heat gun with filler material is the appropriate method for repairing cracks in polyethylene tanks."},
|
| 136 |
+
{"question": "What is a key step in ensuring a successful tank repair?", "options": ["Leaving the crack dirty", "Cleaning and drying the area thoroughly", "Applying repair material blindly", "Ignoring manufacturer instructions"], "correct_answer_index": 1, "points": 20, "reason": "A clean, dry surface is essential for proper adhesion and a long-lasting repair when working with adhesives or plastic welding."},
|
| 137 |
],
|
| 138 |
"v10": [
|
| 139 |
+
{"question": "What is the main function of a pump in a rainwater system?", "options": ["To filter the water", "To add chemicals to the water", "To pressurize and distribute water", "To cool the water"], "correct_answer_index": 2, "points": 20, "reason": "Pumps are used to move water from the storage tank to where it's needed, often at a specific pressure for household use."},
|
| 140 |
+
{"question": "What kind of power source do most rainwater pumps use?", "options": ["Manual hand crank", "Electricity", "Solar power only", "Wind power"], "correct_answer_index": 1, "points": 20, "reason": "While solar pumps exist, most common rainwater systems utilize electric pumps for consistent power and performance."},
|
| 141 |
+
{"question": "What needs to be considered when selecting a pump?", "options": ["Its color", "Flow rate and pressure requirements", "The brand of your car", "Its weight"], "correct_answer_index": 1, "points": 20, "reason": "The pump must be chosen based on the desired water flow (how much water per minute) and pressure (how strong the water comes out) for the intended application."},
|
| 142 |
],
|
| 143 |
}
|
| 144 |
|
|
|
|
| 289 |
flash("Please complete the video before taking the quiz.", 'warning')
|
| 290 |
return redirect(url_for('dashboard'))
|
| 291 |
|
| 292 |
+
# If quiz already taken, and it's a GET request, redirect to dashboard
|
| 293 |
+
# The user can't retake a quiz, so no need to show old results on GET
|
| 294 |
+
if video_id in user_progress['video_quiz_scores'] and request.method == 'GET':
|
| 295 |
flash(f"You already completed the quiz for '{video['title']}'. Your score: {user_progress['video_quiz_scores'][video_id]} points.", 'info')
|
| 296 |
return redirect(url_for('dashboard'))
|
| 297 |
|
| 298 |
if request.method == 'POST':
|
| 299 |
user_score = 0
|
| 300 |
correct_answers_count = 0
|
| 301 |
+
quiz_feedback = [] # To store feedback for each question
|
| 302 |
+
|
| 303 |
for i, question_data in enumerate(quiz_questions):
|
| 304 |
+
user_answer_index_str = request.form.get(f'question_{i}')
|
| 305 |
+
user_answer_index = None
|
| 306 |
+
is_correct = False
|
| 307 |
+
points_for_this_question = 0
|
| 308 |
+
user_selected_option_text = "No answer" # Default if nothing selected
|
| 309 |
+
|
| 310 |
+
if user_answer_index_str:
|
| 311 |
try:
|
| 312 |
+
user_answer_index = int(user_answer_index_str)
|
| 313 |
+
user_selected_option_text = question_data['options'][user_answer_index]
|
| 314 |
if user_answer_index == question_data['correct_answer_index']:
|
| 315 |
+
is_correct = True
|
| 316 |
+
points_for_this_question = question_data['points']
|
| 317 |
+
user_score += points_for_this_question
|
| 318 |
correct_answers_count += 1
|
| 319 |
except ValueError:
|
| 320 |
+
pass # user_answer_index remains None, user_selected_option_text is "No answer"
|
| 321 |
+
|
| 322 |
+
correct_option_text = question_data['options'][question_data['correct_answer_index']]
|
| 323 |
+
reason_text = question_data.get('reason', 'No specific reason provided for this question.') # Get reason, provide default
|
| 324 |
+
|
| 325 |
+
quiz_feedback.append({
|
| 326 |
+
'question': question_data['question'],
|
| 327 |
+
'user_answer_index': user_answer_index,
|
| 328 |
+
'user_selected_option': user_selected_option_text,
|
| 329 |
+
'correct_answer_index': question_data['correct_answer_index'],
|
| 330 |
+
'correct_option': correct_option_text,
|
| 331 |
+
'is_correct': is_correct,
|
| 332 |
+
'points_earned': points_for_this_question,
|
| 333 |
+
'reason': reason_text
|
| 334 |
+
})
|
| 335 |
|
| 336 |
user_progress['points'] += user_score
|
| 337 |
user_progress['video_quiz_scores'][video_id] = user_score
|
| 338 |
flash(f"Quiz completed for '{video['title']}': You scored {user_score} points ({correct_answers_count}/{len(quiz_questions)} correct)!", 'success')
|
| 339 |
session['user_progress'] = user_progress # Update session after modification
|
| 340 |
evaluate_badges()
|
|
|
|
| 341 |
|
| 342 |
+
# Render the quiz page again, but this time with feedback
|
| 343 |
+
return render_template('quiz.html', video=video, quiz_questions=quiz_questions,
|
| 344 |
+
quiz_feedback=quiz_feedback, user_score=user_score,
|
| 345 |
+
total_quiz_points=sum(q['points'] for q in quiz_questions),
|
| 346 |
+
enumerate=enumerate, quiz_submitted=True)
|
| 347 |
+
|
| 348 |
+
# For GET request (displaying quiz for the first time)
|
| 349 |
+
return render_template('quiz.html', video=video, quiz_questions=quiz_questions, enumerate=enumerate, quiz_submitted=False)
|
| 350 |
|
| 351 |
@app.route('/set_username', methods=['POST'])
|
| 352 |
def set_username():
|
static/WhatsApp Image 2025-09-18 at 18.33.55_105edc80.jpg
ADDED
|
templates/base.html
CHANGED
|
@@ -44,6 +44,7 @@
|
|
| 44 |
</style>
|
| 45 |
</head>
|
| 46 |
<body>
|
|
|
|
| 47 |
<div class="container">
|
| 48 |
{% with messages = get_flashed_messages(with_categories=true) %}
|
| 49 |
{% if messages %}
|
|
|
|
| 44 |
</style>
|
| 45 |
</head>
|
| 46 |
<body>
|
| 47 |
+
<img src="/static/WhatsApp Image 2025-09-18 at 18.33.55_105edc80.jpg" alt="Logo" style="position: fixed; top: 20px; right: 30px; width: 80px; height: auto; z-index: 1000; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.12);">
|
| 48 |
<div class="container">
|
| 49 |
{% with messages = get_flashed_messages(with_categories=true) %}
|
| 50 |
{% if messages %}
|
templates/certificate.html
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 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>Certificate of Completion</title>
|
| 8 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
| 9 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
| 10 |
+
<link href="https://fonts.googleapis.com/css2?family=Great+Vibes&family=Playfair+Display:wght@700&family=Open+Sans&display=swap" rel="stylesheet">
|
| 11 |
+
<style>
|
| 12 |
+
body {
|
| 13 |
+
font-family: 'Open Sans', sans-serif;
|
| 14 |
+
background: linear-gradient(135deg, #f0f2f5 0%, #e0e7ef 100%);
|
| 15 |
+
min-height: 100vh;
|
| 16 |
+
display: flex;
|
| 17 |
+
flex-direction: column;
|
| 18 |
+
align-items: center;
|
| 19 |
+
justify-content: center;
|
| 20 |
+
padding: 20px;
|
| 21 |
+
position: relative;
|
| 22 |
+
}
|
| 23 |
+
.certificate-container {
|
| 24 |
+
background: rgba(255, 255, 255, 0.95);
|
| 25 |
+
border-radius: 24px;
|
| 26 |
+
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
|
| 27 |
+
max-width: 900px;
|
| 28 |
+
width: 100%;
|
| 29 |
+
margin-bottom: 30px;
|
| 30 |
+
border: 10px double #FFD700;
|
| 31 |
+
overflow: hidden;
|
| 32 |
+
position: relative;
|
| 33 |
+
}
|
| 34 |
+
.certificate {
|
| 35 |
+
padding: 60px 40px 40px 40px;
|
| 36 |
+
position: relative;
|
| 37 |
+
background: linear-gradient(135deg, #fdfdfd 0%, #f3f9ff 100%);
|
| 38 |
+
}
|
| 39 |
+
.logo-container {
|
| 40 |
+
width: 100px;
|
| 41 |
+
height: 100px;
|
| 42 |
+
margin: 0 auto 30px auto;
|
| 43 |
+
display: flex;
|
| 44 |
+
align-items: center;
|
| 45 |
+
justify-content: center;
|
| 46 |
+
border-radius: 20px;
|
| 47 |
+
background: #fff;
|
| 48 |
+
box-shadow: 0 4px 16px rgba(0,0,0,0.08);
|
| 49 |
+
position: relative;
|
| 50 |
+
}
|
| 51 |
+
.logo-container img {
|
| 52 |
+
width: 90px;
|
| 53 |
+
height: auto;
|
| 54 |
+
border-radius: 12px;
|
| 55 |
+
}
|
| 56 |
+
.certificate-title {
|
| 57 |
+
font-family: 'Playfair Display', serif;
|
| 58 |
+
font-size: 3em;
|
| 59 |
+
color: #1d3557;
|
| 60 |
+
margin-bottom: 10px;
|
| 61 |
+
text-transform: uppercase;
|
| 62 |
+
letter-spacing: 2px;
|
| 63 |
+
}
|
| 64 |
+
.certificate-subtitle {
|
| 65 |
+
font-size: 1.2em;
|
| 66 |
+
color: #444;
|
| 67 |
+
margin-bottom: 30px;
|
| 68 |
+
}
|
| 69 |
+
.certificate-body {
|
| 70 |
+
text-align: center;
|
| 71 |
+
margin: 40px 0 30px 0;
|
| 72 |
+
}
|
| 73 |
+
.certificate-name-label {
|
| 74 |
+
font-size: 1.1em;
|
| 75 |
+
color: #6c757d;
|
| 76 |
+
margin-bottom: 10px;
|
| 77 |
+
font-weight: 600;
|
| 78 |
+
}
|
| 79 |
+
.certificate-name {
|
| 80 |
+
font-family: 'Great Vibes', cursive;
|
| 81 |
+
font-size: 3.2em;
|
| 82 |
+
color: #0d6efd;
|
| 83 |
+
margin-bottom: 20px;
|
| 84 |
+
line-height: 1.2;
|
| 85 |
+
text-shadow: 2px 2px 6px rgba(0, 0, 0, 0.10);
|
| 86 |
+
}
|
| 87 |
+
.certificate-text {
|
| 88 |
+
font-size: 1.1em;
|
| 89 |
+
color: #495057;
|
| 90 |
+
line-height: 1.7;
|
| 91 |
+
margin: 0 auto 20px auto;
|
| 92 |
+
max-width: 700px;
|
| 93 |
+
}
|
| 94 |
+
.certificate-points {
|
| 95 |
+
font-size: 1.3em;
|
| 96 |
+
color: #0a9396;
|
| 97 |
+
font-weight: 700;
|
| 98 |
+
margin-top: 15px;
|
| 99 |
+
}
|
| 100 |
+
.certificate-footer {
|
| 101 |
+
width: 100%;
|
| 102 |
+
display: flex;
|
| 103 |
+
justify-content: space-between;
|
| 104 |
+
margin-top: 40px;
|
| 105 |
+
font-size: 1em;
|
| 106 |
+
color: #555;
|
| 107 |
+
}
|
| 108 |
+
.certificate-signature {
|
| 109 |
+
width: 40%;
|
| 110 |
+
text-align: center;
|
| 111 |
+
}
|
| 112 |
+
.certificate-signature p {
|
| 113 |
+
margin-top: 40px;
|
| 114 |
+
border-top: 2px solid #000;
|
| 115 |
+
padding-top: 8px;
|
| 116 |
+
font-weight: 600;
|
| 117 |
+
}
|
| 118 |
+
.certificate-id {
|
| 119 |
+
font-size: 0.95em;
|
| 120 |
+
color: #888;
|
| 121 |
+
text-align: center;
|
| 122 |
+
margin-top: 30px;
|
| 123 |
+
font-family: 'SF Mono', 'Monaco', 'Inconsolata', monospace;
|
| 124 |
+
padding: 10px 20px;
|
| 125 |
+
background: #f8f9fa;
|
| 126 |
+
border-radius: 10px;
|
| 127 |
+
border: 1px solid #eee;
|
| 128 |
+
display: inline-block;
|
| 129 |
+
}
|
| 130 |
+
.download-btn {
|
| 131 |
+
background: linear-gradient(135deg, #00b4d8 0%, #0077b6 100%);
|
| 132 |
+
color: white;
|
| 133 |
+
border: none;
|
| 134 |
+
padding: 16px 32px;
|
| 135 |
+
border-radius: 50px;
|
| 136 |
+
font-size: 1.1em;
|
| 137 |
+
font-weight: 600;
|
| 138 |
+
cursor: pointer;
|
| 139 |
+
transition: all 0.3s ease;
|
| 140 |
+
box-shadow: 0 8px 32px rgba(0, 180, 216, 0.15);
|
| 141 |
+
margin: 30px auto 0 auto;
|
| 142 |
+
display: block;
|
| 143 |
+
letter-spacing: 0.5px;
|
| 144 |
+
}
|
| 145 |
+
.download-btn:hover {
|
| 146 |
+
background: linear-gradient(135deg, #0077b6 0%, #00b4d8 100%);
|
| 147 |
+
transform: translateY(-2px) scale(1.01);
|
| 148 |
+
box-shadow: 0 12px 32px rgba(0, 180, 216, 0.22);
|
| 149 |
+
}
|
| 150 |
+
@media (max-width: 700px) {
|
| 151 |
+
.certificate {
|
| 152 |
+
padding: 30px 10px;
|
| 153 |
+
}
|
| 154 |
+
.certificate-footer {
|
| 155 |
+
flex-direction: column;
|
| 156 |
+
gap: 20px;
|
| 157 |
+
}
|
| 158 |
+
}
|
| 159 |
+
@media print {
|
| 160 |
+
body {
|
| 161 |
+
background: white;
|
| 162 |
+
padding: 0;
|
| 163 |
+
}
|
| 164 |
+
.download-btn {
|
| 165 |
+
display: none !important;
|
| 166 |
+
}
|
| 167 |
+
.certificate-container {
|
| 168 |
+
box-shadow: none;
|
| 169 |
+
max-width: none;
|
| 170 |
+
width: 100%;
|
| 171 |
+
background: white;
|
| 172 |
+
border: none;
|
| 173 |
+
}
|
| 174 |
+
.certificate {
|
| 175 |
+
background: white;
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
</style>
|
| 179 |
+
</head>
|
| 180 |
+
<body>
|
| 181 |
+
<div class="certificate-container" id="certificate">
|
| 182 |
+
<div class="certificate">
|
| 183 |
+
<div class="logo-container">
|
| 184 |
+
<img src="/static/WhatsApp Image 2025-09-18 at 18.33.55_105edc80.jpg" alt="Logo">
|
| 185 |
+
</div>
|
| 186 |
+
<h1 class="certificate-title">Certificate of Completion</h1>
|
| 187 |
+
<p class="certificate-subtitle">This certifies that</p>
|
| 188 |
+
<div class="certificate-body">
|
| 189 |
+
<div class="certificate-name-label">Name:</div>
|
| 190 |
+
<div class="certificate-name" id="recipientName">{{ username }}</div>
|
| 191 |
+
<div class="certificate-name-label">has successfully completed the course</div>
|
| 192 |
+
<div class="certificate-text">
|
| 193 |
+
for demonstrating outstanding dedication and mastering the principles of Rainwater Harvesting
|
| 194 |
+
through the <strong>Raindrop Quest: Harvest Hero</strong> learning program.
|
| 195 |
+
</div>
|
| 196 |
+
<div class="certificate-points">Total Points Earned: <span id="points">{{ total_points }}</span></div>
|
| 197 |
+
</div>
|
| 198 |
+
<div class="certificate-footer">
|
| 199 |
+
<div class="certificate-signature">
|
| 200 |
+
<p>Date: <span id="issueDate">{{ 'today' | date('%B %d, %Y') }}</span></p>
|
| 201 |
+
</div>
|
| 202 |
+
<div class="certificate-signature">
|
| 203 |
+
<p>Instructor: HydroHero Academy</p>
|
| 204 |
+
</div>
|
| 205 |
+
</div>
|
| 206 |
+
<div class="certificate-id">
|
| 207 |
+
Certificate ID: RWH-2025-<span id="certId">001234</span>
|
| 208 |
+
</div>
|
| 209 |
+
</div>
|
| 210 |
+
</div>
|
| 211 |
+
<button class="download-btn" onclick="downloadPDF()">
|
| 212 |
+
๐ฅ Download Certificate
|
| 213 |
+
</button>
|
| 214 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
| 215 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
| 216 |
+
<script>
|
| 217 |
+
// Function to generate random certificate ID
|
| 218 |
+
function generateCertId() {
|
| 219 |
+
return Math.random().toString(36).substr(2, 6).toUpperCase();
|
| 220 |
+
}
|
| 221 |
+
// Set current date
|
| 222 |
+
function setDate() {
|
| 223 |
+
const currentDate = new Date();
|
| 224 |
+
const options = { month: 'short', year: 'numeric' };
|
| 225 |
+
document.getElementById('issueDate').textContent = currentDate.toLocaleDateString('en-US', options);
|
| 226 |
+
}
|
| 227 |
+
// Set certificate ID
|
| 228 |
+
function setCertId() {
|
| 229 |
+
document.getElementById('certId').textContent = generateCertId();
|
| 230 |
+
}
|
| 231 |
+
// Function to download certificate as PDF
|
| 232 |
+
async function downloadPDF() {
|
| 233 |
+
const certificate = document.getElementById('certificate');
|
| 234 |
+
const downloadBtn = document.querySelector('.download-btn');
|
| 235 |
+
downloadBtn.style.display = 'none';
|
| 236 |
+
try {
|
| 237 |
+
const canvas = await html2canvas(certificate, {
|
| 238 |
+
scale: 3,
|
| 239 |
+
useCORS: true,
|
| 240 |
+
backgroundColor: '#ffffff',
|
| 241 |
+
width: certificate.offsetWidth,
|
| 242 |
+
height: certificate.offsetHeight,
|
| 243 |
+
logging: false
|
| 244 |
+
});
|
| 245 |
+
const { jsPDF } = window.jspdf;
|
| 246 |
+
const pdf = new jsPDF({
|
| 247 |
+
orientation: 'landscape',
|
| 248 |
+
unit: 'mm',
|
| 249 |
+
format: 'a4'
|
| 250 |
+
});
|
| 251 |
+
const imgWidth = 297;
|
| 252 |
+
const imgHeight = (canvas.height * imgWidth) / canvas.width;
|
| 253 |
+
const yPosition = (210 - imgHeight) / 2;
|
| 254 |
+
pdf.addImage(
|
| 255 |
+
canvas.toDataURL('image/png', 1.0),
|
| 256 |
+
'PNG',
|
| 257 |
+
0,
|
| 258 |
+
yPosition,
|
| 259 |
+
imgWidth,
|
| 260 |
+
imgHeight
|
| 261 |
+
);
|
| 262 |
+
const recipientName = document.getElementById('recipientName').textContent;
|
| 263 |
+
const fileName = `Certificate_${recipientName.replace(/\s+/g, '_')}_Rainwater_Harvesting.pdf`;
|
| 264 |
+
pdf.save(fileName);
|
| 265 |
+
} catch (error) {
|
| 266 |
+
alert('Error generating PDF. Please try again.');
|
| 267 |
+
} finally {
|
| 268 |
+
downloadBtn.style.display = 'block';
|
| 269 |
+
}
|
| 270 |
+
}
|
| 271 |
+
// Initialize on load
|
| 272 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 273 |
+
setDate();
|
| 274 |
+
setCertId();
|
| 275 |
+
});
|
| 276 |
+
</script>
|
| 277 |
+
</body>
|
| 278 |
+
</html>
|
templates/landing.html
CHANGED
|
@@ -176,6 +176,7 @@
|
|
| 176 |
</style>
|
| 177 |
</head>
|
| 178 |
<body>
|
|
|
|
| 179 |
<div class="landing-container">
|
| 180 |
<h1>๐ง Raindrop Quest: Harvest Hero</h1>
|
| 181 |
<p>Learn about Rainwater Harvesting in a Fun Way!</p>
|
|
|
|
| 176 |
</style>
|
| 177 |
</head>
|
| 178 |
<body>
|
| 179 |
+
<img src="/static/WhatsApp Image 2025-09-18 at 18.33.55_105edc80.jpg" alt="Logo" style="position: fixed; top: 20px; right: 30px; width: 80px; height: auto; z-index: 1000; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.12);">
|
| 180 |
<div class="landing-container">
|
| 181 |
<h1>๐ง Raindrop Quest: Harvest Hero</h1>
|
| 182 |
<p>Learn about Rainwater Harvesting in a Fun Way!</p>
|
templates/quiz.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
| 12 |
|
| 13 |
.header {
|
| 14 |
background: #1d3557;
|
| 15 |
-
color:
|
| 16 |
padding: 20px;
|
| 17 |
text-align: center;
|
| 18 |
border-bottom: 5px solid #457b9d;
|
|
@@ -40,7 +40,7 @@
|
|
| 40 |
background: #1d3557;
|
| 41 |
}
|
| 42 |
|
| 43 |
-
.quiz-form {
|
| 44 |
background: rgba(255, 255, 255, 0.9);
|
| 45 |
margin: 40px auto;
|
| 46 |
padding: 30px;
|
|
@@ -51,7 +51,7 @@
|
|
| 51 |
border: 2px solid #457b9d;
|
| 52 |
}
|
| 53 |
|
| 54 |
-
.quiz-form h3 {
|
| 55 |
font-size: 20px;
|
| 56 |
color: #1d3557;
|
| 57 |
margin-bottom: 10px;
|
|
@@ -96,6 +96,77 @@
|
|
| 96 |
transform: scale(1.05);
|
| 97 |
background: linear-gradient(90deg, #48cae4, #023047);
|
| 98 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
</style>
|
| 100 |
|
| 101 |
<div class="header">
|
|
@@ -103,17 +174,44 @@
|
|
| 103 |
<a href="{{ url_for('dashboard') }}">Back to Dashboard</a>
|
| 104 |
</div>
|
| 105 |
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
<
|
| 109 |
-
{
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
{% endfor %}
|
| 115 |
-
<
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
{% endblock %}
|
|
|
|
| 12 |
|
| 13 |
.header {
|
| 14 |
background: #1d3557;
|
| 15 |
+
color: white; /* Changed to white for better contrast */
|
| 16 |
padding: 20px;
|
| 17 |
text-align: center;
|
| 18 |
border-bottom: 5px solid #457b9d;
|
|
|
|
| 40 |
background: #1d3557;
|
| 41 |
}
|
| 42 |
|
| 43 |
+
.quiz-form, .quiz-results {
|
| 44 |
background: rgba(255, 255, 255, 0.9);
|
| 45 |
margin: 40px auto;
|
| 46 |
padding: 30px;
|
|
|
|
| 51 |
border: 2px solid #457b9d;
|
| 52 |
}
|
| 53 |
|
| 54 |
+
.quiz-form h3, .quiz-results h3 {
|
| 55 |
font-size: 20px;
|
| 56 |
color: #1d3557;
|
| 57 |
margin-bottom: 10px;
|
|
|
|
| 96 |
transform: scale(1.05);
|
| 97 |
background: linear-gradient(90deg, #48cae4, #023047);
|
| 98 |
}
|
| 99 |
+
|
| 100 |
+
/* Styles for quiz results */
|
| 101 |
+
.quiz-results h2 {
|
| 102 |
+
font-family: 'Montserrat', sans-serif;
|
| 103 |
+
color: #1d3557;
|
| 104 |
+
margin-bottom: 25px;
|
| 105 |
+
font-size: 2.2em;
|
| 106 |
+
}
|
| 107 |
+
.quiz-results p.score {
|
| 108 |
+
font-size: 1.5em;
|
| 109 |
+
font-weight: bold;
|
| 110 |
+
color: #023047;
|
| 111 |
+
margin-bottom: 30px;
|
| 112 |
+
}
|
| 113 |
+
.quiz-question-feedback {
|
| 114 |
+
margin-bottom: 30px;
|
| 115 |
+
padding: 20px;
|
| 116 |
+
border-radius: 15px;
|
| 117 |
+
border: 1px solid #ddd;
|
| 118 |
+
text-align: left;
|
| 119 |
+
}
|
| 120 |
+
.quiz-question-feedback.correct {
|
| 121 |
+
background-color: #e6ffed; /* Light green */
|
| 122 |
+
border-color: #28a745; /* Green */
|
| 123 |
+
}
|
| 124 |
+
.quiz-question-feedback.incorrect {
|
| 125 |
+
background-color: #ffe6e6; /* Light red */
|
| 126 |
+
border-color: #dc3545; /* Red */
|
| 127 |
+
}
|
| 128 |
+
.quiz-question-feedback h4 {
|
| 129 |
+
margin-top: 0;
|
| 130 |
+
color: #1d3557;
|
| 131 |
+
font-size: 1.3em;
|
| 132 |
+
}
|
| 133 |
+
.quiz-question-feedback .user-answer, .quiz-question-feedback .correct-answer {
|
| 134 |
+
font-size: 1.1em;
|
| 135 |
+
margin-bottom: 8px;
|
| 136 |
+
}
|
| 137 |
+
.quiz-question-feedback .user-answer span, .quiz-question-feedback .correct-answer span {
|
| 138 |
+
font-weight: bold;
|
| 139 |
+
}
|
| 140 |
+
.quiz-question-feedback .user-answer.correct-choice {
|
| 141 |
+
color: #28a745;
|
| 142 |
+
}
|
| 143 |
+
.quiz-question-feedback .user-answer.incorrect-choice {
|
| 144 |
+
color: #dc3545;
|
| 145 |
+
}
|
| 146 |
+
.quiz-question-feedback .correct-answer-text {
|
| 147 |
+
color: #28a745;
|
| 148 |
+
}
|
| 149 |
+
.quiz-question-feedback .reason {
|
| 150 |
+
font-style: italic;
|
| 151 |
+
color: #555;
|
| 152 |
+
margin-top: 15px;
|
| 153 |
+
padding-top: 10px;
|
| 154 |
+
border-top: 1px dashed #ccc;
|
| 155 |
+
}
|
| 156 |
+
.quiz-results .back-to-dashboard {
|
| 157 |
+
display: inline-block;
|
| 158 |
+
margin-top: 30px;
|
| 159 |
+
background: #007bff;
|
| 160 |
+
color: white;
|
| 161 |
+
padding: 12px 25px;
|
| 162 |
+
border-radius: 20px;
|
| 163 |
+
text-decoration: none;
|
| 164 |
+
font-weight: bold;
|
| 165 |
+
transition: background 0.3s;
|
| 166 |
+
}
|
| 167 |
+
.quiz-results .back-to-dashboard:hover {
|
| 168 |
+
background: #0056b3;
|
| 169 |
+
}
|
| 170 |
</style>
|
| 171 |
|
| 172 |
<div class="header">
|
|
|
|
| 174 |
<a href="{{ url_for('dashboard') }}">Back to Dashboard</a>
|
| 175 |
</div>
|
| 176 |
|
| 177 |
+
{% if quiz_submitted %}
|
| 178 |
+
<div class="quiz-results">
|
| 179 |
+
<h2>Quiz Results</h2>
|
| 180 |
+
<p class="score">Your Score: {{ user_score }} / {{ total_quiz_points }} points</p>
|
| 181 |
+
|
| 182 |
+
{% for feedback in quiz_feedback %}
|
| 183 |
+
<div class="quiz-question-feedback {% if feedback.is_correct %}correct{% else %}incorrect{% endif %}">
|
| 184 |
+
<h4>{{ loop.index }}. {{ feedback.question }}</h4>
|
| 185 |
+
<p class="user-answer {% if feedback.is_correct %}correct-choice{% else %}incorrect-choice{% endif %}">
|
| 186 |
+
Your Answer: <span>{{ feedback.user_selected_option }}</span>
|
| 187 |
+
{% if feedback.is_correct %} (Correct! ๐){% else %} (Incorrect ๐){% endif %}
|
| 188 |
+
</p>
|
| 189 |
+
{% if not feedback.is_correct %}
|
| 190 |
+
<p class="correct-answer">
|
| 191 |
+
Correct Answer: <span class="correct-answer-text">{{ feedback.correct_option }}</span>
|
| 192 |
+
</p>
|
| 193 |
+
{% endif %}
|
| 194 |
+
<p class="reason">
|
| 195 |
+
<strong>Reason:</strong> {{ feedback.reason }}
|
| 196 |
+
</p>
|
| 197 |
+
</div>
|
| 198 |
+
{% endfor %}
|
| 199 |
+
|
| 200 |
+
<a href="{{ url_for('dashboard') }}" class="back-to-dashboard">Return to Dashboard</a>
|
| 201 |
+
</div>
|
| 202 |
+
{% else %}
|
| 203 |
+
<form method="POST" class="quiz-form">
|
| 204 |
+
{% for i, question_data in enumerate(quiz_questions) %}
|
| 205 |
+
<h3>{{ i+1 }}. {{ question_data.question }}</h3>
|
| 206 |
+
{% for j, option in enumerate(question_data.options) %}
|
| 207 |
+
<label>
|
| 208 |
+
<input type="radio" name="question_{{ i }}" value="{{ j }}" required>
|
| 209 |
+
{{ option }}
|
| 210 |
+
</label>
|
| 211 |
+
{% endfor %}
|
| 212 |
+
<br>
|
| 213 |
{% endfor %}
|
| 214 |
+
<button type="submit">Submit Quiz</button>
|
| 215 |
+
</form>
|
| 216 |
+
{% endif %}
|
| 217 |
+
{% endblock %}
|
|
|