diff --git a/web/src/components/students/StudentsFormModal.tsx b/web/src/components/students/StudentsFormModal.tsx index 99ad60b..33e5832 100644 --- a/web/src/components/students/StudentsFormModal.tsx +++ b/web/src/components/students/StudentsFormModal.tsx @@ -3,6 +3,7 @@ import { FormComponentProps } from "antd/lib/form"; import FormItem from "antd/lib/form/FormItem"; import React from "react"; import { FormValidationTrigger } from "../../helpers/types"; +import { IEducation } from "../../models/Education"; import { ISchool } from "../../models/School"; import { IStudent } from "../../models/Student"; @@ -13,6 +14,8 @@ interface IStudentsFormModalProps { studentToEdit: IStudent | undefined; schools: ISchool[]; isLoadingSchools: boolean; + educations: IEducation[]; + isLoadingEducations: boolean; onCloseRequest: () => void; submitStudent(student: IStudent): Promise; } @@ -52,10 +55,19 @@ class StudentsFormModal extends React.Component e.id === studentEducationId) + ? studentEducationId + : undefined; + } + this.props.form.setFieldsValue({ // TODO: fill these keys dynamically firstName: this.props.studentToEdit.firstName, lastName: this.props.studentToEdit.lastName, schoolId, + educationId, }); } } @@ -109,6 +121,19 @@ class StudentsFormModal extends React.Component, )} + + {getFieldDecorator("educationId", { + validateTrigger: this.state.formValidateTrigger, + })( + , + )} + ); @@ -120,6 +145,12 @@ class StudentsFormModal extends React.Component{education.name} + ); + } + private doClose(): void { this.props.onCloseRequest(); } @@ -130,7 +161,7 @@ class StudentsFormModal extends React.Component = ["firstName", "lastName", "schoolId"]; + const fields: Array = ["firstName", "lastName", "schoolId", "educationId"]; this.props.form.validateFieldsAndScroll(fields, (errors, values) => { if (!errors) { this.setState({ diff --git a/web/src/components/students/StudentsPage.tsx b/web/src/components/students/StudentsPage.tsx index dbbdf19..404ef0e 100644 --- a/web/src/components/students/StudentsPage.tsx +++ b/web/src/components/students/StudentsPage.tsx @@ -1,8 +1,10 @@ import { Col, notification, Row } from "antd"; import React from "react"; +import { IEducation } from "../../models/Education"; import { ISchool } from "../../models/School"; import { IStudent } from "../../models/Student"; import { RoutePageComponentProps, routes } from "../../routes"; +import { EducationsService } from "../../services/EducationsService"; import { SchoolsService } from "../../services/SchoolsService"; import { StudentsService } from "../../services/StudentsService"; import AuthenticatedLayout from "../layouts/AuthenticatedLayout"; @@ -19,12 +21,15 @@ interface IStudentsPageState { studentToEdit: IStudent | undefined; schools: ISchool[]; isFetchingSchools: boolean; + educations: IEducation[]; + isFetchingEducations: boolean; } export default class StudentsPage extends React.Component { private readonly studentsService = new StudentsService(); private readonly schoolsService = new SchoolsService(); + private readonly educationsService = new EducationsService(); constructor(props: StudentsPageProps) { super(props); @@ -37,6 +42,8 @@ export default class StudentsPage extends React.Component { + this.setState({ + isFetchingEducations: false, + educations, + }); + }); } public render(): React.ReactNode { @@ -77,6 +90,8 @@ export default class StudentsPage extends React.Component @@ -90,6 +105,8 @@ export default class StudentsPage extends React.Component ); diff --git a/web/src/components/students/StudentsTable.tsx b/web/src/components/students/StudentsTable.tsx index d32c6ca..2f3c1b2 100644 --- a/web/src/components/students/StudentsTable.tsx +++ b/web/src/components/students/StudentsTable.tsx @@ -3,6 +3,7 @@ import { ColumnFilterItem, ColumnProps } from "antd/lib/table"; import React from "react"; import { emptyFilterOptionValue, exactMatchOrDefaultOptionFilter, hasElementWithId } from "../../helpers/filters"; import { stringSorter } from "../../helpers/sorters"; +import { IEducation } from "../../models/Education"; import { ISchool } from "../../models/School"; import { IStudent } from "../../models/Student"; import styles from "../DataTable.module.scss"; @@ -12,6 +13,8 @@ interface IStudentsTableProps { students: IStudent[]; schools: ISchool[]; isLoadingSchools: boolean; + educations: IEducation[]; + isLoadingEducations: boolean; deleteStudent: (student: IStudent) => Promise; onAddStudentRequest: () => void; onEditStudentRequest: (student: IStudent) => void; @@ -57,6 +60,18 @@ class StudentsTable extends React.Component { return this.getSchoolNameForStudent(student); } + private renderEducationName(student: IStudent): React.ReactNode { + if (this.props.isLoadingEducations) { + return ; + } + + if (student.educationId === undefined) { + return ""; + } + + return this.getEducationNameForStudent(student); + } + private renderActions(student: IStudent): React.ReactNode { const deleteFunc = () => this.props.deleteStudent(student); const editFunc = () => this.props.onEditStudentRequest(student); @@ -115,6 +130,15 @@ class StudentsTable extends React.Component { return school.name; } + private getEducationNameForStudent(student: IStudent): string { + const education = this.props.educations.find((e) => student.educationId !== undefined && student.educationId === e.id); + if (education === undefined) { + return ""; + } + + return education.name; + } + private getTableColumns(): Array> { return [ { @@ -136,6 +160,19 @@ class StudentsTable extends React.Component { : undefined); }, }, + { + title: "Opleiding", + key: "education", + render: (record: IStudent) => this.renderEducationName(record), + sorter: (a, b) => stringSorter(this.getEducationNameForStudent(a), this.getEducationNameForStudent(b)), + filters: this.getEducationFilters(), + onFilter: (value, record: IStudent) => { + return exactMatchOrDefaultOptionFilter(value, + hasElementWithId(this.props.educations, record.educationId) + ? record.educationId + : undefined); + }, + }, { title: "Acties", key: "actions", @@ -159,6 +196,20 @@ class StudentsTable extends React.Component { }); return filters; } + + private getEducationFilters(): ColumnFilterItem[] { + const filters: ColumnFilterItem[] = this.props.educations.map((education) => { + return { + text: education.name, + value: education.id!, + }; + }); + filters.unshift({ + text: "Zonder opleiding", + value: emptyFilterOptionValue, + }); + return filters; + } } export default StudentsTable; diff --git a/web/src/models/Student.ts b/web/src/models/Student.ts index 5f7cf13..936f7fb 100644 --- a/web/src/models/Student.ts +++ b/web/src/models/Student.ts @@ -4,4 +4,5 @@ export interface IStudent extends IFirebaseTable { firstName: string; lastName?: string; schoolId?: string; + educationId?: string; }