Merge branch 'frontend' into gruppPP
This commit is contained in:
		
						commit
						e4a0246b84
					
				
					 37 changed files with 772 additions and 240 deletions
				
			
		|  | @ -1,74 +1,36 @@ | |||
| import React, { useEffect, useState } from "react"; | ||||
| import { NewWeeklyReport } from "../Types/goTypes"; | ||||
| //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<NewWeeklyReport[]>([]); | ||||
| 
 | ||||
|   /*   const getWeeklyReports = async (): Promise<void> => { | ||||
|     const token = localStorage.getItem("accessToken") ?? ""; | ||||
|     const response = await api.getWeeklyReports(token); | ||||
|     console.log(response); | ||||
|     if (response.success) { | ||||
|         setWeeklyReports(response.data ?? []); | ||||
|     } else { | ||||
|         console.error(response.message); | ||||
|     } | ||||
| }; */ | ||||
|   const [weeklyReports, setWeeklyReports] = useState<WeeklyReport[]>([]); | ||||
| 
 | ||||
|   const getWeeklyReports = async (): Promise<void> => { | ||||
|     const report: NewWeeklyReport[] = [ | ||||
|       { | ||||
|         projectName: projectName ?? "", | ||||
|         week: 10, | ||||
|         developmentTime: 1, | ||||
|         meetingTime: 1, | ||||
|         adminTime: 1, | ||||
|         ownWorkTime: 1, | ||||
|         studyTime: 1, | ||||
|         testingTime: 1, | ||||
|       }, | ||||
|       { | ||||
|         projectName: projectName ?? "", | ||||
|         week: 11, | ||||
|         developmentTime: 1, | ||||
|         meetingTime: 1, | ||||
|         adminTime: 1, | ||||
|         ownWorkTime: 100, | ||||
|         studyTime: 1, | ||||
|         testingTime: 1, | ||||
|       }, | ||||
|       { | ||||
|         projectName: projectName ?? "", | ||||
|         week: 12, | ||||
|         developmentTime: 1, | ||||
|         meetingTime: 1, | ||||
|         adminTime: 1, | ||||
|         ownWorkTime: 1, | ||||
|         studyTime: 1, | ||||
|         testingTime: 1000, | ||||
|       }, | ||||
|       { | ||||
|         projectName: projectName ?? "", | ||||
|         week: 20, | ||||
|         developmentTime: 1, | ||||
|         meetingTime: 1, | ||||
|         adminTime: 1, | ||||
|         ownWorkTime: 1, | ||||
|         studyTime: 1, | ||||
|         testingTime: 10000, | ||||
|       }, | ||||
|       // Add more reports as needed
 | ||||
|     ]; | ||||
|     setWeeklyReports(report); | ||||
|     await Promise.resolve(); | ||||
|     const token = localStorage.getItem("accessToken") ?? ""; | ||||
|     const response = await api.getWeeklyReportsForUser( | ||||
|       token, | ||||
|       projectName ?? "", | ||||
|     ); | ||||
|     console.log(response); | ||||
|     if (response.success) { | ||||
|       setWeeklyReports(response.data ?? []); | ||||
|     } else { | ||||
|       console.error(response.message); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   // Call getProjects when the component mounts
 | ||||
|   useEffect(() => { | ||||
|     void getWeeklyReports(); | ||||
|   }, []); | ||||
|   }); | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|  | @ -96,7 +58,7 @@ function AllTimeReportsInProject(): JSX.Element { | |||
|               </h1> | ||||
|               <h1> | ||||
|                 <span className="font-bold">{"Signed: "}</span> | ||||
|                 YES | ||||
|                 {newWeeklyReport.signedBy ? "YES" : "NO"} | ||||
|               </h1> | ||||
|             </div> | ||||
|           </Link> | ||||
|  |  | |||
							
								
								
									
										18
									
								
								frontend/src/Components/AuthorizedRoute.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								frontend/src/Components/AuthorizedRoute.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 <Navigate to="/unauthorized" />; | ||||
|   } | ||||
| 
 | ||||
|   return children as React.ReactElement; | ||||
| } | ||||
|  | @ -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 => { | ||||
|  |  | |||
|  | @ -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 = [ | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
							
								
								
									
										83
									
								
								frontend/src/Components/ChangeRoles.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								frontend/src/Components/ChangeRoles.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<HTMLInputElement>, | ||||
|   ): void => { | ||||
|     setSelectedRole(event.target.value); | ||||
|   }; | ||||
| 
 | ||||
|   //   const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
 | ||||
|   //     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 ( | ||||
|     <> | ||||
|       <h1 className="font-bold text-[30px] mb-[20px]"> | ||||
|         Change roll for: {username} | ||||
|       </h1> | ||||
|       <form | ||||
|         className="text-[20px] font-bold border-4 border-black bg-white flex flex-col items-center justify-center min-h-[50vh] h-fit w-[30vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px]" | ||||
|         onSubmit={undefined} | ||||
|       > | ||||
|         <div className="self-start"> | ||||
|           <div> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="radio" | ||||
|                 value="System Manager" | ||||
|                 checked={selectedRole === "System Manager"} | ||||
|                 onChange={handleRoleChange} | ||||
|                 className="ml-2 mr-2 mb-6" | ||||
|               /> | ||||
|               System Manager | ||||
|             </label> | ||||
|           </div> | ||||
|           <div> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="radio" | ||||
|                 value="Developer" | ||||
|                 checked={selectedRole === "Developer"} | ||||
|                 onChange={handleRoleChange} | ||||
|                 className="ml-2 mr-2 mb-6" | ||||
|               /> | ||||
|               Developer | ||||
|             </label> | ||||
|           </div> | ||||
|           <div> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="radio" | ||||
|                 value="Tester" | ||||
|                 checked={selectedRole === "Tester"} | ||||
|                 onChange={handleRoleChange} | ||||
|                 className="ml-2 mr-2 mb-6" | ||||
|               /> | ||||
|               Tester | ||||
|             </label> | ||||
|           </div> | ||||
|         </div> | ||||
|         <Button | ||||
|           text="Save" | ||||
|           onClick={(): void => { | ||||
|             return; | ||||
|           }} | ||||
|           type="submit" | ||||
|         /> | ||||
|       </form> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
|  | @ -1,5 +1,4 @@ | |||
| import React, { useState } from "react"; | ||||
| import { api } from "../API/API"; | ||||
| import InputField from "./InputField"; | ||||
| 
 | ||||
| function ChangeUsername(): JSX.Element { | ||||
|  | @ -9,16 +8,16 @@ function ChangeUsername(): JSX.Element { | |||
|     setNewUsername(e.target.value); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = async (): Promise<void> => { | ||||
|     try { | ||||
|       // Call the API function to update the username
 | ||||
|       await api.updateUsername(newUsername); | ||||
|       // Optionally, add a success message or redirect the user
 | ||||
|     } catch (error) { | ||||
|       console.error("Error updating username:", error); | ||||
|       // Optionally, handle the error
 | ||||
|     } | ||||
|   }; | ||||
|   // const handleSubmit = async (): Promise<void> => {
 | ||||
|   //   try {
 | ||||
|   //     // Call the API function to update the username
 | ||||
|   //     await api.updateUsername(newUsername);
 | ||||
|   //     // Optionally, add a success message or redirect the user
 | ||||
|   //   } catch (error) {
 | ||||
|   //     console.error("Error updating username:", error);
 | ||||
|   //     // Optionally, handle the error
 | ||||
|   //   }
 | ||||
|   // };
 | ||||
| 
 | ||||
|   return ( | ||||
|     <div> | ||||
|  |  | |||
|  | @ -1,38 +0,0 @@ | |||
| import { useState, useEffect } from "react"; | ||||
| 
 | ||||
| // Interface for the response from the server
 | ||||
| // This should eventually reside in a dedicated file
 | ||||
| interface CountResponse { | ||||
|   pressCount: number; | ||||
| } | ||||
| 
 | ||||
| // Some constants for the button
 | ||||
| const BUTTON_ENDPOINT = "/api/button"; | ||||
| 
 | ||||
| // A simple button that counts how many times it's been pressed
 | ||||
| export function CountButton(): JSX.Element { | ||||
|   const [count, setCount] = useState<number>(NaN); | ||||
| 
 | ||||
|   // useEffect with a [] dependency array runs only once
 | ||||
|   useEffect(() => { | ||||
|     async function getCount(): Promise<void> { | ||||
|       const response = await fetch(BUTTON_ENDPOINT); | ||||
|       const data = (await response.json()) as CountResponse; | ||||
|       setCount(data.pressCount); | ||||
|     } | ||||
|     void getCount(); | ||||
|   }, []); | ||||
| 
 | ||||
|   // This is what runs on every button click
 | ||||
|   function press(): void { | ||||
|     async function pressPost(): Promise<void> { | ||||
|       const response = await fetch(BUTTON_ENDPOINT, { method: "POST" }); | ||||
|       const data = (await response.json()) as CountResponse; | ||||
|       setCount(data.pressCount); | ||||
|     } | ||||
|     void pressPost(); | ||||
|   } | ||||
| 
 | ||||
|   // Return some JSX with the button and associated handler
 | ||||
|   return <button onClick={press}>count is {count}</button>; | ||||
| } | ||||
							
								
								
									
										45
									
								
								frontend/src/Components/DisplayUserProjects.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								frontend/src/Components/DisplayUserProjects.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<Project[]>([]); | ||||
| 
 | ||||
|   const getProjects = async (): Promise<void> => { | ||||
|     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 ( | ||||
|     <> | ||||
|       <h1 className="font-bold text-[30px] mb-[20px]">Your Projects</h1> | ||||
|       <div className="border-4 border-black bg-white flex flex-col items-center justify-center min-h-[65vh] h-fit w-[50vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px]"> | ||||
|         {projects.map((project, index) => ( | ||||
|           <Link to={`/project/${project.name}`} key={index}> | ||||
|             <h1 className="font-bold underline text-[30px] cursor-pointer"> | ||||
|               {project.name} | ||||
|             </h1> | ||||
|           </Link> | ||||
|         ))} | ||||
|       </div> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default DisplayUserProject; | ||||
|  | @ -1,9 +1,13 @@ | |||
| import { useState, useEffect } from "react"; | ||||
| import { NewWeeklyReport } from "../Types/goTypes"; | ||||
| import { WeeklyReport, NewWeeklyReport } from "../Types/goTypes"; | ||||
| import { api } from "../API/API"; | ||||
| 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 [week, setWeek] = useState(0); | ||||
|   const [developmentTime, setDevelopmentTime] = useState(0); | ||||
|  | @ -27,8 +31,10 @@ export default function GetWeeklyReport(): JSX.Element { | |||
|     ); | ||||
| 
 | ||||
|     if (response.success) { | ||||
|       const report: NewWeeklyReport = response.data ?? { | ||||
|         projectName: "", | ||||
|       const report: WeeklyReport = response.data ?? { | ||||
|         reportId: 0, | ||||
|         userId: 0, | ||||
|         projectId: 0, | ||||
|         week: 0, | ||||
|         developmentTime: 0, | ||||
|         meetingTime: 0, | ||||
|  | @ -37,7 +43,6 @@ export default function GetWeeklyReport(): JSX.Element { | |||
|         studyTime: 0, | ||||
|         testingTime: 0, | ||||
|       }; | ||||
| 
 | ||||
|       setWeek(report.week); | ||||
|       setDevelopmentTime(report.developmentTime); | ||||
|       setMeetingTime(report.meetingTime); | ||||
|  |  | |||
|  | @ -1,5 +1,13 @@ | |||
| //info: Footer component to display the footer of a page where the buttons are placed
 | ||||
| import React from "react"; | ||||
| 
 | ||||
| /** | ||||
|  * Footer component. | ||||
|  * | ||||
|  * @param {Object} props - The component props. | ||||
|  * @param {React.ReactNode} props.children - The children elements to render inside the footer (buttons). | ||||
|  * @returns {JSX.Element} The rendered footer component. | ||||
|  */ | ||||
| function Footer({ children }: { children: React.ReactNode }): JSX.Element { | ||||
|   return ( | ||||
|     <footer className="bg-white"> | ||||
|  |  | |||
|  | @ -1,7 +1,12 @@ | |||
| //info: Header component to display the header of the page including the logo and user information where thr user can logout
 | ||||
| import { useState } from "react"; | ||||
| import { Link } from "react-router-dom"; | ||||
| import backgroundImage from "../assets/1.jpg"; | ||||
| 
 | ||||
| /** | ||||
|  * Renders the header component. | ||||
|  * @returns JSX.Element representing the header component. | ||||
|  */ | ||||
| function Header(): JSX.Element { | ||||
|   const [isOpen, setIsOpen] = useState(false); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,9 +1,15 @@ | |||
| //info: New weekly report form component to create a new weekly report to
 | ||||
| //sumbit development time, meeting time, admin time, own work time, study time and testing time
 | ||||
| import { useState } from "react"; | ||||
| import type { NewWeeklyReport } from "../Types/goTypes"; | ||||
| import { api } from "../API/API"; | ||||
| import { useNavigate, useParams } from "react-router-dom"; | ||||
| import Button from "./Button"; | ||||
| 
 | ||||
| /** | ||||
|  * Renders a form for creating a new weekly report. | ||||
|  * @returns The JSX element representing the new weekly report form. | ||||
|  */ | ||||
| export default function NewWeeklyReport(): JSX.Element { | ||||
|   const [week, setWeek] = useState<number>(0); | ||||
|   const [developmentTime, setDevelopmentTime] = useState<number>(); | ||||
|  |  | |||
							
								
								
									
										34
									
								
								frontend/src/Components/PMProjectMenu.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								frontend/src/Components/PMProjectMenu.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| import { Link, useParams } from "react-router-dom"; | ||||
| import { JSX } from "react/jsx-runtime"; | ||||
| 
 | ||||
| function PMProjectMenu(): JSX.Element { | ||||
|   const { projectName } = useParams(); | ||||
|   return ( | ||||
|     <> | ||||
|       <h1 className="font-bold text-[30px] mb-[20px]">{projectName}</h1> | ||||
|       <div className="border-4 border-black bg-white flex flex-col items-center justify-center min-h-[65vh] h-fit w-[50vw] rounded-3xl content-center overflow-scroll space-y-[5vh] p-[30px]"> | ||||
|         <Link to={`/timeReports/${projectName}/`}> | ||||
|           <h1 className="font-bold underline text-[30px] cursor-pointer"> | ||||
|             Your Time Reports | ||||
|           </h1> | ||||
|         </Link> | ||||
|         <Link to={`/newTimeReport/${projectName}`}> | ||||
|           <h1 className="font-bold underline text-[30px] cursor-pointer"> | ||||
|             New Time Report | ||||
|           </h1> | ||||
|         </Link> | ||||
|         <Link to={`/projectMembers/${projectName}`}> | ||||
|           <h1 className="font-bold underline text-[30px] cursor-pointer"> | ||||
|             Statistics | ||||
|           </h1> | ||||
|         </Link> | ||||
|         <Link to={`/unsignedReports/${projectName}`}> | ||||
|           <h1 className="font-bold underline text-[30px] cursor-pointer"> | ||||
|             Unsigned Time Reports | ||||
|           </h1> | ||||
|         </Link> | ||||
|       </div> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
| export default PMProjectMenu; | ||||
							
								
								
									
										99
									
								
								frontend/src/Components/ProjectMembers.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								frontend/src/Components/ProjectMembers.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,99 @@ | |||
| import { useEffect, useState } from "react"; | ||||
| import { Link, useParams } from "react-router-dom"; | ||||
| 
 | ||||
| function ProjectMembers(): JSX.Element { | ||||
|   const { projectName } = useParams(); | ||||
|   const [projectMembers, setProjectMembers] = useState<ProjectMember[]>([]); | ||||
| 
 | ||||
|   //   const getProjectMembers = async (): Promise<void> => {
 | ||||
|   //     const token = localStorage.getItem("accessToken") ?? "";
 | ||||
|   //     const response = await api.getProjectMembers(projectName ?? "", token);
 | ||||
|   //     console.log(response);
 | ||||
|   //     if (response.success) {
 | ||||
|   //       setProjectMembers(response.data ?? []);
 | ||||
|   //     } else {
 | ||||
|   //       console.error(response.message);
 | ||||
|   //     }
 | ||||
|   //   };
 | ||||
| 
 | ||||
|   interface ProjectMember { | ||||
|     username: string; | ||||
|     role: string; | ||||
|   } | ||||
| 
 | ||||
|   const mockProjectMembers = [ | ||||
|     { | ||||
|       username: "username1", | ||||
|       role: "Project Manager", | ||||
|     }, | ||||
|     { | ||||
|       username: "username2", | ||||
|       role: "System Manager", | ||||
|     }, | ||||
|     { | ||||
|       username: "username3", | ||||
|       role: "Developer", | ||||
|     }, | ||||
|     { | ||||
|       username: "username4", | ||||
|       role: "Tester", | ||||
|     }, | ||||
|     { | ||||
|       username: "username5", | ||||
|       role: "Tester", | ||||
|     }, | ||||
|     { | ||||
|       username: "username6", | ||||
|       role: "Tester", | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   const getProjectMembers = async (): Promise<void> => { | ||||
|     // Use the mock data
 | ||||
|     setProjectMembers(mockProjectMembers); | ||||
| 
 | ||||
|     await Promise.resolve(); | ||||
|   }; | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     void getProjectMembers(); | ||||
|   }); | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <div className="border-4 border-black bg-white flex flex-col items-center justify-center min-h-[65vh] h-fit w-[70vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px] text-[20px]"> | ||||
|         {projectMembers.map((projectMember, index) => ( | ||||
|           <h1 key={index} className="border-b-2 border-black w-full"> | ||||
|             <div className="flex justify-between"> | ||||
|               <div className="flex"> | ||||
|                 <h1>{projectMember.username}</h1> | ||||
|                 <span className="ml-6 mr-2 font-bold">Role:</span> | ||||
|                 <h1>{projectMember.role}</h1> | ||||
|               </div> | ||||
|               <div className="flex"> | ||||
|                 <div className="ml-auto flex space-x-4"> | ||||
|                   <Link | ||||
|                     to={`/viewReports/${projectName}/${projectMember.username}`} | ||||
|                   > | ||||
|                     <h1 className="underline cursor-pointer font-bold"> | ||||
|                       View Reports | ||||
|                     </h1> | ||||
|                   </Link> | ||||
|                   <Link | ||||
|                     to={`/changeRole/${projectName}/${projectMember.username}`} | ||||
|                   > | ||||
|                     <h1 className="underline cursor-pointer font-bold"> | ||||
|                       Change Role | ||||
|                     </h1> | ||||
|                   </Link> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </h1> | ||||
|         ))} | ||||
|       </div> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default ProjectMembers; | ||||
|  | @ -6,6 +6,10 @@ import Button from "./Button"; | |||
| import InputField from "./InputField"; | ||||
| import { useNavigate } from "react-router-dom"; | ||||
| 
 | ||||
| /** | ||||
|  * Renders a registration form for the admin to add new users in. | ||||
|  * @returns The JSX element representing the registration form. | ||||
|  */ | ||||
| export default function Register(): JSX.Element { | ||||
|   const [username, setUsername] = useState<string>(); | ||||
|   const [password, setPassword] = useState<string>(); | ||||
|  |  | |||
							
								
								
									
										32
									
								
								frontend/src/Components/UserProjectMenu.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								frontend/src/Components/UserProjectMenu.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| //info: User project menu component to display the user project menu where the user can navigate to
 | ||||
| //existing time reports in a project and create a new time report
 | ||||
| import { useParams, Link } from "react-router-dom"; | ||||
| import { JSX } from "react/jsx-runtime"; | ||||
| 
 | ||||
| /** | ||||
|  * Renders the user project menu component. | ||||
|  * | ||||
|  * @returns JSX.Element representing the user project menu. | ||||
|  */ | ||||
| function UserProjectMenu(): JSX.Element { | ||||
|   const { projectName } = useParams(); | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <h1 className="font-bold text-[30px] mb-[20px]">{projectName}</h1> | ||||
|       <div className="border-4 border-black bg-white flex flex-col items-center justify-center min-h-[65vh] h-fit w-[50vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px]"> | ||||
|         <Link to={`/timeReports/${projectName}/`}> | ||||
|           <h1 className="font-bold underline text-[30px] cursor-pointer"> | ||||
|             Your Time Reports | ||||
|           </h1> | ||||
|         </Link> | ||||
|         <Link to={`/newTimeReport/${projectName}`}> | ||||
|           <h1 className="font-bold underline text-[30px] cursor-pointer"> | ||||
|             New Time Report | ||||
|           </h1> | ||||
|         </Link> | ||||
|       </div> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
| export default UserProjectMenu; | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Peter KW
						Peter KW