From 228b7a2b17e13c45a847f83e4a2fe721213bf2f3 Mon Sep 17 00:00:00 2001
From: Subrojit-Roy <57319006+Subrojit-Roy@users.noreply.github.com>
Date: Mon, 10 Nov 2025 11:50:29 +0000
Subject: [PATCH 1/3] feat: add new extracurricular activities and validation
for sign-up
---
src/app.py | 44 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
diff --git a/src/app.py b/src/app.py
index 4ebb1d9..efe1674 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-related activities
+ "Soccer Team": {
+ "description": "Join the school soccer team for practices and matches",
+ "schedule": "Mondays, Wednesdays, 4:30 PM - 6:00 PM",
+ "max_participants": 22,
+ "participants": ["liam@mergington.edu", "ava@mergington.edu"]
+ },
+ "Basketball Club": {
+ "description": "Pickup games and skill development for all levels",
+ "schedule": "Tuesdays, Thursdays, 5:00 PM - 6:30 PM",
+ "max_participants": 18,
+ "participants": ["noah@mergington.edu", "mia@mergington.edu"]
+ },
+ # Artistic activities
+ "Art Club": {
+ "description": "Explore drawing, painting, and mixed media projects",
+ "schedule": "Wednesdays, 3:30 PM - 5:00 PM",
+ "max_participants": 16,
+ "participants": ["isabella@mergington.edu", "lucas@mergington.edu"]
+ },
+ "Music Ensemble": {
+ "description": "Practice and perform ensemble pieces across genres",
+ "schedule": "Fridays, 4:00 PM - 6:00 PM",
+ "max_participants": 25,
+ "participants": ["amelia@mergington.edu", "ethan@mergington.edu"]
+ },
+ # Intellectual activities
+ "Debate Team": {
+ "description": "Develop public speaking and argumentation skills; compete in tournaments",
+ "schedule": "Thursdays, 3:30 PM - 5:00 PM",
+ "max_participants": 14,
+ "participants": ["harper@mergington.edu", "jack@mergington.edu"]
+ },
+ "Robotics Club": {
+ "description": "Design, build, and program robots for competitions and projects",
+ "schedule": "Tuesdays, 4:00 PM - 6:00 PM",
+ "max_participants": 12,
+ "participants": ["charlotte@mergington.edu", "logan@mergington.edu"]
}
}
@@ -61,7 +100,10 @@ def signup_for_activity(activity_name: str, email: str):
# Get the specific activity
activity = activities[activity_name]
-
+
+# Validate student is not already signed up
+ if email in activity["participants"]:
+ raise HTTPException(status_code=400, detail="Student already signed up for this activity")
# Add student
activity["participants"].append(email)
return {"message": f"Signed up {email} for {activity_name}"}
From 0ee5192b78392f34d984b2dd0017426475a08824 Mon Sep 17 00:00:00 2001
From: Subrojit-Roy <57319006+Subrojit-Roy@users.noreply.github.com>
Date: Mon, 10 Nov 2025 12:18:17 +0000
Subject: [PATCH 2/3] demo
---
src/static/app.js | 73 ++++++++++++++++++++++++++++++++++++++---
src/static/index.html | 41 +++++++++++++++++++++++
src/static/styles.css | 75 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 185 insertions(+), 4 deletions(-)
diff --git a/src/static/app.js b/src/static/app.js
index dcc1e38..73616e0 100644
--- a/src/static/app.js
+++ b/src/static/app.js
@@ -4,6 +4,20 @@ document.addEventListener("DOMContentLoaded", () => {
const signupForm = document.getElementById("signup-form");
const messageDiv = document.getElementById("message");
+ // Function to create a display name and initials from an email or name
+ function nameFromIdentifier(id) {
+ if (!id) return { display: "Unknown", initials: "?" };
+ // if it's an email, use part before @
+ const raw = id.includes("@") ? id.split("@")[0] : id;
+ // replace dots/underscores with spaces and split to words
+ const parts = raw.replace(/[._\-]+/g, " ").split(" ").filter(Boolean);
+ const display = parts.map(p => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
+ const initials = parts.length === 1
+ ? parts[0].substring(0, 2).toUpperCase()
+ : (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
+ return { display: display || raw, initials };
+ }
+
// Function to fetch activities from API
async function fetchActivities() {
try {
@@ -13,20 +27,69 @@ document.addEventListener("DOMContentLoaded", () => {
// Clear loading message
activitiesList.innerHTML = "";
+ // Reset select (keep placeholder if present)
+ const placeholderOption = activitySelect.querySelector('option[value=""]');
+ activitySelect.innerHTML = "";
+ if (placeholderOption) {
+ activitySelect.appendChild(placeholderOption);
+ } else {
+ // ensure a default placeholder exists
+ const opt = document.createElement("option");
+ opt.value = "";
+ opt.textContent = "-- Select an activity --";
+ activitySelect.appendChild(opt);
+ }
+
// Populate activities list
Object.entries(activities).forEach(([name, details]) => {
const activityCard = document.createElement("div");
activityCard.className = "activity-card";
- const spotsLeft = details.max_participants - details.participants.length;
+ const spotsLeft = details.max_participants - (details.participants?.length || 0);
- activityCard.innerHTML = `
+ // Basic info
+ const infoHtml = `
${name}
- ${details.description}
- Schedule: ${details.schedule}
+ ${details.description || ""}
+ Schedule: ${details.schedule || "TBA"}
Availability: ${spotsLeft} spots left
`;
+ activityCard.innerHTML = infoHtml;
+
+ // Participants section
+ const participantsDiv = document.createElement("div");
+ participantsDiv.className = "participants";
+ participantsDiv.setAttribute("aria-label", `Participants for ${name}`);
+
+ const title = document.createElement("h5");
+ title.textContent = "Participants";
+ participantsDiv.appendChild(title);
+
+ const participants = details.participants || [];
+
+ if (participants.length === 0) {
+ const none = document.createElement("p");
+ none.className = "info";
+ none.textContent = "No participants yet";
+ participantsDiv.appendChild(none);
+ } else {
+ const list = document.createElement("ul");
+ participants.forEach((p) => {
+ const { display, initials } = nameFromIdentifier(p);
+ const li = document.createElement("li");
+
+ const span = document.createElement("span");
+ span.className = "participant-initials";
+ span.textContent = initials;
+
+ li.appendChild(span);
+ li.appendChild(document.createTextNode(" " + display));
+ list.appendChild(li);
+ });
+ participantsDiv.appendChild(list);
+ }
+ activityCard.appendChild(participantsDiv);
activitiesList.appendChild(activityCard);
// Add option to select dropdown
@@ -62,6 +125,8 @@ document.addEventListener("DOMContentLoaded", () => {
messageDiv.textContent = result.message;
messageDiv.className = "success";
signupForm.reset();
+ // Refresh activities to show updated participants & availability
+ await fetchActivities();
} else {
messageDiv.textContent = result.detail || "An error occurred";
messageDiv.className = "error";
diff --git a/src/static/index.html b/src/static/index.html
index 3074f6e..3ae8250 100644
--- a/src/static/index.html
+++ b/src/static/index.html
@@ -39,6 +39,47 @@ Sign Up for an Activity
+
+
+ Example Activities
+
+
Morning Hike
+
Saturday, 8:00 AM · Easy
+
+
+
Participants
+
+ -
+ AL
+ Alice
+
+ -
+
+ Bob
+
+ -
+ CM
+ Casey
+
+
+
+
+
+
+
Photography Walk
+
Sunday, 4:00 PM · Photo tips included
+
+
+
Participants
+
+ - EM Emma
+ - RK Raj
+ - SO Simone
+ - +3 More
+
+
+
+