Merge branch 'frontend' into gruppDM
This commit is contained in:
commit
544383809b
14 changed files with 346 additions and 138 deletions
|
@ -17,6 +17,7 @@ type Database interface {
|
|||
AddUser(username string, password string) error
|
||||
CheckUser(username string, password string) bool
|
||||
RemoveUser(username string) error
|
||||
RemoveUserFromProject(username string, projectname string) error
|
||||
PromoteToAdmin(username string) error
|
||||
GetUserId(username string) (int, error)
|
||||
AddProject(name string, description string, username string) error
|
||||
|
@ -43,6 +44,7 @@ type Database interface {
|
|||
GetProjectTimes(projectName string) (map[string]int, error)
|
||||
UpdateWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error
|
||||
RemoveProject(projectname string) error
|
||||
GetUserName(id int) (string, error)
|
||||
}
|
||||
|
||||
// This struct is a wrapper type that holds the database connection
|
||||
|
@ -86,6 +88,10 @@ const isProjectManagerQuery = `SELECT COUNT(*) > 0 FROM user_roles
|
|||
JOIN projects ON user_roles.project_id = projects.id
|
||||
WHERE users.username = ? AND projects.name = ? AND user_roles.p_role = 'project_manager'`
|
||||
|
||||
const removeUserFromProjectQuery = `DELETE FROM user_roles
|
||||
WHERE user_id = (SELECT id FROM users WHERE username = ?)
|
||||
AND project_id = (SELECT id FROM projects WHERE name = ?)`
|
||||
|
||||
// DbConnect connects to the database
|
||||
func DbConnect(dbpath string) Database {
|
||||
// Open the database
|
||||
|
@ -147,6 +153,11 @@ func (d *Db) AddUserToProject(username string, projectname string, role string)
|
|||
return err
|
||||
}
|
||||
|
||||
func (d *Db) RemoveUserFromProject(username string, projectname string) error {
|
||||
_, err := d.Exec(removeUserFromProjectQuery, username, projectname)
|
||||
return err
|
||||
}
|
||||
|
||||
// ChangeUserRole changes the role of a user within a project.
|
||||
func (d *Db) ChangeUserRole(username string, projectname string, role string) error {
|
||||
// Execute the SQL query to change the user's role
|
||||
|
@ -601,3 +612,9 @@ func (d *Db) RemoveProject(projectname string) error {
|
|||
_, err := d.Exec("DELETE FROM projects WHERE name = ?", projectname)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Db) GetUserName(id int) (string, error) {
|
||||
var username string
|
||||
err := d.Get(&username, "SELECT username FROM users WHERE id = ?", id)
|
||||
return username, err
|
||||
}
|
||||
|
|
40
backend/internal/handlers/projects/RemoveUserFromProject.go
Normal file
40
backend/internal/handlers/projects/RemoveUserFromProject.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package projects
|
||||
|
||||
import (
|
||||
db "ttime/internal/database"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/log"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
func RemoveUserFromProject(c *fiber.Ctx) error {
|
||||
user := c.Locals("user").(*jwt.Token)
|
||||
claims := user.Claims.(jwt.MapClaims)
|
||||
pm_name := claims["name"].(string)
|
||||
|
||||
project := c.Params("projectName")
|
||||
username := c.Query("userName")
|
||||
|
||||
// Check if the user is a project manager
|
||||
isPM, err := db.GetDb(c).IsProjectManager(pm_name, project)
|
||||
if err != nil {
|
||||
log.Info("Error checking if user is project manager:", err)
|
||||
return c.Status(500).SendString(err.Error())
|
||||
}
|
||||
|
||||
if !isPM {
|
||||
log.Info("User: ", pm_name, " is not a project manager in project: ", project)
|
||||
return c.Status(403).SendString("User is not a project manager")
|
||||
}
|
||||
|
||||
// Remove the user from the project
|
||||
if err = db.GetDb(c).RemoveUserFromProject(username, project); err != nil {
|
||||
log.Info("Error removing user from project:", err)
|
||||
return c.Status(500).SendString(err.Error())
|
||||
}
|
||||
|
||||
// Return success message
|
||||
log.Info("User : ", username, " removed from project: ", project)
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
32
backend/internal/handlers/users/GetUserName.go
Normal file
32
backend/internal/handlers/users/GetUserName.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
db "ttime/internal/database"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// Return the username of a user given their user id
|
||||
func GetUserName(c *fiber.Ctx) error {
|
||||
// Check the query params for userId
|
||||
user_id_string := c.Query("userId")
|
||||
if user_id_string == "" {
|
||||
return c.Status(400).SendString("Missing user id")
|
||||
}
|
||||
|
||||
// Convert to int
|
||||
user_id, err := strconv.Atoi(user_id_string)
|
||||
if err != nil {
|
||||
return c.Status(400).SendString("Invalid user id")
|
||||
}
|
||||
|
||||
// Get the username from the database
|
||||
username, err := db.GetDb(c).GetUserName(user_id)
|
||||
if err != nil {
|
||||
return c.Status(500).SendString(err.Error())
|
||||
}
|
||||
|
||||
// Send the nuclear launch codes to north korea
|
||||
return c.JSON(fiber.Map{"username": username})
|
||||
}
|
|
@ -103,6 +103,7 @@ func main() {
|
|||
// userGroup := api.Group("/user") // Not currently in use
|
||||
api.Get("/users/all", users.ListAllUsers)
|
||||
api.Get("/project/getAllUsers", users.GetAllUsersProject)
|
||||
api.Get("/username", users.GetUserName)
|
||||
api.Post("/login", users.Login)
|
||||
api.Post("/register", users.Register)
|
||||
api.Post("/loginrenew", users.LoginRenew)
|
||||
|
@ -121,6 +122,7 @@ func main() {
|
|||
api.Post("/ProjectRoleChange", projects.ProjectRoleChange)
|
||||
api.Put("/promoteToPm/:projectName", projects.PromoteToPm)
|
||||
api.Put("/addUserToProject/:projectName", projects.AddUserToProjectHandler)
|
||||
api.Delete("/removeUserFromProject/:projectName", projects.RemoveUserFromProject)
|
||||
api.Delete("/removeProject/:projectName", projects.RemoveProject)
|
||||
api.Delete("/project/:projectID", projects.DeleteProject)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { NewProjMember } from "../Components/AddMember";
|
||||
import { AddMemberInfo } from "../Components/AddMember";
|
||||
import { ProjectRoleChange } from "../Components/ChangeRole";
|
||||
import { projectTimes } from "../Components/GetProjectTimes";
|
||||
import { ProjectMember } from "../Components/GetUsersInProject";
|
||||
|
@ -197,7 +197,13 @@ interface API {
|
|||
): Promise<APIResponse<void>>;
|
||||
|
||||
addUserToProject(
|
||||
user: NewProjMember,
|
||||
addMemberInfo: AddMemberInfo,
|
||||
token: string,
|
||||
): Promise<APIResponse<void>>;
|
||||
|
||||
removeUserFromProject(
|
||||
user: string,
|
||||
project: string,
|
||||
token: string,
|
||||
): Promise<APIResponse<void>>;
|
||||
|
||||
|
@ -227,6 +233,12 @@ interface API {
|
|||
projectName: string,
|
||||
token: string,
|
||||
): Promise<APIResponse<string>>;
|
||||
/**
|
||||
* Get the username from the id
|
||||
* @param {number} id The id of the user
|
||||
* @param {string} token Your token
|
||||
*/
|
||||
getUsername(id: number, token: string): Promise<APIResponse<string>>;
|
||||
}
|
||||
|
||||
/** An instance of the API */
|
||||
|
@ -336,18 +348,20 @@ export const api: API = {
|
|||
},
|
||||
|
||||
async addUserToProject(
|
||||
user: NewProjMember,
|
||||
addMemberInfo: AddMemberInfo,
|
||||
token: string,
|
||||
): Promise<APIResponse<void>> {
|
||||
try {
|
||||
const response = await fetch("/api/addUserToProject", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer " + token,
|
||||
const response = await fetch(
|
||||
`/api/addUserToProject/${addMemberInfo.projectName}/?userName=${addMemberInfo.userName}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer " + token,
|
||||
},
|
||||
},
|
||||
body: JSON.stringify(user),
|
||||
});
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
return { success: false, message: "Failed to add member" };
|
||||
|
@ -359,6 +373,31 @@ export const api: API = {
|
|||
}
|
||||
},
|
||||
|
||||
async removeUserFromProject(
|
||||
user: string,
|
||||
project: string,
|
||||
token: string,
|
||||
): Promise<APIResponse<void>> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/removeUserFromProject/${project}?userName=${user}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer " + token,
|
||||
},
|
||||
},
|
||||
);
|
||||
if (!response.ok) {
|
||||
return { success: false, message: "Failed to remove member" };
|
||||
}
|
||||
} catch (e) {
|
||||
return { success: false, message: "Failed to remove member" };
|
||||
}
|
||||
return { success: true, message: "Removed member" };
|
||||
},
|
||||
|
||||
async renewToken(token: string): Promise<APIResponse<string>> {
|
||||
try {
|
||||
const response = await fetch("/api/loginrenew", {
|
||||
|
@ -837,4 +876,25 @@ export const api: API = {
|
|||
}
|
||||
return { success: true, message: "User promoted to project manager" };
|
||||
},
|
||||
|
||||
async getUsername(id: number, token: string): Promise<APIResponse<string>> {
|
||||
try {
|
||||
const response = await fetch(`/api/username?userId=${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer " + token,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return { success: false, message: "Failed to get username" };
|
||||
} else {
|
||||
const data = (await response.json()) as string;
|
||||
return { success: true, data };
|
||||
}
|
||||
} catch (e) {
|
||||
return { success: false, message: "Failed to get username" };
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,44 +1,35 @@
|
|||
import { APIResponse, api } from "../API/API";
|
||||
import { api } from "../API/API";
|
||||
|
||||
export interface NewProjMember {
|
||||
username: string;
|
||||
role: string;
|
||||
projectname: string;
|
||||
export interface AddMemberInfo {
|
||||
userName: string;
|
||||
projectName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to add a member to a project
|
||||
* @param {Object} props - A NewProjMember
|
||||
* @returns {boolean} True if added, false if not
|
||||
* @param {AddMemberInfo} props.membertoAdd - Contains user's name and project's name
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
function AddMember(props: { memberToAdd: NewProjMember }): boolean {
|
||||
let added = false;
|
||||
if (
|
||||
props.memberToAdd.username === "" ||
|
||||
props.memberToAdd.role === "" ||
|
||||
props.memberToAdd.projectname === ""
|
||||
) {
|
||||
alert("All fields must be filled before adding");
|
||||
return added;
|
||||
async function AddMember(props: { memberToAdd: AddMemberInfo }): Promise<void> {
|
||||
if (props.memberToAdd.userName === "") {
|
||||
alert("You must choose at least one user to add");
|
||||
return;
|
||||
}
|
||||
api
|
||||
.addUserToProject(
|
||||
try {
|
||||
const response = await api.addUserToProject(
|
||||
props.memberToAdd,
|
||||
localStorage.getItem("accessToken") ?? "",
|
||||
)
|
||||
.then((response: APIResponse<void>) => {
|
||||
if (response.success) {
|
||||
alert("Member added");
|
||||
added = true;
|
||||
} else {
|
||||
alert("Member not added");
|
||||
console.error(response.message);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("An error occurred during member add:", error);
|
||||
});
|
||||
return added;
|
||||
);
|
||||
if (response.success) {
|
||||
alert(`[${props.memberToAdd.userName}] added`);
|
||||
} else {
|
||||
alert(`[${props.memberToAdd.userName}] not added`);
|
||||
console.error(response.message);
|
||||
}
|
||||
} catch (error) {
|
||||
alert(`[${props.memberToAdd.userName}] not added`);
|
||||
console.error("An error occurred during member add:", error);
|
||||
}
|
||||
}
|
||||
|
||||
export default AddMember;
|
||||
|
|
|
@ -1,37 +1,10 @@
|
|||
import { useState } from "react";
|
||||
import { APIResponse, api } from "../API/API";
|
||||
import { api } from "../API/API";
|
||||
import { NewProject } from "../Types/goTypes";
|
||||
import InputField from "./InputField";
|
||||
import Logo from "../assets/Logo.svg";
|
||||
import Button from "./Button";
|
||||
|
||||
/**
|
||||
* Tries to add a project to the system
|
||||
* @param {Object} props - Project name and description
|
||||
* @returns {boolean} True if created, false if not
|
||||
*/
|
||||
function CreateProject(props: { name: string; description: string }): void {
|
||||
const project: NewProject = {
|
||||
name: props.name,
|
||||
description: props.description,
|
||||
};
|
||||
|
||||
api
|
||||
.createProject(project, localStorage.getItem("accessToken") ?? "")
|
||||
.then((response: APIResponse<void>) => {
|
||||
if (response.success) {
|
||||
alert("Project added!");
|
||||
} else {
|
||||
alert("Project NOT added!");
|
||||
console.error(response.message);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert("Project NOT added!");
|
||||
console.error("An error occurred during creation:", error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides UI for adding a project to the system.
|
||||
* @returns {JSX.Element} - Returns the component UI for adding a project
|
||||
|
@ -40,6 +13,33 @@ function AddProject(): JSX.Element {
|
|||
const [name, setName] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
|
||||
/**
|
||||
* Tries to add a project to the system
|
||||
*/
|
||||
const handleCreateProject = async (): Promise<void> => {
|
||||
const project: NewProject = {
|
||||
name: name.replace(/ /g, ""),
|
||||
description: description.trim(),
|
||||
};
|
||||
try {
|
||||
const response = await api.createProject(
|
||||
project,
|
||||
localStorage.getItem("accessToken") ?? "",
|
||||
);
|
||||
if (response.success) {
|
||||
alert(`${project.name} added!`);
|
||||
setDescription("");
|
||||
setName("");
|
||||
} else {
|
||||
alert("Project not added, name could be taken");
|
||||
console.error(response.message);
|
||||
}
|
||||
} catch (error) {
|
||||
alert("Project not added");
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-fit w-screen items-center justify-center">
|
||||
<div className="border-4 border-black bg-white flex flex-col items-center justify-center h-fit w-fit rounded-3xl content-center pl-20 pr-20">
|
||||
|
@ -47,10 +47,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,
|
||||
});
|
||||
void handleCreateProject();
|
||||
}}
|
||||
>
|
||||
<img
|
||||
|
|
|
@ -1,71 +1,86 @@
|
|||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import Button from "./Button";
|
||||
import GetAllUsers from "./GetAllUsers";
|
||||
import AddMember, { NewProjMember } from "./AddMember";
|
||||
import AddMember, { AddMemberInfo } from "./AddMember";
|
||||
import BackButton from "./BackButton";
|
||||
import GetUsersInProject, { ProjectMember } from "./GetUsersInProject";
|
||||
import GetAllUsers from "./GetAllUsers";
|
||||
|
||||
/**
|
||||
* Provides UI for adding a member to a project.
|
||||
* @returns {JSX.Element} - Returns the component UI for adding a member
|
||||
*/
|
||||
function AddUserToProject(props: { projectName: string }): JSX.Element {
|
||||
const [name, setName] = useState("");
|
||||
const [names, setNames] = useState<string[]>([]);
|
||||
const [users, setUsers] = useState<string[]>([]);
|
||||
const [role, setRole] = useState("");
|
||||
GetAllUsers({ setUsersProp: setUsers });
|
||||
const [usersProj, setUsersProj] = useState<ProjectMember[]>([]);
|
||||
|
||||
const handleClick = (): boolean => {
|
||||
const newMember: NewProjMember = {
|
||||
username: name,
|
||||
projectname: props.projectName,
|
||||
role: role,
|
||||
};
|
||||
return AddMember({ memberToAdd: newMember });
|
||||
// Gets all users and project members for filtering
|
||||
GetAllUsers({ setUsersProp: setUsers });
|
||||
GetUsersInProject({
|
||||
setUsersProp: setUsersProj,
|
||||
projectName: props.projectName,
|
||||
});
|
||||
/*
|
||||
* Filters the members from users so that users who are already
|
||||
* members are not shown
|
||||
*/
|
||||
useEffect(() => {
|
||||
setUsers((prevUsers) => {
|
||||
const filteredUsers = prevUsers.filter(
|
||||
(user) =>
|
||||
!usersProj.some((projectUser) => projectUser.Username === user),
|
||||
);
|
||||
return filteredUsers;
|
||||
});
|
||||
}, [usersProj]);
|
||||
|
||||
// Attempts to add all of the selected users to the project
|
||||
const handleAddClick = async (): Promise<void> => {
|
||||
if (names.length === 0)
|
||||
alert("You have to choose at least one user to add");
|
||||
for (const name of names) {
|
||||
const newMember: AddMemberInfo = {
|
||||
userName: name,
|
||||
projectName: props.projectName,
|
||||
};
|
||||
await AddMember({ memberToAdd: newMember });
|
||||
}
|
||||
setNames([]);
|
||||
location.reload();
|
||||
};
|
||||
|
||||
// Updates the names that have been selected
|
||||
const handleUserClick = (user: string): void => {
|
||||
setNames((prevNames): string[] => {
|
||||
if (!prevNames.includes(user)) {
|
||||
return [...prevNames, user];
|
||||
}
|
||||
return prevNames.filter((name) => name !== user);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="border-4 border-black bg-white flex flex-col items-center justify-center rounded-3xl content-center pl-20 pr-20 h-[75vh] w-[50vh]">
|
||||
<p className="pb-4 mb-2 text-center font-bold text-[18px]">
|
||||
User chosen: [{name}]
|
||||
<div className="border-4 border-black bg-white flex flex-col items-center pt-10 rounded-3xl content-center pl-20 pr-20 h-[63vh] w-[50] overflow-auto">
|
||||
<h1 className="text-center font-bold text-[36px] pb-10">
|
||||
{props.projectName}
|
||||
</h1>
|
||||
<p className="p-1 text-center font-bold text-[26px]">
|
||||
Choose users to add:
|
||||
</p>
|
||||
<p className="pb-4 mb-2 text-center font-bold text-[18px]">
|
||||
Role chosen: [{role}]
|
||||
</p>
|
||||
<p className="pb-4 mb-2 text-center font-bold text-[18px]">
|
||||
Project chosen: [{props.projectName}]
|
||||
</p>
|
||||
<p className="p-1">Choose role:</p>
|
||||
<div className="border-2 border-black p-2 rounded-xl text-center h-[10h] w-[16] overflow-auto">
|
||||
<ul className="text-center items-center font-medium space-y-2">
|
||||
<li
|
||||
className="h-[10] w-[14] items-start px-2 py-1 border-2 border-black rounded-full bg-orange-200 hover:bg-orange-600 hover:text-slate-100 hover:cursor-pointer"
|
||||
onClick={() => {
|
||||
setRole("member");
|
||||
}}
|
||||
>
|
||||
{"Member"}
|
||||
</li>
|
||||
<li
|
||||
className="h-[10] w-[14] items-start px-2 py-1 border-2 border-black rounded-full bg-orange-200 hover:bg-orange-600 hover:text-slate-100 hover:cursor-pointer"
|
||||
onClick={() => {
|
||||
setRole("project_manager");
|
||||
}}
|
||||
>
|
||||
{"Project manager"}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p className="p-1">Choose user:</p>
|
||||
<div className="border-2 border-black p-2 rounded-xl text-center overflow-scroll h-[26vh] w-[26vh]">
|
||||
<div className="border-2 border-black pl-2 pr-2 pb-2 rounded-xl text-center overflow-auto h-[26vh] w-[26vh]">
|
||||
<ul className="text-center font-medium space-y-2">
|
||||
<div></div>
|
||||
{users.map((user) => (
|
||||
<li
|
||||
className="items-start p-1 border-2 border-black rounded-full bg-orange-200 hover:bg-orange-600 hover:text-slate-100 hover:cursor-pointer"
|
||||
className={
|
||||
names.includes(user)
|
||||
? "items-start p-1 border-2 border-transparent rounded-full bg-orange-500 hover:bg-orange-600 text-white hover:cursor-pointer ring-2 ring-black"
|
||||
: "items-start p-1 border-2 border-black rounded-full bg-orange-200 hover:bg-orange-400 hover:text-slate-100 hover:cursor-pointer"
|
||||
}
|
||||
key={user}
|
||||
value={user}
|
||||
onClick={() => {
|
||||
setName(user);
|
||||
handleUserClick(user);
|
||||
}}
|
||||
>
|
||||
<span>{user}</span>
|
||||
|
@ -73,13 +88,16 @@ function AddUserToProject(props: { projectName: string }): JSX.Element {
|
|||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="flex space-x-5 items-center justify-between">
|
||||
<p className="pt-10 pb-5 underline text-center font-bold text-[18px]">
|
||||
Number of users to be added: {names.length}
|
||||
</p>
|
||||
<div className="space-x-10 items-center">
|
||||
<Button
|
||||
text="Add"
|
||||
onClick={(): void => {
|
||||
handleClick();
|
||||
void handleAddClick();
|
||||
}}
|
||||
type="submit"
|
||||
type="button"
|
||||
/>
|
||||
<BackButton />
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useState } from "react";
|
|||
import Button from "./Button";
|
||||
import ChangeRole, { ProjectRoleChange } from "./ChangeRole";
|
||||
|
||||
export default function ChangeRoles(props: {
|
||||
export default function ChangeRoleView(props: {
|
||||
projectName: string;
|
||||
username: string;
|
||||
}): JSX.Element {
|
||||
|
|
|
@ -2,8 +2,11 @@ import { APIResponse, api } from "../API/API";
|
|||
import { StrNameChange } from "../Types/goTypes";
|
||||
|
||||
function ChangeUsername(props: { nameChange: StrNameChange }): void {
|
||||
if (props.nameChange.newName === "") {
|
||||
alert("You have to select a new name");
|
||||
if (
|
||||
props.nameChange.newName === "" ||
|
||||
props.nameChange.newName === props.nameChange.prevName
|
||||
) {
|
||||
alert("You have to give a new name\n\nName not changed");
|
||||
return;
|
||||
}
|
||||
api
|
||||
|
@ -13,7 +16,7 @@ function ChangeUsername(props: { nameChange: StrNameChange }): void {
|
|||
alert("Name changed successfully");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Name not changed");
|
||||
alert("Name not changed, name could be taken");
|
||||
console.error(response.message);
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import Button from "./Button";
|
||||
import DeleteUser from "./DeleteUser";
|
||||
import UserProjectListAdmin from "./UserProjectListAdmin";
|
||||
import { useState } from "react";
|
||||
import ChangeRoleView from "./ChangeRoleView";
|
||||
import RemoveUserFromProj from "./RemoveUserFromProj";
|
||||
|
||||
function MemberInfoModal(props: {
|
||||
projectName: string;
|
||||
|
@ -20,7 +20,7 @@ function MemberInfoModal(props: {
|
|||
};
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm
|
||||
className="fixed inset-10 bg-opacity-30 backdrop-blur-sm
|
||||
flex justify-center items-center"
|
||||
>
|
||||
<div className="border-4 border-black bg-white rounded-lg text-center flex flex-col">
|
||||
|
@ -42,13 +42,16 @@ function MemberInfoModal(props: {
|
|||
<UserProjectListAdmin username={props.username} />
|
||||
<div className="items-center space-x-6">
|
||||
<Button
|
||||
text={"Delete"}
|
||||
text={"Remove"}
|
||||
onClick={function (): void {
|
||||
if (
|
||||
window.confirm("Are you sure you want to delete this user?")
|
||||
window.confirm(
|
||||
"Are you sure you want to remove this user from the project?",
|
||||
)
|
||||
) {
|
||||
DeleteUser({
|
||||
usernameToDelete: props.username,
|
||||
RemoveUserFromProj({
|
||||
userToRemove: props.username,
|
||||
projectName: props.projectName,
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -15,17 +15,21 @@ export default function Register(): JSX.Element {
|
|||
const [errMessage, setErrMessage] = useState<string>();
|
||||
|
||||
const handleRegister = async (): Promise<void> => {
|
||||
if (username === "" || password === "") {
|
||||
alert("Must provide username and password");
|
||||
return;
|
||||
}
|
||||
const newUser: NewUser = {
|
||||
username: username ?? "",
|
||||
username: username?.replace(/ /g, "") ?? "",
|
||||
password: password ?? "",
|
||||
};
|
||||
const response = await api.registerUser(newUser);
|
||||
if (response.success) {
|
||||
alert("User added!");
|
||||
alert(`${newUser.username} added!`);
|
||||
setPassword("");
|
||||
setUsername("");
|
||||
} else {
|
||||
alert("User not added");
|
||||
alert("User not added, name could be taken");
|
||||
setErrMessage(response.message ?? "Unknown error");
|
||||
console.error(errMessage);
|
||||
}
|
||||
|
|
41
frontend/src/Components/RemoveUserFromProj.tsx
Normal file
41
frontend/src/Components/RemoveUserFromProj.tsx
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { api, APIResponse } from "../API/API";
|
||||
|
||||
/**
|
||||
* Removes a user from a project
|
||||
* @param {string} props.usernameToDelete - The username of user to remove
|
||||
* @param {string} props.projectName - Project to remove user from
|
||||
* @returns {void}
|
||||
* @example
|
||||
* const exampleUsername = "user";
|
||||
* const exampleProjectName "project";
|
||||
* RemoveUserFromProj({ userToRemove: exampleUsername, projectName: exampleProjectName });
|
||||
*/
|
||||
|
||||
export default function RemoveUserFromProj(props: {
|
||||
userToRemove: string;
|
||||
projectName: string;
|
||||
}): void {
|
||||
if (props.userToRemove === localStorage.getItem("username")) {
|
||||
alert("Cannot remove yourself");
|
||||
return;
|
||||
}
|
||||
api
|
||||
.removeUserFromProject(
|
||||
props.userToRemove,
|
||||
props.projectName,
|
||||
localStorage.getItem("accessToken") ?? "",
|
||||
)
|
||||
.then((response: APIResponse<void>) => {
|
||||
if (response.success) {
|
||||
alert(`${props.userToRemove} has been removed!`);
|
||||
location.reload();
|
||||
} else {
|
||||
alert(`${props.userToRemove} has not been removed due to an error`);
|
||||
console.error(response.message);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert(`${props.userToRemove} has not been removed due to an error`);
|
||||
console.error("An error occurred during deletion:", error);
|
||||
});
|
||||
}
|
|
@ -28,7 +28,7 @@ function UserInfoModal(props: {
|
|||
const handleClickChangeName = (): void => {
|
||||
const nameChange: StrNameChange = {
|
||||
prevName: props.username,
|
||||
newName: newUsername,
|
||||
newName: newUsername.replace(/ /g, ""),
|
||||
};
|
||||
ChangeUsername({ nameChange: nameChange });
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue