-
Notifications
You must be signed in to change notification settings - Fork 0
Improve student activity registration system #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
242ccd8
cf00578
ea6a1ed
722eaa3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| fastapi | ||
| uvicorn | ||
| httpx | ||
| watchfiles | ||
| watchfiles | ||
| pytest |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,16 @@ document.addEventListener("DOMContentLoaded", () => { | |
| const signupForm = document.getElementById("signup-form"); | ||
| const messageDiv = document.getElementById("message"); | ||
|
|
||
| function showMessage(text, type) { | ||
| messageDiv.textContent = text; | ||
| messageDiv.className = type; | ||
| messageDiv.classList.remove("hidden"); | ||
|
|
||
| setTimeout(() => { | ||
| messageDiv.classList.add("hidden"); | ||
| }, 5000); | ||
| } | ||
|
|
||
| // Function to fetch activities from API | ||
| async function fetchActivities() { | ||
| try { | ||
|
|
@@ -12,19 +22,46 @@ document.addEventListener("DOMContentLoaded", () => { | |
|
|
||
| // Clear loading message | ||
| activitiesList.innerHTML = ""; | ||
| activitySelect.innerHTML = '<option value="">-- Select an activity --</option>'; | ||
|
|
||
| // 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 participantsMarkup = details.participants.length | ||
| ? details.participants | ||
| .map( | ||
| (participant) => ` | ||
| <li class="participant-item"> | ||
| <span class="participant-email">${participant}</span> | ||
| <button | ||
| class="participant-delete-button" | ||
| type="button" | ||
| data-activity="${encodeURIComponent(name)}" | ||
| data-email="${encodeURIComponent(participant)}" | ||
| aria-label="Unregister ${participant} from ${name}" | ||
| > | ||
| <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"> | ||
| <path d="M9 3h6l1 2h4v2H4V5h4l1-2zm1 6h2v8h-2V9zm4 0h2v8h-2V9zM7 9h2v8H7V9zm-1 11h12l1-12H5l1 12z" /> | ||
| </svg> | ||
| </button> | ||
| </li> | ||
| ` | ||
| ) | ||
| .join("") | ||
| : '<li class="participant-empty">No students registered yet.</li>'; | ||
|
|
||
| activityCard.innerHTML = ` | ||
| <h4>${name}</h4> | ||
| <p>${details.description}</p> | ||
| <p><strong>Schedule:</strong> ${details.schedule}</p> | ||
| <p><strong>Availability:</strong> ${spotsLeft} spots left</p> | ||
| <div class="participants-section"> | ||
| <p class="participants-title">Participants</p> | ||
| <ul class="participants-list">${participantsMarkup}</ul> | ||
| </div> | ||
| `; | ||
|
Comment on lines
+33
to
65
|
||
|
|
||
| activitiesList.appendChild(activityCard); | ||
|
|
@@ -59,25 +96,47 @@ document.addEventListener("DOMContentLoaded", () => { | |
| const result = await response.json(); | ||
|
|
||
| if (response.ok) { | ||
| messageDiv.textContent = result.message; | ||
| messageDiv.className = "success"; | ||
| signupForm.reset(); | ||
| await fetchActivities(); | ||
| showMessage(result.message, "success"); | ||
| } else { | ||
| messageDiv.textContent = result.detail || "An error occurred"; | ||
| messageDiv.className = "error"; | ||
| showMessage(result.detail || "An error occurred", "error"); | ||
| } | ||
| } catch (error) { | ||
| showMessage("Failed to sign up. Please try again.", "error"); | ||
| console.error("Error signing up:", error); | ||
| } | ||
| }); | ||
|
|
||
| activitiesList.addEventListener("click", async (event) => { | ||
| const deleteButton = event.target.closest(".participant-delete-button"); | ||
|
|
||
| if (!deleteButton) { | ||
| return; | ||
| } | ||
|
|
||
| const activity = decodeURIComponent(deleteButton.dataset.activity); | ||
| const email = decodeURIComponent(deleteButton.dataset.email); | ||
|
|
||
| messageDiv.classList.remove("hidden"); | ||
| try { | ||
| const response = await fetch( | ||
| `/activities/${encodeURIComponent(activity)}/participants?email=${encodeURIComponent(email)}`, | ||
| { | ||
| method: "DELETE", | ||
| } | ||
| ); | ||
|
|
||
| // Hide message after 5 seconds | ||
| setTimeout(() => { | ||
| messageDiv.classList.add("hidden"); | ||
| }, 5000); | ||
| const result = await response.json(); | ||
|
|
||
| if (response.ok) { | ||
| await fetchActivities(); | ||
| showMessage(result.message, "success"); | ||
| } else { | ||
| showMessage(result.detail || "Unable to unregister participant.", "error"); | ||
| } | ||
| } catch (error) { | ||
| messageDiv.textContent = "Failed to sign up. Please try again."; | ||
| messageDiv.className = "error"; | ||
| messageDiv.classList.remove("hidden"); | ||
| console.error("Error signing up:", error); | ||
| showMessage("Failed to unregister participant. Please try again.", "error"); | ||
| console.error("Error unregistering participant:", error); | ||
| } | ||
| }); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
showMessage()overwritesmessageDiv.classNameand starts a newsetTimeouton every call without clearing any prior timeout. This can cause the message to be hidden unexpectedly if multiple actions happen within 5 seconds, and it also makes it hard to preserve any base styling classes on the message element. Consider keeping a single timeout handle (clear it before setting a new one) and setting classes in a way that preserves any baseline class (e.g., add/removesuccess/errorrather than replacing the entire class list).