diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 890a7e6..c1480fb 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -3,6 +3,7 @@ import { ProjectRoleChange } from "../Components/ChangeRole"; import { projectTimes } from "../Components/GetProjectTimes"; import { ProjectMember } from "../Components/GetUsersInProject"; import { + UpdateWeeklyReport, NewWeeklyReport, NewUser, User, @@ -87,6 +88,17 @@ interface API { token: string, ): Promise>; + /** + * Updates a weekly report. + * @param {UpdateWeeklyReport} weeklyReport The updated weekly report object. + * @param {string} token The authentication token. + * @returns {Promise>} A promise containing the API response with the updated report. + */ + updateWeeklyReport( + weeklyReport: UpdateWeeklyReport, + token: string, + ): Promise>; + /** Gets a weekly report for a specific user, project and week * @param {string} projectName The name of the project. * @param {string} week The week number. @@ -147,6 +159,17 @@ interface API { projectName: string, token: string, ): Promise>; + + /** Gets all unsigned reports in a project. + * @param {string} projectName The name of the project. + * @param {string} token The authentication token. + * @returns {Promise>} A promise resolving to an API response containing the list of unsigned reports. + */ + getUnsignedReportsInProject( + projectName: string, + token: string, + ): Promise>; + /** * Changes the username of a user in the database. * @param {StrNameChange} data The object containing the previous and new username. @@ -458,6 +481,37 @@ export const api: API = { } }, + async updateWeeklyReport( + weeklyReport: UpdateWeeklyReport, + token: string, + ): Promise> { + try { + const response = await fetch("/api/updateWeeklyReport", { + method: "PUT", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + body: JSON.stringify(weeklyReport), + }); + + if (!response.ok) { + return { + success: false, + message: "Failed to update weekly report", + }; + } + + const data = await response.text(); + return { success: true, message: data }; + } catch (e) { + return { + success: false, + message: "Failed to update weekly report", + }; + } + }, + async getWeeklyReport( projectName: string, week: string, @@ -621,6 +675,38 @@ export const api: API = { } }, + async getUnsignedReportsInProject( + projectName: string, + token: string, + ): Promise> { + try { + const response = await fetch(`/api/getUnsignedReports/${projectName}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + }); + + if (!response.ok) { + return { + success: false, + message: + "Failed to get unsigned reports for project: Response code " + + response.status, + }; + } else { + const data = (await response.json()) as WeeklyReport[]; + return { success: true, data }; + } + } catch (e) { + return { + success: false, + message: "Failed to get unsigned reports for project, unknown error", + }; + } + }, + async changeUserName( data: StrNameChange, token: string, diff --git a/frontend/src/Components/AllTimeReportsInProjectOtherUser.tsx b/frontend/src/Components/AllTimeReportsInProjectOtherUser.tsx index 09ca6dc..ef78642 100644 --- a/frontend/src/Components/AllTimeReportsInProjectOtherUser.tsx +++ b/frontend/src/Components/AllTimeReportsInProjectOtherUser.tsx @@ -1,8 +1,9 @@ //Info: This component is used to display all the time reports for a project. It will display the week number, //total time spent, and if the report has been signed or not. The user can click on a report to edit it. import { useEffect, useState } from "react"; -import { NewWeeklyReport } from "../Types/goTypes"; +import { WeeklyReport } from "../Types/goTypes"; import { Link, useParams } from "react-router-dom"; +import { api } from "../API/API"; /** * Renders a component that displays all the time reports for a specific project. @@ -11,14 +12,14 @@ import { Link, useParams } from "react-router-dom"; function AllTimeReportsInProject(): JSX.Element { const { username } = useParams(); const { projectName } = useParams(); - const [weeklyReports, setWeeklyReports] = useState([]); + const [weeklyReports, setWeeklyReports] = useState([]); - /* // Call getProjects when the component mounts useEffect(() => { const getWeeklyReports = async (): Promise => { const token = localStorage.getItem("accessToken") ?? ""; - const response = await api.getWeeklyReportsForUser( + const response = await api.getWeeklyReportsForDifferentUser( projectName ?? "", + username ?? "", token, ); console.log(response); @@ -27,39 +28,8 @@ function AllTimeReportsInProject(): JSX.Element { } else { console.error(response.message); } - }; */ - // Mock data - const getWeeklyReports = async (): Promise => { - // Simulate a delay - await Promise.resolve(); - const mockWeeklyReports: NewWeeklyReport[] = [ - { - projectName: "Project 1", - week: 1, - developmentTime: 10, - meetingTime: 2, - adminTime: 1, - ownWorkTime: 3, - studyTime: 4, - testingTime: 5, - }, - { - projectName: "Project 1", - week: 2, - developmentTime: 8, - meetingTime: 2, - adminTime: 1, - ownWorkTime: 3, - studyTime: 4, - testingTime: 5, - }, - // Add more reports as needed - ]; + }; - // Use the mock data instead of the real data - setWeeklyReports(mockWeeklyReports); - }; - useEffect(() => { void getWeeklyReports(); }, []); diff --git a/frontend/src/Components/DisplayUnsignedReports.tsx b/frontend/src/Components/DisplayUnsignedReports.tsx index 780f20c..232cb31 100644 --- a/frontend/src/Components/DisplayUnsignedReports.tsx +++ b/frontend/src/Components/DisplayUnsignedReports.tsx @@ -1,12 +1,7 @@ import { useState, useEffect } from "react"; import { Link, useParams } from "react-router-dom"; - -interface UnsignedReports { - projectName: string; - username: string; - week: number; - signed: boolean; -} +import { api } from "../API/API"; +import { WeeklyReport } from "../Types/goTypes"; /** * Renders a component that displays the projects a user is a part of and links to the projects start-page. @@ -14,80 +9,25 @@ interface UnsignedReports { */ function DisplayUserProject(): JSX.Element { const { projectName } = useParams(); - const [unsignedReports, setUnsignedReports] = useState([]); + const [unsignedReports, setUnsignedReports] = useState([]); //const navigate = useNavigate(); - - // const getUnsignedReports = async (): Promise => { - // const token = localStorage.getItem("accessToken") ?? ""; - // const response = await api.getUserProjects(token); - // console.log(response); - // if (response.success) { - // setUnsignedReports(response.data ?? []); - // } else { - // console.error(response.message); - // } - // }; - - // const handleReportClick = async (projectName: string): Promise => { - // const username = localStorage.getItem("username") ?? ""; - // const token = localStorage.getItem("accessToken") ?? ""; - // const response = await api.checkIfProjectManager( - // username, - // projectName, - // token, - // ); - // if (response.success) { - // if (response.data) { - // navigate(`/PMProjectPage/${projectName}`); - // } else { - // navigate(`/project/${projectName}`); - // } - // } else { - // // handle error - // console.error(response.message); - // } - // }; - - const getUnsignedReports = async (): Promise => { - // Simulate a delay - await Promise.resolve(); - - // Use mock data - const reports: UnsignedReports[] = [ - { - projectName: "projecttest", - username: "user1", - week: 2, - signed: false, - }, - { - projectName: "projecttest", - username: "user2", - week: 2, - signed: false, - }, - { - projectName: "projecttest", - username: "user3", - week: 2, - signed: false, - }, - { - projectName: "projecttest", - username: "user4", - week: 2, - signed: false, - }, - ]; - - // Set the state with the mock data - setUnsignedReports(reports); - }; - - // Call getProjects when the component mounts useEffect(() => { + const getUnsignedReports = async (): Promise => { + const token = localStorage.getItem("accessToken") ?? ""; + const response = await api.getUnsignedReportsInProject( + projectName ?? "", + token, + ); + console.log(response); + if (response.success) { + setUnsignedReports(response.data ?? []); + } else { + console.error(response.message); + } + }; + void getUnsignedReports(); - }, []); + }, [projectName]); // Include 'projectName' in the dependency array return ( <> @@ -95,32 +35,40 @@ function DisplayUserProject(): JSX.Element { All Unsigned Reports In: {projectName}{" "}
- {unsignedReports.map( - (unsignedReport: UnsignedReports, index: number) => ( -

-
-
-

{unsignedReport.username}

- Week: -

{unsignedReport.week}

- Signed: -

NO

-
-
-
- -

- View Report -

- -
+ {unsignedReports.map((unsignedReport: WeeklyReport, index: number) => ( +

+
+
+ UserID: +

{unsignedReport.userId}

+ Week: +

{unsignedReport.week}

+ Total Time: +

+ {unsignedReport.developmentTime + + unsignedReport.meetingTime + + unsignedReport.adminTime + + unsignedReport.ownWorkTime + + unsignedReport.studyTime + + unsignedReport.testingTime} +

+ Signed: +

NO

+
+
+
+ +

+ View Report +

+
-

- ), - )} +
+

+ ))}
); diff --git a/frontend/src/Components/EditWeeklyReport.tsx b/frontend/src/Components/EditWeeklyReport.tsx index 384359e..d56ee42 100644 --- a/frontend/src/Components/EditWeeklyReport.tsx +++ b/frontend/src/Components/EditWeeklyReport.tsx @@ -1,5 +1,5 @@ import { useState, useEffect } from "react"; -import { WeeklyReport, NewWeeklyReport } from "../Types/goTypes"; +import { WeeklyReport, UpdateWeeklyReport } from "../Types/goTypes"; import { api } from "../API/API"; import { useNavigate, useParams } from "react-router-dom"; import Button from "./Button"; @@ -22,6 +22,7 @@ export default function GetWeeklyReport(): JSX.Element { projectName: string; fetchedWeek: string; }>(); + const username = localStorage.getItem("userName") ?? ""; console.log(projectName, fetchedWeek); useEffect(() => { @@ -60,8 +61,9 @@ export default function GetWeeklyReport(): JSX.Element { void fetchWeeklyReport(); }, [projectName, fetchedWeek, token]); - const handleNewWeeklyReport = async (): Promise => { - const newWeeklyReport: NewWeeklyReport = { + const handleUpdateWeeklyReport = async (): Promise => { + const updateWeeklyReport: UpdateWeeklyReport = { + userName: username, projectName: projectName ?? "", week, developmentTime, @@ -72,7 +74,7 @@ export default function GetWeeklyReport(): JSX.Element { testingTime, }; - await api.submitWeeklyReport(newWeeklyReport, token); + await api.updateWeeklyReport(updateWeeklyReport, token); }; const navigate = useNavigate(); @@ -89,7 +91,8 @@ export default function GetWeeklyReport(): JSX.Element { return; } e.preventDefault(); - void handleNewWeeklyReport(); + void handleUpdateWeeklyReport(); + alert("Changes submitted"); navigate(-1); }} > @@ -128,7 +131,12 @@ export default function GetWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -152,7 +160,12 @@ export default function GetWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -176,7 +189,12 @@ export default function GetWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -200,7 +218,12 @@ export default function GetWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -224,7 +247,12 @@ export default function GetWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -248,7 +276,12 @@ export default function GetWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> diff --git a/frontend/src/Components/NewWeeklyReport.tsx b/frontend/src/Components/NewWeeklyReport.tsx index f684b0c..1bb5cd4 100644 --- a/frontend/src/Components/NewWeeklyReport.tsx +++ b/frontend/src/Components/NewWeeklyReport.tsx @@ -139,7 +139,12 @@ export default function NewWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -163,7 +168,12 @@ export default function NewWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -187,7 +197,12 @@ export default function NewWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -211,7 +226,12 @@ export default function NewWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -235,7 +255,12 @@ export default function NewWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> @@ -259,7 +284,12 @@ export default function NewWeeklyReport(): JSX.Element { }} onKeyDown={(event) => { const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") + if ( + !/\d/.test(keyValue) && + keyValue !== "Backspace" && + keyValue !== "ArrowLeft" && + keyValue !== "ArrowRight" + ) event.preventDefault(); }} /> diff --git a/frontend/src/Components/TimePerActivity.tsx b/frontend/src/Components/TimePerActivity.tsx index 3dc1a6b..6175845 100644 --- a/frontend/src/Components/TimePerActivity.tsx +++ b/frontend/src/Components/TimePerActivity.tsx @@ -1,70 +1,45 @@ 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 [developmentTime, setDevelopmentTime] = useState(); - const [meetingTime, setMeetingTime] = useState(); - const [adminTime, setAdminTime] = useState(); - const [ownWorkTime, setOwnWorkTime] = useState(); - const [studyTime, setStudyTime] = useState(); - const [testingTime, setTestingTime] = useState(); + const [development, setDevelopment] = useState(); + const [meeting, setMeeting] = useState(); + const [admin, setAdmin] = useState(); + const [own_work, setOwnWork] = useState(); + const [study, setStudy] = useState(); + const [testing, setTesting] = useState(); - // const token = localStorage.getItem("accessToken") ?? ""; - // const username = localStorage.getItem("username") ?? ""; + const token = localStorage.getItem("accessToken") ?? ""; const { projectName } = useParams(); - // const fetchTimePerRole = async (): Promise => { - // const response = await api.getTimePerRole( - // username, - // projectName ?? "", - // token, - // ); - // { - // if (response.success) { - // const report: TimePerRole = response.data ?? { - // PManagerTime: 0, - // SManagerTime: 0, - // DeveloperTime: 0, - // TesterTime: 0, - // }; - // } else { - // console.error("Failed to fetch weekly report:", response.message); - // } - // } - - interface TimePerActivity { - developmentTime: number; - meetingTime: number; - adminTime: number; - ownWorkTime: number; - studyTime: number; - testingTime: number; - } - const fetchTimePerActivity = async (): Promise => { - // Use mock data - const report: TimePerActivity = { - developmentTime: 100, - meetingTime: 200, - adminTime: 300, - ownWorkTime: 50, - studyTime: 75, - testingTime: 110, - }; - - // Set the state with the mock data - setDevelopmentTime(report.developmentTime); - setMeetingTime(report.meetingTime); - setAdminTime(report.adminTime); - setOwnWorkTime(report.ownWorkTime); - setStudyTime(report.studyTime); - setTestingTime(report.testingTime); - - await Promise.resolve(); + 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(() => { @@ -94,10 +69,8 @@ export default function TimePerRole(): JSX.Element { { - event.preventDefault(); - }} + value={development} + readOnly /> @@ -107,10 +80,8 @@ export default function TimePerRole(): JSX.Element { { - event.preventDefault(); - }} + value={meeting} + readOnly /> @@ -120,10 +91,8 @@ export default function TimePerRole(): JSX.Element { { - event.preventDefault(); - }} + value={admin} + readOnly /> @@ -133,10 +102,8 @@ export default function TimePerRole(): JSX.Element { { - event.preventDefault(); - }} + value={own_work} + readOnly /> @@ -146,10 +113,8 @@ export default function TimePerRole(): JSX.Element { { - event.preventDefault(); - }} + value={study} + readOnly /> @@ -159,10 +124,8 @@ export default function TimePerRole(): JSX.Element { { - event.preventDefault(); - }} + value={testing} + readOnly /> diff --git a/frontend/src/Components/ViewOtherTimeReport.tsx b/frontend/src/Components/ViewOtherTimeReport.tsx index 32e0716..bde0529 100644 --- a/frontend/src/Components/ViewOtherTimeReport.tsx +++ b/frontend/src/Components/ViewOtherTimeReport.tsx @@ -1,5 +1,5 @@ import { useState, useEffect } from "react"; -import { WeeklyReport, NewWeeklyReport } from "../Types/goTypes"; +import { WeeklyReport } from "../Types/goTypes"; import { api } from "../API/API"; import { useNavigate, useParams } from "react-router-dom"; import Button from "./Button"; @@ -18,6 +18,7 @@ export default function GetOtherUsersReport(): 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(); @@ -45,6 +46,7 @@ export default function GetOtherUsersReport(): JSX.Element { studyTime: 0, testingTime: 0, }; + setReportId(report.reportId); setWeek(report.week); setDevelopmentTime(report.developmentTime); setMeetingTime(report.meetingTime); @@ -61,30 +63,23 @@ export default function GetOtherUsersReport(): JSX.Element { }); const handleSignWeeklyReport = async (): Promise => { - const newWeeklyReport: NewWeeklyReport = { - projectName: projectName ?? "", - week, - developmentTime, - meetingTime, - adminTime, - ownWorkTime, - studyTime, - testingTime, - }; - - await api.submitWeeklyReport(newWeeklyReport, token); + await api.signReport(reportId, token); }; const navigate = useNavigate(); return ( <> -

{username}'s Report

+

+ {" "} + UserId: {username}'s Report +

{ e.preventDefault(); void handleSignWeeklyReport(); + alert("Report successfully signed!"); navigate(-1); }} > @@ -112,7 +107,10 @@ export default function GetOtherUsersReport(): JSX.Element { type="text" min="0" className="border-2 border-black rounded-md text-center w-1/2" - value={developmentTime === 0 ? "" : developmentTime} + defaultValue={ + developmentTime === 0 ? "" : developmentTime + } + readOnly /> @@ -123,7 +121,8 @@ export default function GetOtherUsersReport(): JSX.Element { type="text" min="0" className="border-2 border-black rounded-md text-center w-1/2" - value={meetingTime === 0 ? "" : meetingTime} + defaultValue={meetingTime === 0 ? "" : meetingTime} + readOnly /> @@ -134,7 +133,8 @@ export default function GetOtherUsersReport(): JSX.Element { type="text" min="0" className="border-2 border-black rounded-md text-center w-1/2" - value={adminTime === 0 ? "" : adminTime} + defaultValue={adminTime === 0 ? "" : adminTime} + readOnly /> @@ -145,7 +145,8 @@ export default function GetOtherUsersReport(): JSX.Element { type="text" min="0" className="border-2 border-black rounded-md text-center w-1/2" - value={ownWorkTime === 0 ? "" : ownWorkTime} + defaultValue={ownWorkTime === 0 ? "" : ownWorkTime} + readOnly /> @@ -156,7 +157,8 @@ export default function GetOtherUsersReport(): JSX.Element { type="text" min="0" className="border-2 border-black rounded-md text-center w-1/2" - value={studyTime === 0 ? "" : studyTime} + defaultValue={studyTime === 0 ? "" : studyTime} + readOnly /> @@ -167,7 +169,8 @@ export default function GetOtherUsersReport(): JSX.Element { type="text" min="0" className="border-2 border-black rounded-md text-center w-1/2" - value={testingTime === 0 ? "" : testingTime} + defaultValue={testingTime === 0 ? "" : testingTime} + readOnly />