Compare commits
51 commits
7db03e8dbd
...
5f6977354f
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5f6977354f | ||
![]() |
ab313551c9 | ||
![]() |
2ce1837223 | ||
![]() |
502cd67b4c | ||
![]() |
4dbbee3249 | ||
![]() |
e3fd9f52ca | ||
![]() |
8081f289b5 | ||
![]() |
cdbd6ca0ce | ||
![]() |
77a24421e9 | ||
![]() |
de234c12f2 | ||
![]() |
6a84b1c14d | ||
![]() |
c072aff9da | ||
![]() |
9434c31013 | ||
![]() |
ba2bb1fc5e | ||
![]() |
847427a543 | ||
![]() |
b8c69fabf5 | ||
![]() |
d2a8399bde | ||
![]() |
b3dfbc47a4 | ||
![]() |
17c30f5dd9 | ||
![]() |
d7e14f1886 | ||
![]() |
59c4dab2e2 | ||
![]() |
d2ff2428cd | ||
![]() |
36524e5cbb | ||
![]() |
a2bc13ec22 | ||
![]() |
83f8097c2b | ||
![]() |
a0759b099a | ||
![]() |
db4f869712 | ||
![]() |
652f74884f | ||
![]() |
3e1f899414 | ||
![]() |
e55b380bb4 | ||
![]() |
2eab030212 | ||
![]() |
ff9eba039f | ||
![]() |
2cd2ef9ef5 | ||
![]() |
cc09eb0ead | ||
![]() |
8df3311f5a | ||
![]() |
f5a4c3d0e5 | ||
![]() |
55fd42090d | ||
![]() |
5a4049eaf3 | ||
![]() |
59add3b6b3 | ||
![]() |
6982d21016 | ||
![]() |
f16dc1722c | ||
![]() |
31c5a78dae | ||
![]() |
93addc9870 | ||
![]() |
847180cf75 | ||
![]() |
b9d7e57f2c | ||
![]() |
25713443e2 | ||
![]() |
d64ec708a1 | ||
![]() |
3e9dc87100 | ||
![]() |
a2ad2913e4 | ||
![]() |
83e781c877 | ||
![]() |
531e9a0535 |
16 changed files with 212 additions and 86 deletions
2
Justfile
2
Justfile
|
@ -15,7 +15,7 @@ remove-podman-containers:
|
||||||
|
|
||||||
# Saves the release container to a tarball, pigz is just gzip but multithreaded
|
# Saves the release container to a tarball, pigz is just gzip but multithreaded
|
||||||
save-release: build-container-release
|
save-release: build-container-release
|
||||||
podman save --format=oci-archive ttime-server | pigz -9 > ttime-server.tar.gz
|
podman save --format=oci-archive ttime-server | pigz -9 > ttime-server_`date -I`_`git rev-parse --short HEAD`.tar.gz
|
||||||
|
|
||||||
# Loads the release container from a tarball
|
# Loads the release container from a tarball
|
||||||
load-release file:
|
load-release file:
|
||||||
|
|
|
@ -204,15 +204,22 @@ func (d *Db) AddProject(name string, description string, username string) error
|
||||||
tx := d.MustBegin()
|
tx := d.MustBegin()
|
||||||
_, err := tx.Exec(projectInsert, name, description, username)
|
_, err := tx.Exec(projectInsert, name, description, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
if err := tx.Rollback(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = tx.Exec(changeUserRole, "project_manager", username, name)
|
_, err = tx.Exec(changeUserRole, "project_manager", username, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
if err := tx.Rollback(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tx.Commit()
|
if err := tx.Commit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,10 +42,7 @@ interface API {
|
||||||
token: string,
|
token: string,
|
||||||
): Promise<APIResponse<NewWeeklyReport>>;
|
): Promise<APIResponse<NewWeeklyReport>>;
|
||||||
/** Gets all the projects of a user*/
|
/** Gets all the projects of a user*/
|
||||||
getUserProjects(
|
getUserProjects(token: string): Promise<APIResponse<Project[]>>;
|
||||||
username: string,
|
|
||||||
token: string,
|
|
||||||
): Promise<APIResponse<Project[]>>;
|
|
||||||
/** Gets a project from id*/
|
/** Gets a project from id*/
|
||||||
getProject(id: number): Promise<APIResponse<Project>>;
|
getProject(id: number): Promise<APIResponse<Project>>;
|
||||||
}
|
}
|
||||||
|
@ -150,10 +147,7 @@ export const api: API = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async getUserProjects(
|
async getUserProjects(token: string): Promise<APIResponse<Project[]>> {
|
||||||
username: string,
|
|
||||||
token: string,
|
|
||||||
): Promise<APIResponse<Project[]>> {
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/getUserProjects", {
|
const response = await fetch("/api/getUserProjects", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
@ -161,7 +155,6 @@ export const api: API = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: "Bearer " + token,
|
Authorization: "Bearer " + token,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ username }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
@ -176,7 +169,7 @@ export const api: API = {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
success: false,
|
success: false,
|
||||||
message: "Failed to get user projects",
|
message: "API fucked",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
0
frontend/src/Components/AdminUserList.tsx
Normal file
0
frontend/src/Components/AdminUserList.tsx
Normal file
34
frontend/src/Components/DeleteUser.tsx
Normal file
34
frontend/src/Components/DeleteUser.tsx
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { User } from "../Types/goTypes";
|
||||||
|
import { api, APIResponse } from "../API/API";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use to remove a user from the system
|
||||||
|
* @param props - The username of user to remove
|
||||||
|
* @returns {boolean} True if removed, false if not
|
||||||
|
* @example
|
||||||
|
* const exampleUsername = "user";
|
||||||
|
* DeleteUser({ usernameToDelete: exampleUsername });
|
||||||
|
*/
|
||||||
|
|
||||||
|
function DeleteUser(props: { usernameToDelete: string }): boolean {
|
||||||
|
//console.log(props.usernameToDelete); FOR DEBUG
|
||||||
|
let removed = false;
|
||||||
|
api
|
||||||
|
.removeUser(
|
||||||
|
props.usernameToDelete,
|
||||||
|
localStorage.getItem("accessToken") ?? "",
|
||||||
|
)
|
||||||
|
.then((response: APIResponse<User>) => {
|
||||||
|
if (response.success) {
|
||||||
|
removed = true;
|
||||||
|
} else {
|
||||||
|
console.error(response.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("An error occurred during creation:", error);
|
||||||
|
});
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DeleteUser;
|
|
@ -1,5 +1,6 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import backgroundImage from "../assets/1.jpg";
|
||||||
|
|
||||||
function Header(): JSX.Element {
|
function Header(): JSX.Element {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
@ -11,7 +12,7 @@ function Header(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
className="fixed top-0 left-0 right-0 border-[1.75px] border-black text-black p-3 pl-5 flex items-center justify-between bg-cover"
|
className="fixed top-0 left-0 right-0 border-[1.75px] border-black text-black p-3 pl-5 flex items-center justify-between bg-cover"
|
||||||
style={{ backgroundImage: `url('src/assets/1.jpg')` }}
|
style={{ backgroundImage: `url(${backgroundImage})` }}
|
||||||
>
|
>
|
||||||
<Link to="/your-projects">
|
<Link to="/your-projects">
|
||||||
<img
|
<img
|
||||||
|
|
|
@ -1,32 +1,31 @@
|
||||||
import { useState, useContext } from "react";
|
import { useState } from "react";
|
||||||
import type { NewWeeklyReport } from "../Types/goTypes";
|
import type { NewWeeklyReport } from "../Types/goTypes";
|
||||||
import { api } from "../API/API";
|
import { api } from "../API/API";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import Button from "./Button";
|
import Button from "./Button";
|
||||||
import { ProjectNameContext } from "../Pages/YourProjectsPage";
|
|
||||||
|
|
||||||
export default function NewWeeklyReport(): JSX.Element {
|
export default function NewWeeklyReport(): JSX.Element {
|
||||||
const [week, setWeek] = useState(0);
|
const [week, setWeek] = useState<number>();
|
||||||
const [developmentTime, setDevelopmentTime] = useState(0);
|
const [developmentTime, setDevelopmentTime] = useState<number>();
|
||||||
const [meetingTime, setMeetingTime] = useState(0);
|
const [meetingTime, setMeetingTime] = useState<number>();
|
||||||
const [adminTime, setAdminTime] = useState(0);
|
const [adminTime, setAdminTime] = useState<number>();
|
||||||
const [ownWorkTime, setOwnWorkTime] = useState(0);
|
const [ownWorkTime, setOwnWorkTime] = useState<number>();
|
||||||
const [studyTime, setStudyTime] = useState(0);
|
const [studyTime, setStudyTime] = useState<number>();
|
||||||
const [testingTime, setTestingTime] = useState(0);
|
const [testingTime, setTestingTime] = useState<number>();
|
||||||
|
|
||||||
const projectName = useContext(ProjectNameContext);
|
const { projectName } = useParams();
|
||||||
const token = localStorage.getItem("accessToken") ?? "";
|
const token = localStorage.getItem("accessToken") ?? "";
|
||||||
|
|
||||||
const handleNewWeeklyReport = async (): Promise<void> => {
|
const handleNewWeeklyReport = async (): Promise<void> => {
|
||||||
const newWeeklyReport: NewWeeklyReport = {
|
const newWeeklyReport: NewWeeklyReport = {
|
||||||
projectName,
|
projectName: projectName ?? "",
|
||||||
week,
|
week: week ?? 0,
|
||||||
developmentTime,
|
developmentTime: developmentTime ?? 0,
|
||||||
meetingTime,
|
meetingTime: meetingTime ?? 0,
|
||||||
adminTime,
|
adminTime: adminTime ?? 0,
|
||||||
ownWorkTime,
|
ownWorkTime: ownWorkTime ?? 0,
|
||||||
studyTime,
|
studyTime: studyTime ?? 0,
|
||||||
testingTime,
|
testingTime: testingTime ?? 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
await api.submitWeeklyReport(newWeeklyReport, token);
|
await api.submitWeeklyReport(newWeeklyReport, token);
|
||||||
|
@ -59,7 +58,9 @@ export default function NewWeeklyReport(): JSX.Element {
|
||||||
setWeek(weekNumber);
|
setWeek(weekNumber);
|
||||||
}}
|
}}
|
||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => {
|
||||||
event.preventDefault();
|
const keyValue = event.key;
|
||||||
|
if (!/\d/.test(keyValue) && keyValue !== "Backspace")
|
||||||
|
event.preventDefault();
|
||||||
}}
|
}}
|
||||||
onPaste={(event) => {
|
onPaste={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
54
frontend/src/Components/UserInfoModal.tsx
Normal file
54
frontend/src/Components/UserInfoModal.tsx
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import Button from "./Button";
|
||||||
|
import DeleteUser from "./DeleteUser";
|
||||||
|
import UserProjectListAdmin from "./UserProjectListAdmin";
|
||||||
|
|
||||||
|
function UserInfoModal(props: {
|
||||||
|
isVisible: boolean;
|
||||||
|
username: string;
|
||||||
|
onClose: () => void;
|
||||||
|
}): JSX.Element {
|
||||||
|
if (!props.isVisible) return <></>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm
|
||||||
|
flex justify-center items-center"
|
||||||
|
>
|
||||||
|
<div className="border-4 border-black bg-white p-2 rounded-lg text-center">
|
||||||
|
<p className="font-bold text-[30px]">{props.username}</p>
|
||||||
|
<Link to="/AdminChangeUserName">
|
||||||
|
<p className="mb-[20px] hover:font-bold hover:cursor-pointer underline">
|
||||||
|
(Change Username)
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
<div>
|
||||||
|
<h2 className="font-bold text-[22px] mb-[20px]">
|
||||||
|
Member of these projects:
|
||||||
|
</h2>
|
||||||
|
<div className="pr-6 pl-6">
|
||||||
|
<UserProjectListAdmin />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="items-center space-x-6 pr-6 pl-6">
|
||||||
|
<Button
|
||||||
|
text={"Delete"}
|
||||||
|
onClick={function (): void {
|
||||||
|
DeleteUser({ usernameToDelete: props.username });
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
text={"Close"}
|
||||||
|
onClick={function (): void {
|
||||||
|
props.onClose();
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserInfoModal;
|
|
@ -1,5 +1,6 @@
|
||||||
import { Link } from "react-router-dom";
|
import { useState } from "react";
|
||||||
import { PublicUser } from "../Types/goTypes";
|
import { PublicUser } from "../Types/goTypes";
|
||||||
|
import UserInfoModal from "./UserInfoModal";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The props for the UserProps component
|
* The props for the UserProps component
|
||||||
|
@ -9,27 +10,52 @@ interface UserProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of users for admin manage users page, that links admin to the right user page
|
* A list of users for admin manage users page, that sets an onClick
|
||||||
* thanks to the state property
|
* function for eact user <li> element, which displays a modul with
|
||||||
* @param props - The users to display
|
* user info.
|
||||||
|
* @param props - An array of users users to display
|
||||||
* @returns {JSX.Element} The user list
|
* @returns {JSX.Element} The user list
|
||||||
* @example
|
* @example
|
||||||
* const users = [{ id: 1, userName: "Random name" }];
|
* const users = [{ id: 1, userName: "ExampleName" }];
|
||||||
* return <UserList users={users} />;
|
* return <UserList users={users} />;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function UserListAdmin(props: UserProps): JSX.Element {
|
export function UserListAdmin(props: UserProps): JSX.Element {
|
||||||
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
|
||||||
|
const handleClick = (username: string): void => {
|
||||||
|
setUsername(username);
|
||||||
|
setModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = (): void => {
|
||||||
|
setUsername("");
|
||||||
|
setModalVisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<ul className="font-bold underline text-[30px] cursor-pointer padding">
|
<UserInfoModal
|
||||||
{props.users.map((user) => (
|
onClose={handleClose}
|
||||||
<Link to="/adminUserInfo" key={user.userId} state={user.username}>
|
isVisible={modalVisible}
|
||||||
<li className="pt-5" key={user.userId}>
|
username={username}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<ul className="font-bold underline text-[30px] cursor-pointer padding">
|
||||||
|
{props.users.map((user) => (
|
||||||
|
<li
|
||||||
|
className="pt-5"
|
||||||
|
key={user.userId}
|
||||||
|
onClick={() => {
|
||||||
|
handleClick(user.username);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{user.username}
|
{user.username}
|
||||||
</li>
|
</li>
|
||||||
</Link>
|
))}
|
||||||
))}
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { api } from "../API/API";
|
import { api } from "../API/API";
|
||||||
import { Project } from "../Types/goTypes";
|
import { Project } from "../Types/goTypes";
|
||||||
|
|
||||||
const UserProjectListAdmin: React.FC = () => {
|
function UserProjectListAdmin(): JSX.Element {
|
||||||
const [projects, setProjects] = useState<Project[]>([]);
|
const [projects, setProjects] = useState<Project[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchProjects = async (): Promise<void> => {
|
const fetchProjects = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const token = localStorage.getItem("accessToken") ?? "";
|
const token = localStorage.getItem("accessToken") ?? "";
|
||||||
const username = "NoUser"; // getUsernameFromContext(); // Assuming you have a function to get the username from your context
|
// const username = props.username;
|
||||||
|
|
||||||
const response = await api.getUserProjects(username, token);
|
const response = await api.getUserProjects(token);
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
setProjects(response.data ?? []);
|
setProjects(response.data ?? []);
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,18 +26,16 @@ const UserProjectListAdmin: React.FC = () => {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="border-2 border-black bg-white p-2 rounded-lg text-center">
|
||||||
<h2>User Projects</h2>
|
|
||||||
<ul>
|
<ul>
|
||||||
{projects.map((project) => (
|
{projects.map((project) => (
|
||||||
<li key={project.id}>
|
<li key={project.id}>
|
||||||
<span>{project.name}</span>
|
<span>{project.name}</span>
|
||||||
{/* Add any additional project details you want to display */}
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default UserProjectListAdmin;
|
export default UserProjectListAdmin;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import BackButton from "../../Components/BackButton";
|
||||||
import BasicWindow from "../../Components/BasicWindow";
|
import BasicWindow from "../../Components/BasicWindow";
|
||||||
import Button from "../../Components/Button";
|
import Button from "../../Components/Button";
|
||||||
|
|
||||||
|
@ -13,13 +14,7 @@ function AdminChangeUsername(): JSX.Element {
|
||||||
}}
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
/>
|
/>
|
||||||
<Button
|
<BackButton />
|
||||||
text="Back"
|
|
||||||
onClick={(): void => {
|
|
||||||
return;
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ function App(): JSX.Element {
|
||||||
} else if (authority === 2) {
|
} else if (authority === 2) {
|
||||||
navigate("/pm");
|
navigate("/pm");
|
||||||
} else if (authority === 3) {
|
} else if (authority === 3) {
|
||||||
navigate("/user");
|
navigate("/yourProjects");
|
||||||
}
|
}
|
||||||
}, [authority, navigate]);
|
}, [authority, navigate]);
|
||||||
|
|
||||||
|
|
18
frontend/src/Pages/NotFoundPage.tsx
Normal file
18
frontend/src/Pages/NotFoundPage.tsx
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import Button from "../Components/Button";
|
||||||
|
|
||||||
|
export default function NotFoundPage(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-screen bg-white">
|
||||||
|
<h1 className="text-[30px]">404 Page Not Found</h1>
|
||||||
|
<a href="/">
|
||||||
|
<Button
|
||||||
|
text="Go to Home Page"
|
||||||
|
onClick={(): void => {
|
||||||
|
localStorage.clear();
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,18 +1,20 @@
|
||||||
import { Link, useLocation } from "react-router-dom";
|
import { Link, useLocation, useParams } from "react-router-dom";
|
||||||
import BasicWindow from "../../Components/BasicWindow";
|
import BasicWindow from "../../Components/BasicWindow";
|
||||||
import BackButton from "../../Components/BackButton";
|
import BackButton from "../../Components/BackButton";
|
||||||
|
|
||||||
function UserProjectPage(): JSX.Element {
|
function UserProjectPage(): JSX.Element {
|
||||||
|
const { projectName } = useParams();
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<>
|
<>
|
||||||
<h1 className="font-bold text-[30px] mb-[20px]">{useLocation().state}</h1>
|
<h1 className="font-bold text-[30px] mb-[20px]">{useLocation().state}</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-scroll 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="/project-page">
|
<Link to={`/projectPage/${projectName}`}>
|
||||||
<h1 className="font-bold underline text-[30px] cursor-pointer">
|
<h1 className="font-bold underline text-[30px] cursor-pointer">
|
||||||
Your Time Reports
|
Your Time Reports
|
||||||
</h1>
|
</h1>
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/new-time-report">
|
<Link to={`/newTimeReport/${projectName}`}>
|
||||||
<h1 className="font-bold underline text-[30px] cursor-pointer">
|
<h1 className="font-bold underline text-[30px] cursor-pointer">
|
||||||
New Time Report
|
New Time Report
|
||||||
</h1>
|
</h1>
|
||||||
|
|
|
@ -11,9 +11,8 @@ function UserProjectPage(): JSX.Element {
|
||||||
const [selectedProject, setSelectedProject] = useState("");
|
const [selectedProject, setSelectedProject] = useState("");
|
||||||
|
|
||||||
const getProjects = async (): Promise<void> => {
|
const getProjects = async (): Promise<void> => {
|
||||||
const username = localStorage.getItem("username") ?? ""; // replace with actual username
|
const token = localStorage.getItem("accessToken") ?? "";
|
||||||
const token = localStorage.getItem("accessToken") ?? ""; // replace with actual token
|
const response = await api.getUserProjects(token);
|
||||||
const response = await api.getUserProjects(username, token);
|
|
||||||
console.log(response);
|
console.log(response);
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
setProjects(response.data ?? []);
|
setProjects(response.data ?? []);
|
||||||
|
@ -36,7 +35,7 @@ function UserProjectPage(): JSX.Element {
|
||||||
<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]">
|
<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]">
|
||||||
{projects.map((project, index) => (
|
{projects.map((project, index) => (
|
||||||
<Link
|
<Link
|
||||||
to={`/project/${project.id}`}
|
to={`/project/${project.name}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleProjectClick(project.name);
|
handleProjectClick(project.name);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -29,12 +29,14 @@ import AdminProjectManageMembers from "./Pages/AdminPages/AdminProjectManageMemb
|
||||||
import AdminProjectStatistics from "./Pages/AdminPages/AdminProjectStatistics.tsx";
|
import AdminProjectStatistics from "./Pages/AdminPages/AdminProjectStatistics.tsx";
|
||||||
import AdminProjectViewMemberInfo from "./Pages/AdminPages/AdminProjectViewMemberInfo.tsx";
|
import AdminProjectViewMemberInfo from "./Pages/AdminPages/AdminProjectViewMemberInfo.tsx";
|
||||||
import AdminProjectPage from "./Pages/AdminPages/AdminProjectPage.tsx";
|
import AdminProjectPage from "./Pages/AdminPages/AdminProjectPage.tsx";
|
||||||
|
import NotFoundPage from "./Pages/NotFoundPage.tsx";
|
||||||
|
|
||||||
// This is where the routes are mounted
|
// This is where the routes are mounted
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
element: <App />,
|
element: <App />,
|
||||||
|
errorElement: <NotFoundPage />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/admin",
|
path: "/admin",
|
||||||
|
@ -44,30 +46,26 @@ const router = createBrowserRouter([
|
||||||
path: "/pm",
|
path: "/pm",
|
||||||
element: <YourProjectsPage />,
|
element: <YourProjectsPage />,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "/user",
|
|
||||||
element: <YourProjectsPage />,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/yourProjects",
|
path: "/yourProjects",
|
||||||
element: <YourProjectsPage />,
|
element: <YourProjectsPage />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/editTimeReport",
|
path: "/project/:projectName",
|
||||||
element: <UserEditTimeReportPage />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/newTimeReport",
|
|
||||||
element: <UserNewTimeReportPage />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/project",
|
|
||||||
element: <UserProjectPage />,
|
element: <UserProjectPage />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/projectPage",
|
path: "/newTimeReport/:projectName",
|
||||||
|
element: <UserNewTimeReportPage />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/projectPage/:projectName",
|
||||||
element: <UserViewTimeReportsPage />,
|
element: <UserViewTimeReportsPage />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/editTimeReport",
|
||||||
|
element: <UserEditTimeReportPage />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/changeRole",
|
path: "/changeRole",
|
||||||
element: <PMChangeRole />,
|
element: <PMChangeRole />,
|
||||||
|
|
Loading…
Add table
Reference in a new issue