diff --git a/backend/internal/database/sample_data/0010_sample_data.sql b/backend/internal/database/sample_data/0010_sample_data.sql index 70499b0..ab74f1a 100644 --- a/backend/internal/database/sample_data/0010_sample_data.sql +++ b/backend/internal/database/sample_data/0010_sample_data.sql @@ -21,12 +21,6 @@ VALUES ("projecttest3","test project3", 1); INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) VALUES (1,1,"project_manager"); -INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) -VALUES (1,2,"project_manager"); - -INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) -VALUES (1,3,"project_manager"); - INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) VALUES (2,1,"member"); diff --git a/backend/internal/handlers/projects/GetUserProject.go b/backend/internal/handlers/projects/GetUserProject.go index 6c80515..99ed63b 100644 --- a/backend/internal/handlers/projects/GetUserProject.go +++ b/backend/internal/handlers/projects/GetUserProject.go @@ -4,16 +4,15 @@ import ( db "ttime/internal/database" "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/log" + "github.com/golang-jwt/jwt/v5" ) // GetUserProjects returns all projects that the user is a member of func GetUserProjects(c *fiber.Ctx) error { - username := c.Params("username") - if username == "" { - log.Info("No username provided") - return c.Status(400).SendString("No username provided") - } + // First we get the username from the token + user := c.Locals("user").(*jwt.Token) + claims := user.Claims.(jwt.MapClaims) + username := claims["name"].(string) // Then dip into the database to get the projects projects, err := db.GetDb(c).GetProjectsForUser(username) diff --git a/backend/internal/handlers/projects/ProjectRoleChange.go b/backend/internal/handlers/projects/ProjectRoleChange.go index 6c5d455..266127d 100644 --- a/backend/internal/handlers/projects/ProjectRoleChange.go +++ b/backend/internal/handlers/projects/ProjectRoleChange.go @@ -24,13 +24,7 @@ func ProjectRoleChange(c *fiber.Ctx) error { return c.Status(400).SendString(err.Error()) } - // Check if user is trying to change its own role - if username == data.UserName { - log.Info("Can't change your own role") - return c.Status(403).SendString("Can't change your own role") - } - - log.Info("Changing role for user: ", data.UserName, " in project: ", data.Projectname, " to: ", data.Role) + log.Info("Changing role for user: ", username, " in project: ", data.Projectname, " to: ", data.Role) // Dubble diping and checcking if current user is if ismanager, err := db.GetDb(c).IsProjectManager(username, data.Projectname); err != nil { @@ -42,7 +36,7 @@ func ProjectRoleChange(c *fiber.Ctx) error { } // Change the user's role within the project in the database - if err := db.GetDb(c).ChangeUserRole(data.UserName, data.Projectname, data.Role); err != nil { + if err := db.GetDb(c).ChangeUserRole(username, data.Projectname, data.Role); err != nil { return c.Status(500).SendString(err.Error()) } diff --git a/backend/main.go b/backend/main.go index 6e65386..cf58280 100644 --- a/backend/main.go +++ b/backend/main.go @@ -112,8 +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("/getUserProjects", projects.GetUserProjects) api.Get("/project/:projectId", projects.GetProject) api.Get("/checkIfProjectManager/:projectName", projects.IsProjectManagerHandler) api.Get("/getUsersProject/:projectName", projects.ListAllUsersProject) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 890a7e6..e7de646 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -1,15 +1,13 @@ -import { NewProjMember } from "../Components/AddMember"; -import { ProjectRoleChange } from "../Components/ChangeRole"; -import { projectTimes } from "../Components/GetProjectTimes"; -import { ProjectMember } from "../Components/GetUsersInProject"; import { NewWeeklyReport, NewUser, User, Project, NewProject, + UserProjectMember, WeeklyReport, StrNameChange, + NewProjMember, } from "../Types/goTypes"; /** @@ -75,7 +73,10 @@ interface API { * @param {string} token The authentication token. * @returns {Promise>} A promise resolving to an API response with the created project. */ - createProject(project: NewProject, token: string): Promise>; + createProject( + project: NewProject, + token: string, + ): Promise>; /** Submits a weekly report * @param {NewWeeklyReport} weeklyReport The weekly report object. @@ -127,16 +128,6 @@ 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. @@ -146,7 +137,7 @@ interface API { getAllUsersProject( projectName: string, token: string, - ): Promise>; + ): Promise>; /** * Changes the username of a user in the database. * @param {StrNameChange} data The object containing the previous and new username. @@ -157,21 +148,10 @@ interface API { data: StrNameChange, token: string, ): Promise>; - /** - * Changes the role of a user in the database. - * @param {RoleChange} roleInfo The object containing the previous and new username. - * @param {string} token The authentication token. - * @returns {Promise>} A promise resolving to an API response. - */ - changeUserRole( - roleInfo: ProjectRoleChange, - token: string, - ): Promise>; - addUserToProject( user: NewProjMember, token: string, - ): Promise>; + ): Promise>; removeProject( projectName: string, @@ -185,7 +165,10 @@ interface API { * @param {number} reportId The id of the report to sign * @param {string} token The authentication token */ - signReport(reportId: number, token: string): Promise>; + signReport( + reportId: number, + token: string, + ): Promise>; } /** An instance of the API */ @@ -273,7 +256,7 @@ export const api: API = { async createProject( project: NewProject, token: string, - ): Promise> { + ): Promise> { try { const response = await fetch("/api/project", { method: "POST", @@ -287,17 +270,18 @@ export const api: API = { if (!response.ok) { return { success: false, message: "Failed to create project" }; } else { - return { success: true }; + const data = (await response.json()) as Project; + return { success: true, data }; } } catch (e) { - return { success: false, message: "Failed to create project!" }; + return { success: false, message: "Failed to create project" }; } }, async addUserToProject( user: NewProjMember, token: string, - ): Promise> { + ): Promise> { try { const response = await fetch("/api/addUserToProject", { method: "PUT", @@ -339,33 +323,6 @@ export const api: API = { } }, - async changeUserRole( - roleInfo: ProjectRoleChange, - token: string, - ): Promise> { - try { - const response = await fetch("/api/ProjectRoleChange", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }, - body: JSON.stringify(roleInfo), - }); - - if (!response.ok) { - if (response.status === 403) { - return { success: false, message: "Cannot change your own role" }; - } - return { success: false, message: "Could not change role" }; - } else { - return { success: true }; - } - } catch (e) { - return { success: false, message: "Could not change role" }; - } - }, - async getUserProjects( username: string, token: string, @@ -396,37 +353,6 @@ 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, @@ -594,7 +520,7 @@ export const api: API = { async getAllUsersProject( projectName: string, token: string, - ): Promise> { + ): Promise> { try { const response = await fetch(`/api/getUsersProject/${projectName}`, { method: "GET", @@ -610,7 +536,7 @@ export const api: API = { message: "Failed to get users", }); } else { - const data = (await response.json()) as ProjectMember[]; + const data = (await response.json()) as UserProjectMember[]; return Promise.resolve({ success: true, data }); } } catch (e) { @@ -650,7 +576,7 @@ export const api: API = { token: string, ): Promise> { try { - const response = await fetch(`/api/removeProject/${projectName}`, { + const response = await fetch(`/api/projectdelete/${projectName}`, { method: "DELETE", headers: { "Content-Type": "application/json", @@ -696,5 +622,5 @@ export const api: API = { } catch (e) { return { success: false, message: "Failed to sign report" }; } - }, + } }; diff --git a/frontend/src/Components/AddMember.tsx b/frontend/src/Components/AddMember.tsx index 194afe8..d29be68 100644 --- a/frontend/src/Components/AddMember.tsx +++ b/frontend/src/Components/AddMember.tsx @@ -1,10 +1,5 @@ import { APIResponse, api } from "../API/API"; - -export interface NewProjMember { - username: string; - role: string; - projectname: string; -} +import { NewProjMember } from "../Types/goTypes"; /** * Tries to add a member to a project @@ -26,7 +21,7 @@ function AddMember(props: { memberToAdd: NewProjMember }): boolean { props.memberToAdd, localStorage.getItem("accessToken") ?? "", ) - .then((response: APIResponse) => { + .then((response: APIResponse) => { if (response.success) { alert("Member added"); added = true; diff --git a/frontend/src/Components/AddProject.tsx b/frontend/src/Components/AddProject.tsx index e2ad8b9..f5f4a08 100644 --- a/frontend/src/Components/AddProject.tsx +++ b/frontend/src/Components/AddProject.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; import { APIResponse, api } from "../API/API"; -import { NewProject } from "../Types/goTypes"; +import { NewProject, Project } from "../Types/goTypes"; import InputField from "./InputField"; import Logo from "../assets/Logo.svg"; import Button from "./Button"; @@ -10,26 +10,27 @@ import Button from "./Button"; * @param {Object} props - Project name and description * @returns {boolean} True if created, false if not */ -function CreateProject(props: { name: string; description: string }): void { +function CreateProject(props: { name: string; description: string }): boolean { const project: NewProject = { name: props.name, description: props.description, }; + let created = false; + api .createProject(project, localStorage.getItem("accessToken") ?? "") - .then((response: APIResponse) => { + .then((response: APIResponse) => { if (response.success) { - alert("Project added!"); + created = true; } else { - alert("Project NOT added!"); console.error(response.message); } }) .catch((error) => { - alert("Project NOT added!"); console.error("An error occurred during creation:", error); }); + return created; } /** @@ -47,10 +48,7 @@ function AddProject(): JSX.Element { className="bg-white rounded px-8 pt-6 pb-8 mb-4 items-center justify-center flex flex-col w-fit h-fit" onSubmit={(e) => { e.preventDefault(); - CreateProject({ - name: name, - description: description, - }); + CreateProject({ name: name, description: description }); }} > Create a new project -
- { - e.preventDefault(); - setName(e.target.value); - }} - /> - { - e.preventDefault(); - setDescription(e.target.value); - }} - /> -
+ { + setName(e.target.value); + }} + /> + { + setDescription(e.target.value); + }} + />
- ); -} diff --git a/frontend/src/Components/ChangeUsername.tsx b/frontend/src/Components/ChangeUsername.tsx index 78d7da9..e297a04 100644 --- a/frontend/src/Components/ChangeUsername.tsx +++ b/frontend/src/Components/ChangeUsername.tsx @@ -1,26 +1,61 @@ -import { APIResponse, api } from "../API/API"; -import { StrNameChange } from "../Types/goTypes"; +import React, { useState } from "react"; +import InputField from "./InputField"; +import { api } from "../API/API"; -function ChangeUsername(props: { nameChange: StrNameChange }): void { - if (props.nameChange.newName === "") { - alert("You have to select a new name"); - return; - } - api - .changeUserName(props.nameChange, localStorage.getItem("accessToken") ?? "") - .then((response: APIResponse) => { - if (response.success) { - alert("Name changed successfully"); - location.reload(); - } else { - alert("Name not changed"); - console.error(response.message); +function ChangeUsername(): JSX.Element { + const [newUsername, setNewUsername] = useState(""); + const [errorMessage, setErrorMessage] = useState(""); + + const handleChange = (e: React.ChangeEvent): void => { + setNewUsername(e.target.value); + }; + + const handleSubmit = async (): Promise => { + try { + // Call the API function to change the username + const token = localStorage.getItem("accessToken"); + if (!token) { + throw new Error("Access token not found"); } - }) - .catch((error) => { - alert("Name not changed"); - console.error("An error occurred during change:", error); + + const response = await api.changeUserName( + { prevName: "currentName", newName: newUsername }, + token, + ); + + if (response.success) { + // Optionally, add a success message or redirect the user + console.log("Username changed successfully"); + } else { + // Handle the error message + console.error("Failed to change username:", response.message); + setErrorMessage(response.message ?? "Failed to change username"); + } + } catch (error) { + console.error("Error changing username:", error); + // Optionally, handle the error + setErrorMessage("Failed to change username"); + } + }; + + const handleButtonClick = (): void => { + handleSubmit().catch((error) => { + console.error("Error in handleSubmit:", error); }); + }; + + return ( +
+ + {errorMessage &&
{errorMessage}
} + +
+ ); } export default ChangeUsername; diff --git a/frontend/src/Components/DeleteProject.tsx b/frontend/src/Components/DeleteProject.tsx deleted file mode 100644 index 4add857..0000000 --- a/frontend/src/Components/DeleteProject.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { api, APIResponse } from "../API/API"; - -/** - * Use to delete a project from the system - * @param {string} props.projectToDelete - The projectname of project to delete - * @returns {void} Nothing - * @example - * const exampleProjectName = "project"; - * DeleteProject({ projectToDelete: exampleProjectName }); - */ - -function DeleteProject(props: { projectToDelete: string }): void { - api - .removeProject( - props.projectToDelete, - localStorage.getItem("accessToken") ?? "", - ) - .then((response: APIResponse) => { - if (response.success) { - alert("Project has been deleted!"); - location.reload(); - } else { - alert("Project has not been deleted"); - console.error(response.message); - } - }) - .catch((error) => { - alert("project has not been deleted"); - console.error("An error occurred during deletion:", error); - }); -} - -export default DeleteProject; diff --git a/frontend/src/Components/DeleteUser.tsx b/frontend/src/Components/DeleteUser.tsx index 7c5e8e8..d1dbc7f 100644 --- a/frontend/src/Components/DeleteUser.tsx +++ b/frontend/src/Components/DeleteUser.tsx @@ -3,7 +3,7 @@ import { api, APIResponse } from "../API/API"; /** * Use to remove a user from the system - * @param {string} props.usernameToDelete - The username of user to remove + * @param props - The username of user to remove * @returns {boolean} True if removed, false if not * @example * const exampleUsername = "user"; @@ -29,7 +29,7 @@ function DeleteUser(props: { usernameToDelete: string }): boolean { }) .catch((error) => { alert("User has not been deleted"); - console.error("An error occurred during deletion:", error); + console.error("An error occurred during creation:", error); }); return removed; } diff --git a/frontend/src/Components/DisplayUserProjects.tsx b/frontend/src/Components/DisplayUserProjects.tsx index 65bd4f5..92ba84f 100644 --- a/frontend/src/Components/DisplayUserProjects.tsx +++ b/frontend/src/Components/DisplayUserProjects.tsx @@ -2,7 +2,6 @@ import { useState } from "react"; import { Project } from "../Types/goTypes"; import { useNavigate } from "react-router-dom"; import GetProjects from "./GetProjects"; -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. @@ -12,20 +11,22 @@ function DisplayUserProject(): JSX.Element { const [projects, setProjects] = useState([]); const navigate = useNavigate(); - GetProjects({ - setProjectsProp: setProjects, - username: localStorage.getItem("username") ?? "", - }); + 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); + } + }; const handleProjectClick = async (projectName: string): Promise => { const token = localStorage.getItem("accessToken") ?? ""; const response = await api.checkIfProjectManager(projectName, token); - console.log(response.data); if (response.success) { - if ( - (response.data as unknown as { isProjectManager: boolean }) - .isProjectManager - ) { + if (response.data) { navigate(`/PMProjectPage/${projectName}`); } else { navigate(`/project/${projectName}`); @@ -36,6 +37,11 @@ function DisplayUserProject(): JSX.Element { } }; + // Call getProjects when the component mounts + useEffect(() => { + void getProjects(); + }, []); + return ( <>

Your Projects

diff --git a/frontend/src/Components/GetProjectTimes.tsx b/frontend/src/Components/GetProjectTimes.tsx deleted file mode 100644 index 38288ec..0000000 --- a/frontend/src/Components/GetProjectTimes.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { Dispatch, SetStateAction, useEffect } from "react"; -import { api } from "../API/API"; - -/** - * Interface for reported time per category + total time reported - */ -export interface projectTimes { - admin: number; - development: number; - meeting: number; - own_work: number; - study: number; - testing: number; - totalTime?: number; -} - -/** - * Gets all reported times for this project - * @param {Dispatch} props.setTimesProp - A setStateAction for the map you want to put times in - * @param {string} props.projectName - Username - * @returns {void} Nothing - * @example - * const projectName = "Example"; - * const [times, setTimes] = useState(); - * GetProjectTimes({ setTimesProp: setTimes, projectName: projectName }); - */ -function GetProjectTimes(props: { - setTimesProp: Dispatch>; - projectName: string; -}): void { - const setTimes: Dispatch> = - props.setTimesProp; - useEffect(() => { - const fetchUsers = async (): Promise => { - try { - const token = localStorage.getItem("accessToken") ?? ""; - const response = await api.getProjectTimes(props.projectName, token); - if (response.success && response.data) { - // Calculates total time reported - response.data.totalTime = response.data.admin; - response.data.totalTime += response.data.development; - response.data.totalTime += response.data.meeting; - response.data.totalTime += response.data.own_work; - response.data.totalTime += response.data.study; - response.data.totalTime += response.data.testing; - setTimes(response.data); - } else { - console.error("Failed to fetch project times:", response.message); - } - } catch (error) { - console.error("Error fetching times:", error); - } - }; - - void fetchUsers(); - }, [props.projectName, setTimes]); -} - -export default GetProjectTimes; diff --git a/frontend/src/Components/GetProjects.tsx b/frontend/src/Components/GetProjects.tsx index bd6c303..764b082 100644 --- a/frontend/src/Components/GetProjects.tsx +++ b/frontend/src/Components/GetProjects.tsx @@ -4,13 +4,11 @@ import { api } from "../API/API"; /** * Gets all projects that user is a member of - * @param {Dispatch} props.setProjectsProp - A setStateAction for the array you want to put projects in - * @param {string} props.username - Username + * @param props - A setStateAction for the array you want to put projects in * @returns {void} Nothing * @example - * const username = "Example"; * const [projects, setProjects] = useState([]); - * GetProjects({ setProjectsProp: setProjects, username: username }); + * GetAllUsers({ setProjectsProp: setProjects }); */ function GetProjects(props: { setProjectsProp: Dispatch>; diff --git a/frontend/src/Components/GetUsersInProject.tsx b/frontend/src/Components/GetUsersInProject.tsx index eb32e9b..acdd965 100644 --- a/frontend/src/Components/GetUsersInProject.tsx +++ b/frontend/src/Components/GetUsersInProject.tsx @@ -1,25 +1,20 @@ import { Dispatch, useEffect } from "react"; +import { UserProjectMember } from "../Types/goTypes"; import { api } from "../API/API"; -export interface ProjectMember { - Username: string; - UserRole: string; -} - /** - * Gets all members of a project - * @param string - The project's name - * @param Dispatch - A setStateAction for the array you want to put members in + * Gets all projects that user is a member of + * @param props - A setStateAction for the array you want to put projects in * @returns {void} Nothing * @example - * const [users, setUsers] = useState([]); - * GetUsersInProject({ projectName: props.projectname, setUsersProp: setUsers }); + * const [projects, setProjects] = useState([]); + * GetAllUsers({ setProjectsProp: setProjects }); */ function GetUsersInProject(props: { projectName: string; - setUsersProp: Dispatch>; + setUsersProp: Dispatch>; }): void { - const setUsers: Dispatch> = + const setUsers: Dispatch> = props.setUsersProp; useEffect(() => { const fetchUsers = async (): Promise => { @@ -29,10 +24,10 @@ function GetUsersInProject(props: { if (response.success) { setUsers(response.data ?? []); } else { - console.error("Failed to fetch members:", response.message); + console.error("Failed to fetch projects:", response.message); } } catch (error) { - console.error("Error fetching members:", error); + console.error("Error fetching projects:", error); } }; void fetchUsers(); diff --git a/frontend/src/Components/InputField.tsx b/frontend/src/Components/InputField.tsx index 699d8fa..639b4ca 100644 --- a/frontend/src/Components/InputField.tsx +++ b/frontend/src/Components/InputField.tsx @@ -19,7 +19,7 @@ function InputField(props: { onChange: (e: React.ChangeEvent) => void; }): JSX.Element { return ( -
+
-
- - - ); -} - -export default MemberInfoModal; diff --git a/frontend/src/Components/ProjectInfoModal.tsx b/frontend/src/Components/ProjectInfoModal.tsx index 1f98d79..3075b19 100644 --- a/frontend/src/Components/ProjectInfoModal.tsx +++ b/frontend/src/Components/ProjectInfoModal.tsx @@ -1,54 +1,31 @@ -import { useEffect, useRef, useState } from "react"; +import { useState } from "react"; import Button from "./Button"; -import GetUsersInProject, { ProjectMember } from "./GetUsersInProject"; +import { UserProjectMember } from "../Types/goTypes"; +import GetUsersInProject 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); + const [users, setUsers] = useState([]); GetUsersInProject({ projectName: props.projectname, setUsersProp: setUsers }); - - GetProjectTimes({ setTimesProp: setTimes, projectName: props.projectname }); - - useEffect(() => { - if (times?.totalTime !== undefined) { - totalTime.current = times.totalTime; - } - }, [times]); + if (!props.isVisible) return <>; return (
-
-
+
+

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

-
-

Statistics:

-
-
-

Number of members: {users.length}

-

- Total time reported:{" "} - {Math.floor(totalTime.current / 60 / 24) + " d "} - {Math.floor((totalTime.current / 60) % 24) + " h "} - {(totalTime.current % 60) + " m "} -

-
-
-

Project members:

-
-
+

Project members:

+
    {users.map((user) => ( @@ -68,44 +45,31 @@ function ProjectInfoModal(props: { ))}
-
+
+
+
+ +
diff --git a/frontend/src/Components/ProjectListAdmin.tsx b/frontend/src/Components/ProjectListAdmin.tsx index 294a131..f25ee47 100644 --- a/frontend/src/Components/ProjectListAdmin.tsx +++ b/frontend/src/Components/ProjectListAdmin.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { NewProject } from "../Types/goTypes"; import ProjectInfoModal from "./ProjectInfoModal"; -import MemberInfoModal from "./MemberInfoModal"; +import UserInfoModal from "./UserInfoModal"; /** * A list of projects for admin manage projects page, that sets an onClick @@ -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,36 +28,39 @@ export function ProjectListAdmin(props: { }; const handleClickProject = (projectname: string): void => { - setProjectName(projectname); + setProjectname(projectname); + localStorage.setItem("projectName", projectname); setProjectModalVisible(true); }; const handleCloseProject = (): void => { - setProjectName(""); + setProjectname(""); setProjectModalVisible(false); }; const handleCloseUser = (): void => { - setUsername(""); + setProjectname(""); setUserModalVisible(false); }; return ( <> - {projectModalVisible && ( - - )} - {userModalVisible && ( - - )} + + { + return; + }} + isVisible={userModalVisible} + username={username} + />
    {props.projects.map((project) => ( diff --git a/frontend/src/Components/ProjectMembers.tsx b/frontend/src/Components/ProjectMembers.tsx index 52e8559..60ffcd9 100644 --- a/frontend/src/Components/ProjectMembers.tsx +++ b/frontend/src/Components/ProjectMembers.tsx @@ -1,15 +1,31 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { Link, useParams } from "react-router-dom"; -import GetUsersInProject, { ProjectMember } from "./GetUsersInProject"; +import { api } from "../API/API"; +import { UserProjectMember } from "../Types/goTypes"; function ProjectMembers(): JSX.Element { const { projectName } = useParams(); - const [projectMembers, setProjectMembers] = useState([]); + const [projectMembers, setProjectMembers] = useState([]); - GetUsersInProject({ - projectName: projectName ?? "", - setUsersProp: setProjectMembers, - }); + useEffect(() => { + const getProjectMembers = async (): Promise => { + const token = localStorage.getItem("accessToken") ?? ""; + const response = await api.getAllUsersProject(projectName ?? "", token); + console.log(response); + if (response.success) { + setProjectMembers(response.data ?? []); + } else { + console.error(response.message); + } + }; + + void getProjectMembers(); + }, [projectName]); + + interface ProjectMember { + Username: string; + UserRole: string; + } return ( <> diff --git a/frontend/src/Components/Register.tsx b/frontend/src/Components/Register.tsx index 68e0979..6192637 100644 --- a/frontend/src/Components/Register.tsx +++ b/frontend/src/Components/Register.tsx @@ -22,8 +22,6 @@ export default function Register(): JSX.Element { const response = await api.registerUser(newUser); if (response.success) { alert("User added!"); - setPassword(""); - setUsername(""); } else { alert("User not added"); setErrMessage(response.message ?? "Unknown error"); @@ -49,24 +47,22 @@ 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:

    - -
    -
); diff --git a/frontend/src/Components/UserListAdmin.tsx b/frontend/src/Components/UserListAdmin.tsx index 76cae9f..c08b05c 100644 --- a/frontend/src/Components/UserListAdmin.tsx +++ b/frontend/src/Components/UserListAdmin.tsx @@ -1,5 +1,6 @@ import { useState } from "react"; import UserInfoModal from "./UserInfoModal"; +import DeleteUser from "./DeleteUser"; /** * A list of users for admin manage users page, that sets an onClick @@ -29,7 +30,9 @@ export function UserListAdmin(props: { users: string[] }): JSX.Element { return ( <> DeleteUser} isVisible={modalVisible} username={username} /> diff --git a/frontend/src/Components/UserProjectListAdmin.tsx b/frontend/src/Components/UserProjectListAdmin.tsx index bc85c5b..5335f1b 100644 --- a/frontend/src/Components/UserProjectListAdmin.tsx +++ b/frontend/src/Components/UserProjectListAdmin.tsx @@ -1,17 +1,35 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; +import { api } from "../API/API"; import { Project } from "../Types/goTypes"; -import GetProjects from "./GetProjects"; function UserProjectListAdmin(props: { username: string }): JSX.Element { const [projects, setProjects] = useState([]); - GetProjects({ setProjectsProp: setProjects, username: props.username }); + useEffect(() => { + const fetchProjects = async (): Promise => { + try { + const token = localStorage.getItem("accessToken") ?? ""; + const username = props.username; + + const response = await api.getUserProjects(username, token); + if (response.success) { + setProjects(response.data ?? []); + } else { + console.error("Failed to fetch projects:", response.message); + } + } catch (error) { + console.error("Error fetching projects:", error); + } + }; + + void fetchProjects(); + }, [props.username]); return ( -
-
    +
    +
      {projects.map((project) => ( -
    • +
    • {project.name}
    • ))} diff --git a/frontend/src/Pages/AdminPages/AdminChangeUsername.tsx b/frontend/src/Pages/AdminPages/AdminChangeUsername.tsx new file mode 100644 index 0000000..b130fae --- /dev/null +++ b/frontend/src/Pages/AdminPages/AdminChangeUsername.tsx @@ -0,0 +1,28 @@ +import BackButton from "../../Components/BackButton"; +import BasicWindow from "../../Components/BasicWindow"; +import Button from "../../Components/Button"; +import ChangeUsername from "../../Components/ChangeUsername"; + +function AdminChangeUsername(): JSX.Element { + const content = ( + <> + + + ); + + const buttons = ( + <> +