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 ( +
+ {skills.map((skill, index) => ( + + + {skill.skill} + + { + updateSkills(event, index, true); + }} + /> + { + const newSkills = [...skills]; + newSkills.splice(index, 1); + setSkills(newSkills); + }} + > + + + + + + { + updateSkills(event, index, false); + }} + /> + + + ))} +
+ ); +} 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" + /> + + {availableCoaches.map((availableCoach, _index) => { + return + + { + 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" + /> + + + {availablePartners.map((availablePartner, _index) => { + return + + { + 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" + /> + + {availableSkills.map((availableCoach, _index) => { + return + + { + 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 + + )}