Skip to content
Snippets Groups Projects
Commit f66b34b9 authored by Planoetscher Daniel (Student Com20)'s avatar Planoetscher Daniel (Student Com20)
Browse files

trying around with create task page

parent 4d74eb1a
No related branches found
No related tags found
No related merge requests found
......@@ -15,6 +15,7 @@
"@types/react": "^16.9.53",
"@types/react-dom": "^16.9.8",
"@types/react-router-dom": "^5.1.7",
"emoji-picker-react": "^3.4.4",
"react": "^17.0.2",
"react-alice-carousel": "^2.5.1",
"react-dom": "^17.0.2",
......
......@@ -95,8 +95,8 @@ interface AddTaskBody {
name: string;
text: string;
icon: string;
priority: string;
dependentcies: Array<string>;
priority: Priority;
dependencies: Array<string>;
requirements: Array<TaskRequirement>;
assigned: Array<TaskAssignment>;
}
......@@ -111,10 +111,10 @@ interface UpdateTaskBody {
icon?: string;
priority?: string;
status?: string;
remove_dependentcies?: Array<string>;
remove_dependencies?: Array<string>;
remove_requirements?: Array<string>;
remove_assigned?: Array<string>;
add_dependentcies?: Array<string>;
add_dependencies?: Array<string>;
add_requirements?: Array<TaskRequirement>;
add_assigned?: Array<TaskAssignment>;
}
......
......@@ -5,6 +5,7 @@ import Button from 'components/ui/Button';
import TextInput from 'components/ui/TextInput';
import './project-form.scss';
import { getTeam, getTeams, Team } from 'adapters/team';
import CheckboxGroup from 'components/ui/CheckboxGroup';
interface Props {
project?: Project
......@@ -76,7 +77,6 @@ export default function ProjectForm({ project, onSubmit }: Props) {
const colors = Object.values(ProjectColors);
const allStatus = Object.values(Status);
console.log(allStatus);
const handleSubmit = useCallback(async (e: FormEvent) => {
......@@ -134,28 +134,12 @@ export default function ProjectForm({ project, onSubmit }: Props) {
/>
<div className="teams">
{
allTeams.map((team) => (
<div className="team-item" key={team.id}>
<input type="checkbox" id={team.id}
checked={teams.indexOf(team.id) >= 0}
onClick={(e) => {
if (teams.find(id => team.id === id)) {
setTeams(state => state.filter(id => id !== team.id));
} else {
setTeams(state => [...state, team.id]);
}
}} />
<label htmlFor={team.id}>{team.name}</label>
</div>
))
}
<CheckboxGroup choices={allTeams} chosen={teams} setChosen={setTeams} />
</div>
{
status &&
<select onChange={(e: any) => {
<select onChange={(e) => {
let currentStatus = Object.values(Status).find(s => s === e.target.value) ?? Status.OPEN;
setStatus(currentStatus);
}
......
import { TaskRequirement } from 'adapters/task';
import { TeamRole } from 'adapters/team';
import { useState } from 'react';
import { possibleRole } from '../TaskForm';
interface Props {
roles: possibleRole[],
requirements: TaskRequirement[],
setRequirements: Function
}
export default function RequirementsChoice({ roles, requirements, setRequirements }: Props) {
const [possibleRoles, setPossibleRoles] = useState<possibleRole[]>(roles
.filter(role => !requirements.find(r => r.role === role.id))
);
return (
<div className="requirements-field">
{
requirements.map((requirement) => (
<div className="requirement" key={requirement.role + '/' + requirement.time}>
<select>
<option value={requirement.role}>{roles.find(r => r.id === requirement.role)}</option>
{
possibleRoles.map(role => (
<option value={role.id} key={role.id}>{role.label}</option>
))
}
</select>
<input type="number" value={requirement.time} min={0}
/>
</div>
))
}
{
possibleRoles.length > 0 && (
<div className="add-btn" onClick={() => setRequirements(
(state: any) => {
setPossibleRoles(state => {
return state.slice(1);
})
return [...state, {
role: possibleRoles[0].id,
time: 0
}];
}
)}>
new
</div>
)
}
</div>
)
}
import { Priority, Task } from 'adapters/task';
import { FormEvent, useCallback, useEffect, useState } from 'react';
import './task-form.scss';
import Callout from 'components/ui/Callout';
import TextInput from 'components/ui/TextInput';
import Picker from 'emoji-picker-react';
import { getProjectTasks, Project } from 'adapters/project';
import CheckboxGroup from 'components/ui/CheckboxGroup';
import { getTeam, getTeamRoles } from 'adapters/team';
import RequirementsChoice from './RequirementsChoice';
interface Props {
task?: Task;
onSubmit: (name: string, text: string, icon: string, priority: string) => void;
project: Project;
}
function validateName(name: string): string | null {
if (name.length > 0) {
return null;
} else {
return 'Please enter a name';
}
}
function validateText(text: string): string | null {
if (text.length > 0) {
return null;
} else {
return 'Please enter a description';
}
}
function validateIcon(icon: string): string | null {
if (icon.length > 0) {
return null;
} else {
return 'Please enter an icon';
}
}
function validatePriority(priority: string): string | null {
if (priority.length > 0) {
return null;
} else {
return 'Please choose a priority';
}
}
export interface possibleRole {
id: string;
label: string;
}
export default function TaskForm({ task, onSubmit, project }: Props) {
const [name, setName] = useState(task?.name);
const [text, setText] = useState(task?.text);
const [icon, setIcon] = useState(task?.icon);
const [priority, setPriority] = useState(task?.priority);
const [error, setError] = useState('');
const [tasks, setTasks] = useState(task?.dependencies);
const [requirements, setRequirements] = useState(task?.requirements ?? []);
const allPriorities = Object.values(Priority);
const [allTasks, setAllTasks] = useState<Task[]>([]);
const [allRoles, setAllRoles] = useState<possibleRole[]>([]);
useEffect(() => {
getProjectTasks(project.id).then((tasks) => {
setAllTasks(tasks.filter(cTask => task?.id !== cTask.id));
});
project.teams.forEach((teamId) => {
getTeam(teamId).then(team => {
getTeamRoles(teamId).then((roles) => {
setAllRoles(state => [...state, ...roles.map(role => {
return {
id: role.id,
label: team.name + ': ' + role.name
}
})]);
})
})
})
}, []);
const handleSubmit = useCallback(async (e: FormEvent) => {
e.preventDefault();
if (validateName(name ?? '') === null &&
validateText(text ?? '') === null &&
validateIcon(icon ?? '') === null &&
validatePriority(priority ?? '') === null
) {
onSubmit?.(name ?? '', text ?? '', icon ?? '', priority ?? '');
} else {
setError('Please fill in the mandatory fields.');
}
}, [onSubmit, setError, name, text, priority, icon]);
return (
<form className="task-form" onSubmit={handleSubmit}>
{error && <Callout message={error} />}
<TextInput
label="Name"
name="name"
onChange={setName}
defaultText={name}
validation={validateName}
/>
<TextInput
label="Description"
name="text"
onChange={setText}
defaultText={text}
validation={validateText}
type="textarea"
/>
<select onChange={(e) => {
let currentPriority = Object.values(Priority).find(s => s === e.target.value) ?? Priority.LOW;
setPriority(currentPriority);
}}>
{
allPriorities.map((prio) => (
<option value={prio} key={prio}>{prio}</option>
))
}
</select>
<Picker onEmojiClick={(e, emoji) => setIcon(emoji.unified)} />
<h2>Dependencies</h2>
{
allTasks.length > 0 ? (
<CheckboxGroup choices={allTasks ?? []} setChosen={setTasks} chosen={tasks ?? []} />
) : <div>No other tasks in this project</div>
}
{
allRoles.length > 0 && (
<RequirementsChoice setRequirements={setRequirements} roles={allRoles} requirements={requirements ?? []} />
)
}
</form>
)
}
\ No newline at end of file
import './task-list.scss';
import { Task as ITask } from 'adapters/task';
import Task from 'components/ui/Task';
import { Link } from 'react-router-dom';
interface Props {
tasks: ITask[]
......@@ -12,9 +13,9 @@ export default function TaskList({ tasks, addButton }: Props) {
<div className="task-list">
{
addButton && (
<div className="add-btn">
<Link to="tasks/create" className="add-btn">
+
</div>
</Link>
)
}
{
......
interface Props {
choices: {
id: string;
name: string;
}[],
chosen: string[],
setChosen: Function
}
export default function CheckboxGroup({ choices, chosen, setChosen }: Props) {
return (
<div className="checkbox-group">
{
choices.map((choice) => (
<div className="team-item" key={choice.id}>
<input type="checkbox" id={choice.id}
checked={chosen.indexOf(choice.id) >= 0}
onClick={(e) => {
if (chosen.find(id => choice.id === id)) {
setChosen((state: any) => state.filter((id: any) => id !== choice.id));
} else {
setChosen((state: any) => [...state, choice.id]);
}
}} />
<label htmlFor={choice.id}>{choice.name}</label>
</div>
))
}
</div>
)
}
\ No newline at end of file
......@@ -10,6 +10,7 @@ const TaskDetail = lazy(() => import('pages/Tasks/TaskDetail'));
const TaskStart = lazy(() => import('pages/Tasks/TaskStart'));
const ProjectDetail = lazy(() => import('pages/Projects/ProjectDetail'));
const ProjectCreate = lazy(() => import('pages/Projects/ProjectCreate'));
const TaskCreate = lazy(() => import('pages/Tasks/TaskCreate'));
const ProjectEdit = lazy(() => import('pages/Projects/ProjectEdit'));
const Projects = lazy(() => import('pages/Projects'));
const Stats = lazy(() => import('pages/Stats'));
......@@ -27,6 +28,7 @@ export default function AppWrapper() {
<ProtectedRoute path="/tasks/:uuid" component={TaskDetail} />
<ProtectedRoute path="/tasks" exact component={Tasks} />
<ProtectedRoute path="/projects/create" component={ProjectCreate} />
<ProtectedRoute path="/projects/:projectId/tasks/create" component={TaskCreate} />
<ProtectedRoute path="/projects/:projectId/edit" component={ProjectEdit} />
<ProtectedRoute path="/projects/:projectId" component={ProjectDetail} />
<ProtectedRoute path="/projects" component={Projects} />
......
import { useHistory, useParams } from "react-router";
import TaskForm from 'components/forms/TaskForm';
import { useCallback, useEffect, useState } from "react";
import { createTask } from "adapters/task";
import Callout from "components/ui/Callout";
import { getProject, Project } from "adapters/project";
interface Params {
projectId: string;
}
export default function TaskCreate() {
const { projectId } = useParams<Params>();
const history = useHistory();
const [error, setError] = useState('');
const [project, setProject] = useState<Project>();
useEffect(() => {
getProject(projectId).then((project) => setProject(project));
}, []);
const handleSubmit = useCallback(async (name: string, text: string, icon: string, priority: string) => {
try {
//if (await createTask({ project: projectId name, text, icon, priority })) {
history.push('/projects/' + projectId);
//} else {
setError('There was an error with creating your project. Please try again!');
//}
} catch (e) { }
}, [history, projectId]);
return (
<div className="task-create-page">
<div className="content-container">
<h1>Create a new Task</h1>
{error && <Callout message={error} />}
{
project &&
<TaskForm onSubmit={handleSubmit} project={project} />
}
</div>
</div>
)
}
\ No newline at end of file
......@@ -4316,6 +4316,11 @@ emittery@^0.7.1:
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82"
integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==
emoji-picker-react@^3.4.4:
version "3.4.4"
resolved "https://registry.yarnpkg.com/emoji-picker-react/-/emoji-picker-react-3.4.4.tgz#027786af60d4b7ebe04338c5456ae7ae4b3d3eb6"
integrity sha512-j5atTz5Uawt926Bc37MG5S0MwfIa9Gh4CVDGhnMSBhKZkDmgd5Q0QtQgcv+baLGdByYBsYx1OyQHORc6o8Ce5Q==
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
......@@ -9075,6 +9080,13 @@ raw-body@2.4.0:
iconv-lite "0.4.24"
unpipe "1.0.0"
react-alice-carousel@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/react-alice-carousel/-/react-alice-carousel-2.5.1.tgz#d8b27f942d342bf57367eb2c3301358a28758381"
integrity sha512-UeAd+O83TEiCxbDMMd9xAOLRr+xPNFPai9W6cNQgmIfEBgOiKDdntpTnhhwfXKoirXxQcbPlg9eG7FG9D1M4SA==
dependencies:
vanilla-swipe "^2.2.0"
react-app-polyfill@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz#a0bea50f078b8a082970a9d853dc34b6dcc6a3cf"
......@@ -11111,6 +11123,11 @@ value-equal@^1.0.1:
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==
vanilla-swipe@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/vanilla-swipe/-/vanilla-swipe-2.3.0.tgz#a2cd466aabed00c1e8abd7b69a86940bf9319516"
integrity sha512-4m8vZ/kckRG7RQUYNg+0lGILMHT08KEgwePlRLzediDSu7aQFBLB0V2n36vUmYqq5CVWASOzZ8zpnQFZXIbHbA==
vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment