Skip to content

Commit f51252c

Browse files
authored
Merge pull request #2 from octodemo/accelerate-with-copilot
Accelerate with copilot
2 parents 4b483b0 + f359aa5 commit f51252c

File tree

7 files changed

+420
-1
lines changed

7 files changed

+420
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Getting Started with GitHub Copilot
1+
# Getting Started with GitHub Copilot
22

33
<img src="https://octodex.github.com/images/Professortocat_v2.png" align="right" height="200px" />
44

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
fastapi
22
uvicorn
3+
pytest
4+
httpx

src/app.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,42 @@
3838
"schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM",
3939
"max_participants": 30,
4040
"participants": ["[email protected]", "[email protected]"]
41+
},
42+
"Basketball Team": {
43+
"description": "Competitive basketball practice and games",
44+
"schedule": "Tuesdays and Thursdays, 4:00 PM - 6:00 PM",
45+
"max_participants": 15,
46+
"participants": ["[email protected]", "[email protected]"]
47+
},
48+
"Swimming Club": {
49+
"description": "Swimming lessons and competitive training",
50+
"schedule": "Wednesdays, 3:30 PM - 5:00 PM",
51+
"max_participants": 25,
52+
"participants": ["[email protected]", "[email protected]"]
53+
},
54+
"Art Club": {
55+
"description": "Explore various art mediums including painting and sculpture",
56+
"schedule": "Mondays, 3:30 PM - 5:00 PM",
57+
"max_participants": 18,
58+
"participants": ["[email protected]", "[email protected]"]
59+
},
60+
"Drama Club": {
61+
"description": "Acting, theater production, and performance arts",
62+
"schedule": "Thursdays, 3:30 PM - 5:30 PM",
63+
"max_participants": 24,
64+
"participants": ["[email protected]", "[email protected]"]
65+
},
66+
"Debate Team": {
67+
"description": "Develop critical thinking and public speaking skills through debates",
68+
"schedule": "Wednesdays, 3:30 PM - 5:00 PM",
69+
"max_participants": 16,
70+
"participants": ["[email protected]", "[email protected]"]
71+
},
72+
"Science Olympiad": {
73+
"description": "Prepare for science competitions and conduct experiments",
74+
"schedule": "Fridays, 3:30 PM - 5:30 PM",
75+
"max_participants": 20,
76+
"participants": ["[email protected]", "[email protected]"]
4177
}
4278
}
4379

@@ -62,6 +98,29 @@ def signup_for_activity(activity_name: str, email: str):
6298
# Get the specific activity
6399
activity = activities[activity_name]
64100

101+
# Validate student is not already signed up
102+
if email in activity["participants"]:
103+
raise HTTPException(status_code=400, detail="Student already signed up for this activity")
104+
65105
# Add student
66106
activity["participants"].append(email)
67107
return {"message": f"Signed up {email} for {activity_name}"}
108+
109+
110+
@app.delete("/activities/{activity_name}/unregister")
111+
def unregister_from_activity(activity_name: str, email: str):
112+
"""Unregister a student from an activity"""
113+
# Validate activity exists
114+
if activity_name not in activities:
115+
raise HTTPException(status_code=404, detail="Activity not found")
116+
117+
# Get the specific activity
118+
activity = activities[activity_name]
119+
120+
# Validate student is signed up
121+
if email not in activity["participants"]:
122+
raise HTTPException(status_code=400, detail="Student not signed up for this activity")
123+
124+
# Remove student
125+
activity["participants"].remove(email)
126+
return {"message": f"Unregistered {email} from {activity_name}"}

src/static/app.js

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

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

23+
const participantsList = details.participants.length > 0
24+
? `<ul class="participants-list">
25+
${details.participants.map(email => `
26+
<li>
27+
<span class="participant-email">${email}</span>
28+
<button class="delete-btn" data-activity="${name}" data-email="${email}" title="Unregister">🗑️</button>
29+
</li>
30+
`).join('')}
31+
</ul>`
32+
: `<p class="no-participants">No participants yet. Be the first to sign up!</p>`;
33+
2334
activityCard.innerHTML = `
2435
<h4>${name}</h4>
2536
<p>${details.description}</p>
2637
<p><strong>Schedule:</strong> ${details.schedule}</p>
2738
<p><strong>Availability:</strong> ${spotsLeft} spots left</p>
39+
<div class="participants-section">
40+
<p class="participants-header"><strong>Participants:</strong></p>
41+
${participantsList}
42+
</div>
2843
`;
2944

3045
activitiesList.appendChild(activityCard);
@@ -59,6 +74,9 @@ document.addEventListener("DOMContentLoaded", () => {
5974
const result = await response.json();
6075

6176
if (response.ok) {
77+
// Refresh activities to show updated list
78+
await fetchActivities();
79+
6280
messageDiv.textContent = result.message;
6381
messageDiv.className = "success";
6482
signupForm.reset();
@@ -81,6 +99,52 @@ document.addEventListener("DOMContentLoaded", () => {
8199
}
82100
});
83101

102+
// Handle delete button clicks
103+
activitiesList.addEventListener("click", async (event) => {
104+
if (event.target.classList.contains("delete-btn")) {
105+
const activityName = event.target.dataset.activity;
106+
const email = event.target.dataset.email;
107+
108+
if (!confirm(`Are you sure you want to unregister ${email} from ${activityName}?`)) {
109+
return;
110+
}
111+
112+
try {
113+
const response = await fetch(
114+
`/activities/${encodeURIComponent(activityName)}/unregister?email=${encodeURIComponent(email)}`,
115+
{
116+
method: "DELETE",
117+
}
118+
);
119+
120+
const result = await response.json();
121+
122+
if (response.ok) {
123+
// Refresh activities to show updated list
124+
await fetchActivities();
125+
126+
messageDiv.textContent = result.message;
127+
messageDiv.className = "success";
128+
messageDiv.classList.remove("hidden");
129+
130+
// Hide message after 3 seconds
131+
setTimeout(() => {
132+
messageDiv.classList.add("hidden");
133+
}, 3000);
134+
} else {
135+
messageDiv.textContent = result.detail || "Failed to unregister";
136+
messageDiv.className = "error";
137+
messageDiv.classList.remove("hidden");
138+
}
139+
} catch (error) {
140+
messageDiv.textContent = "Failed to unregister. Please try again.";
141+
messageDiv.className = "error";
142+
messageDiv.classList.remove("hidden");
143+
console.error("Error unregistering:", error);
144+
}
145+
}
146+
});
147+
84148
// Initialize app
85149
fetchActivities();
86150
});

src/static/styles.css

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

77+
.participants-section {
78+
margin-top: 15px;
79+
padding-top: 12px;
80+
border-top: 1px solid #e0e0e0;
81+
}
82+
83+
.participants-header {
84+
margin-bottom: 8px;
85+
color: #1a237e;
86+
}
87+
88+
.participants-list {
89+
list-style-type: none;
90+
margin-left: 0;
91+
color: #555;
92+
}
93+
94+
.participants-list li {
95+
margin-bottom: 5px;
96+
padding: 8px;
97+
display: flex;
98+
justify-content: space-between;
99+
align-items: center;
100+
background-color: #f0f0f0;
101+
border-radius: 4px;
102+
}
103+
104+
.participant-email {
105+
flex-grow: 1;
106+
}
107+
108+
.delete-btn {
109+
background-color: transparent;
110+
border: none;
111+
cursor: pointer;
112+
font-size: 18px;
113+
padding: 4px 8px;
114+
margin-left: 10px;
115+
transition: transform 0.2s;
116+
}
117+
118+
.delete-btn:hover {
119+
transform: scale(1.2);
120+
background-color: transparent;
121+
}
122+
123+
.no-participants {
124+
font-style: italic;
125+
color: #999;
126+
margin: 0;
127+
}
128+
77129
.form-group {
78130
margin-bottom: 15px;
79131
}

tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Tests package for the Mergington High School API"""

0 commit comments

Comments
 (0)