From 9e2a3cca8114939f17e17e4594c8a25520a6f8a4 Mon Sep 17 00:00:00 2001 From: pavel Hamawand Date: Thu, 21 Mar 2024 01:56:27 +0100 Subject: [PATCH 01/23] Update the method signature in the API interface to use StrNameChange --- frontend/src/API/API.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 5c49a8d..a39ce9b 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -6,6 +6,7 @@ import { NewProject, UserProjectMember, WeeklyReport, + StrNameChange, } from "../Types/goTypes"; /** @@ -133,6 +134,16 @@ interface API { 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. + * @param {string} token The authentication token. + * @returns {Promise>} A promise resolving to an API response. + */ + changeUserName( + data: StrNameChange, + token: string, + ): Promise>; } /** An instance of the API */ @@ -342,7 +353,9 @@ export const api: API = { if (!response.ok) { return { success: false, message: "Failed to get weekly report" }; } else { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const data = (await response.json()) as WeeklyReport; + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment return { success: true, data }; } } catch (e) { @@ -484,4 +497,12 @@ export const api: API = { }); } }, + changeUserName: function ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _data: StrNameChange, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + token: string, + ): Promise> { + throw new Error("Function not implemented."); + }, }; From 3e11b87eee3bf7c0ac8468e6a303790dc3956e64 Mon Sep 17 00:00:00 2001 From: pavel Hamawand Date: Thu, 21 Mar 2024 01:58:57 +0100 Subject: [PATCH 02/23] Modify the implementation of the changeUserName method in the api object --- frontend/src/API/API.ts | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index a39ce9b..70e36c9 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -497,12 +497,28 @@ export const api: API = { }); } }, - changeUserName: function ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _data: StrNameChange, - // eslint-disable-next-line @typescript-eslint/no-unused-vars + + async changeUserName( + data: StrNameChange, token: string, ): Promise> { - throw new Error("Function not implemented."); + try { + const response = await fetch("/api/changeUserName", { + method: "PUT", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + body: JSON.stringify(data), + }); + + if (!response.ok) { + return { success: false, message: "Failed to change username" }; + } else { + return { success: true }; + } + } catch (e) { + return { success: false, message: "Failed to change username" }; + } }, }; From 19501122020f52baa1f607cf80b93c77e60f98e3 Mon Sep 17 00:00:00 2001 From: pavel Hamawand Date: Thu, 21 Mar 2024 02:22:23 +0100 Subject: [PATCH 03/23] implementing changeUsername component --- frontend/src/Components/ChangeUsername.tsx | 40 ++++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/frontend/src/Components/ChangeUsername.tsx b/frontend/src/Components/ChangeUsername.tsx index 3c35e94..04abc26 100644 --- a/frontend/src/Components/ChangeUsername.tsx +++ b/frontend/src/Components/ChangeUsername.tsx @@ -1,23 +1,41 @@ import React, { useState } from "react"; import InputField from "./InputField"; +import { api } from "../API/API"; 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 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 => { + try { + // Call the API function to change the username + 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); + } + } 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 (
@@ -27,6 +45,8 @@ function ChangeUsername(): JSX.Element { value={newUsername} onChange={handleChange} /> + {errorMessage &&
{errorMessage}
} +
); } From baf11f19d6c5fab9a4856c22115845179b9d4b44 Mon Sep 17 00:00:00 2001 From: pavel Hamawand Date: Thu, 21 Mar 2024 02:47:51 +0100 Subject: [PATCH 04/23] added token --- frontend/src/Components/ChangeUsername.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/Components/ChangeUsername.tsx b/frontend/src/Components/ChangeUsername.tsx index 04abc26..247c2fb 100644 --- a/frontend/src/Components/ChangeUsername.tsx +++ b/frontend/src/Components/ChangeUsername.tsx @@ -13,9 +13,10 @@ function ChangeUsername(): JSX.Element { const handleSubmit = async (): Promise => { try { // Call the API function to change the username + const token = localStorage.getItem("accessToken") ?? ""; const response = await api.changeUserName( { prevName: "currentName", newName: newUsername }, - "token", + token, ); if (response.success) { // Optionally, add a success message or redirect the user From e9eb2e9ab60133840328485b2b70b53488678a8f Mon Sep 17 00:00:00 2001 From: pavel Hamawand Date: Thu, 21 Mar 2024 02:51:28 +0100 Subject: [PATCH 05/23] checks --- frontend/src/Components/ChangeUsername.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/Components/ChangeUsername.tsx b/frontend/src/Components/ChangeUsername.tsx index 247c2fb..e297a04 100644 --- a/frontend/src/Components/ChangeUsername.tsx +++ b/frontend/src/Components/ChangeUsername.tsx @@ -13,17 +13,23 @@ function ChangeUsername(): JSX.Element { const handleSubmit = async (): Promise => { try { // Call the API function to change the username - const token = localStorage.getItem("accessToken") ?? ""; + const token = localStorage.getItem("accessToken"); + if (!token) { + throw new Error("Access token not found"); + } + 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); From a73432669cc71db1c2a19a957278db705fda95fc Mon Sep 17 00:00:00 2001 From: Peter KW Date: Thu, 21 Mar 2024 03:36:30 +0100 Subject: [PATCH 06/23] New path --- frontend/src/main.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index bac2292..5fd4d68 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -31,6 +31,7 @@ import AdminProjectViewMemberInfo from "./Pages/AdminPages/AdminProjectViewMembe import AdminProjectPage from "./Pages/AdminPages/AdminProjectPage.tsx"; import NotFoundPage from "./Pages/NotFoundPage.tsx"; import UnauthorizedPage from "./Pages/UnauthorizedPage.tsx"; +import AddUserToProject from "./Components/AddUserToProject.tsx"; // This is where the routes are mounted const router = createBrowserRouter([ @@ -147,6 +148,10 @@ const router = createBrowserRouter([ path: "/unauthorized", element: , }, + { + path: "/addUserToProject", + element: , + }, ]); // Semi-hacky way to get the root element From 2694beb0e8d80a95565b2f6a14c46e07e30f4464 Mon Sep 17 00:00:00 2001 From: Peter KW Date: Thu, 21 Mar 2024 03:36:57 +0100 Subject: [PATCH 07/23] AddUserToProject API --- frontend/src/API/API.ts | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 70e36c9..7920e0e 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -7,6 +7,7 @@ import { UserProjectMember, WeeklyReport, StrNameChange, + NewProjMember, } from "../Types/goTypes"; /** @@ -144,6 +145,10 @@ interface API { data: StrNameChange, token: string, ): Promise>; + addUserToProject( + user: NewProjMember, + token: string, + ): Promise>; } /** An instance of the API */ @@ -254,6 +259,30 @@ export const api: API = { } }, + async addUserToProject( + user: NewProjMember, + token: string, + ): Promise> { + try { + const response = await fetch("/api/addUserToProject", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + body: JSON.stringify(user), + }); + + if (!response.ok) { + return { success: false, message: "Failed to add member" }; + } else { + return { success: true, message: "Added member" }; + } + } catch (e) { + return { success: false, message: "Failed to add member" }; + } + }, + async renewToken(token: string): Promise> { try { const response = await fetch("/api/loginrenew", { @@ -353,9 +382,7 @@ export const api: API = { if (!response.ok) { return { success: false, message: "Failed to get weekly report" }; } else { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const data = (await response.json()) as WeeklyReport; - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment return { success: true, data }; } } catch (e) { From c5bc6c1c585ae0efae9b818f70d2a4333ff42688 Mon Sep 17 00:00:00 2001 From: Peter KW Date: Thu, 21 Mar 2024 03:37:37 +0100 Subject: [PATCH 08/23] Add user to project component --- frontend/src/Components/AddUserToProject.tsx | 132 +++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 frontend/src/Components/AddUserToProject.tsx diff --git a/frontend/src/Components/AddUserToProject.tsx b/frontend/src/Components/AddUserToProject.tsx new file mode 100644 index 0000000..debd0f9 --- /dev/null +++ b/frontend/src/Components/AddUserToProject.tsx @@ -0,0 +1,132 @@ +import { useState } from "react"; +import { APIResponse, api } from "../API/API"; +import { NewProjMember } from "../Types/goTypes"; +import Logo from "../assets/Logo.svg"; +import Button from "./Button"; +import GetAllUsers from "./GetAllUsers"; + +/** + * Tries to add a member to a project + * @param {Object} props - A NewProjMember + * @returns {boolean} True if added, false if not + */ +function MemberAdd(props: { memberToAdd: NewProjMember }): boolean { + let added = false; + + api + .addUserToProject( + props.memberToAdd, + localStorage.getItem("accessToken") ?? "", + ) + .then((response: APIResponse) => { + if (response.success) { + added = true; + } else { + console.error(response.message); + } + }) + .catch((error) => { + console.error("An error occurred during member add:", error); + }); + return added; +} + +/** + * Provides UI for adding a project to the system. + * @returns {JSX.Element} - Returns the component UI for adding a project + */ +function AddUserToProject(): JSX.Element { + const [name, setName] = useState(""); + const [users, setUsers] = useState([]); + const [role, setRole] = useState(""); + GetAllUsers({ setUsersProp: setUsers }); + + const handleClick = (): boolean => { + const newMember: NewProjMember = { + username: name, + projectname: localStorage.getItem("projectName") ?? "", + role: "user", + }; + return MemberAdd({ memberToAdd: newMember }); + }; + + return ( +
+
+
{ + e.preventDefault(); + MemberAdd({ + memberToAdd: { + username: "", + projectname: "", + role: "project_manager", + }, + }); + }} + > + TTIME Logo +

+ Add {name} to {localStorage.getItem("projectName") ?? ""} as {role} +

+

Role for user:

+
+
    +
  • { + setRole("user"); + }} + > + {"User"} +
  • +
  • { + setRole("project_manager"); + }} + > + {"Project manager"} +
  • +
+
+

User to add:

+
+
    +
    + {users.map((user) => ( +
  • { + setName(user); + }} + > + {user} +
  • + ))} +
+
+
+
+
+

+
+
+ ); +} + +export default AddUserToProject; From b2db9c54ca78a1fd0499e441630895f2a39ace91 Mon Sep 17 00:00:00 2001 From: Peter KW Date: Thu, 21 Mar 2024 03:39:18 +0100 Subject: [PATCH 09/23] Add member functionality added --- frontend/src/Components/ProjectInfoModal.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frontend/src/Components/ProjectInfoModal.tsx b/frontend/src/Components/ProjectInfoModal.tsx index b153e9c..4d79cac 100644 --- a/frontend/src/Components/ProjectInfoModal.tsx +++ b/frontend/src/Components/ProjectInfoModal.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import Button from "./Button"; import { UserProjectMember } from "../Types/goTypes"; import GetUsersInProject from "./GetUsersInProject"; +import { Link } from "react-router-dom"; function ProjectInfoModal(props: { isVisible: boolean; @@ -50,6 +51,16 @@ function ProjectInfoModal(props: { }} type="button" /> + +