diff --git a/src/app.py b/src/app.py index 4ebb1d9..f627fa3 100644 --- a/src/app.py +++ b/src/app.py @@ -38,6 +38,45 @@ "schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM", "max_participants": 30, "participants": ["john@mergington.edu", "olivia@mergington.edu"] + }, + # Sports activities + "Soccer Team": { + "description": "Join the school soccer team and compete in local leagues", + "schedule": "Tuesdays and Thursdays, 4:00 PM - 5:30 PM", + "max_participants": 22, + "participants": ["lucas@mergington.edu", "mia@mergington.edu"] + }, + "Basketball Club": { + "description": "Practice basketball skills and play friendly matches", + "schedule": "Wednesdays, 3:30 PM - 5:00 PM", + "max_participants": 15, + "participants": ["liam@mergington.edu", "ava@mergington.edu"] + }, + # Artistic activities + "Art Club": { + "description": "Explore painting, drawing, and other visual arts", + "schedule": "Mondays, 3:30 PM - 5:00 PM", + "max_participants": 18, + "participants": ["noah@mergington.edu", "isabella@mergington.edu"] + }, + "Drama Society": { + "description": "Participate in theater productions and acting workshops", + "schedule": "Thursdays, 4:00 PM - 5:30 PM", + "max_participants": 25, + "participants": ["amelia@mergington.edu", "jack@mergington.edu"] + }, + # Intellectual activities + "Math Olympiad": { + "description": "Prepare for math competitions and solve challenging problems", + "schedule": "Fridays, 2:00 PM - 3:30 PM", + "max_participants": 16, + "participants": ["charlotte@mergington.edu", "benjamin@mergington.edu"] + }, + "Science Club": { + "description": "Conduct experiments and explore scientific concepts", + "schedule": "Wednesdays, 4:00 PM - 5:00 PM", + "max_participants": 20, + "participants": ["elijah@mergington.edu", "harper@mergington.edu"] } } @@ -62,6 +101,26 @@ def signup_for_activity(activity_name: str, email: str): # Get the specific activity activity = activities[activity_name] - # Add student +# Validate student is not already signed up + if email in activity["participants"]: + raise HTTPException(status_code=400, detail="Already signed up for this activity") + + # Check if max participants reached + if len(activity["participants"]) >= activity["max_participants"]: + raise HTTPException(status_code=400, detail="Activity is full") + + # Add student to participants activity["participants"].append(email) return {"message": f"Signed up {email} for {activity_name}"} + + +@app.post("/activities/{activity_name}/unregister") +def unregister_from_activity(activity_name: str, email: str): + """Unregister a student from an activity""" + if activity_name not in activities: + raise HTTPException(status_code=404, detail="Activity not found") + activity = activities[activity_name] + if email not in activity["participants"]: + raise HTTPException(status_code=400, detail="Participant not found in this activity") + activity["participants"].remove(email) + return {"message": f"Unregistered {email} from {activity_name}"} diff --git a/src/static/app.js b/src/static/app.js index dcc1e38..1873c42 100644 --- a/src/static/app.js +++ b/src/static/app.js @@ -20,11 +20,32 @@ document.addEventListener("DOMContentLoaded", () => { const spotsLeft = details.max_participants - details.participants.length; + // Create participants list HTML + let participantsHTML = ""; + if (details.participants.length > 0) { + participantsHTML = ` +
+ Participants: + +
+ `; + } else { + participantsHTML = ` +
+ Participants: + No participants yet +
+ `; + } + activityCard.innerHTML = `

${name}

${details.description}

Schedule: ${details.schedule}

Availability: ${spotsLeft} spots left

+ ${participantsHTML} `; activitiesList.appendChild(activityCard); @@ -81,6 +102,29 @@ document.addEventListener("DOMContentLoaded", () => { } }); + // Add event listener for delete icons + activitiesList.addEventListener("click", async (event) => { + if (event.target.classList.contains("delete-participant")) { + const activity = event.target.getAttribute("data-activity"); + const email = event.target.getAttribute("data-email"); + if (confirm(`Unregister ${email} from ${activity}?`)) { + try { + const response = await fetch(`/activities/${encodeURIComponent(activity)}/unregister?email=${encodeURIComponent(email)}`, { + method: "POST" + }); + if (!response.ok) { + const data = await response.json(); + alert(data.detail || "Failed to unregister participant."); + } else { + fetchActivities(); + } + } catch (error) { + alert("Error unregistering participant."); + } + } + } + }); + // Initialize app fetchActivities(); }); diff --git a/src/static/styles.css b/src/static/styles.css index a533b32..e722f8c 100644 --- a/src/static/styles.css +++ b/src/static/styles.css @@ -63,6 +63,7 @@ section h3 { border: 1px solid #ddd; border-radius: 5px; background-color: #f9f9f9; + position: relative; } .activity-card h4 { @@ -74,6 +75,46 @@ section h3 { margin-bottom: 8px; } +.participants-section { + margin-top: 12px; + padding: 10px; + background-color: #eef2fa; + border-radius: 4px; + border: 1px solid #c5cae9; +} + +.participants-section strong { + color: #3949ab; + display: block; + margin-bottom: 5px; +} + +.participants-list { + margin: 0 0 0 18px; + padding: 0; + list-style-type: none; /* Hide bullet points */ + color: #333; + font-size: 15px; +} + +.delete-participant { + cursor: pointer; + color: #c62828; + margin-left: 8px; + font-size: 16px; + vertical-align: middle; + transition: color 0.2s; +} +.delete-participant:hover { + color: #a31515; +} + +.no-participants { + color: #888; + font-style: italic; + margin-left: 5px; +} + .form-group { margin-bottom: 15px; }