diff --git a/frontend/src/Router.tsx b/frontend/src/Router.tsx
index 703e7e015..407393242 100644
--- a/frontend/src/Router.tsx
+++ b/frontend/src/Router.tsx
@@ -11,6 +11,7 @@ import {
PendingPage,
ProjectsPage,
ProjectDetailPage,
+ CreateProjectPage,
RegisterPage,
StudentsPage,
UsersPage,
@@ -68,11 +69,10 @@ export default function Router() {
}>
} />
}>
- {/* TODO create project page */}
- } />
+ {/* create project page */}
+ } />
{/* project page */}
-
}
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedCoaches/AddedCoaches.tsx b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedCoaches/AddedCoaches.tsx
new file mode 100644
index 000000000..6417e7964
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedCoaches/AddedCoaches.tsx
@@ -0,0 +1,30 @@
+import { TiDeleteOutline } from "react-icons/ti";
+import { User } from "../../../../utils/api/users/users";
+import { AddedItem, ItemName, RemoveButton } from "../styles";
+
+export default function AddedCoaches({
+ coaches,
+ setCoaches,
+}: {
+ coaches: User[];
+ setCoaches: (coaches: User[]) => void;
+}) {
+ return (
+
+ {coaches.map((element, _index) => (
+
+ {element.name}
+ {
+ const newItems = [...coaches];
+ newItems.splice(_index, 1);
+ setCoaches(newItems);
+ }}
+ >
+
+
+
+ ))}
+
+ );
+}
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedCoaches/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedCoaches/index.ts
new file mode 100644
index 000000000..fe048b5a7
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedCoaches/index.ts
@@ -0,0 +1 @@
+export { default } from "./AddedCoaches";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedPartners/AddedPartners.tsx b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedPartners/AddedPartners.tsx
new file mode 100644
index 000000000..0cf5b0040
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedPartners/AddedPartners.tsx
@@ -0,0 +1,29 @@
+import { TiDeleteOutline } from "react-icons/ti";
+import { AddedItem, ItemName, RemoveButton } from "../styles";
+
+export default function AddedPartners({
+ items,
+ setItems,
+}: {
+ items: string[];
+ setItems: (items: string[]) => void;
+}) {
+ return (
+
+ {items.map((element, _index) => (
+
+ {element}
+ {
+ const newItems = [...items];
+ newItems.splice(_index, 1);
+ setItems(newItems);
+ }}
+ >
+
+
+
+ ))}
+
+ );
+}
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedPartners/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedPartners/index.ts
new file mode 100644
index 000000000..ee4652a7d
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedPartners/index.ts
@@ -0,0 +1 @@
+export { default } from "./AddedPartners";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedSkills/AddedSkills.tsx b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedSkills/AddedSkills.tsx
new file mode 100644
index 000000000..1194c5c87
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedSkills/AddedSkills.tsx
@@ -0,0 +1,98 @@
+import { SkillProject } from "../../../../data/interfaces/projects";
+import { Input } from "../styles";
+import {
+ AmountInput,
+ SkillContainer,
+ DescriptionContainer,
+ Delete,
+ TopContainer,
+ SkillName,
+} from "./styles";
+import { TiDeleteOutline } from "react-icons/ti";
+import React from "react";
+
+/**
+ *
+ * @param skills the state of the added skills
+ * @param setSkills used to update the added skills and there attributes
+
+ * @returns a react component of all the added skills
+ */
+export default function AddedSkills({
+ skills,
+ setSkills,
+}: {
+ skills: SkillProject[];
+ setSkills: (skills: SkillProject[]) => void;
+}) {
+ /**
+ * This function is called when an input field is changed.
+ * @param event a react event
+ * @param index the index of the skill to change
+ * @param amount whether to update the amount (true) or to update the description (false)
+ */
+ function updateSkills(
+ event: React.ChangeEvent,
+ index: number,
+ amount: boolean
+ ) {
+ const newList = skills.map((item, otherIndex) => {
+ if (index === otherIndex) {
+ if (amount && !isNaN(event.target.valueAsNumber)) {
+ return {
+ ...item,
+ amount: event.target.valueAsNumber,
+ };
+ }
+ return {
+ ...item,
+ description: event.target.value,
+ };
+ }
+ return item;
+ });
+ setSkills(newList);
+ }
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedSkills/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedSkills/index.ts
new file mode 100644
index 000000000..f3661f314
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedSkills/index.ts
@@ -0,0 +1 @@
+export { default } from "./AddedSkills";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedSkills/styles.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedSkills/styles.ts
new file mode 100644
index 000000000..9b4a4b069
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/AddedSkills/styles.ts
@@ -0,0 +1,46 @@
+import styled from "styled-components";
+
+export const SkillContainer = styled.div`
+ border-radius: 5px;
+ margin-top: 10px;
+ background-color: #1a1a36;
+ padding: 5px 10px;
+ width: min-content;
+ max-width: 75%;
+`;
+
+export const TopContainer = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+`;
+
+export const SkillName = styled.div`
+ overflow-x: auto;
+ text-overflow: ellipsis;
+`;
+
+export const Delete = styled.button`
+ background-color: #f14a3b;
+ border: 0;
+ padding: 2.5px 2.5px;
+ border-radius: 1px;
+ color: white;
+ display: flex;
+ align-items: center;
+`;
+
+export const DescriptionContainer = styled.div`
+ margin-bottom: 10px;
+ width: fit-content;
+`;
+
+export const AmountInput = styled.input`
+ margin: 5px;
+ padding: 2px 10px;
+ background-color: #131329;
+ color: white;
+ border: none;
+ border-radius: 5px;
+ width: 100px;
+`;
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Coach/Coach.tsx b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Coach/Coach.tsx
new file mode 100644
index 000000000..ab5a1ec47
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Coach/Coach.tsx
@@ -0,0 +1,84 @@
+import { useEffect, useState } from "react";
+import { Alert } from "react-bootstrap";
+import { useParams } from "react-router-dom";
+import { getCoaches } from "../../../../../utils/api/users/coaches";
+import { User } from "../../../../../utils/api/users/users";
+import { AddButton, Input, WarningContainer } from "../../styles";
+
+export default function Coach({
+ coach,
+ setCoach,
+ coaches,
+ setCoaches,
+}: {
+ coach: string;
+ setCoach: (coach: string) => void;
+ coaches: User[];
+ setCoaches: (coaches: User[]) => void;
+}) {
+ const [showAlert, setShowAlert] = useState(false);
+ const [availableCoaches, setAvailableCoaches] = useState([]);
+ const params = useParams();
+ const editionId = params.editionId!;
+
+ useEffect(() => {
+ async function callCoaches() {
+ setAvailableCoaches((await getCoaches(editionId, coach, 0)).users);
+ }
+ callCoaches();
+ }, [coach, editionId]);
+
+ return (
+
+
{
+ setCoach(e.target.value);
+ }}
+ list="users"
+ placeholder="Coach"
+ />
+
+
+
{
+ let coachToAdd = null;
+ availableCoaches.forEach(availableCoach => {
+ if (availableCoach.name === coach) {
+ coachToAdd = availableCoach;
+ }
+ });
+ if (coachToAdd) {
+ if (!coaches.some(presentCoach => presentCoach.name === coach)) {
+ const newCoaches = [...coaches];
+ newCoaches.push(coachToAdd);
+ setCoaches(newCoaches);
+ setShowAlert(false);
+ }
+ } else setShowAlert(true);
+ setCoach("");
+ }}
+ >
+ Add coach
+
+
+
+
+
+ );
+}
+
+function BadCoachAlert({ show, setShow }: { show: boolean; setShow: (state: boolean) => void }) {
+ if (show) {
+ return (
+ setShow(false)} dismissible>
+ Please choose an option from the list
+
+ );
+ }
+ return null;
+}
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Coach/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Coach/index.ts
new file mode 100644
index 000000000..07c25c743
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Coach/index.ts
@@ -0,0 +1 @@
+export { default } from "./Coach";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Name/Name.tsx b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Name/Name.tsx
new file mode 100644
index 000000000..67ad8f7d9
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Name/Name.tsx
@@ -0,0 +1,7 @@
+import { Input } from "../../styles";
+
+export default function Name({ name, setName }: { name: string; setName: (name: string) => void }) {
+ return (
+ setName(e.target.value)} placeholder="Project name" />
+ );
+}
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Name/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Name/index.ts
new file mode 100644
index 000000000..4e90e41d5
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Name/index.ts
@@ -0,0 +1 @@
+export { default } from "./Name";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/NumberOfStudents/NumberOfStudents.tsx b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/NumberOfStudents/NumberOfStudents.tsx
new file mode 100644
index 000000000..7586d250b
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/NumberOfStudents/NumberOfStudents.tsx
@@ -0,0 +1,23 @@
+import { Input } from "../../styles";
+
+export default function NumberOfStudents({
+ numberOfStudents,
+ setNumberOfStudents,
+}: {
+ numberOfStudents: number;
+ setNumberOfStudents: (numberOfStudents: number) => void;
+}) {
+ return (
+
+ {
+ setNumberOfStudents(e.target.valueAsNumber);
+ }}
+ placeholder="Number of students"
+ />
+
+ );
+}
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/NumberOfStudents/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/NumberOfStudents/index.ts
new file mode 100644
index 000000000..7594e8ecf
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/NumberOfStudents/index.ts
@@ -0,0 +1 @@
+export { default } from "./NumberOfStudents";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Partner/Partner.tsx b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Partner/Partner.tsx
new file mode 100644
index 000000000..a6096de81
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Partner/Partner.tsx
@@ -0,0 +1,45 @@
+import { Input, AddButton } from "../../styles";
+
+export default function Partner({
+ partner,
+ setPartner,
+ partners,
+ setPartners,
+}: {
+ partner: string;
+ setPartner: (partner: string) => void;
+ partners: string[];
+ setPartners: (partners: string[]) => void;
+}) {
+ const availablePartners = ["partner1", "partner2"]; // TODO get partners from API call
+
+ return (
+
+
setPartner(e.target.value)}
+ list="partners"
+ placeholder="Partner"
+ />
+
+
+
+
{
+ if (!partners.includes(partner) && partner.length > 0) {
+ const newPartners = [...partners];
+ newPartners.push(partner);
+ setPartners(newPartners);
+ }
+ setPartner("");
+ }}
+ >
+ Add partner
+
+
+ );
+}
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Partner/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Partner/index.ts
new file mode 100644
index 000000000..ccf0fba3a
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Partner/index.ts
@@ -0,0 +1 @@
+export { default } from "./Partner";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Skill/Skill.tsx b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Skill/Skill.tsx
new file mode 100644
index 000000000..588e846d4
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Skill/Skill.tsx
@@ -0,0 +1,50 @@
+import { SkillProject } from "../../../../../data/interfaces/projects";
+import { Input, AddButton } from "../../styles";
+
+export default function Skill({
+ skill,
+ setSkill,
+ skills,
+ setSkills,
+}: {
+ skill: string;
+ setSkill: (skill: string) => void;
+ skills: SkillProject[];
+ setSkills: (skills: SkillProject[]) => void;
+}) {
+ const availableSkills = ["Frontend", "Backend", "Database", "Design"];
+
+ return (
+
+
setSkill(e.target.value)}
+ placeholder="Skill"
+ list="skills"
+ />
+
+
+
{
+ if (availableSkills.some(availableSkill => availableSkill === skill)) {
+ const newSkills = [...skills];
+ const newSkill: SkillProject = {
+ skill: skill,
+ description: "",
+ amount: 1,
+ };
+ newSkills.push(newSkill);
+ setSkills(newSkills);
+ }
+ setSkill("");
+ }}
+ >
+ Add skill
+
+
+ );
+}
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Skill/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Skill/index.ts
new file mode 100644
index 000000000..c5a820d40
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/Skill/index.ts
@@ -0,0 +1 @@
+export { default } from "./Skill";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/index.ts
new file mode 100644
index 000000000..b0235977d
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/InputFields/index.ts
@@ -0,0 +1,5 @@
+export { default as NameInput } from "./Name";
+export { default as NumberOfStudentsInput } from "./NumberOfStudents";
+export { default as CoachInput } from "./Coach";
+export { default as SkillInput } from "./Skill";
+export { default as PartnerInput } from "./Partner";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/index.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/index.ts
new file mode 100644
index 000000000..63f743cf3
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/index.ts
@@ -0,0 +1,10 @@
+export {
+ NameInput,
+ NumberOfStudentsInput,
+ CoachInput,
+ SkillInput,
+ PartnerInput,
+} from "./InputFields";
+export { default as AddedPartners } from "./AddedPartners";
+export { default as AddedCoaches } from "./AddedCoaches";
+export { default as AddedSkills } from "./AddedSkills";
diff --git a/frontend/src/components/ProjectsComponents/CreateProjectComponents/styles.ts b/frontend/src/components/ProjectsComponents/CreateProjectComponents/styles.ts
new file mode 100644
index 000000000..d40fefa38
--- /dev/null
+++ b/frontend/src/components/ProjectsComponents/CreateProjectComponents/styles.ts
@@ -0,0 +1,51 @@
+import styled from "styled-components";
+
+export const Input = styled.input`
+ margin-top: 10px;
+ padding: 5px 10px;
+ background-color: #131329;
+ color: white;
+ border: none;
+ border-radius: 5px;
+`;
+
+export const AddButton = styled.button`
+ padding: 5px 10px;
+ background-color: #00bfff;
+ color: white;
+ border: none;
+ margin-left: 5px;
+ border-radius: 5px;
+`;
+
+export const RemoveButton = styled.button`
+ padding: 0px 2.5px;
+ background-color: #f14a3b;
+ color: white;
+ border: none;
+ margin-left: 10px;
+ border-radius: 1px;
+ display: flex;
+ align-items: center;
+`;
+
+export const ItemName = styled.div`
+ overflow-x: auto;
+ text-overflow: ellipsis;
+`;
+
+export const AddedItem = styled.div`
+ margin: 5px;
+ margin-left: 0;
+ padding: 5px;
+ background-color: #1a1a36;
+ width: fit-content;
+ max-width: 75%;
+ border-radius: 5px;
+ display: flex;
+`;
+
+export const WarningContainer = styled.div`
+ max-width: fit-content;
+ margin-top: 10px;
+`;
diff --git a/frontend/src/components/ProjectsComponents/ProjectCard/ProjectCard.tsx b/frontend/src/components/ProjectsComponents/ProjectCard/ProjectCard.tsx
index d1a0f7e13..ca815f2ee 100644
--- a/frontend/src/components/ProjectsComponents/ProjectCard/ProjectCard.tsx
+++ b/frontend/src/components/ProjectsComponents/ProjectCard/ProjectCard.tsx
@@ -24,6 +24,7 @@ import { useNavigate, useParams } from "react-router-dom";
import { Project } from "../../../data/interfaces";
import { useAuth } from "../../../contexts";
+import { Role } from "../../../data/enums";
/**
*
@@ -68,7 +69,7 @@ export default function ProjectCard({
- {!role && (
+ {role === Role.ADMIN && (
diff --git a/frontend/src/data/interfaces/projects.ts b/frontend/src/data/interfaces/projects.ts
index 42a322b9f..6609d8574 100644
--- a/frontend/src/data/interfaces/projects.ts
+++ b/frontend/src/data/interfaces/projects.ts
@@ -53,6 +53,40 @@ export interface Projects {
projects: Project[];
}
+/**
+ * Used to add skills to a project
+ */
+export interface SkillProject {
+ /** The name of the skill */
+ skill: string;
+
+ /** More info about this skill in a specific project */
+ description: string;
+
+ /** Number of positions of this skill in a project */
+ amount: number;
+}
+
+/**
+ * Used when creating a new project
+ */
+export interface CreateProject {
+ /** The name of the new project */
+ name: string;
+
+ /** Number of students the project needs */
+ number_of_students: number;
+
+ /** The required skills for the project */
+ skills: string[];
+
+ /** The partners that belong to this project */
+ partners: string[];
+
+ /** The IDs of the users that will coach this project */
+ coaches: number[];
+}
+
/**
* Data about a place in a project
*/
diff --git a/frontend/src/utils/api/projects.ts b/frontend/src/utils/api/projects.ts
index e83f60e9b..b3efdde13 100644
--- a/frontend/src/utils/api/projects.ts
+++ b/frontend/src/utils/api/projects.ts
@@ -1,7 +1,15 @@
import axios from "axios";
-import { Projects, Project } from "../../data/interfaces/projects";
+import { Projects, Project, CreateProject } from "../../data/interfaces/projects";
import { axiosInstance } from "./api";
+/**
+ * API call to get projects (and filter them)
+ * @param edition The edition name.
+ * @param name To filter on project name.
+ * @param ownProjects To filter on your own projects.
+ * @param page The requested page.
+ * @returns
+ */
export async function getProjects(
edition: string,
name: string,
@@ -30,6 +38,12 @@ export async function getProjects(
}
}
+/**
+ * API call to get a specific project.
+ * @param edition The edition name.
+ * @param projectId The ID of the project.
+ * @returns A Project object when successful.
+ */
export async function getProject(edition: string, projectId: number): Promise {
try {
const response = await axiosInstance.get("/editions/" + edition + "/projects/" + projectId);
@@ -44,6 +58,52 @@ export async function getProject(edition: string, projectId: number): Promise {
+ const payload: CreateProject = {
+ name: name,
+ number_of_students: numberOfStudents,
+ skills: skills,
+ partners: partners,
+ coaches: coaches,
+ };
+
+ try {
+ const response = await axiosInstance.post("editions/" + edition + "/projects/", payload);
+ const project = response.data as Project;
+
+ return project;
+ } catch (error) {
+ if (axios.isAxiosError(error)) {
+ return null;
+ } else {
+ throw error;
+ }
+ }
+}
+
+/**
+ * API call to delete a project.
+ * @param edition The edition name.
+ * @param projectId The ID of the project that needs to be deleted.
+ * @returns true if the deletion was successful or false if it failed.
+ */
export async function deleteProject(edition: string, projectId: number): Promise {
try {
await axiosInstance.delete("/editions/" + edition + "/projects/" + projectId);
diff --git a/frontend/src/views/index.ts b/frontend/src/views/index.ts
index b91876b43..0aa72e445 100644
--- a/frontend/src/views/index.ts
+++ b/frontend/src/views/index.ts
@@ -3,8 +3,7 @@ export { default as LoginPage } from "./LoginPage";
export { default as EditionsPage } from "./EditionsPage";
export { default as CreateEditionPage } from "./CreateEditionPage";
export { default as PendingPage } from "./PendingPage";
-export { ProjectsPage } from "./projectViews";
-export { ProjectDetailPage } from "./projectViews";
+export { ProjectsPage, ProjectDetailPage, CreateProjectPage } from "./projectViews";
export { default as RegisterPage } from "./RegisterPage";
export { default as StudentsPage } from "./StudentsPage";
export { default as UsersPage } from "./UsersPage";
diff --git a/frontend/src/views/projectViews/CreateProjectPage/CreateProjectPage.tsx b/frontend/src/views/projectViews/CreateProjectPage/CreateProjectPage.tsx
new file mode 100644
index 000000000..33d800399
--- /dev/null
+++ b/frontend/src/views/projectViews/CreateProjectPage/CreateProjectPage.tsx
@@ -0,0 +1,108 @@
+import { CreateProjectContainer, CreateButton, Label } from "./styles";
+import { createProject } from "../../../utils/api/projects";
+import { useState } from "react";
+import { useNavigate, useParams } from "react-router-dom";
+import { GoBack } from "../ProjectDetailPage/styles";
+import { BiArrowBack } from "react-icons/bi";
+import {
+ NameInput,
+ NumberOfStudentsInput,
+ CoachInput,
+ SkillInput,
+ PartnerInput,
+ AddedCoaches,
+ AddedPartners,
+ AddedSkills,
+} from "../../../components/ProjectsComponents/CreateProjectComponents";
+import { SkillProject } from "../../../data/interfaces/projects";
+import { User } from "../../../utils/api/users/users";
+
+/**
+ * React component of the create project page.
+ * @returns The create project page.
+ */
+export default function CreateProjectPage() {
+ const [name, setName] = useState("");
+ const [numberOfStudents, setNumberOfStudents] = useState(1);
+
+ // States for coaches
+ const [coach, setCoach] = useState("");
+ const [coaches, setCoaches] = useState([]);
+
+ // States for skills
+ const [skill, setSkill] = useState("");
+ const [skills, setSkills] = useState([]);
+
+ // States for partners
+ const [partner, setPartner] = useState("");
+ const [partners, setPartners] = useState([]);
+
+ const navigate = useNavigate();
+
+ const params = useParams();
+ const editionId = params.editionId!;
+
+ return (
+
+ navigate("/editions/" + editionId + "/projects/")}>
+
+ Cancel
+
+ New Project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ const coachIds: number[] = [];
+ coaches.forEach(coachToAdd => {
+ coachIds.push(coachToAdd.userId);
+ });
+
+ const response = await createProject(
+ editionId,
+ name,
+ numberOfStudents!,
+ [], // Empty skills for now TODO
+ partners,
+ coachIds
+ );
+ if (response) {
+ navigate("/editions/" + editionId + "/projects/");
+ } else alert("Something went wrong :(");
+ }}
+ >
+ Create Project
+
+
+ );
+}
diff --git a/frontend/src/views/projectViews/CreateProjectPage/index.ts b/frontend/src/views/projectViews/CreateProjectPage/index.ts
new file mode 100644
index 000000000..f20b5ad36
--- /dev/null
+++ b/frontend/src/views/projectViews/CreateProjectPage/index.ts
@@ -0,0 +1 @@
+export { default } from "./CreateProjectPage";
diff --git a/frontend/src/views/projectViews/CreateProjectPage/styles.ts b/frontend/src/views/projectViews/CreateProjectPage/styles.ts
new file mode 100644
index 000000000..6cbd8c1c3
--- /dev/null
+++ b/frontend/src/views/projectViews/CreateProjectPage/styles.ts
@@ -0,0 +1,48 @@
+import styled from "styled-components";
+
+export const CreateProjectContainer = styled.div`
+ margin: 20px;
+`;
+
+export const Input = styled.input`
+ margin-top: 10px;
+ padding: 5px 10px;
+ background-color: #131329;
+ color: white;
+ border: none;
+ border-radius: 5px;
+`;
+
+export const AddButton = styled.button`
+ padding: 5px 10px;
+ background-color: #00bfff;
+ color: white;
+ border: none;
+ margin-left: 5px;
+ border-radius: 5px;
+`;
+
+export const RemoveButton = styled.button`
+ padding: 0px 2.5px;
+ background-color: #f14a3b;
+ color: white;
+ border: none;
+ margin-left: 10px;
+ border-radius: 1px;
+ display: flex;
+ align-items: center;
+`;
+
+export const CreateButton = styled.button`
+ padding: 5px 10px;
+ background-color: #44dba4;
+ color: white;
+ border: none;
+ margin-top: 30px;
+ border-radius: 5px;
+`;
+
+export const Label = styled.h5`
+ margin-top: 30px;
+ margin-bottom: 0px;
+`;
diff --git a/frontend/src/views/projectViews/ProjectsPage/ProjectsPage.tsx b/frontend/src/views/projectViews/ProjectsPage/ProjectsPage.tsx
index 9b03ec694..1fe9daae8 100644
--- a/frontend/src/views/projectViews/ProjectsPage/ProjectsPage.tsx
+++ b/frontend/src/views/projectViews/ProjectsPage/ProjectsPage.tsx
@@ -12,9 +12,10 @@ import {
LoadMoreButton,
} from "./styles";
import { Project } from "../../../data/interfaces";
-import { useParams } from "react-router-dom";
+import { useNavigate, useParams } from "react-router-dom";
import InfiniteScroll from "react-infinite-scroller";
import { useAuth } from "../../../contexts";
+import { Role } from "../../../data/enums";
/**
* @returns The projects overview page where you can see all the projects.
* You can filter on your own projects or filter on project name.
@@ -29,6 +30,7 @@ export default function ProjectPage() {
const [searchString, setSearchString] = useState("");
const [ownProjects, setOwnProjects] = useState(false);
+ const navigate = useNavigate();
const [page, setPage] = useState(0);
const params = useParams();
@@ -81,7 +83,13 @@ export default function ProjectPage() {
}}
/>
Search
- {!role && Create Project}
+ {role === Role.ADMIN && (
+ navigate("/editions/" + editionId + "/projects/new")}
+ >
+ Create Project
+
+ )}