From e63377effa702950d5c529cd057487e43b467d76 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 8 Apr 2024 22:43:26 +0200 Subject: [PATCH 01/30] Update route path in main.tsx to include signedOrUnsigned parameter --- frontend/src/main.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index d4ef5f9..3e987b5 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -55,7 +55,7 @@ const router = createBrowserRouter([ element: , }, { - path: "/editTimeReport/:projectName/:fetchedWeek", + path: "/editTimeReport/:projectName/:fetchedWeek/:signedOrUnsigned", element: , }, { From badeb842824ae299ec5528fd1f72ec82a54f3eca Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 8 Apr 2024 22:43:46 +0200 Subject: [PATCH 02/30] Update route path in main.tsx to include signedOrUnsigned parameter --- frontend/src/Components/AllTimeReportsInProject.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Components/AllTimeReportsInProject.tsx b/frontend/src/Components/AllTimeReportsInProject.tsx index 0d5916b..d911a4e 100644 --- a/frontend/src/Components/AllTimeReportsInProject.tsx +++ b/frontend/src/Components/AllTimeReportsInProject.tsx @@ -37,7 +37,7 @@ function AllTimeReportsInProject(): JSX.Element {
{weeklyReports.map((newWeeklyReport, index) => ( From 6d0775586ed482b2adcc2005aa51640659dc41fc Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 8 Apr 2024 22:44:55 +0200 Subject: [PATCH 03/30] Update EditWeeklyReport component to change depending on if the report is signed or not --- frontend/src/Components/EditWeeklyReport.tsx | 29 +++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/frontend/src/Components/EditWeeklyReport.tsx b/frontend/src/Components/EditWeeklyReport.tsx index d56ee42..d402aa5 100644 --- a/frontend/src/Components/EditWeeklyReport.tsx +++ b/frontend/src/Components/EditWeeklyReport.tsx @@ -18,12 +18,13 @@ export default function GetWeeklyReport(): JSX.Element { const [testingTime, setTestingTime] = useState(0); const token = localStorage.getItem("accessToken") ?? ""; - const { projectName, fetchedWeek } = useParams<{ + const { projectName, fetchedWeek, signedOrUnsigned } = useParams<{ projectName: string; fetchedWeek: string; + signedOrUnsigned: string; }>(); const username = localStorage.getItem("userName") ?? ""; - console.log(projectName, fetchedWeek); + console.log(projectName, fetchedWeek, signedOrUnsigned); useEffect(() => { const fetchWeeklyReport = async (): Promise => { @@ -59,7 +60,7 @@ export default function GetWeeklyReport(): JSX.Element { }; void fetchWeeklyReport(); - }, [projectName, fetchedWeek, token]); + }, [projectName, fetchedWeek, signedOrUnsigned, token]); const handleUpdateWeeklyReport = async (): Promise => { const updateWeeklyReport: UpdateWeeklyReport = { @@ -139,6 +140,7 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + readOnly={signedOrUnsigned === "signed"} /> @@ -168,6 +170,7 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + readOnly={signedOrUnsigned === "signed"} /> @@ -197,6 +200,7 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + readOnly={signedOrUnsigned === "signed"} /> @@ -226,6 +230,7 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + readOnly={signedOrUnsigned === "signed"} /> @@ -255,6 +260,7 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + readOnly={signedOrUnsigned === "signed"} /> @@ -284,18 +290,21 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + readOnly={signedOrUnsigned === "signed"} /> -
From 9725a0fc488cbece5e707197e0e2f3d28a1521ab Mon Sep 17 00:00:00 2001 From: Davenludd Date: Mon, 8 Apr 2024 22:57:34 +0200 Subject: [PATCH 04/30] Update EditWeeklyReport component to prevent editing of signed reports --- frontend/src/Components/EditWeeklyReport.tsx | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/frontend/src/Components/EditWeeklyReport.tsx b/frontend/src/Components/EditWeeklyReport.tsx index d402aa5..5037a76 100644 --- a/frontend/src/Components/EditWeeklyReport.tsx +++ b/frontend/src/Components/EditWeeklyReport.tsx @@ -140,6 +140,11 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + onClick={() => { + if (signedOrUnsigned === "signed") { + alert("You cannot edit a signed report."); + } + }} readOnly={signedOrUnsigned === "signed"} /> @@ -170,6 +175,11 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + onClick={() => { + if (signedOrUnsigned === "signed") { + alert("You cannot edit a signed report."); + } + }} readOnly={signedOrUnsigned === "signed"} /> @@ -200,6 +210,11 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + onClick={() => { + if (signedOrUnsigned === "signed") { + alert("You cannot edit a signed report."); + } + }} readOnly={signedOrUnsigned === "signed"} /> @@ -230,6 +245,11 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + onClick={() => { + if (signedOrUnsigned === "signed") { + alert("You cannot edit a signed report."); + } + }} readOnly={signedOrUnsigned === "signed"} /> @@ -260,6 +280,11 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + onClick={() => { + if (signedOrUnsigned === "signed") { + alert("You cannot edit a signed report."); + } + }} readOnly={signedOrUnsigned === "signed"} /> @@ -290,6 +315,11 @@ export default function GetWeeklyReport(): JSX.Element { ) event.preventDefault(); }} + onClick={() => { + if (signedOrUnsigned === "signed") { + alert("You cannot edit a signed report."); + } + }} readOnly={signedOrUnsigned === "signed"} /> From fd7c609e5de84cd8913665e3f9b8c4f1396bd1b7 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Tue, 9 Apr 2024 10:14:34 +0200 Subject: [PATCH 05/30] Update route path in main.tsx to include signedOrUnsigned parameter --- frontend/src/main.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 3e987b5..a4ef469 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -67,7 +67,7 @@ const router = createBrowserRouter([ element: , }, { - path: "/editOthersTR/:projectName/:username/:fetchedWeek", + path: "/editOthersTR/:projectName/:username/:fetchedWeek/:signedOrUnsigned", element: , }, { From f61449dea1f0779176b9ba383f5127d6dbd0319c Mon Sep 17 00:00:00 2001 From: Davenludd Date: Tue, 9 Apr 2024 10:14:48 +0200 Subject: [PATCH 06/30] Update AllTimeReportsInProjectOtherUser component to include signed status in route path --- frontend/src/Components/AllTimeReportsInProjectOtherUser.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Components/AllTimeReportsInProjectOtherUser.tsx b/frontend/src/Components/AllTimeReportsInProjectOtherUser.tsx index 4218f0a..0878c0f 100644 --- a/frontend/src/Components/AllTimeReportsInProjectOtherUser.tsx +++ b/frontend/src/Components/AllTimeReportsInProjectOtherUser.tsx @@ -39,7 +39,7 @@ function AllTimeReportsInProject(): JSX.Element {
{weeklyReports.map((newWeeklyReport, index) => ( From b56e4ed76e3731420e9e775c5090fdba70211dff Mon Sep 17 00:00:00 2001 From: Davenludd Date: Tue, 9 Apr 2024 10:15:19 +0200 Subject: [PATCH 07/30] Add Button component to OtherUsersTR and update route path in main.tsx to include signedOrUnsigned parameter --- frontend/src/Components/OtherUsersTR.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/frontend/src/Components/OtherUsersTR.tsx b/frontend/src/Components/OtherUsersTR.tsx index ce7761c..4cbbd48 100644 --- a/frontend/src/Components/OtherUsersTR.tsx +++ b/frontend/src/Components/OtherUsersTR.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import { WeeklyReport } from "../Types/goTypes"; import { api } from "../API/API"; import { useParams } from "react-router-dom"; +import Button from "./Button"; /** * Renders the component for editing a weekly report. @@ -22,6 +23,8 @@ export default function OtherUsersTR(): JSX.Element { const { projectName } = useParams(); const { username } = useParams(); const { fetchedWeek } = useParams(); + const { signedOrUnsigned } = useParams(); + console.log(projectName, username, fetchedWeek, signedOrUnsigned); useEffect(() => { const fetchUsersWeeklyReport = async (): Promise => { @@ -153,6 +156,15 @@ export default function OtherUsersTR(): JSX.Element { + {signedOrUnsigned === "signed" && ( +
From a266a6f7fce56b859e653ac4d041afbff2004dd6 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Tue, 9 Apr 2024 10:59:27 +0200 Subject: [PATCH 08/30] Update ProjectMembers component to allow deleting users from a project --- frontend/src/Components/ProjectMembers.tsx | 75 ++++++++++++++++------ 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/frontend/src/Components/ProjectMembers.tsx b/frontend/src/Components/ProjectMembers.tsx index 52e8559..cffd7f8 100644 --- a/frontend/src/Components/ProjectMembers.tsx +++ b/frontend/src/Components/ProjectMembers.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import { Link, useParams } from "react-router-dom"; import GetUsersInProject, { ProjectMember } from "./GetUsersInProject"; +import { api } from "../API/API"; function ProjectMembers(): JSX.Element { const { projectName } = useParams(); @@ -11,34 +12,68 @@ function ProjectMembers(): JSX.Element { setUsersProp: setProjectMembers, }); + const handleUserDeleteClick = async (username: string): Promise => { + const token = localStorage.getItem("accessToken") ?? ""; + const response = await api.removeUserFromProject( + username, + projectName ?? "", + token, + ); + console.log(response.data); + + // Remove the deleted user from the state + setProjectMembers((prevMembers) => + prevMembers.filter((member) => member.Username !== username), + ); + }; + return ( <>

All Members In: {projectName}{" "}

- {projectMembers.map((projectMember: ProjectMember, index: number) => ( -

-
-
-

{projectMember.Username}

- Role: -

{projectMember.UserRole}

-
-
-
- -

- View Reports -

- + {projectMembers.map((projectMember: ProjectMember, index: number) => { + if (projectMember.Username === "admin") { + return null; // Skip rendering for admin user + } + return ( +

+
+
+

{projectMember.Username}

+ Role: +

{projectMember.UserRole}

+
+
+
+ {projectMember.Username !== + localStorage.getItem("username") && ( +

{ + confirm( + "Are you sure you want to delete this user?", + ) && + void handleUserDeleteClick(projectMember.Username); + }} + > + Delete User +

+ )} + +

+ View Reports +

+ +
-

-

- ))} + + ); + })}
); From 56e566ea9bd1e2db0bc579095f9523a7812e9db0 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Tue, 9 Apr 2024 20:57:22 +0200 Subject: [PATCH 09/30] Update confirmation message for deleting a user in ProjectMembers component --- frontend/src/Components/ProjectMembers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Components/ProjectMembers.tsx b/frontend/src/Components/ProjectMembers.tsx index cffd7f8..06825bc 100644 --- a/frontend/src/Components/ProjectMembers.tsx +++ b/frontend/src/Components/ProjectMembers.tsx @@ -53,7 +53,7 @@ function ProjectMembers(): JSX.Element { className="underline cursor-pointer font-bold" onClick={() => { confirm( - "Are you sure you want to delete this user?", + "Are you sure you want to delete this user? This action cannot be undone.", ) && void handleUserDeleteClick(projectMember.Username); }} From ff07bd1ed6bb1ca0b6cb0f7e861e765bbba68e22 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Tue, 9 Apr 2024 22:14:00 +0200 Subject: [PATCH 10/30] Update OtherUsersTR component to include unsign and delete functionality --- frontend/src/Components/OtherUsersTR.tsx | 68 +++++++++++++++++++++--- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/frontend/src/Components/OtherUsersTR.tsx b/frontend/src/Components/OtherUsersTR.tsx index 4cbbd48..40e0b94 100644 --- a/frontend/src/Components/OtherUsersTR.tsx +++ b/frontend/src/Components/OtherUsersTR.tsx @@ -1,7 +1,7 @@ import { useState, useEffect } from "react"; import { WeeklyReport } from "../Types/goTypes"; import { api } from "../API/API"; -import { useParams } from "react-router-dom"; +import { useParams, useNavigate } from "react-router-dom"; import Button from "./Button"; /** @@ -18,6 +18,7 @@ export default function OtherUsersTR(): JSX.Element { const [ownWorkTime, setOwnWorkTime] = useState(0); const [studyTime, setStudyTime] = useState(0); const [testingTime, setTestingTime] = useState(0); + const [reportId, setReportId] = useState(0); const token = localStorage.getItem("accessToken") ?? ""; const { projectName } = useParams(); @@ -48,6 +49,7 @@ export default function OtherUsersTR(): JSX.Element { studyTime: 0, testingTime: 0, }; + setReportId(report.reportId); setWeek(report.week); setDevelopmentTime(report.developmentTime); setMeetingTime(report.meetingTime); @@ -63,6 +65,27 @@ export default function OtherUsersTR(): JSX.Element { void fetchUsersWeeklyReport(); }); + const handleUnsignWeeklyReport = async (): Promise => { + const response = await api.unsignReport(reportId, token); + console.log(response); + console.log(reportId); + if (response.success) { + return true; + } else { + return false; + } + }; + + const handleDeleteWeeklyReport = async (): Promise => { + const response = await api.deleteWeeklyReport(reportId, token); + console.log(response); + if (response.success) { + return true; + } + return false; + }; + const navigate = useNavigate(); + return ( <>

{username}'s Report

@@ -156,15 +179,48 @@ export default function OtherUsersTR(): JSX.Element { - {signedOrUnsigned === "signed" && ( +
+ {signedOrUnsigned === "signed" && ( +
From 980ac19199eb6d211208d55e84b36c48608a54fb Mon Sep 17 00:00:00 2001 From: Davenludd Date: Sun, 14 Apr 2024 15:23:42 +0200 Subject: [PATCH 11/30] Add UserViewStatistics component to main.tsx --- frontend/src/main.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index a4ef469..6dcdbda 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -9,6 +9,7 @@ import AdminMenuPage from "./Pages/AdminPages/AdminMenuPage.tsx"; import UserEditTimeReportPage from "./Pages/UserPages/UserEditTimeReportPage.tsx"; import UserNewTimeReportPage from "./Pages/UserPages/UserNewTimeReportPage.tsx"; import UserViewTimeReportsPage from "./Pages/UserPages/UserViewTimeReportsPage.tsx"; +import UserViewStatistics from "./Pages/UserPages/UserViewStatistics.tsx"; import PMChangeRole from "./Pages/ProjectManagerPages/PMChangeRole.tsx"; import PMOtherUsersTR from "./Pages/ProjectManagerPages/PMOtherUsersTR.tsx"; import PMProjectMembers from "./Pages/ProjectManagerPages/PMProjectMembers.tsx"; @@ -58,6 +59,10 @@ const router = createBrowserRouter([ path: "/editTimeReport/:projectName/:fetchedWeek/:signedOrUnsigned", element: , }, + { + path: "/viewStatistics/:projectName", + element: , + }, { path: "/changeRole/:projectName/:username", element: , From 48dd53b56bc08505ff6422b2d3a3f3c990805f2a Mon Sep 17 00:00:00 2001 From: Davenludd Date: Sun, 14 Apr 2024 15:24:10 +0200 Subject: [PATCH 12/30] Add UserStatistics component to show total time per activity in a project --- frontend/src/Components/UserStatistics.tsx | 145 +++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 frontend/src/Components/UserStatistics.tsx diff --git a/frontend/src/Components/UserStatistics.tsx b/frontend/src/Components/UserStatistics.tsx new file mode 100644 index 0000000..efb61d9 --- /dev/null +++ b/frontend/src/Components/UserStatistics.tsx @@ -0,0 +1,145 @@ +import { useState, useEffect } from "react"; +import { useParams } from "react-router-dom"; +import { api } from "../API/API"; +import { projectTimes } from "./GetProjectTimes"; + +/** + * Renders the component for showing total time per role in a project. + * @returns JSX.Element + */ +export default function TimePerRole(): JSX.Element { + const [development, setDevelopment] = useState(0); + const [meeting, setMeeting] = useState(0); + const [admin, setAdmin] = useState(0); + const [own_work, setOwnWork] = useState(0); + const [study, setStudy] = useState(0); + const [testing, setTesting] = useState(0); + const total = development + meeting + admin + own_work + study + testing; + + const token = localStorage.getItem("accessToken") ?? ""; + const { projectName } = useParams(); + + const fetchTimePerActivity = async (): Promise => { + const response = await api.getProjectTimes(projectName ?? "", token); + { + if (response.success) { + const report: projectTimes = response.data ?? { + development: 0, + meeting: 0, + admin: 0, + own_work: 0, + study: 0, + testing: 0, + }; + setDevelopment(report.development); + setMeeting(report.meeting); + setAdmin(report.admin); + setOwnWork(report.own_work); + setStudy(report.study); + setTesting(report.testing); + } else { + console.error("Failed to fetch weekly report:", response.message); + } + } + }; + + useEffect(() => { + void fetchTimePerActivity(); + }); + + return ( + <> +

+ Total Time In: {projectName}{" "} +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Activity + Total Time (min) +
Development + +
Meeting + +
Administration + +
Own Work + +
Studies + +
Testing + +
In Total: +

{total}

+
+
+
+ + ); +} From ac5e67d77f341ea0296da7772b5edd2f066600a2 Mon Sep 17 00:00:00 2001 From: Davenludd Date: Sun, 14 Apr 2024 15:24:42 +0200 Subject: [PATCH 13/30] Update button text in PMProjectMembers component --- frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx b/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx index 7aa692d..0a7d82a 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMProjectMembers.tsx @@ -16,7 +16,7 @@ function PMProjectMembers(): JSX.Element { <>