-
Notifications
You must be signed in to change notification settings - Fork 10
Add delete button to allow coordinators to drop sections #443
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
base: master
Are you sure you want to change the base?
Changes from 11 commits
d223b4f
86b0537
533c942
1cecffb
e2e56b3
e53cc8b
92fd246
268962f
4da7c30
6997dc7
3bc3ff9
410e740
c8b1998
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,20 +1,37 @@ | ||
| import React, { useState } from "react"; | ||
| import { useSectionStudents } from "../../utils/queries/sections"; | ||
| import { Mentor, Spacetime, Student } from "../../utils/types"; | ||
| import { Navigate, Route, Routes } from "react-router-dom"; | ||
| import { useSectionStudents, useDropSectionMutation } from "../../utils/queries/sections"; | ||
| import { Mentor, Spacetime, Student, Course } from "../../utils/types"; | ||
| import LoadingSpinner from "../LoadingSpinner"; | ||
| import { CoordinatorAddStudentModal } from "./CoordinatorAddStudentModal"; | ||
| import MetaEditModal from "./MetaEditModal"; | ||
| import { InfoCard, SectionSpacetime } from "./Section"; | ||
| import SpacetimeEditModal from "./SpacetimeEditModal"; | ||
| import StudentDropper from "./StudentDropper"; | ||
| import SpacetimeDeleteModal from "./SpacetimeDeleteModal"; | ||
| import { fetchWithMethod, HTTP_METHODS } from "../../utils/api"; | ||
|
|
||
| import { useProfiles, useUserInfo } from "../../utils/queries/base"; | ||
| import { useCourses } from "../../utils/queries/courses"; | ||
|
|
||
| import Modal from "../Modal"; | ||
|
|
||
| import { useMutation, UseMutationResult, useQuery, useQueryClient, UseQueryResult } from "@tanstack/react-query"; | ||
| import { | ||
| handleError, | ||
| handlePermissionsError, | ||
| handleRetry, | ||
| PermissionError, | ||
| ServerError | ||
| } from "./../../utils/queries/helpers"; | ||
|
|
||
| // Images | ||
| import XIcon from "../../../static/frontend/img/x.svg"; | ||
| import PencilIcon from "../../../static/frontend/img/pencil.svg"; | ||
|
|
||
| // Styles | ||
| import "../../css/coordinator-add-student.scss"; | ||
| import { NavLink } from "react-router-dom"; | ||
|
|
||
| enum ModalStates { | ||
| NONE = "NONE", | ||
|
|
@@ -44,6 +61,8 @@ export default function MentorSectionInfo({ | |
| }: MentorSectionInfoProps) { | ||
| const { data: students, isSuccess: studentsLoaded, isError: studentsLoadError } = useSectionStudents(sectionId); | ||
|
|
||
| const { data: courses, isSuccess: coursesLoaded, isError: coursesLoadError } = useCourses(); | ||
|
|
||
| const [showModal, setShowModal] = useState(ModalStates.NONE); | ||
| const [focusedSpacetimeID, setFocusedSpacetimeID] = useState<number>(-1); | ||
| const [isAddingStudent, setIsAddingStudent] = useState<boolean>(false); | ||
|
|
@@ -232,6 +251,58 @@ export default function MentorSectionInfo({ | |
| </InfoCard> | ||
| </div> | ||
| </div> | ||
| <DropSection sectionId={sectionId} /> | ||
| </React.Fragment> | ||
| ); | ||
| } | ||
|
|
||
| interface DropSectionProps { | ||
| sectionId: number; | ||
| } | ||
|
|
||
| enum DropSectionStage { | ||
| INITIAL = "INITIAL", | ||
| CONFIRM = "CONFIRM", | ||
| DROPPED = "DROPPED" | ||
| } | ||
|
|
||
| function DropSection({ sectionId }: DropSectionProps) { | ||
| const sectionDropMutation = useDropSectionMutation(sectionId); | ||
| const [stage, setStage] = useState<DropSectionStage>(DropSectionStage.INITIAL); | ||
|
|
||
| const performDrop = () => { | ||
| sectionDropMutation.mutate(undefined, { | ||
| onSuccess: () => { | ||
| // console.log(sectionId) | ||
| setStage(DropSectionStage.DROPPED); | ||
| } | ||
| }); | ||
| }; | ||
|
Comment on lines
+273
to
+279
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should be a failure case handled here (ex. if there are students in the section). The query hook will also need to be modified to raise this error as well. |
||
|
|
||
| switch (stage) { | ||
| case DropSectionStage.INITIAL: | ||
| return ( | ||
| <InfoCard title="Drop Section" showTitle={false}> | ||
| <h5>Delete Section</h5> | ||
| <button className="danger-btn" onClick={() => setStage(DropSectionStage.CONFIRM)}> | ||
| <XIcon className="icon" /> | ||
| Delete | ||
| </button> | ||
| </InfoCard> | ||
| ); | ||
| case DropSectionStage.CONFIRM: | ||
| return ( | ||
| <Modal closeModal={() => setStage(DropSectionStage.INITIAL)}> | ||
| <div className="drop-confirmation"> | ||
| <h5>Are you sure you want to delete?</h5> | ||
|
|
||
| <button className="danger-btn" onClick={performDrop}> | ||
| Confirm | ||
| </button> | ||
| </div> | ||
| </Modal> | ||
| ); | ||
| case DropSectionStage.DROPPED: | ||
| return <Navigate to="/" />; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -308,3 +308,45 @@ $modal-effective-height: calc($modal-height - $modal-padding-y); | |
| .coordinator-email-response-item-right > * { | ||
| flex: 1; | ||
| } | ||
|
|
||
| .coordinator-delete-position { | ||
| display: flex; | ||
| justify-content: flex-end; | ||
| } | ||
|
|
||
| .coordinator-delete-button { | ||
| width: 250px; | ||
| height: 50px; | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
|
|
||
| // background-color: #fc4a14; | ||
| background-color: #ff7272; | ||
| cursor: pointer; | ||
| border-radius: 10px; | ||
| border: none; | ||
| outline: none; | ||
| transition: background-color 0.4s; | ||
| //box-shadow: 0px 8px 24px rgba(149, 157, 165, 0.5); | ||
| box-shadow: 0px 4px 4px rgba(198, 198, 198, 0.25); | ||
| } | ||
|
|
||
| .coordinator-delete-link { | ||
| display: flex; | ||
| text-decoration: none; | ||
| color: white; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| // background: none; | ||
|
|
||
| // border: none; | ||
| // padding: 0; | ||
| // font: inherit; | ||
| // cursor: pointer; | ||
| // outline: inherit; | ||
|
|
||
| // :hover { | ||
| // background-color: #f15120; | ||
| // } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If these styles are unused, they should be deleted, rather than commented out. |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| import pytest | ||
| from django.urls import reverse | ||
| from scheduler.factories import ( | ||
| CoordinatorFactory, | ||
| CourseFactory, | ||
| MentorFactory, | ||
| SectionFactory, | ||
| StudentFactory, | ||
| UserFactory, | ||
| ) | ||
| from scheduler.models import Section | ||
|
|
||
|
|
||
| @pytest.fixture(name="setup") | ||
| def setup_test(): | ||
| """ | ||
| Create a course, coordinator, mentor, and a student for testing. | ||
| """ | ||
| # Setup course | ||
| course = CourseFactory.create() | ||
| # Setup sections | ||
| section_one = create_section(course) | ||
| section_two = create_section(course) | ||
| # Setup students | ||
| create_students(course, section_one, 3) | ||
| create_students(course, section_two, 3) | ||
| # Setup coordinator for course | ||
| coordinator_user = UserFactory.create() | ||
| # Create coordinator for course | ||
| CoordinatorFactory.create(user=coordinator_user, course=course) | ||
|
|
||
| return ( | ||
| section_one, | ||
| coordinator_user, | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.django_db | ||
| def test_section_delete(client, setup): | ||
|
KartavyaSharma marked this conversation as resolved.
|
||
| """ | ||
| Test that a section can be deleted. | ||
| """ | ||
| ( | ||
| section_one, | ||
| coordinator_user, | ||
| ) = setup | ||
| # Login as coordinator | ||
| client.force_login(coordinator_user) | ||
| # Delete section | ||
| response = client.delete(reverse("section-detail", kwargs={"pk": section_one.id})) | ||
| # Check that section was deleted | ||
| assert response.status_code == 204 | ||
| assert Section.objects.count() == 1 | ||
|
|
||
|
|
||
| def create_students(course, section, quantity): | ||
| """ | ||
| Creates a given number of students for a given section. | ||
| """ | ||
| student_users = UserFactory.create_batch(quantity) | ||
| students = [] | ||
| for student_user in student_users: | ||
| student = StudentFactory.create( | ||
| user=student_user, course=course, section=section | ||
| ) | ||
| students.append(student) | ||
| return students | ||
|
|
||
|
|
||
| def create_section(course): | ||
| """ | ||
| Creates a section for a given course. | ||
| """ | ||
| mentor_user = UserFactory.create() | ||
| mentor = MentorFactory.create(user=mentor_user, course=course) | ||
| section = SectionFactory.create(mentor=mentor) | ||
| return section | ||
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.
There are a lot of ESLint warnings here about unused variables; you should delete the unused variables here.