From 47f0e5eda857952af5b0f1c9452863c12b345ec0 Mon Sep 17 00:00:00 2001 From: matisse Date: Fri, 19 Apr 2024 15:33:29 +0200 Subject: [PATCH 1/4] initial draft --- frontend/src/types/course.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/types/course.ts b/frontend/src/types/course.ts index 6b365ff9..a21fd7dc 100644 --- a/frontend/src/types/course.ts +++ b/frontend/src/types/course.ts @@ -1,4 +1,6 @@ export interface Course { name: string; + teacher: string; + projects: [string]; course_id: string; } From 9ffa93aad2f10c98c07739ad0c4e58a709eb455a Mon Sep 17 00:00:00 2001 From: matisse Date: Fri, 19 Apr 2024 15:33:59 +0200 Subject: [PATCH 2/4] commit --- frontend/src/pages/course/CourseDetails.tsx | 53 +++++++++++++++++++++ frontend/src/types/project.ts | 12 +++++ 2 files changed, 65 insertions(+) create mode 100644 frontend/src/pages/course/CourseDetails.tsx create mode 100644 frontend/src/types/project.ts diff --git a/frontend/src/pages/course/CourseDetails.tsx b/frontend/src/pages/course/CourseDetails.tsx new file mode 100644 index 00000000..bfc29c99 --- /dev/null +++ b/frontend/src/pages/course/CourseDetails.tsx @@ -0,0 +1,53 @@ +import { useParams } from "react-router-dom"; +import { useEffect, useState } from "react"; + +import { Course } from "../../types/course"; +import { Project } from "../../types/project"; +import { Box, Typography } from "@mui/material"; + +const API_URL = import.meta.env.VITE_API_HOST; + +export default function CourseDetails() { + const { courseId } = useParams<{ courseId: string }>(); + const [courseData, setCourseData] = useState(null); + const [projects, setProjects] = useState([]); + + useEffect(() => { + fetch(`${API_URL}/courses/${courseId}`, { + headers: { Authorization: "student" }, + credentials: "include" + }).then((response) => { + if (response.ok) { + response.json().then((json) => { + setCourseData(json["data"]); + }); + } + }); + + courseData?.projects.forEach((projectId) => { + fetch(`${API_URL}/courses/${projectId}`, { + headers: { Authorization: "student" }, + credentials: "include" + }).then((response) => { + if (response.ok) { + response.json().then((json) => { + setProjects([...projects, json["data"]]); + }); + } + }); + }); + }, [courseId]); + + return ( + <> + + + {courseData?.name} + + + {projects[0].title} + + + + ) +} \ No newline at end of file diff --git a/frontend/src/types/project.ts b/frontend/src/types/project.ts new file mode 100644 index 00000000..0aa3975f --- /dev/null +++ b/frontend/src/types/project.ts @@ -0,0 +1,12 @@ +export interface Project { + title: string; + description: string; + assignment_file: string; + deadline: string; + course_id: string; + visible_for_students: boolean; + archived: boolean; + test_path: string; + script_name: string; + regex_expressions: [string]; +} \ No newline at end of file From 7c9755337fdf77b6171da0b18dd74e58ec7f165e Mon Sep 17 00:00:00 2001 From: matisse Date: Thu, 9 May 2024 14:25:53 +0200 Subject: [PATCH 3/4] course details for students added --- frontend/public/locales/en/translation.json | 2 +- frontend/src/App.tsx | 4 +- .../Courses/CourseDetailTeacher.tsx | 8 +-- frontend/src/pages/course/CourseDetails.tsx | 53 ------------------- 4 files changed, 7 insertions(+), 60 deletions(-) delete mode 100644 frontend/src/pages/course/CourseDetails.tsx diff --git a/frontend/public/locales/en/translation.json b/frontend/public/locales/en/translation.json index 86ed53b3..da103965 100644 --- a/frontend/public/locales/en/translation.json +++ b/frontend/public/locales/en/translation.json @@ -17,7 +17,7 @@ "welcomeDescription": "Welcome to PeristerĂ³nas, the online submission platform of UGent", "login": "Login" }, - "courseDetailTeacher": { + "courseDetail": { "title": "Course Details", "deleteCourse": "Delete Course", "unauthorizedDelete": "You are unauthorized to delete this course", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index a1402c22..1f2370e8 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -6,7 +6,7 @@ import { } from "react-router-dom"; import Layout from "./components/Header/Layout"; import { AllCoursesTeacher } from "./components/Courses/AllCoursesTeacher"; -import { CourseDetailTeacher } from "./components/Courses/CourseDetailTeacher"; +import { CourseDetail } from "./components/Courses/CourseDetail.tsx"; import { dataLoaderCourseDetail, dataLoaderCourses, @@ -41,7 +41,7 @@ const router = createBrowserRouter( } loader={dataLoaderCourses}/> - } loader={dataLoaderCourseDetail} /> + } loader={dataLoaderCourseDetail} /> ([]); const [studentObjects, setStudentObjects] = useState([]); const { t } = useTranslation("translation", { - keyPrefix: "courseDetailTeacher", + keyPrefix: "courseDetail", }); const { i18n } = useTranslation(); const lang = i18n.language; @@ -303,13 +303,13 @@ export function CourseDetailTeacher(): JSX.Element { * @param projects - The array of projects. * @returns Either a place holder for no projects or a grid of cards describing the projects. */ -function EmptyOrNotProjects({ +export function EmptyOrNotProjects({ projects, }: { projects: ProjectDetail[]; }): JSX.Element { const { t } = useTranslation("translation", { - keyPrefix: "courseDetailTeacher", + keyPrefix: "courseDetail", }); if (projects === undefined || projects.length === 0) { return {t("noProjects")}; @@ -474,7 +474,7 @@ function JoinCodeMenu({ anchorEl: HTMLElement | null; }) { const { t } = useTranslation("translation", { - keyPrefix: "courseDetailTeacher", + keyPrefix: "courseDetail", }); const [codes, setCodes] = useState([]); diff --git a/frontend/src/pages/course/CourseDetails.tsx b/frontend/src/pages/course/CourseDetails.tsx deleted file mode 100644 index bfc29c99..00000000 --- a/frontend/src/pages/course/CourseDetails.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useParams } from "react-router-dom"; -import { useEffect, useState } from "react"; - -import { Course } from "../../types/course"; -import { Project } from "../../types/project"; -import { Box, Typography } from "@mui/material"; - -const API_URL = import.meta.env.VITE_API_HOST; - -export default function CourseDetails() { - const { courseId } = useParams<{ courseId: string }>(); - const [courseData, setCourseData] = useState(null); - const [projects, setProjects] = useState([]); - - useEffect(() => { - fetch(`${API_URL}/courses/${courseId}`, { - headers: { Authorization: "student" }, - credentials: "include" - }).then((response) => { - if (response.ok) { - response.json().then((json) => { - setCourseData(json["data"]); - }); - } - }); - - courseData?.projects.forEach((projectId) => { - fetch(`${API_URL}/courses/${projectId}`, { - headers: { Authorization: "student" }, - credentials: "include" - }).then((response) => { - if (response.ok) { - response.json().then((json) => { - setProjects([...projects, json["data"]]); - }); - } - }); - }); - }, [courseId]); - - return ( - <> - - - {courseData?.name} - - - {projects[0].title} - - - - ) -} \ No newline at end of file From e8edbfcd2e186ee7392e078eb70bff2fdb353f5b Mon Sep 17 00:00:00 2001 From: matisse Date: Thu, 9 May 2024 14:27:11 +0200 Subject: [PATCH 4/4] commit --- .../src/components/Courses/CourseDetail.tsx | 27 ++++++++++ .../Courses/CourseDetailStudent.tsx | 49 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 frontend/src/components/Courses/CourseDetail.tsx create mode 100644 frontend/src/components/Courses/CourseDetailStudent.tsx diff --git a/frontend/src/components/Courses/CourseDetail.tsx b/frontend/src/components/Courses/CourseDetail.tsx new file mode 100644 index 00000000..77475f69 --- /dev/null +++ b/frontend/src/components/Courses/CourseDetail.tsx @@ -0,0 +1,27 @@ +import { useEffect, useState } from "react"; +import { fetchMe } from "../../utils/fetches/FetchMe"; +import { CourseDetailStudent } from "./CourseDetailStudent"; +import { CourseDetailTeacher } from "./CourseDetailTeacher"; +import { Me } from "../../types/me"; + +/** + * + * @returns The right course detail component according to the role of the user. + */ +export function CourseDetail(): JSX.Element { + const [me, setMe] = useState(null); + + useEffect(() => { + fetchMe().then((data) => { + setMe(data); + }); + }, []); + + if (me?.role === "STUDENT") { + return ; + } + if (me === undefined) { + return <>; + } + return ; +} \ No newline at end of file diff --git a/frontend/src/components/Courses/CourseDetailStudent.tsx b/frontend/src/components/Courses/CourseDetailStudent.tsx new file mode 100644 index 00000000..6bdc9920 --- /dev/null +++ b/frontend/src/components/Courses/CourseDetailStudent.tsx @@ -0,0 +1,49 @@ +import { + Grid, + Paper, + Typography +} from "@mui/material"; +import { useLoaderData } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { Course } from "../../types/course"; +import { ProjectDetail } from "./CourseUtils"; +import { Title } from "../Header/Title"; +import { EmptyOrNotProjects } from "./CourseDetailTeacher"; + +/** + * + * @returns The component representing the course details page for a student. + */ +export function CourseDetailStudent(): JSX.Element { + const courseDetail = useLoaderData() as { + course: Course; + projects: ProjectDetail[]; + }; + + const { course, projects } = courseDetail; + const { t } = useTranslation("translation", { + keyPrefix: "courseDetail", + }); + + return ( + <> + + + + + {t("projects")}: + + + + + + ); +}