diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index bcd22eb..dfec5e9 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -66,6 +66,8 @@ interface API { getUserProjects(token: string): Promise>; /** Gets a project from id*/ getProject(id: number): Promise>; + /** Gets a project from id*/ + getAllUsers(token: string): Promise>; } // Export an instance of the API @@ -102,7 +104,7 @@ export const api: API = { token: string, ): Promise> { try { - const response = await fetch("/api/userdelete", { + const response = await fetch(`/api/userdelete/${username}`, { method: "POST", headers: { "Content-Type": "application/json", @@ -298,7 +300,9 @@ export const api: API = { if (!response.ok) { return { success: false, - message: "Failed to get weekly reports for project", + message: + "Failed to get weekly reports for project: Response code " + + response.status, }; } else { const data = (await response.json()) as WeeklyReport[]; @@ -307,7 +311,7 @@ export const api: API = { } catch (e) { return { success: false, - message: "fucked again", + message: "Failed to get weekly reports for project, unknown error", }; } }, @@ -358,4 +362,32 @@ export const api: API = { }; } }, + + // Gets all users + async getAllUsers(token: string): Promise> { + try { + const response = await fetch("/api/users/all", { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + }); + + if (!response.ok) { + return Promise.resolve({ + success: false, + message: "Failed to get users", + }); + } else { + const data = (await response.json()) as string[]; + return Promise.resolve({ success: true, data }); + } + } catch (e) { + return Promise.resolve({ + success: false, + message: "API is not ok", + }); + } + }, }; diff --git a/frontend/src/Components/AllTimeReportsInProject.tsx b/frontend/src/Components/AllTimeReportsInProject.tsx new file mode 100644 index 0000000..26f26cf --- /dev/null +++ b/frontend/src/Components/AllTimeReportsInProject.tsx @@ -0,0 +1,72 @@ +//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 { 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. + * @returns JSX.Element representing the component. + */ +function AllTimeReportsInProject(): JSX.Element { + const { projectName } = useParams(); + const [weeklyReports, setWeeklyReports] = useState([]); + + const getWeeklyReports = async (): Promise => { + const token = localStorage.getItem("accessToken") ?? ""; + const response = await api.getWeeklyReportsForProject( + localStorage.getItem("username") ?? "", + projectName ?? "", + token, + ); + console.log(response); + if (response.success) { + setWeeklyReports(response.data ?? []); + } else { + console.error(response.message); + } + }; + + // Call getProjects when the component mounts + useEffect(() => { + void getWeeklyReports(); + }); + + return ( + <> +
+ {weeklyReports.map((newWeeklyReport, index) => ( + +
+

+ {"Week: "} + {newWeeklyReport.week} +

+

+ {"Total Time: "} + {newWeeklyReport.developmentTime + + newWeeklyReport.meetingTime + + newWeeklyReport.adminTime + + newWeeklyReport.ownWorkTime + + newWeeklyReport.studyTime + + newWeeklyReport.testingTime}{" "} + min +

+

+ {"Signed: "} + {newWeeklyReport.signedBy ? "YES" : "NO"} +

+
+ + ))} +
+ + ); +} + +export default AllTimeReportsInProject; diff --git a/frontend/src/Components/AuthorizedRoute.tsx b/frontend/src/Components/AuthorizedRoute.tsx new file mode 100644 index 0000000..d9c8c59 --- /dev/null +++ b/frontend/src/Components/AuthorizedRoute.tsx @@ -0,0 +1,18 @@ +import { Navigate } from "react-router-dom"; +import React from "react"; + +interface AuthorizedRouteProps { + children: React.ReactNode; + isAuthorized: boolean; +} + +export function AuthorizedRoute({ + children, + isAuthorized, +}: AuthorizedRouteProps): JSX.Element { + if (!isAuthorized) { + return ; + } + + return children as React.ReactElement; +} diff --git a/frontend/src/Components/BackButton.tsx b/frontend/src/Components/BackButton.tsx index 7a1ac81..4f58140 100644 --- a/frontend/src/Components/BackButton.tsx +++ b/frontend/src/Components/BackButton.tsx @@ -1,5 +1,11 @@ +//info: Back button component to navigate back to the previous page import { useNavigate } from "react-router-dom"; +/** + * Renders a back button component. + * + * @returns The JSX element representing the back button. + */ function BackButton(): JSX.Element { const navigate = useNavigate(); const goBack = (): void => { diff --git a/frontend/src/Components/BackgroundAnimation.tsx b/frontend/src/Components/BackgroundAnimation.tsx index 5f402c0..87fca9e 100644 --- a/frontend/src/Components/BackgroundAnimation.tsx +++ b/frontend/src/Components/BackgroundAnimation.tsx @@ -1,5 +1,10 @@ +//info: Background animation component to animate the background of loginpage import { useEffect } from "react"; +/** + * Renders a background animation component. + * This component pre-loads images and starts a background transition animation. + */ const BackgroundAnimation = (): JSX.Element => { useEffect(() => { const images = [ diff --git a/frontend/src/Components/BasicWindow.tsx b/frontend/src/Components/BasicWindow.tsx index d5fd3b6..d53d367 100644 --- a/frontend/src/Components/BasicWindow.tsx +++ b/frontend/src/Components/BasicWindow.tsx @@ -1,6 +1,16 @@ +//info: Basic window component to display content and buttons of a page, inclduing header and footer +//content to insert is placed in the content prop, and buttons in the buttons prop import Header from "./Header"; import Footer from "./Footer"; +/** + * Renders a basic window component with a header, content, and footer. + * + * @param {Object} props - The component props. + * @param {React.ReactNode} props.content - The content to be rendered in the window. + * @param {React.ReactNode} props.buttons - The buttons to be rendered in the footer. + * @returns {JSX.Element} The rendered basic window component. + */ function BasicWindow({ content, buttons, diff --git a/frontend/src/Components/Button.tsx b/frontend/src/Components/Button.tsx index 38a1853..13ae807 100644 --- a/frontend/src/Components/Button.tsx +++ b/frontend/src/Components/Button.tsx @@ -1,3 +1,12 @@ +/** + * Button component to display a button with text and onClick function. + * + * @param {Object} props - The component props. + * @param {string} props.text - The text to display on the button. + * @param {Function} props.onClick - The function to run when the button is clicked. + * @param {"submit" | "button" | "reset"} props.type - The type of button. + * @returns {JSX.Element} The rendered Button component. + */ function Button({ text, onClick, diff --git a/frontend/src/Components/ChangeRoles.tsx b/frontend/src/Components/ChangeRoles.tsx new file mode 100644 index 0000000..e11d623 --- /dev/null +++ b/frontend/src/Components/ChangeRoles.tsx @@ -0,0 +1,83 @@ +import { useState } from "react"; +import { useParams } from "react-router-dom"; +import Button from "./Button"; + +export default function ChangeRoles(): JSX.Element { + const [selectedRole, setSelectedRole] = useState(""); + const { username } = useParams(); + + const handleRoleChange = ( + event: React.ChangeEvent, + ): void => { + setSelectedRole(event.target.value); + }; + + // const handleSubmit = async (event: React.FormEvent) => { + // event.preventDefault(); + + // const response = await api.changeRole(username, selectedRole, token); + // if (response.success) { + // console.log("Role changed successfully"); + // } else { + // console.error("Failed to change role:", response.message); + // } + // }; + + return ( + <> +

+ Change roll for: {username} +

+
+
+
+ +
+
+ +
+
+ +
+
+
; -} diff --git a/frontend/src/Components/DisplayUserProjects.tsx b/frontend/src/Components/DisplayUserProjects.tsx new file mode 100644 index 0000000..f4fd782 --- /dev/null +++ b/frontend/src/Components/DisplayUserProjects.tsx @@ -0,0 +1,45 @@ +import { useState, useEffect } from "react"; +import { Project } from "../Types/goTypes"; +import { Link } from "react-router-dom"; +import { api } from "../API/API"; + +/** + * Renders a component that displays the projects a user is a part of and links to the projects start-page. + * @returns The JSX element representing the component. + */ +function DisplayUserProject(): JSX.Element { + const [projects, setProjects] = useState([]); + + const getProjects = async (): Promise => { + const token = localStorage.getItem("accessToken") ?? ""; + const response = await api.getUserProjects(token); + console.log(response); + if (response.success) { + setProjects(response.data ?? []); + } else { + console.error(response.message); + } + }; + + // Call getProjects when the component mounts + useEffect(() => { + void getProjects(); + }, []); + + return ( + <> +

Your Projects

+
+ {projects.map((project, index) => ( + +

+ {project.name} +

+ + ))} +
+ + ); +} + +export default DisplayUserProject; diff --git a/frontend/src/Components/EditWeeklyReport.tsx b/frontend/src/Components/EditWeeklyReport.tsx index b0e8771..76c2b94 100644 --- a/frontend/src/Components/EditWeeklyReport.tsx +++ b/frontend/src/Components/EditWeeklyReport.tsx @@ -1,11 +1,14 @@ import { useState, useEffect } from "react"; -import { NewWeeklyReport } from "../Types/goTypes"; +import { WeeklyReport, NewWeeklyReport } from "../Types/goTypes"; import { api } from "../API/API"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; import Button from "./Button"; +/** + * Renders the component for editing a weekly report. + * @returns JSX.Element + */ export default function GetWeeklyReport(): JSX.Element { - const [projectName, setProjectName] = useState(""); const [week, setWeek] = useState(0); const [developmentTime, setDevelopmentTime] = useState(0); const [meetingTime, setMeetingTime] = useState(0); @@ -16,46 +19,49 @@ export default function GetWeeklyReport(): JSX.Element { const token = localStorage.getItem("accessToken") ?? ""; const username = localStorage.getItem("username") ?? ""; + const { projectName } = useParams(); + const { fetchedWeek } = useParams(); + + const fetchWeeklyReport = async (): Promise => { + const response = await api.getWeeklyReport( + username, + projectName ?? "", + fetchedWeek?.toString() ?? "0", + token, + ); + + if (response.success) { + const report: WeeklyReport = response.data ?? { + reportId: 0, + userId: 0, + projectId: 0, + week: 0, + developmentTime: 0, + meetingTime: 0, + adminTime: 0, + ownWorkTime: 0, + studyTime: 0, + testingTime: 0, + }; + setWeek(report.week); + setDevelopmentTime(report.developmentTime); + setMeetingTime(report.meetingTime); + setAdminTime(report.adminTime); + setOwnWorkTime(report.ownWorkTime); + setStudyTime(report.studyTime); + setTestingTime(report.testingTime); + } else { + console.error("Failed to fetch weekly report:", response.message); + } + }; useEffect(() => { - const fetchWeeklyReport = async (): Promise => { - const response = await api.getWeeklyReport( - username, - projectName, - week.toString(), - token, - ); - - if (response.success) { - const report: NewWeeklyReport = response.data ?? { - projectName: "", - week: 0, - developmentTime: 0, - meetingTime: 0, - adminTime: 0, - ownWorkTime: 0, - studyTime: 0, - testingTime: 0, - }; - setProjectName(report.projectName); - setWeek(report.week); - setDevelopmentTime(report.developmentTime); - setMeetingTime(report.meetingTime); - setAdminTime(report.adminTime); - setOwnWorkTime(report.ownWorkTime); - setStudyTime(report.studyTime); - setTestingTime(report.testingTime); - } else { - console.error("Failed to fetch weekly report:", response.message); - } - }; - void fetchWeeklyReport(); - }, [projectName, token, username, week]); + }); const handleNewWeeklyReport = async (): Promise => { const newWeeklyReport: NewWeeklyReport = { - projectName, + projectName: projectName ?? "", week, developmentTime, meetingTime, @@ -82,7 +88,7 @@ export default function GetWeeklyReport(): JSX.Element { } e.preventDefault(); void handleNewWeeklyReport(); - navigate("/project"); + navigate(-1); }} >
@@ -233,7 +239,7 @@ export default function GetWeeklyReport(): JSX.Element {
+ ); +} diff --git a/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx b/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx index 2cdeb15..cd69b3b 100644 --- a/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx +++ b/frontend/src/Pages/UserPages/UserNewTimeReportPage.tsx @@ -1,7 +1,6 @@ +import BackButton from "../../Components/BackButton"; import BasicWindow from "../../Components/BasicWindow"; -import Button from "../../Components/Button"; import NewWeeklyReport from "../../Components/NewWeeklyReport"; -import { Link } from "react-router-dom"; function UserNewTimeReportPage(): JSX.Element { const content = ( @@ -13,15 +12,7 @@ function UserNewTimeReportPage(): JSX.Element { const buttons = ( <> - -