Skip to content
This repository has been archived by the owner on May 24, 2022. It is now read-only.

Commit

Permalink
Merge pull request #325 from SELab-2/create_project
Browse files Browse the repository at this point in the history
Create project
  • Loading branch information
WardM99 authored Apr 28, 2022
2 parents b0b02d1 + 7fef2f0 commit 57d684d
Show file tree
Hide file tree
Showing 30 changed files with 755 additions and 9 deletions.
6 changes: 3 additions & 3 deletions frontend/src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
PendingPage,
ProjectsPage,
ProjectDetailPage,
CreateProjectPage,
RegisterPage,
StudentsPage,
UsersPage,
Expand Down Expand Up @@ -68,11 +69,10 @@ export default function Router() {
<Route path="projects" element={<Outlet />}>
<Route path={""} element={<ProjectsPage />} />
<Route path={"new"} element={<AdminRoute />}>
{/* TODO create project page */}
<Route path={""} element={<div />} />
{/* create project page */}
<Route path={""} element={<CreateProjectPage />} />
</Route>
{/* project page */}

<Route
path={":projectId"}
element={<ProjectDetailPage />}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<div>
{coaches.map((element, _index) => (
<AddedItem key={element.userId}>
<ItemName>{element.name}</ItemName>
<RemoveButton
onClick={() => {
const newItems = [...coaches];
newItems.splice(_index, 1);
setCoaches(newItems);
}}
>
<TiDeleteOutline size={"20px"} />
</RemoveButton>
</AddedItem>
))}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./AddedCoaches";
Original file line number Diff line number Diff line change
@@ -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 (
<div>
{items.map((element, _index) => (
<AddedItem key={_index}>
<ItemName>{element}</ItemName>
<RemoveButton
onClick={() => {
const newItems = [...items];
newItems.splice(_index, 1);
setItems(newItems);
}}
>
<TiDeleteOutline size={"20px"} />
</RemoveButton>
</AddedItem>
))}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./AddedPartners";
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement>,
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 (
<div>
{skills.map((skill, index) => (
<SkillContainer key={index}>
<TopContainer>
<SkillName>{skill.skill}</SkillName>

<AmountInput
type="number"
value={skill.amount}
placeholder="Amount"
min={1}
onChange={event => {
updateSkills(event, index, true);
}}
/>
<Delete
onClick={() => {
const newSkills = [...skills];
newSkills.splice(index, 1);
setSkills(newSkills);
}}
>
<TiDeleteOutline size={"20px"} />
</Delete>
</TopContainer>

<DescriptionContainer>
<Input
type="text"
value={skill.description}
placeholder="Description"
onChange={event => {
updateSkills(event, index, false);
}}
/>
</DescriptionContainer>
</SkillContainer>
))}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./AddedSkills";
Original file line number Diff line number Diff line change
@@ -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;
`;
Original file line number Diff line number Diff line change
@@ -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<User[]>([]);
const params = useParams();
const editionId = params.editionId!;

useEffect(() => {
async function callCoaches() {
setAvailableCoaches((await getCoaches(editionId, coach, 0)).users);
}
callCoaches();
}, [coach, editionId]);

return (
<div>
<Input
value={coach}
onChange={e => {
setCoach(e.target.value);
}}
list="users"
placeholder="Coach"
/>
<datalist id="users">
{availableCoaches.map((availableCoach, _index) => {
return <option key={_index} value={availableCoach.name} />;
})}
</datalist>

<AddButton
onClick={() => {
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
</AddButton>
<WarningContainer>
<BadCoachAlert show={showAlert} setShow={setShowAlert}></BadCoachAlert>
</WarningContainer>
</div>
);
}

function BadCoachAlert({ show, setShow }: { show: boolean; setShow: (state: boolean) => void }) {
if (show) {
return (
<Alert variant="warning" onClose={() => setShow(false)} dismissible>
Please choose an option from the list
</Alert>
);
}
return null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./Coach";
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Input } from "../../styles";

export default function Name({ name, setName }: { name: string; setName: (name: string) => void }) {
return (
<Input value={name} onChange={e => setName(e.target.value)} placeholder="Project name" />
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./Name";
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Input } from "../../styles";

export default function NumberOfStudents({
numberOfStudents,
setNumberOfStudents,
}: {
numberOfStudents: number;
setNumberOfStudents: (numberOfStudents: number) => void;
}) {
return (
<div>
<Input
type="number"
min="1"
value={numberOfStudents}
onChange={e => {
setNumberOfStudents(e.target.valueAsNumber);
}}
placeholder="Number of students"
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./NumberOfStudents";
Loading

0 comments on commit 57d684d

Please sign in to comment.