diff --git a/backend/main.go b/backend/main.go index e4cffae..6e65386 100644 --- a/backend/main.go +++ b/backend/main.go @@ -112,6 +112,7 @@ func main() { // All project related routes // projectGroup := api.Group("/project") // Not currently in use + api.Get("/getProjectTimes/:projectName", projects.GetProjectTimesHandler) api.Get("/getUserProjects/:username", projects.GetUserProjects) api.Get("/project/:projectId", projects.GetProject) api.Get("/checkIfProjectManager/:projectName", projects.IsProjectManagerHandler) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 6b5e3fa..553f943 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -1,5 +1,6 @@ import { NewProjMember } from "../Components/AddMember"; import { ProjectRoleChange } from "../Components/ChangeRole"; +import { projectTimes } from "../Components/GetProjectTimes"; import { ProjectMember } from "../Components/GetUsersInProject"; import { UpdateWeeklyReport, @@ -138,6 +139,16 @@ interface API { */ getProject(id: number): Promise>; + /** Gets a projects reported time + * @param {string} projectName The name of the project. + * @param {string} token The usertoken. + * @returns {Promise>} A promise resolving to an API response containing the project times. + */ + getProjectTimes( + projectName: string, + token: string, + ): Promise>; + /** Gets a list of all users. * @param {string} token The authentication token of the requesting user. * @returns {Promise>} A promise resolving to an API response containing the list of users. @@ -397,6 +408,37 @@ export const api: API = { } }, + async getProjectTimes( + projectName: string, + token: string, + ): Promise> { + try { + const response = await fetch(`/api/getProjectTimes/${projectName}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + }); + + if (!response.ok) { + return Promise.resolve({ + success: false, + message: + "Fetch error: " + response.status + ", failed to get project times", + }); + } else { + const data = (await response.json()) as projectTimes; + return Promise.resolve({ success: true, data }); + } + } catch (e) { + return Promise.resolve({ + success: false, + message: "API error! Could not get times.", + }); + } + }, + async submitWeeklyReport( weeklyReport: NewWeeklyReport, token: string, @@ -651,7 +693,7 @@ export const api: API = { token: string, ): Promise> { try { - const response = await fetch(`/api/projectdelete/${projectName}`, { + const response = await fetch(`/api/removeProject/${projectName}`, { method: "DELETE", headers: { "Content-Type": "application/json", diff --git a/frontend/src/Components/AddProject.tsx b/frontend/src/Components/AddProject.tsx index c157b04..e2ad8b9 100644 --- a/frontend/src/Components/AddProject.tsx +++ b/frontend/src/Components/AddProject.tsx @@ -61,24 +61,26 @@ function AddProject(): JSX.Element {

Create a new project

- { - e.preventDefault(); - setName(e.target.value); - }} - /> - { - e.preventDefault(); - setDescription(e.target.value); - }} - /> +
+ { + e.preventDefault(); + setName(e.target.value); + }} + /> + { + e.preventDefault(); + setDescription(e.target.value); + }} + /> +
-
-
); diff --git a/frontend/src/Components/ProjectInfoModal.tsx b/frontend/src/Components/ProjectInfoModal.tsx index 27d4e6e..6236089 100644 --- a/frontend/src/Components/ProjectInfoModal.tsx +++ b/frontend/src/Components/ProjectInfoModal.tsx @@ -1,30 +1,49 @@ -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import Button from "./Button"; import GetUsersInProject, { ProjectMember } from "./GetUsersInProject"; import { Link } from "react-router-dom"; +import GetProjectTimes, { projectTimes } from "./GetProjectTimes"; +import DeleteProject from "./DeleteProject"; function ProjectInfoModal(props: { - isVisible: boolean; projectname: string; onClose: () => void; onClick: (username: string) => void; }): JSX.Element { const [users, setUsers] = useState([]); + const [times, setTimes] = useState(); + const totalTime = useRef(0); GetUsersInProject({ projectName: props.projectname, setUsersProp: setUsers }); - if (!props.isVisible) return <>; + + GetProjectTimes({ setTimesProp: setTimes, projectName: props.projectname }); + + useEffect(() => { + if (times?.totalTime !== undefined) { + totalTime.current = times.totalTime; + } + }, [times]); return (
-
-
+
+

- {localStorage.getItem("projectName") ?? ""} + {props.projectname}

-

Project members:

-
+
+

Statistics:

+
+
+

Number of members: {users.length}

+

Total time reported: {totalTime.current}

+
+
+

Project members:

+
+
    {users.map((user) => ( @@ -44,31 +63,44 @@ function ProjectInfoModal(props: { ))}
-
-
-
diff --git a/frontend/src/Components/ProjectListAdmin.tsx b/frontend/src/Components/ProjectListAdmin.tsx index 7305ea4..294a131 100644 --- a/frontend/src/Components/ProjectListAdmin.tsx +++ b/frontend/src/Components/ProjectListAdmin.tsx @@ -18,7 +18,7 @@ export function ProjectListAdmin(props: { projects: NewProject[]; }): JSX.Element { const [projectModalVisible, setProjectModalVisible] = useState(false); - const [projectname, setProjectname] = useState(""); + const [projectName, setProjectName] = useState(""); const [userModalVisible, setUserModalVisible] = useState(false); const [username, setUsername] = useState(""); @@ -28,34 +28,36 @@ export function ProjectListAdmin(props: { }; const handleClickProject = (projectname: string): void => { - setProjectname(projectname); - localStorage.setItem("projectName", projectname); + setProjectName(projectname); setProjectModalVisible(true); }; const handleCloseProject = (): void => { - setProjectname(""); + setProjectName(""); setProjectModalVisible(false); }; const handleCloseUser = (): void => { - setProjectname(""); + setUsername(""); setUserModalVisible(false); }; return ( <> - - + {projectModalVisible && ( + + )} + {userModalVisible && ( + + )}
    {props.projects.map((project) => ( diff --git a/frontend/src/Components/Register.tsx b/frontend/src/Components/Register.tsx index 8a22806..68e0979 100644 --- a/frontend/src/Components/Register.tsx +++ b/frontend/src/Components/Register.tsx @@ -49,22 +49,24 @@ export default function Register(): JSX.Element {

    Register New User

    - { - setUsername(e.target.value); - }} - /> - { - setPassword(e.target.value); - }} - /> +
    + { + setUsername(e.target.value); + }} + /> + { + setPassword(e.target.value); + }} + /> +
    + )} +

    Member of these projects:

    + +
    +
    - )} -
    -

    - Member of these projects: -

    -
    - -
    -
    -
    -
diff --git a/frontend/src/Components/UserProjectListAdmin.tsx b/frontend/src/Components/UserProjectListAdmin.tsx index 50ae054..bc85c5b 100644 --- a/frontend/src/Components/UserProjectListAdmin.tsx +++ b/frontend/src/Components/UserProjectListAdmin.tsx @@ -8,10 +8,10 @@ function UserProjectListAdmin(props: { username: string }): JSX.Element { GetProjects({ setProjectsProp: setProjects, username: props.username }); return ( -
-
    +
    +
      {projects.map((project) => ( -
    • +
    • {project.name}
    • ))} diff --git a/frontend/src/Pages/AdminPages/AdminProjectAddMember.tsx b/frontend/src/Pages/AdminPages/AdminProjectAddMember.tsx index 893bdad..fa592c9 100644 --- a/frontend/src/Pages/AdminPages/AdminProjectAddMember.tsx +++ b/frontend/src/Pages/AdminPages/AdminProjectAddMember.tsx @@ -1,11 +1,11 @@ +import { useLocation } from "react-router-dom"; import AddUserToProject from "../../Components/AddUserToProject"; import BasicWindow from "../../Components/BasicWindow"; function AdminProjectAddMember(): JSX.Element { - const content = ; - + const projectName = useLocation().search.slice(1); + const content = ; const buttons = <>; - return ; } export default AdminProjectAddMember;