Skip to content

Commit 7d6e28f

Browse files
authored
Merge pull request #2 from HarshitMCT/accelerate-with-copilot
Improve student activity registration system
2 parents fbc97f6 + 3eb390b commit 7d6e28f

5 files changed

Lines changed: 286 additions & 28 deletions

File tree

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# For testing
2+
pytest
13
fastapi
24
uvicorn
35
httpx

src/app.py

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,61 @@
2121

2222
# In-memory activity database
2323
activities = {
24-
"Chess Club": {
25-
"description": "Learn strategies and compete in chess tournaments",
26-
"schedule": "Fridays, 3:30 PM - 5:00 PM",
27-
"max_participants": 12,
28-
"participants": ["michael@mergington.edu", "daniel@mergington.edu"]
29-
},
30-
"Programming Class": {
31-
"description": "Learn programming fundamentals and build software projects",
32-
"schedule": "Tuesdays and Thursdays, 3:30 PM - 4:30 PM",
33-
"max_participants": 20,
34-
"participants": ["emma@mergington.edu", "sophia@mergington.edu"]
35-
},
36-
"Gym Class": {
37-
"description": "Physical education and sports activities",
38-
"schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM",
39-
"max_participants": 30,
40-
"participants": ["john@mergington.edu", "olivia@mergington.edu"]
41-
}
24+
"Chess Club": {
25+
"description": "Learn strategies and compete in chess tournaments",
26+
"schedule": "Fridays, 3:30 PM - 5:00 PM",
27+
"max_participants": 12,
28+
"participants": ["michael@mergington.edu", "daniel@mergington.edu"]
29+
},
30+
"Programming Class": {
31+
"description": "Learn programming fundamentals and build software projects",
32+
"schedule": "Tuesdays and Thursdays, 3:30 PM - 4:30 PM",
33+
"max_participants": 20,
34+
"participants": ["emma@mergington.edu", "sophia@mergington.edu"]
35+
},
36+
"Gym Class": {
37+
"description": "Physical education and sports activities",
38+
"schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM",
39+
"max_participants": 30,
40+
"participants": ["john@mergington.edu", "olivia@mergington.edu"]
41+
},
42+
"Soccer Team": {
43+
"description": "Practice soccer skills and compete in inter-school matches",
44+
"schedule": "Mondays and Wednesdays, 4:00 PM - 5:30 PM",
45+
"max_participants": 22,
46+
"participants": ["liam@mergington.edu", "noah@mergington.edu"]
47+
},
48+
"Basketball Club": {
49+
"description": "Develop teamwork and basketball fundamentals",
50+
"schedule": "Tuesdays and Fridays, 4:00 PM - 5:30 PM",
51+
"max_participants": 15,
52+
"participants": ["ava@mergington.edu", "isabella@mergington.edu"]
53+
},
54+
"Drama Club": {
55+
"description": "Explore acting, stage presence, and theater production",
56+
"schedule": "Thursdays, 3:30 PM - 5:00 PM",
57+
"max_participants": 18,
58+
"participants": ["mia@mergington.edu", "charlotte@mergington.edu"]
59+
},
60+
"Painting Workshop": {
61+
"description": "Learn painting techniques and create visual art projects",
62+
"schedule": "Wednesdays, 3:30 PM - 5:00 PM",
63+
"max_participants": 16,
64+
"participants": ["amelia@mergington.edu", "harper@mergington.edu"]
65+
},
66+
"Debate Team": {
67+
"description": "Build public speaking and critical thinking through debates",
68+
"schedule": "Mondays, 3:30 PM - 5:00 PM",
69+
"max_participants": 14,
70+
"participants": ["elijah@mergington.edu", "james@mergington.edu"]
71+
},
72+
"Math Olympiad": {
73+
"description": "Solve advanced math problems and prepare for competitions",
74+
"schedule": "Fridays, 3:30 PM - 5:00 PM",
75+
"max_participants": 12,
76+
"participants": ["lucas@mergington.edu", "benjamin@mergington.edu"]
77+
}
78+
4279
}
4380

4481

@@ -52,16 +89,27 @@ def get_activities():
5289
return activities
5390

5491

92+
93+
# POST: Register participant
5594
@app.post("/activities/{activity_name}/signup")
5695
def signup_for_activity(activity_name: str, email: str):
57-
"""Sign up a student for an activity"""
58-
# Validate activity exists
59-
if activity_name not in activities:
60-
raise HTTPException(status_code=404, detail="Activity not found")
61-
62-
# Get the specific activity
63-
activity = activities[activity_name]
96+
"""Sign up a student for an activity"""
97+
if activity_name not in activities:
98+
raise HTTPException(status_code=404, detail="Activity not found")
99+
activity = activities[activity_name]
100+
if email in activity["participants"]:
101+
raise HTTPException(status_code=400, detail="Student already signed up for this activity")
102+
activity["participants"].append(email)
103+
return {"message": f"Signed up {email} for {activity_name}"}
64104

65-
# Add student
66-
activity["participants"].append(email)
67-
return {"message": f"Signed up {email} for {activity_name}"}
105+
# DELETE: Unregister participant
106+
@app.delete("/activities/{activity_name}/signup")
107+
def unregister_from_activity(activity_name: str, email: str):
108+
"""Remove a student from an activity"""
109+
if activity_name not in activities:
110+
raise HTTPException(status_code=404, detail="Activity not found")
111+
activity = activities[activity_name]
112+
if email not in activity["participants"]:
113+
raise HTTPException(status_code=404, detail="Student not registered for this activity")
114+
activity["participants"].remove(email)
115+
return {"message": f"Removed {email} from {activity_name}"}

src/static/app.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,67 @@ document.addEventListener("DOMContentLoaded", () => {
2020

2121
const spotsLeft = details.max_participants - details.participants.length;
2222

23+
// Create participants list HTML
24+
let participantsHTML = "";
25+
if (details.participants && details.participants.length > 0) {
26+
participantsHTML = `
27+
<div class="participants-section">
28+
<strong>Participants:</strong>
29+
<ul class="participants-list no-bullets">
30+
${details.participants.map(p => `
31+
<li class="participant-item">
32+
<span class="participant-email">${p}</span>
33+
<button class="delete-participant" title="Remove participant" data-activity="${name}" data-email="${p}">
34+
<span aria-hidden="true">&times;</span>
35+
</button>
36+
</li>
37+
`).join("")}
38+
</ul>
39+
</div>
40+
`;
41+
} else {
42+
participantsHTML = `
43+
<div class="participants-section empty">
44+
<em>No participants yet</em>
45+
</div>
46+
`;
47+
}
48+
2349
activityCard.innerHTML = `
2450
<h4>${name}</h4>
2551
<p>${details.description}</p>
2652
<p><strong>Schedule:</strong> ${details.schedule}</p>
2753
<p><strong>Availability:</strong> ${spotsLeft} spots left</p>
54+
${participantsHTML}
2855
`;
2956

3057
activitiesList.appendChild(activityCard);
58+
activitiesList.appendChild(activityCard);
59+
60+
// Add delete event listeners after card is in DOM
61+
const deleteButtons = activityCard.querySelectorAll('.delete-participant');
62+
deleteButtons.forEach(btn => {
63+
btn.addEventListener('click', async (e) => {
64+
e.preventDefault();
65+
e.stopPropagation();
66+
const email = btn.getAttribute('data-email');
67+
const activity = btn.getAttribute('data-activity');
68+
if (!email || !activity) return;
69+
try {
70+
const response = await fetch(`/activities/${encodeURIComponent(activity)}/signup?email=${encodeURIComponent(email)}`, {
71+
method: 'DELETE',
72+
});
73+
if (response.ok) {
74+
fetchActivities(); // Refresh list
75+
} else {
76+
const result = await response.json();
77+
alert(result.detail || 'Failed to remove participant.');
78+
}
79+
} catch (error) {
80+
alert('Failed to remove participant.');
81+
}
82+
});
83+
});
3184

3285
// Add option to select dropdown
3386
const option = document.createElement("option");
@@ -62,6 +115,7 @@ document.addEventListener("DOMContentLoaded", () => {
62115
messageDiv.textContent = result.message;
63116
messageDiv.className = "success";
64117
signupForm.reset();
118+
fetchActivities(); // Refresh activities list after successful signup
65119
} else {
66120
messageDiv.textContent = result.detail || "An error occurred";
67121
messageDiv.className = "error";

src/static/styles.css

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,69 @@ section h3 {
7474
margin-bottom: 8px;
7575
}
7676

77+
.participants-section {
78+
margin-top: 10px;
79+
padding: 10px;
80+
background-color: #eef3fa;
81+
border-radius: 4px;
82+
border: 1px solid #c5cae9;
83+
}
84+
85+
.participants-section strong {
86+
color: #3949ab;
87+
font-size: 15px;
88+
}
89+
90+
.participants-list {
91+
margin: 8px 0 0 0;
92+
padding-left: 0;
93+
list-style-type: none;
94+
color: #333;
95+
font-size: 15px;
96+
}
97+
98+
.no-bullets {
99+
list-style-type: none;
100+
padding-left: 0;
101+
}
102+
103+
.participant-item {
104+
display: flex;
105+
align-items: center;
106+
margin-bottom: 4px;
107+
}
108+
109+
.participant-email {
110+
flex: 1;
111+
word-break: break-all;
112+
}
113+
114+
.delete-participant {
115+
background: none;
116+
border: none;
117+
color: #c62828;
118+
font-size: 20px;
119+
margin-left: 8px;
120+
cursor: pointer;
121+
padding: 2px 6px;
122+
border-radius: 50%;
123+
transition: background 0.2s;
124+
line-height: 1;
125+
}
126+
127+
.delete-participant:hover {
128+
background: #ffebee;
129+
color: #b71c1c;
130+
}
131+
132+
.participants-section.empty {
133+
background: none;
134+
border: none;
135+
color: #888;
136+
font-style: italic;
137+
padding-left: 0;
138+
}
139+
77140
.form-group {
78141
margin-bottom: 15px;
79142
}

0 commit comments

Comments
 (0)