diff --git a/src/pages/course/index.tsx b/src/pages/course/index.tsx
index c82ac25..b862c4a 100644
--- a/src/pages/course/index.tsx
+++ b/src/pages/course/index.tsx
@@ -2,28 +2,13 @@ import { useState, useEffect } from "react";
import RootPage from "../root";
import Container from "@mui/material/Container";
import Typography from "@mui/material/Typography";
-import Cookies from "js-cookie";
import "./course.css"; // Import CSS file for additional styling
-import {
- IsStudent,
- IsAdmin,
- backend_get,
- deleteAuthCookies,
- useAxiosRequest,
- backend_post
-} from "../../utils";
+import { IsStudent, IsAdmin, useAxiosRequest, backend_post } from "../../utils";
import { useNavigate, useParams } from "react-router-dom";
-import { JwtPayload, jwtDecode } from "jwt-decode";
-import {
- CookieJWT,
- Empty,
- FullCourse,
- FullCourseUser
-} from "../../types/common";
+import { Empty, FullCourse, FullCourseUser } from "../../types/common";
import { Avatar, Button, IconButton, capitalize, styled } from "@mui/material";
-import MoreVertIcon from "@mui/icons-material/MoreVert";
-import { render } from "@testing-library/react";
+import CancelIcon from "@mui/icons-material/Cancel";
const Course = () => {
const { response, error, loading, sendRequest } = useAxiosRequest<
@@ -99,9 +84,10 @@ const Course = () => {
);
};
- const handleEnrollment = (enroll: boolean) => {
+ const handleEnrollment = (enroll: boolean, username: string = "") => {
let url = "course/enroll/" + id;
if (!enroll) url = "course/disenroll/" + id;
+ if (username != "") url = `${url}/${username}`;
backend_post(url, "", true).then((resp) => {
if (resp.status == 200) {
getCourseData();
@@ -151,6 +137,32 @@ const Course = () => {
marginRight: "5%"
}}
>
+
+
+ {!IsStudent() ? (
+
+ ) : null}
+
{!IsAdmin() ? (
courseData?.enrolled == true ? (
)
) : null}
-
-
@@ -208,7 +210,9 @@ const Course = () => {
Name |
Role |
{IsAdmin() ? (
- Actions |
+
+ Disenroll
+ |
) : null}
@@ -235,6 +239,15 @@ const Course = () => {
textTransform: "none",
fontSize: "1em"
}}
+ sx={{
+ "&.MuiButtonBase-root:hover":
+ {
+ bgcolor:
+ "transparent",
+ textDecoration:
+ "underline"
+ }
+ }}
onClick={() =>
handleProfileClick(
user.username
@@ -249,8 +262,23 @@ const Course = () => {
{IsAdmin() ? (
-
-
+ {
+ handleEnrollment(
+ false,
+ user.username
+ );
+ }}
+ sx={{
+ "&.MuiButtonBase-root:hover":
+ {
+ bgcolor:
+ "transparent",
+ color: "red"
+ }
+ }}
+ >
+
|
) : null}
diff --git a/src/pages/courses/index.tsx b/src/pages/courses/index.tsx
index 6a7c95e..550849a 100644
--- a/src/pages/courses/index.tsx
+++ b/src/pages/courses/index.tsx
@@ -3,20 +3,20 @@ import Container from "@mui/material/Container";
import "./courses.css"; // Import CSS file for additional styling
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
-import { backend_post, useAxiosRequest } from "../../utils";
+import { backend_delete, backend_post, useAxiosRequest } from "../../utils";
import { Course, Empty } from "../../types/common";
import { IsAdmin } from "../../utils";
-import { User } from "../../types/common";
import {
Button,
Checkbox,
+ Icon,
IconButton,
Typography,
styled
} from "@mui/material";
-import MoreVertIcon from "@mui/icons-material/MoreVert";
import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline";
-import Avatar from "@mui/material/Avatar";
+import CheckCircleIcon from "@mui/icons-material/CheckCircle";
+import CancelIcon from "@mui/icons-material/Cancel";
type ResponseData = Course[];
@@ -39,6 +39,7 @@ const Courses = () => {
}, [sendRequest]);
useEffect(() => {
+ console.log(response);
if (response) setCourseData(response);
}, [response]);
@@ -92,20 +93,21 @@ const Courses = () => {
navigate(`/course/${course_id}`);
};
- const handleEnrollment =
- (courseId: number, enroll: boolean) =>
- (event: React.ChangeEvent) => {
- if (enroll) {
- backend_post("course/enroll/" + courseId, "", true);
- if (response == null) return;
- const new_data = course_data?.map((course: Course) =>
- course.id == courseId
- ? { ...course, enrolled: true }
- : course
- );
- setCourseData(new_data);
+ const deleteCourse = (course_id: number) => {
+ backend_delete("/course/delete/" + course_id, true).then((resp) => {
+ if (resp.ok) {
+ if (course_data == undefined) return;
+ let tempCourses: Course[] = [...course_data];
+ for (let i = 0; i < tempCourses.length; i++) {
+ if (tempCourses[i].id === course_id) {
+ tempCourses.splice(i, 1);
+ break;
+ }
+ }
+ setCourseData(tempCourses);
}
- };
+ });
+ };
return (
@@ -131,10 +133,11 @@ const Courses = () => {
Course Name |
Students |
+ Teachers |
{IsAdmin() ? (
Actions |
) : (
- Enroll |
+ Enrolled |
)}
@@ -153,6 +156,12 @@ const Courses = () => {
textTransform: "none",
fontSize: "1em"
}}
+ sx={{
+ "&.MuiButtonBase-root:hover": {
+ bgcolor: "transparent",
+ textDecoration: "underline"
+ }
+ }}
onClick={() =>
handleCourseClick(course.id)
}
@@ -160,21 +169,31 @@ const Courses = () => {
{`${course.course_name}`}
- |
+ {course.num_students} |
+ {course.num_teachers} |
{IsAdmin() ? (
-
-
+ {
+ deleteCourse(course.id);
+ }}
+ sx={{
+ "&.MuiButtonBase-root:hover": {
+ bgcolor: "transparent",
+ color: "red"
+ }
+ }}
+ >
+
|
) : (
}
+ checkedIcon={}
className="actions-icon"
checked={course.enrolled}
- onChange={handleEnrollment(
- course.id,
- !course.enrolled
- )}
+ disabled={true}
sx={{
"& .MuiSvgIcon-root": {
color: "white"
diff --git a/src/pages/create_course/index.tsx b/src/pages/create_course/index.tsx
index 4a60c6d..58b221e 100644
--- a/src/pages/create_course/index.tsx
+++ b/src/pages/create_course/index.tsx
@@ -5,7 +5,7 @@ import TextField from "@mui/material/TextField";
import Container from "@mui/material/Container";
import Avatar from "@mui/material/Avatar";
import Typography from "@mui/material/Typography";
-import { Box, MenuItem, Select } from "@mui/material";
+import { Box } from "@mui/material";
import AppRegistrationIcon from "@mui/icons-material/AppRegistration";
import RootPage from "../root";
@@ -17,10 +17,7 @@ const CreateCourse = () => {
// const navigate = useNavigate();
const [regStatus, setRegStatus] = useState("");
- const handleResponse = (
- data: any,
- event: React.FormEvent
- ) => {
+ const handleResponse = (data: any) => {
console.log(data);
if (
!("course_name" in data) ||
@@ -46,7 +43,7 @@ const CreateCourse = () => {
})
)
.then((resp) => resp.json())
- .then((data) => handleResponse(data, event))
+ .then((data) => handleResponse(data))
.catch((error) => console.log(error));
};
diff --git a/src/pages/create_lecture/index.tsx b/src/pages/create_lecture/index.tsx
index 08d3a8b..4833422 100644
--- a/src/pages/create_lecture/index.tsx
+++ b/src/pages/create_lecture/index.tsx
@@ -1,7 +1,6 @@
import React, { useState } from "react";
import Button from "@mui/material/Button";
-import TextField from "@mui/material/TextField";
import Container from "@mui/material/Container";
import Avatar from "@mui/material/Avatar";
import Typography from "@mui/material/Typography";
@@ -21,10 +20,7 @@ const CreateLecture = () => {
const [regStatus, setRegStatus] = useState("");
const { id } = useParams();
- const handleResponse = (
- data: any,
- event: React.FormEvent
- ) => {
+ const handleResponse = (data: any) => {
console.log(data);
if ("ok" in data) {
setRegStatus("success");
@@ -56,7 +52,7 @@ const CreateLecture = () => {
})
)
.then((resp) => resp.json())
- .then((data) => handleResponse(data, event))
+ .then((data) => handleResponse(data))
.catch((error) => console.log(error));
};
diff --git a/src/pages/create_user/index.tsx b/src/pages/create_user/index.tsx
index 9e5c2c3..0de506b 100644
--- a/src/pages/create_user/index.tsx
+++ b/src/pages/create_user/index.tsx
@@ -16,10 +16,7 @@ const CreateUser = () => {
// const navigate = useNavigate();
const [regStatus, setRegStatus] = useState("");
- const handleTokenResponse = (
- data: any,
- event: React.FormEvent
- ) => {
+ const handleTokenResponse = (data: any) => {
console.log(data);
if (!("username" in data) || typeof data["username"] !== "string") {
setRegStatus("failed");
@@ -61,7 +58,7 @@ const CreateUser = () => {
})
)
.then((resp) => resp.json())
- .then((data) => handleTokenResponse(data, event))
+ .then((data) => handleTokenResponse(data))
.catch((error) => console.log(error));
};
diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx
index 32959ed..624fed2 100644
--- a/src/pages/home/index.tsx
+++ b/src/pages/home/index.tsx
@@ -1,7 +1,6 @@
import { FC } from "react";
import Rootpage from "../root";
import { Box, Typography } from "@mui/material";
-import backgroundImage from "../../assets/logo-clear.png";
const HomePage: FC = () => (
diff --git a/src/pages/people/index.tsx b/src/pages/people/index.tsx
index fe0890e..e52c975 100644
--- a/src/pages/people/index.tsx
+++ b/src/pages/people/index.tsx
@@ -2,14 +2,20 @@ import RootPage from "../root";
import Container from "@mui/material/Container";
import "./people.css"; // Import CSS file for additional styling
import { useEffect, useState } from "react";
-import { deleteAuthCookies, backend_get, IsAdmin } from "../../utils";
+import {
+ deleteAuthCookies,
+ backend_get,
+ IsAdmin,
+ json_request,
+ backend_delete
+} from "../../utils";
import { useNavigate } from "react-router-dom";
import { User } from "../../types/common";
import { Button, IconButton, Typography, capitalize } from "@mui/material";
import { styled } from "@mui/material/styles";
-import MoreVertIcon from "@mui/icons-material/MoreVert";
import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline";
import Avatar from "@mui/material/Avatar";
+import CancelIcon from "@mui/icons-material/Cancel";
const People = () => {
const navigate = useNavigate();
@@ -21,36 +27,36 @@ const People = () => {
return resp.json();
};
- useEffect(() => {
- const fetchUsers = async () => {
- try {
- const students_query = await getUserRole("student");
- const teachers_query = await getUserRole("teacher");
- if ("code" in students_query || "code" in teachers_query) {
- // Not authenticated anymore
- deleteAuthCookies();
- navigate("/login");
- navigate(0);
- return;
- }
-
- const students = !(
- "error" in students_query || "detail" in students_query
- )
- ? students_query
- : [];
- const teachers = !(
- "error" in teachers_query || "detail" in teachers_query
- )
- ? teachers_query
- : [];
- setAllUsers(teachers.concat(students));
- } catch (error) {
- console.error("Error fetching profile:", error);
- // Show error on frontend
+ const fetchUsers = async () => {
+ try {
+ const students_query = await getUserRole("student");
+ const teachers_query = await getUserRole("teacher");
+ if ("code" in students_query || "code" in teachers_query) {
+ // Not authenticated anymore
+ deleteAuthCookies();
+ navigate("/login");
+ navigate(0);
+ return;
}
- };
+ const students = !(
+ "error" in students_query || "detail" in students_query
+ )
+ ? students_query
+ : [];
+ const teachers = !(
+ "error" in teachers_query || "detail" in teachers_query
+ )
+ ? teachers_query
+ : [];
+ setAllUsers(teachers.concat(students));
+ } catch (error) {
+ console.error("Error fetching profile:", error);
+ // Show error on frontend
+ }
+ };
+
+ useEffect(() => {
fetchUsers();
}, [navigate]);
@@ -96,6 +102,22 @@ const People = () => {
navigate(`/profile/${username}`);
};
+ const deleteUser = (username: string) => {
+ backend_delete("/user/delete/" + username, true).then((resp) => {
+ if (resp.ok) {
+ if (allUsers == undefined) return;
+ let tempUsers: User[] = [...allUsers];
+ for (let i = 0; i < tempUsers.length; i++) {
+ if (tempUsers[i].username === username) {
+ tempUsers.splice(i, 1);
+ break;
+ }
+ }
+ setAllUsers(tempUsers);
+ }
+ });
+ };
+
return (
@@ -146,6 +168,12 @@ const People = () => {
textTransform: "none",
fontSize: "1em"
}}
+ sx={{
+ "&.MuiButtonBase-root:hover": {
+ bgcolor: "transparent",
+ textDecoration: "underline"
+ }
+ }}
onClick={() =>
handleProfileClick(user.username)
}
@@ -158,8 +186,18 @@ const People = () => {
{IsAdmin() ? (
-
-
+ {
+ deleteUser(user.username);
+ }}
+ sx={{
+ "&.MuiButtonBase-root:hover": {
+ bgcolor: "transparent",
+ color: "red"
+ }
+ }}
+ >
+
|
) : null}
diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx
index e8b3219..a93c2f7 100644
--- a/src/pages/profile/index.tsx
+++ b/src/pages/profile/index.tsx
@@ -7,7 +7,7 @@ import "./profile.css"; // Import CSS file for additional styling
import { backend_get, deleteAuthCookies } from "../../utils";
import { useNavigate, useParams } from "react-router-dom";
-import { JwtPayload, jwtDecode } from "jwt-decode";
+import { jwtDecode } from "jwt-decode";
import { CookieJWT } from "../../types/common";
import { Button, capitalize } from "@mui/material";
@@ -39,10 +39,6 @@ const Profile = () => {
return resp.json();
};
- const updateProfilePicture = async () => {
- console.log("Update Profile Picture function triggered");
- };
-
// const [loggedInUsername, setLoggedInUsername] = useState("");
//store image inside a storage solution (S3 bucket)!
// After, we collect the url from the s3
diff --git a/src/pages/schedule/index.tsx b/src/pages/schedule/index.tsx
index d42d313..29bdf9c 100644
--- a/src/pages/schedule/index.tsx
+++ b/src/pages/schedule/index.tsx
@@ -7,14 +7,26 @@ import ListItemText from "@mui/material/ListItemText";
import Checkbox from "@mui/material/Checkbox";
import { useNavigate, useParams } from "react-router-dom";
import { ScheduleLecture, Empty } from "../../types/common";
-import { backend_post, useAxiosRequest } from "../../utils";
+import {
+ IsStudent,
+ backend_delete,
+ backend_post,
+ useAxiosRequest
+} from "../../utils";
import moment from "moment";
-import { Button, Divider, capitalize } from "@mui/material";
+import {
+ Button,
+ Divider,
+ IconButton,
+ Tooltip,
+ capitalize
+} from "@mui/material";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import IndeterminateCheckBoxIcon from "@mui/icons-material/IndeterminateCheckBox";
import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank";
-import CheckBoxIcon from "@mui/icons-material/CheckBox";
+import CancelIcon from "@mui/icons-material/Cancel";
+import GroupAddIcon from "@mui/icons-material/GroupAdd";
import "./schedule.css";
// Set monday to the first day of the week
@@ -32,16 +44,17 @@ const AttendancePage: React.FC = () => {
const { id } = useParams();
const updateSchedule = () => {
+ let url = `/schedule/get/${schedule_date.year()}/${schedule_date.week()}`;
+ if (id != undefined) url += "/" + id;
sendRequest({
method: "GET",
- route: `/schedule/get/${schedule_date.year()}/${schedule_date.week()}`,
+ route: url,
useJWT: true
});
};
useEffect(() => {
updateSchedule();
- console.log(id);
}, [sendRequest]);
useEffect(() => {
@@ -67,34 +80,32 @@ const AttendancePage: React.FC = () => {
setLectures(new_lectures);
};
- const handleAttendanceChange =
- (lecture: ScheduleLecture) =>
- (event: React.ChangeEvent) => {
- var url = `lecture/${lecture.id}/student_set_att`;
- var attended = true;
+ const handleAttendanceChange = (lecture: ScheduleLecture) => {
+ let url = `lecture/${lecture.id}/student_set_att`;
+ let attended = true;
- if (lecture.attended_student == true) {
- url = `lecture/${lecture.id}/student_unset_att`;
- attended = false;
- }
+ if (lecture.attended_student == true) {
+ url = `lecture/${lecture.id}/student_unset_att`;
+ attended = false;
+ }
- backend_post(url, "", true)
- .then((resp) => {
- if (resp.status == 200)
- setStudentAttendence(lecture.id, attended);
- })
- .catch((error) => console.log(error));
- };
+ backend_post(url, "", true)
+ .then((resp) => {
+ if (resp.status == 200)
+ setStudentAttendence(lecture.id, attended);
+ })
+ .catch((error) => console.log(error));
+ };
- function goBackWeek() {
+ const goBackWeek = () => {
setScheduleDate(schedule_date.subtract(7, "days"));
updateSchedule();
- }
+ };
- function goForwardWeek() {
+ const goForwardWeek = () => {
setScheduleDate(schedule_date.add(7, "days"));
updateSchedule();
- }
+ };
const dayConvert = [
"Monday",
@@ -147,6 +158,23 @@ const AttendancePage: React.FC = () => {
return "";
};
+ const deleteLecture = (lecture_id: number) => {
+ backend_delete(`course/lecture/${lecture_id}/delete`, true).then(
+ (resp) => {
+ if (resp.ok) {
+ const new_lectures = lectures?.map(
+ (lectureGroup: ScheduleLecture[]) =>
+ lectureGroup.filter(
+ (lecture: ScheduleLecture) =>
+ lecture.id !== lecture_id
+ )
+ );
+ setLectures(new_lectures);
+ }
+ }
+ );
+ };
+
return (
{
) : null}
- {day.map((lecture, lectureIndex) => (
+ {day.map((lecture) => (
{
-
-
- }
- icon={}
- indeterminate={
- lecture.attended_student == null
- }
- checked={
- lecture.attended_student == true
- }
- onChange={handleAttendanceChange(
- lecture
- )}
- sx={{
- "& .MuiSvgIcon-root": {
- color: getCheckboxColor(
- lecture,
- lecture.attended_student
- )
- }
- }}
- />
-
- }
- icon={}
- indeterminate={
- lecture.attended_teacher == null
- }
- checked={
- lecture.attended_teacher == true
- }
- disabled={true}
- sx={{
- "& .MuiSvgIcon-root": {
- color: getCheckboxColor(
- lecture,
- lecture.attended_teacher
- )
- }
- }}
- />
+ {IsStudent() ? (
+ <>
+
+ }
+ icon={
+
+ }
+ indeterminate={
+ lecture.attended_student ==
+ null
+ }
+ checked={
+ lecture.attended_student ==
+ true
+ }
+ onChange={() =>
+ handleAttendanceChange(
+ lecture
+ )
+ }
+ sx={{
+ "& .MuiSvgIcon-root": {
+ color: getCheckboxColor(
+ lecture,
+ lecture.attended_student
+ )
+ }
+ }}
+ />
+
+ }
+ icon={
+
+ }
+ indeterminate={
+ lecture.attended_teacher ==
+ null
+ }
+ checked={
+ lecture.attended_teacher ==
+ true
+ }
+ disabled={true}
+ sx={{
+ "& .MuiSvgIcon-root": {
+ color: getCheckboxColor(
+ lecture,
+ lecture.attended_teacher
+ )
+ }
+ }}
+ />
+ >
+ ) : (
+ <>
+
+ {
+ // (
+ // false,
+ // user.username
+ // );
+ // }}
+ sx={{
+ "&.MuiButtonBase-root:hover":
+ {
+ bgcolor:
+ "transparent",
+ color: "gray"
+ }
+ }}
+ >
+
+
+
+
+ {
+ deleteLecture(
+ lecture.id
+ );
+ }}
+ sx={{
+ "&.MuiButtonBase-root:hover":
+ {
+ bgcolor:
+ "transparent",
+ color: "red"
+ }
+ }}
+ >
+
+
+
+ >
+ )}
))}
diff --git a/src/types/common.ts b/src/types/common.ts
index d3f4591..1494b0c 100644
--- a/src/types/common.ts
+++ b/src/types/common.ts
@@ -9,6 +9,8 @@ export interface Course {
id: number;
course_name: string;
enrolled: boolean;
+ num_students: number;
+ num_teachers: number;
}
export interface FullCourseUser {
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 6e1f2ed..50877ff 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -106,6 +106,9 @@ export const json_request = (
export const backend_get = (endpoint: string, useJWT: boolean = false) =>
json_request(backend_url + endpoint, "GET", "", useJWT);
+export const backend_delete = (endpoint: string, useJWT: boolean = false) =>
+ json_request(backend_url + endpoint, "DELETE", "", useJWT);
+
export const backend_post = (
endpoint: string,
body_json: string = "",