Compare commits

..

No commits in common. "d9af77a8f776878596c1b2a9cbcfc32887b53a2f" and "db6fdf3c2914fb5afd9890d0b180429726406434" have entirely different histories.

17 changed files with 165 additions and 490 deletions

View file

@ -1,220 +1,58 @@
INSERT OR IGNORE INTO users(username, password) INSERT OR IGNORE INTO users(username, password)
VALUES ("admin", "123"), VALUES ("admin", "123");
("user", "123"),
("user2", "123"),
("John", "123"),
("Emma", "123"),
("Michael", "123"),
("Liam", "123"),
("Oliver", "123"),
("Amelia", "123"),
("Benjamin", "123"),
("Mia", "123"),
("Elijah", "123"),
("Charlotte", "123"),
("Henry", "123"),
("Harper", "123"),
("Lucas", "123"),
("Emily", "123"),
("Alexander", "123"),
("Daniel", "123"),
("Ella", "123"),
("Matthew", "123"),
("Madison", "123"),
("Samuel", "123"),
("Avery", "123"),
("Sofia", "123"),
("David", "123"),
("Victoria", "123"),
("Jackson", "123"),
("Abigail", "123"),
("Gabriel", "123"),
("Luna", "123"),
("Wyatt", "123"),
("Chloe", "123"),
("Nora", "123"),
("Joshua", "123"),
("Hazel", "123"),
("Riley", "123"),
("Scarlett", "123"),
("Aria", "123"),
("Carter", "123"),
("Grace", "123"),
("Jayden", "123"),
("Hannah", "123"),
("Zoe", "123"),
("Luke", "123"),
("Sophia", "123"),
("Jack", "123"),
("Isabella", "123"),
("William", "123"),
("Mason", "123"),
("Evelyn", "123"),
("James", "123"),
("Cynthia", "123"),
("Abraham", "123"),
("Ava", "123"),
("Aiden", "123"),
("Natalie", "123"),
("Lily", "123"),
("Olivia", "123"),
("Alexander", "123"),
("Ethan", "123"),
("Mila", "123"),
("Evelyn", "123"),
("Logan", "123"),
("Riley", "123"),
("Grace", "123"),
("Arnold", "123"),
("Connor", "123"),
("Samantha", "123"),
("Emma", "123"),
("Sarah", "123"),
("Nathan", "123"),
("Layla", "123"),
("Ryan", "123"),
("Zoey", "123"),
("Megan", "123"),
("Christian", "123"),
("Eva", "123"),
("Isaac", "123"),
("Michaela", "123"),
("Caroline", "123"),
("Elijah", "123"),
("Elena", "123"),
("Julian", "123"),
("Sophie", "123"),
("Gabriella", "123"),
("Cole", "123"),
("Hannah", "123"),
("Lucy", "123"),
("Katherine", "123"),
("Benjamin", "123"),
("Ella", "123"),
("Evan", "123");
INSERT OR IGNORE INTO projects(name, description, owner_user_id) INSERT OR IGNORE INTO users(username, password)
VALUES ("projecttest1", "Description for projecttest1", 1), VALUES ("user", "123");
("projecttest2", "Description for projecttest2", 1),
("projecttest3", "Description for projecttest3", 1), INSERT OR IGNORE INTO users(username, password)
("projecttest4", "Description for projecttest4", 1), VALUES ("user2", "123");
("projecttest5", "Description for projecttest5", 1),
("projecttest6", "Description for projecttest6", 1), INSERT OR IGNORE INTO site_admin VALUES (1);
("projecttest7", "Description for projecttest7", 1),
("projecttest8", "Description for projecttest8", 1), INSERT OR IGNORE INTO projects(name,description,owner_user_id)
("projecttest9", "Description for projecttest9", 1), VALUES ("projecttest","test project", 1);
("projecttest10", "Description for projecttest10", 1),
("projecttest11", "Description for projecttest11", 1), INSERT OR IGNORE INTO projects(name,description,owner_user_id)
("projecttest12", "Description for projecttest12", 1), VALUES ("projecttest2","test project2", 1);
("projecttest13", "Description for projecttest13", 1),
("projecttest14", "Description for projecttest14", 1), INSERT OR IGNORE INTO projects(name,description,owner_user_id)
("projecttest15", "Description for projecttest15", 1); VALUES ("projecttest3","test project3", 1);
INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role) INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role)
VALUES (1,1,"project_manager"), VALUES (1,1,"project_manager");
(1,2,"project_manager"),
(1,3,"project_manager"), INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role)
(1,4,"project_manager"), VALUES (1,2,"project_manager");
(1,5,"project_manager"),
(1,6,"project_manager"), INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role)
(1,7,"project_manager"), VALUES (1,3,"project_manager");
(1,8,"project_manager"),
(1,9,"project_manager"), INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role)
(1,10,"project_manager"), VALUES (2,1,"member");
(1,11,"project_manager"),
(1,12,"project_manager"), INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role)
(1,13,"project_manager"), VALUES (3,1,"member");
(1,14,"project_manager"),
(1,15,"project_manager"), INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role)
(2,1,"project_manager"), VALUES (3,2,"member");
(2,2,"member"),
(2,3,"member"), INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role)
(2,4,"member"), VALUES (3,3,"member");
(2,5,"member"),
(2,6,"member"), INSERT OR IGNORE INTO user_roles(user_id,project_id,p_role)
(2,7,"member"), VALUES (2,1,"project_manager");
(2,8,"member"),
(2,9,"member"),
(2,10,"member"),
(2,11,"member"),
(2,12,"member"),
(2,13,"member"),
(2,14,"member"),
(2,15,"member"),
(3,1,"member"),
(3,2,"member"),
(3,3,"member"),
(3,4,"member"),
(3,5,"member"),
(3,6,"member"),
(3,7,"member"),
(3,8,"member"),
(3,9,"member"),
(3,10,"member"),
(3,11,"member"),
(3,12,"member"),
(3,13,"member"),
(3,14,"member"),
(3,15,"member"),
(4,1,"member"),
(4,2,"member"),
(4,3,"member"),
(4,4,"member"),
(4,5,"member"),
(4,6,"member"),
(4,7,"member"),
(4,8,"member"),
(4,9,"member"),
(4,10,"member"),
(4,11,"member"),
(4,12,"member"),
(4,13,"member"),
(4,14,"member"),
(4,15,"member"),
(5,1,"member"),
(5,2,"member"),
(5,3,"member"),
(5,4,"member"),
(5,5,"member"),
(5,6,"member"),
(5,7,"member"),
(5,8,"member"),
(5,9,"member"),
(5,10,"member"),
(5,11,"member"),
(5,12,"member"),
(5,13,"member"),
(5,14,"member"),
(5,15,"member");
INSERT OR IGNORE INTO weekly_reports (user_id, project_id, week, development_time, meeting_time, admin_time, own_work_time, study_time, testing_time, signed_by) INSERT OR IGNORE INTO weekly_reports (user_id, project_id, week, development_time, meeting_time, admin_time, own_work_time, study_time, testing_time, signed_by)
VALUES (2, 1, 12, 100, 50, 30, 150, 80, 20, NULL), VALUES (2, 1, 12, 20, 10, 5, 30, 15, 10, NULL);
(3, 1, 12, 200, 80, 20, 200, 100, 30, NULL),
(3, 1, 14, 150, 70, 40, 180, 90, 25, NULL),
(3, 2, 12, 120, 60, 35, 160, 85, 15, NULL),
(3, 3, 12, 180, 90, 25, 190, 110, 40, NULL),
(2, 1, 13, 130, 70, 40, 170, 95, 35, NULL),
(3, 1, 15, 140, 60, 50, 200, 120, 30, NULL),
(2, 2, 11, 110, 50, 45, 140, 70, 25, NULL),
(3, 3, 14, 170, 80, 30, 180, 100, 35, NULL),
(3, 3, 15, 200, 100, 20, 220, 130, 45, NULL),
(2, 4, 12, 120, 60, 40, 160, 80, 30, NULL),
(3, 5, 14, 150, 70, 30, 180, 90, 25, NULL),
(3, 5, 15, 180, 90, 20, 190, 110, 35, NULL),
(2, 6, 11, 100, 50, 35, 130, 60, 20, NULL),
(3, 7, 14, 170, 80, 25, 180, 100, 30, NULL),
(2, 8, 12, 130, 70, 30, 170, 90, 25, NULL),
(2, 8, 13, 150, 80, 20, 180, 110, 35, NULL),
(3, 9, 12, 140, 60, 40, 180, 100, 30, NULL),
(3, 10, 11, 120, 50, 45, 150, 70, 25, NULL),
(2, 11, 13, 110, 60, 35, 140, 80, 30, NULL),
(3, 12, 12, 160, 70, 30, 180, 100, 35, NULL),
(3, 12, 13, 180, 90, 25, 190, 110, 40, NULL),
(3, 12, 14, 200, 100, 20, 220, 130, 45, NULL),
(2, 13, 11, 100, 50, 45, 130, 60, 20, NULL),
(2, 13, 12, 120, 60, 40, 160, 80, 30, NULL),
(3, 14, 13, 140, 70, 30, 160, 90, 35, NULL),
(3, 15, 12, 150, 80, 25, 180, 100, 30, NULL),
(3, 15, 13, 170, 90, 20, 190, 110, 35, NULL);
INSERT OR IGNORE INTO site_admin VALUES (1); INSERT OR IGNORE INTO weekly_reports (user_id, project_id, week, development_time, meeting_time, admin_time, own_work_time, study_time, testing_time, signed_by)
VALUES (3, 1, 12, 20, 10, 5, 30, 15, 10, NULL);
INSERT OR IGNORE INTO weekly_reports (user_id, project_id, week, development_time, meeting_time, admin_time, own_work_time, study_time, testing_time, signed_by)
VALUES (3, 1, 14, 20, 10, 5, 30, 15, 10, NULL);
INSERT OR IGNORE INTO weekly_reports (user_id, project_id, week, development_time, meeting_time, admin_time, own_work_time, study_time, testing_time, signed_by)
VALUES (3, 2, 12, 20, 10, 5, 30, 15, 10, NULL);
INSERT OR IGNORE INTO weekly_reports (user_id, project_id, week, development_time, meeting_time, admin_time, own_work_time, study_time, testing_time, signed_by)
VALUES (3, 3, 12, 20, 10, 5, 30, 15, 10, NULL);

View file

@ -67,7 +67,6 @@ function AddProject(): JSX.Element {
e.preventDefault(); e.preventDefault();
setName(e.target.value); setName(e.target.value);
}} }}
placeholder={"Name"}
/> />
<InputField <InputField
label="Description" label="Description"
@ -77,7 +76,6 @@ function AddProject(): JSX.Element {
e.preventDefault(); e.preventDefault();
setDescription(e.target.value); setDescription(e.target.value);
}} }}
placeholder={"Description"}
/> />
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">

View file

@ -1,9 +1,9 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import Button from "./Button"; import Button from "./Button";
import AddMember, { AddMemberInfo } from "./AddMember"; import AddMember, { AddMemberInfo } from "./AddMember";
import BackButton from "./BackButton";
import GetUsersInProject, { ProjectMember } from "./GetUsersInProject"; import GetUsersInProject, { ProjectMember } from "./GetUsersInProject";
import GetAllUsers from "./GetAllUsers"; import GetAllUsers from "./GetAllUsers";
import InputField from "./InputField";
/** /**
* Provides UI for adding a member to a project. * Provides UI for adding a member to a project.
@ -13,7 +13,6 @@ function AddUserToProject(props: { projectName: string }): JSX.Element {
const [names, setNames] = useState<string[]>([]); const [names, setNames] = useState<string[]>([]);
const [users, setUsers] = useState<string[]>([]); const [users, setUsers] = useState<string[]>([]);
const [usersProj, setUsersProj] = useState<ProjectMember[]>([]); const [usersProj, setUsersProj] = useState<ProjectMember[]>([]);
const [search, setSearch] = useState("");
// Gets all users and project members for filtering // Gets all users and project members for filtering
GetAllUsers({ setUsersProp: setUsers }); GetAllUsers({ setUsersProp: setUsers });
@ -37,10 +36,8 @@ function AddUserToProject(props: { projectName: string }): JSX.Element {
// Attempts to add all of the selected users to the project // Attempts to add all of the selected users to the project
const handleAddClick = async (): Promise<void> => { const handleAddClick = async (): Promise<void> => {
if (names.length === 0) { if (names.length === 0)
alert("You have to choose at least one user to add"); alert("You have to choose at least one user to add");
return;
}
for (const name of names) { for (const name of names) {
const newMember: AddMemberInfo = { const newMember: AddMemberInfo = {
userName: name, userName: name,
@ -63,47 +60,32 @@ function AddUserToProject(props: { projectName: string }): JSX.Element {
}; };
return ( return (
<div className="border-4 border-black bg-white flex flex-col items-center py-10 px-20 rounded-3xl content-center overflow-auto"> <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"> <h1 className="text-center font-bold text-[36px] pb-10">
{props.projectName} {props.projectName}
</h1> </h1>
<p className="p-1 text-center font-bold text-[26px]"> <p className="p-1 text-center font-bold text-[26px]">
Choose users to add: Choose users to add:
</p> </p>
<div className="border-2 border-black pl-2 pr-2 pb-2 rounded-xl text-center overflow-auto h-[26vh] w-[26vh]">
<div> <ul className="text-center font-medium space-y-2">
<InputField
placeholder={"Search users"}
type={"Text"}
value={search}
onChange={(e) => {
setSearch(e.target.value);
}}
/>
<ul className="font-medium space-y-2 border-2 border-black mt-2 px-2 pb-2 rounded-2xl text-center overflow-auto h-[26vh] w-[34vh]">
<div></div> <div></div>
{users {users.map((user) => (
.filter((user) => { <li
return search.toLowerCase() === "" className={
? user names.includes(user)
: user.toLowerCase().includes(search.toLowerCase()); ? "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"
.map((user) => ( }
<li key={user}
className={ value={user}
names.includes(user) onClick={() => {
? "items-start p-1 border-2 border-transparent rounded-full bg-orange-500 transition-all hover:bg-orange-600 text-white hover:cursor-pointer ring-2 ring-black" handleUserClick(user);
: "items-start p-1 border-2 border-black rounded-full bg-orange-200 hover:bg-orange-400 transition-all hover:text-white hover:cursor-pointer" }}
} >
key={user} <span>{user}</span>
value={user} </li>
onClick={() => { ))}
handleUserClick(user);
}}
>
<span>{user}</span>
</li>
))}
</ul> </ul>
</div> </div>
<p className="pt-10 pb-5 underline text-center font-bold text-[18px]"> <p className="pt-10 pb-5 underline text-center font-bold text-[18px]">
@ -117,7 +99,9 @@ function AddUserToProject(props: { projectName: string }): JSX.Element {
}} }}
type="button" type="button"
/> />
<BackButton />
</div> </div>
<p className="text-center text-gray-500 text-xs"></p>
</div> </div>
); );
} }

View file

@ -9,10 +9,6 @@ function ChangeUsername(props: { nameChange: StrNameChange }): void {
alert("You have to give a new name\n\nName not changed"); alert("You have to give a new name\n\nName not changed");
return; return;
} }
if (props.nameChange.prevName === localStorage.getItem("username")) {
alert("You cannot change admin name");
return;
}
api api
.changeUserName(props.nameChange, localStorage.getItem("accessToken") ?? "") .changeUserName(props.nameChange, localStorage.getItem("accessToken") ?? "")
.then((response: APIResponse<void>) => { .then((response: APIResponse<void>) => {

View file

@ -4,21 +4,19 @@
* @returns {JSX.Element} The input field * @returns {JSX.Element} The input field
* @example * @example
* <InputField * <InputField
* label="Example"
* placeholder="New placeholder"
* type="text" * type="text"
* value={example} * label="Example"
* onChange={(e) => { * onChange={(e) => {
* setExample(e.target.value); * setExample(e.target.value);
* }} * }}
* value={example}
* /> * />
*/ */
function InputField(props: { function InputField(props: {
label?: string; label: string;
placeholder?: string; type: string;
type?: string; value: string;
value?: string; onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
}): JSX.Element { }): JSX.Element {
return ( return (
<div className=""> <div className="">
@ -32,7 +30,7 @@ function InputField(props: {
className="appearance-none border-2 border-black rounded-2xl w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" className="appearance-none border-2 border-black rounded-2xl w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
id={props.label} id={props.label}
type={props.type} type={props.type}
placeholder={props.placeholder} placeholder={props.label}
value={props.value} value={props.value}
onChange={props.onChange} onChange={props.onChange}
/> />

View file

@ -11,10 +11,6 @@ function LoginCheck(props: {
password: string; password: string;
setAuthority: Dispatch<SetStateAction<number>>; setAuthority: Dispatch<SetStateAction<number>>;
}): void { }): void {
if (props.username === "" || props.password === "") {
alert("Please enter username and password to login");
return;
}
const user: NewUser = { const user: NewUser = {
username: props.username, username: props.username,
password: props.password, password: props.password,
@ -47,7 +43,6 @@ function LoginCheck(props: {
} }
} else { } else {
console.error("Token could not be fetched/No such user"); console.error("Token could not be fetched/No such user");
alert("Could not login, wrong username or password");
} }
}) })
.catch((error) => { .catch((error) => {

View file

@ -33,7 +33,6 @@ function Login(props: {
props.setUsername(e.target.value); props.setUsername(e.target.value);
}} }}
value={props.username} value={props.username}
placeholder={"Username"}
/> />
<InputField <InputField
type="password" type="password"
@ -42,7 +41,6 @@ function Login(props: {
props.setPassword(e.target.value); props.setPassword(e.target.value);
}} }}
value={props.password} value={props.password}
placeholder={"Password"}
/> />
</div> </div>
<Button <Button

View file

@ -23,7 +23,7 @@ function MemberInfoModal(props: {
className="fixed inset-10 bg-opacity-30 backdrop-blur-sm className="fixed inset-10 bg-opacity-30 backdrop-blur-sm
flex justify-center items-center" flex justify-center items-center"
> >
<div className="border-4 border-black bg-white rounded-2xl text-center flex flex-col"> <div className="border-4 border-black bg-white rounded-lg text-center flex flex-col">
<div className="mx-10"> <div className="mx-10">
<p className="font-bold text-[30px]">{props.username}</p> <p className="font-bold text-[30px]">{props.username}</p>
<p <p

View file

@ -4,47 +4,19 @@ import GetUsersInProject, { ProjectMember } from "./GetUsersInProject";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import GetProjectTimes, { projectTimes } from "./GetProjectTimes"; import GetProjectTimes, { projectTimes } from "./GetProjectTimes";
import DeleteProject from "./DeleteProject"; import DeleteProject from "./DeleteProject";
import InputField from "./InputField";
function ProjectInfoModal(props: { function ProjectInfoModal(props: {
projectname: string; projectname: string;
onClose: () => void; onClose: () => void;
onClick: (username: string) => void; onClick: (username: string) => void;
}): JSX.Element { }): JSX.Element {
const [showInput, setShowInput] = useState(false);
const [users, setUsers] = useState<ProjectMember[]>([]); const [users, setUsers] = useState<ProjectMember[]>([]);
const [times, setTimes] = useState<projectTimes>(); const [times, setTimes] = useState<projectTimes>();
const [search, setSearch] = useState("");
const [newProjName, setNewProjName] = useState("");
const totalTime = useRef(0); const totalTime = useRef(0);
GetUsersInProject({ projectName: props.projectname, setUsersProp: setUsers }); GetUsersInProject({ projectName: props.projectname, setUsersProp: setUsers });
GetProjectTimes({ setTimesProp: setTimes, projectName: props.projectname }); GetProjectTimes({ setTimesProp: setTimes, projectName: props.projectname });
const handleChangeNameView = (): void => {
if (showInput) {
setShowInput(false);
} else {
setShowInput(true);
}
};
const handleClickChangeName = (): void => {
if (newProjName === "") return;
if (
confirm(
`Are you sure you want to change name of ${props.projectname} to ${newProjName}?`,
)
) {
//TODO: change and insert change name functionality
alert("Not implemented yet");
setNewProjName("");
} else {
alert("Name was not changed!");
}
};
useEffect(() => { useEffect(() => {
if (times?.totalTime !== undefined) { if (times?.totalTime !== undefined) {
totalTime.current = times.totalTime; totalTime.current = times.totalTime;
@ -56,90 +28,44 @@ function ProjectInfoModal(props: {
className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm
flex justify-center items-center" flex justify-center items-center"
> >
<div className="border-4 border-black bg-white p-2 rounded-2xl text-center h-[64vh] w-[40] overflow-auto"> <div className="border-4 border-black bg-white p-2 rounded-2xl text-center h-[61vh] w-[40] overflow-auto">
<div className="pl-10 pr-10"> <div className="pl-10 pr-10">
<h1 className="font-bold text-[32px]">{props.projectname}</h1> <h1 className="font-bold text-[32px] mb-[20px]">
<p {props.projectname}
className="mb-4 hover:font-bold hover:cursor-pointer hover:underline" </h1>
onClick={handleChangeNameView} <div className="p-1 text-center">
> <h2 className="text-[20px] font-bold">Statistics:</h2>
(Change project name) </div>
</p> <div className="border-2 border-black rounded-lg h-[8vh] text-left divide-y-2 flex flex-col overflow-auto mx-10">
{showInput && ( <p className="p-2">Number of members: {users.length}</p>
<> <p className="p-2">
<h2 className="text-[20px] font-bold pb-2">Change name:</h2>
<div className="border-2 rounded-2xl border-black p-6 mb-7 space-y-4">
<InputField
type={"text"}
value={newProjName}
onChange={function (e): void {
setNewProjName(e.target.value);
}}
placeholder={"Project Name"}
/>
<div className="px-6 grid grid-cols-2 gap-10">
<Button
text={"Change"}
onClick={function (): void {
handleClickChangeName();
}}
type={"submit"}
/>
<Button
text={"Close"}
onClick={function (): void {
handleChangeNameView();
}}
type={"submit"}
/>
</div>
</div>
</>
)}
<h2 className="text-[20px] font-bold pb-2">Statistics:</h2>
<div className="border-2 border-black rounded-2xl px-2 py-1 text-left divide-y-2 flex flex-col overflow-auto">
<p>Number of members: {users.length}</p>
<p>
Total time reported:{" "} Total time reported:{" "}
{Math.floor(totalTime.current / 60 / 24) + " d "} {Math.floor(totalTime.current / 60 / 24) + " d "}
{Math.floor((totalTime.current / 60) % 24) + " h "} {Math.floor((totalTime.current / 60) % 24) + " h "}
{(totalTime.current % 60) + " m "} {(totalTime.current % 60) + " m "}
</p> </p>
</div> </div>
<h3 className="pt-7 text-[20px] font-bold">Project members:</h3> <div className="h-[6vh] p-7 text-center">
<div className=""> <h2 className="text-[20px] font-bold">Project members:</h2>
<InputField </div>
placeholder={"Search member"} <div className="border-2 border-black p-2 rounded-lg text-center overflow-auto h-[24vh] mx-10">
type={"Text"} <ul className="text-left font-medium space-y-2">
value={search} <div></div>
onChange={(e) => { {users.map((user) => (
setSearch(e.target.value); <li
}} className="items-start p-1 border-2 border-black rounded-lg bg-orange-200 hover:bg-orange-600 hover:text-slate-100 hover:cursor-pointer"
/> key={user.Username}
<ul className="border-2 border-black mt-2 p-2 rounded-2xl text-left overflow-auto h-[24vh] font-medium space-y-2"> onClick={() => {
{users props.onClick(user.Username);
.filter((user) => { }}
return search.toLowerCase() === "" >
? user.Username <span>
: user.Username.toLowerCase().includes( Name: {user.Username}
search.toLowerCase(), <div></div>
); Role: {user.UserRole}
}) </span>
.map((user) => ( </li>
<li ))}
className="items-start px-2 py-1 border-2 border-black rounded-2xl bg-orange-200 transition-all hover:bg-orange-600 hover:text-white hover:cursor-pointer"
key={user.Username}
onClick={() => {
props.onClick(user.Username);
}}
>
<span>
Name: {user.Username}
<div></div>
Role: {user.UserRole}
</span>
</li>
))}
</ul> </ul>
</div> </div>
<div className="space-x-5 my-2"> <div className="space-x-5 my-2">

View file

@ -2,7 +2,6 @@ import { useState } from "react";
import { NewProject } from "../Types/goTypes"; import { NewProject } from "../Types/goTypes";
import ProjectInfoModal from "./ProjectInfoModal"; import ProjectInfoModal from "./ProjectInfoModal";
import MemberInfoModal from "./MemberInfoModal"; import MemberInfoModal from "./MemberInfoModal";
import InputField from "./InputField";
/** /**
* A list of projects for admin manage projects page, that sets an onClick * A list of projects for admin manage projects page, that sets an onClick
@ -22,7 +21,6 @@ export function ProjectListAdmin(props: {
const [projectName, setProjectName] = useState(""); const [projectName, setProjectName] = useState("");
const [userModalVisible, setUserModalVisible] = useState(false); const [userModalVisible, setUserModalVisible] = useState(false);
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [search, setSearch] = useState("");
const handleClickUser = (username: string): void => { const handleClickUser = (username: string): void => {
setUsername(username); setUsername(username);
@ -46,7 +44,6 @@ export function ProjectListAdmin(props: {
return ( return (
<> <>
<h1 className="font-bold text-[30px] mb-[20px]">Manage Projects</h1>
{projectModalVisible && ( {projectModalVisible && (
<ProjectInfoModal <ProjectInfoModal
onClose={handleCloseProject} onClose={handleCloseProject}
@ -62,32 +59,18 @@ export function ProjectListAdmin(props: {
/> />
)} )}
<div> <div>
<InputField <ul className="font-bold underline text-[30px] cursor-pointer padding">
placeholder={"Search"} {props.projects.map((project) => (
type={"Text"} <li
value={search} className="pt-5"
onChange={(e) => { key={project.name}
setSearch(e.target.value); onClick={() => {
}} handleClickProject(project.name);
/> }}
<ul className="mt-3 border-2 text-left border-black rounded-2xl px-2 divide-y divide-gray-300 font-semibold text-[30px] cursor-pointer overflow-auto h-[65vh] w-[50vw]"> >
{props.projects {project.name}
.filter((project) => { </li>
return search.toLowerCase() === "" ))}
? project.name
: project.name.toLowerCase().includes(search.toLowerCase());
})
.map((project) => (
<li
className="hover:font-extrabold hover:underline p-1"
key={project.name}
onClick={() => {
handleClickProject(project.name);
}}
>
{project.name}
</li>
))}
</ul> </ul>
</div> </div>
</> </>

View file

@ -61,7 +61,6 @@ export default function Register(): JSX.Element {
onChange={(e) => { onChange={(e) => {
setUsername(e.target.value); setUsername(e.target.value);
}} }}
placeholder={"Username"}
/> />
<InputField <InputField
label="Password" label="Password"
@ -70,7 +69,6 @@ export default function Register(): JSX.Element {
onChange={(e) => { onChange={(e) => {
setPassword(e.target.value); setPassword(e.target.value);
}} }}
placeholder={"Password"}
/> />
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">

View file

@ -13,7 +13,6 @@ function UserInfoModal(props: {
}): JSX.Element { }): JSX.Element {
const [showInput, setShowInput] = useState(false); const [showInput, setShowInput] = useState(false);
const [newUsername, setNewUsername] = useState(""); const [newUsername, setNewUsername] = useState("");
const [newPassword, setNewPassword] = useState("");
if (!props.isVisible) { if (!props.isVisible) {
return <></>; return <></>;
} }
@ -27,34 +26,11 @@ function UserInfoModal(props: {
}; };
const handleClickChangeName = (): void => { const handleClickChangeName = (): void => {
if (newUsername === "") return; const nameChange: StrNameChange = {
if ( prevName: props.username,
confirm( newName: newUsername.replace(/ /g, ""),
`Do you really want to change username of ${props.username} to ${newUsername}?`, };
) ChangeUsername({ nameChange: nameChange });
) {
const nameChange: StrNameChange = {
prevName: props.username,
newName: newUsername.replace(/ /g, ""),
};
ChangeUsername({ nameChange: nameChange });
} else {
alert("Name was not changed!");
}
};
const handleClickChangePassword = (): void => {
if (newPassword === "") return;
if (
confirm(`Are you sure you want to change password of ${props.username}?`)
) {
//TODO: insert change password functionality
alert("Not implemented yet");
setNewPassword("");
} else {
alert("Password was not changed!");
}
}; };
return ( return (
@ -62,14 +38,14 @@ function UserInfoModal(props: {
className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm
flex justify-center items-center" flex justify-center items-center"
> >
<div className="border-4 border-black bg-white rounded-2xl text-center flex flex-col"> <div className="border-4 border-black bg-white rounded-lg text-center flex flex-col">
<div className="mx-10"> <div className="mx-10">
<p className="font-bold text-[30px]">{props.username}</p> <p className="font-bold text-[30px]">{props.username}</p>
<p <p
className="mb-[10px] hover:font-bold hover:cursor-pointer underline" className="mb-[10px] hover:font-bold hover:cursor-pointer underline"
onClick={handleChangeNameView} onClick={handleChangeNameView}
> >
(Change Username or Password) (Change Username)
</p> </p>
{showInput && ( {showInput && (
<div> <div>
@ -78,25 +54,14 @@ function UserInfoModal(props: {
type={"text"} type={"text"}
value={newUsername} value={newUsername}
onChange={function (e): void { onChange={function (e): void {
e.defaultPrevented;
setNewUsername(e.target.value); setNewUsername(e.target.value);
}} }}
placeholder={"Username"}
/>
<div className="m-4"></div>
<InputField
label={"New password"}
type={"password"}
value={newPassword}
onChange={function (e): void {
setNewPassword(e.target.value);
}}
placeholder={"Password"}
/> />
<Button <Button
text={"Change"} text={"Change"}
onClick={function (): void { onClick={function (): void {
handleClickChangeName(); handleClickChangeName();
handleClickChangePassword();
}} }}
type={"submit"} type={"submit"}
/> />

View file

@ -1,6 +1,5 @@
import { useState } from "react"; import { useState } from "react";
import UserInfoModal from "./UserInfoModal"; import UserInfoModal from "./UserInfoModal";
import InputField from "./InputField";
/** /**
* A list of users for admin manage users page, that sets an onClick * A list of users for admin manage users page, that sets an onClick
@ -16,7 +15,6 @@ import InputField from "./InputField";
export function UserListAdmin(props: { users: string[] }): JSX.Element { export function UserListAdmin(props: { users: string[] }): JSX.Element {
const [modalVisible, setModalVisible] = useState(false); const [modalVisible, setModalVisible] = useState(false);
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [search, setSearch] = useState("");
const handleClick = (username: string): void => { const handleClick = (username: string): void => {
setUsername(username); setUsername(username);
@ -30,39 +28,24 @@ export function UserListAdmin(props: { users: string[] }): JSX.Element {
return ( return (
<> <>
<h1 className="font-bold text-[30px] mb-[20px]">Manage Users</h1>
<UserInfoModal <UserInfoModal
onClose={handleClose} onClose={handleClose}
isVisible={modalVisible} isVisible={modalVisible}
username={username} username={username}
/> />
<div> <div>
<InputField <ul className="font-bold underline text-[30px] cursor-pointer padding">
placeholder={"Search"} {props.users.map((user) => (
type={"Text"} <li
value={search} className="pt-5"
onChange={(e) => { key={user}
setSearch(e.target.value); onClick={() => {
}} handleClick(user);
/> }}
<ul className="mt-3 border-2 text-left border-black rounded-2xl px-2 divide-y divide-gray-300 font-semibold text-[30px] transition-all cursor-pointer overflow-auto h-[65vh] w-[50vw]"> >
{props.users {user}
.filter((user) => { </li>
return search.toLowerCase() === "" ))}
? user
: user.toLowerCase().includes(search.toLowerCase());
})
.map((user) => (
<li
className="hover:font-extrabold hover:underline p-1"
key={user}
onClick={() => {
handleClick(user);
}}
>
{user}
</li>
))}
</ul> </ul>
</div> </div>
</> </>

View file

@ -13,7 +13,14 @@ function AdminManageProjects(): JSX.Element {
setProjectsProp: setProjects, setProjectsProp: setProjects,
username: localStorage.getItem("username") ?? "", username: localStorage.getItem("username") ?? "",
}); });
const content = <ProjectListAdmin projects={projects} />; const content = (
<>
<h1 className="font-bold text-[30px] mb-[20px]">Manage Projects</h1>
<div className="border-4 border-black bg-white flex flex-col items-center h-[65vh] w-[50vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px]">
<ProjectListAdmin projects={projects} />
</div>
</>
);
const buttons = ( const buttons = (
<> <>

View file

@ -12,7 +12,14 @@ function AdminManageUsers(): JSX.Element {
const navigate = useNavigate(); const navigate = useNavigate();
const content = <UserListAdmin users={users} />; const content = (
<>
<h1 className="font-bold text-[30px] mb-[20px]">Manage Users</h1>
<div className="border-4 border-black bg-white flex flex-col items-center h-[65vh] w-[50vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px]">
<UserListAdmin users={users} />
</div>
</>
);
const buttons = ( const buttons = (
<> <>

View file

@ -5,14 +5,14 @@ function AdminMenuPage(): JSX.Element {
const content = ( const content = (
<> <>
<h1 className="font-bold text-[30px] mb-[20px]">Administrator Menu</h1> <h1 className="font-bold text-[30px] mb-[20px]">Administrator Menu</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-auto space-y-[10vh] p-[30px]"> <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="/adminManageUser"> <Link to="/adminManageUser">
<h1 className="font-bold hover:underline text-[30px] cursor-pointer hover:font-extrabold"> <h1 className="font-bold underline text-[30px] cursor-pointer">
Manage Users Manage Users
</h1> </h1>
</Link> </Link>
<Link to="/adminManageProject"> <Link to="/adminManageProject">
<h1 className="font-bold hover:underline text-[30px] cursor-pointer hover:font-extrabold"> <h1 className="font-bold underline text-[30px] cursor-pointer">
Manage Projects Manage Projects
</h1> </h1>
</Link> </Link>

View file

@ -1,12 +1,11 @@
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import AddUserToProject from "../../Components/AddUserToProject"; import AddUserToProject from "../../Components/AddUserToProject";
import BasicWindow from "../../Components/BasicWindow"; import BasicWindow from "../../Components/BasicWindow";
import BackButton from "../../Components/BackButton";
function AdminProjectAddMember(): JSX.Element { function AdminProjectAddMember(): JSX.Element {
const projectName = useLocation().search.slice(1); const projectName = useLocation().search.slice(1);
const content = <AddUserToProject projectName={projectName} />; const content = <AddUserToProject projectName={projectName} />;
const buttons = <BackButton />; const buttons = <></>;
return <BasicWindow content={content} buttons={buttons} />; return <BasicWindow content={content} buttons={buttons} />;
} }
export default AdminProjectAddMember; export default AdminProjectAddMember;