From 213a16743d5884b8e9eac6bdc7dfb8a02aef8ad7 Mon Sep 17 00:00:00 2001 From: adam-skowronek Date: Fri, 6 Jan 2023 19:24:02 +0100 Subject: [PATCH] Add more details in group view, add editing group students --- backend/app/coordinator/routes/groups.py | 10 +- backend/app/coordinator/schemas/__init__.py | 2 +- backend/app/coordinator/schemas/groups.py | 4 +- backend/app/coordinator/schemas/students.py | 6 + frontend/src/api/groups.ts | 5 + frontend/src/api/students.ts | 2 +- frontend/src/views/coordinator/AddGroup.tsx | 2 +- frontend/src/views/coordinator/Group.tsx | 144 +++++++++++++++++++- frontend/src/views/coordinator/Students.tsx | 6 +- 9 files changed, 166 insertions(+), 15 deletions(-) diff --git a/backend/app/coordinator/routes/groups.py b/backend/app/coordinator/routes/groups.py index effb160..0aa640d 100644 --- a/backend/app/coordinator/routes/groups.py +++ b/backend/app/coordinator/routes/groups.py @@ -5,7 +5,7 @@ from flask_sqlalchemy import get_debug_queries from ...students.models import Group, Student, YearGroup, ProjectGradeSheet from ...project_supervisor.models import ProjectSupervisor, YearGroupProjectSupervisors from ..schemas import GroupSchema, GroupEditSchema, GroupsPaginationSchema, \ - GroupCreateSchema, MessageSchema, GroupQuerySchema + GroupCreateSchema, MessageSchema, GroupQuerySchema, DetailGroupSchema from ...dependencies import db from ...base.utils import paginate_models from ..utils import load_weight_for_project_grade_sheet, calculate_points_for_one_term @@ -101,7 +101,7 @@ def create_group(year_group_id: int, data: dict) -> dict: @bp.get("//detail/") -@bp.output(GroupSchema) +@bp.output(DetailGroupSchema) def detail_group(id: int) -> Group: group = Group.query.filter_by(id=id).first() if group is None: @@ -135,6 +135,10 @@ def edit_group(id: int, data: dict) -> dict: if group is None: abort(400, f"Group with id {id} doesn't exist!") - group_query.update(data) + students = db.session.query(Student).filter(Student.index.in_(data['students'])).all() + group.students = students + group.name = data['name'] + group.project_supervisor_id = data['project_supervisor_id'] + db.session.commit() return {"message": "Group was updated!"} diff --git a/backend/app/coordinator/schemas/__init__.py b/backend/app/coordinator/schemas/__init__.py index 2318019..708faba 100644 --- a/backend/app/coordinator/schemas/__init__.py +++ b/backend/app/coordinator/schemas/__init__.py @@ -7,5 +7,5 @@ from .project_supervisor import ProjectSupervisorQuerySchema, ProjectSupervisors ProjectSupervisorCreateSchema, ProjectSupervisorEditSchema, ProjectSupervisorYearGroupSchema from .students import ProjectSupervisorSchema, GroupSchema, StudentSchema, StudentsPaginationSchema, \ StudentListFileDownloaderSchema, StudentCreateSchema, StudentEditSchema, MessageSchema, FileSchema, \ - StudentQuerySchema, YearGroupInfoQuery + StudentQuerySchema, YearGroupInfoQuery, DetailGroupSchema from .year_group import YearGroupSchema, YearGroupPaginationSchema, YearGroupQuerySchema diff --git a/backend/app/coordinator/schemas/groups.py b/backend/app/coordinator/schemas/groups.py index cabc983..41c30ff 100644 --- a/backend/app/coordinator/schemas/groups.py +++ b/backend/app/coordinator/schemas/groups.py @@ -23,8 +23,8 @@ class GroupCreateSchema(Schema): class GroupEditSchema(Schema): name = fields.Str(validate=validate.Length(min=1, max=255)) - project_supervisor_id = fields.Integer(validate=validate_index) - students = fields.List(fields.Nested(StudentSchema), validate=validate.Length(min=1, max=255)) + project_supervisor_id = fields.Integer() + students = fields.List(fields.Integer(validate=validate_index)) class GroupIdSchema(Schema): diff --git a/backend/app/coordinator/schemas/students.py b/backend/app/coordinator/schemas/students.py index 0a72204..3689b69 100644 --- a/backend/app/coordinator/schemas/students.py +++ b/backend/app/coordinator/schemas/students.py @@ -68,3 +68,9 @@ class StudentQuerySchema(ma.Schema): class YearGroupInfoQuery(Schema): id = fields.Integer(required=True) + +class DetailGroupSchema(ma.SQLAlchemyAutoSchema): + project_supervisor = fields.Nested(ProjectSupervisorSchema) + students = fields.List(fields.Nested(StudentSchema), validate=validate.Length(min=1, max=255)) + class Meta: + model = Group diff --git a/frontend/src/api/groups.ts b/frontend/src/api/groups.ts index 7f49486..4942485 100644 --- a/frontend/src/api/groups.ts +++ b/frontend/src/api/groups.ts @@ -1,5 +1,6 @@ import axiosInstance from './axiosInstance' import { Leader } from './leaders' +import { Student } from './students' export interface CreateGroup { name: string @@ -16,6 +17,7 @@ export interface Group { project_supervisor: Leader prz_kod: string tzaj_kod: string + students: Student[] } export const getGroups = ( @@ -41,3 +43,6 @@ export const deleteGroup = (id: number) => export const getGroup = (id: number) => axiosInstance.get(`coordinator/groups/${id}/detail/`) + +export const editGroup = (id: number, payload: CreateGroup) => + axiosInstance.put(`coordinator/groups/${id}/`, payload) diff --git a/frontend/src/api/students.ts b/frontend/src/api/students.ts index e181a09..df89c94 100644 --- a/frontend/src/api/students.ts +++ b/frontend/src/api/students.ts @@ -13,7 +13,7 @@ export interface Student { index: number pesel: string mode?: boolean - group?: any + groups?: any[] } export const getStudents = ( diff --git a/frontend/src/views/coordinator/AddGroup.tsx b/frontend/src/views/coordinator/AddGroup.tsx index a616fde..53a7826 100644 --- a/frontend/src/views/coordinator/AddGroup.tsx +++ b/frontend/src/views/coordinator/AddGroup.tsx @@ -33,7 +33,7 @@ const AddGroup = () => { onSuccess: (data) => { setStudentOptions( data?.data.students - // .filter((st) => st.group === null) + .filter(({ groups }) => !groups?.length) .map(({ first_name, last_name, index }) => { return { value: index, diff --git a/frontend/src/views/coordinator/Group.tsx b/frontend/src/views/coordinator/Group.tsx index 2c66d9d..a8836f0 100644 --- a/frontend/src/views/coordinator/Group.tsx +++ b/frontend/src/views/coordinator/Group.tsx @@ -1,14 +1,69 @@ -import { useQuery } from 'react-query' +import { useState } from 'react' +import { useMutation, useQuery } from 'react-query' import { Link, useLocation, useParams } from 'react-router-dom' -import { getGroup } from '../../api/groups' +import ReactSelect from 'react-select' +import useLocalStorageState from 'use-local-storage-state' +import { CreateGroup, editGroup, getGroup } from '../../api/groups' +import { getStudents } from '../../api/students' +import { ReactComponent as IconRemove } from '../../assets/svg/icon-remove.svg' + +type SelectValue = { + value: string | number + label: string +} const Group = () => { const { id } = useParams<{ id: string }>() const location = useLocation() - const { data: groups } = useQuery(['getGroup'], () => getGroup(Number(id))) - const { name, project_supervisor } = groups?.data || {} + const { + data: groups, + refetch, + isLoading: isGroupLoading, + } = useQuery(['getGroup', id], () => getGroup(Number(id))) + const { + name, + project_supervisor, + students, + points_for_first_term, + points_for_second_term, + } = groups?.data || {} + const [yearGroupId] = useLocalStorageState('yearGroupId') + const [studentOptions, setStudentOptions] = useState([]) + const { isLoading: areStudentsLoading } = useQuery( + 'students', + () => getStudents({ year_group_id: Number(yearGroupId), per_page: 1000 }), + { + onSuccess: (data) => { + setStudentOptions( + data?.data.students + .filter(({ groups }) => !groups?.length) + .map(({ first_name, last_name, index }) => { + return { + value: index, + label: `${first_name} ${last_name} (${index})`, + } + }), + ) + }, + }, + ) + const [newStudent, setNewStudent] = useState(0) + const { mutate: mutateEditGroup } = useMutation( + ['editGroup'], + (data: { id: number; payload: CreateGroup }) => + editGroup(data.id, data.payload), + { + onSuccess: () => { + refetch() + }, + }, + ) + + if (isGroupLoading || areStudentsLoading) { + return
Ładowanie
+ } return (

{name}

@@ -16,6 +71,9 @@ const Group = () => { Opiekun: {project_supervisor?.first_name}{' '} {project_supervisor?.last_name} +

Punkty % za semestr 1: {points_for_first_term}

+

Punkty % za semestr 2: {points_for_second_term}

+ { > + +
+ + + + + + + + + + + {students?.map(({ first_name, last_name, index }) => ( + + + + + + + ))} + +
ImięNazwiskoIndeks
{first_name}{last_name}{index} + +
+
+
+ ({ + ...styles, + width: '270px', + padding: '0.3rem', + borderRadius: '0.5rem', + }), + }} + onChange={(val) => { + if (val?.value) setNewStudent(Number(val.value)) + }} + /> + +
) } diff --git a/frontend/src/views/coordinator/Students.tsx b/frontend/src/views/coordinator/Students.tsx index 1a9944e..4b17d9a 100644 --- a/frontend/src/views/coordinator/Students.tsx +++ b/frontend/src/views/coordinator/Students.tsx @@ -177,13 +177,13 @@ const Students = () => { {students?.data?.students - ?.filter((st) => st.group === null || !showGroupless) - .map(({ first_name, last_name, index, group, mode }) => ( + ?.filter((st) => !st.groups?.length || !showGroupless) + .map(({ first_name, last_name, index, groups, mode }) => ( {first_name} {last_name} {index} - {group === null ? 'Nie' : 'Tak'} + {groups?.length ? 'Tak' : 'Nie'}