Skip to content
Snippets Groups Projects
Commit 51947458 authored by Bernard Roland (Student Com20)'s avatar Bernard Roland (Student Com20)
Browse files

Added a button to quickly add/change assignment

parent 91567604
No related branches found
No related tags found
No related merge requests found
import { useCallback, useState } from "react";
import Popup from 'components/ui/Popup';
import Button from 'components/ui/Button';
import TimeInput from "components/ui/TimeInput";
import '../form.scss';
interface Props {
onAssign: (duration: number) => any;
initialTime?: number;
}
export default function AssignForm({ onAssign, initialTime }: Props) {
const [popup, setPopup] = useState(false);
const [selectedTime, setSelectedTime] = useState<number | undefined>(initialTime);
const addAssignee = useCallback((e) => {
e.preventDefault();
setPopup(false);
if (selectedTime && !Number.isNaN(selectedTime)) {
onAssign(selectedTime * 60);
} else {
onAssign(0);
}
}, [onAssign, selectedTime])
return <>
<Button className="expanded" onClick={() => setPopup(true)}>
{initialTime ? 'Change assignment' : 'Assign yourself'}
</Button>
{
popup && (
<Popup onClose={() => setPopup(false)}>
<form onSubmit={addAssignee}>
<TimeInput initialTime={initialTime && (initialTime / 60)} onChange={value => setSelectedTime(value)} />
<div>
<Button type="submit" className="expanded">
{initialTime ? 'Change assignment' : 'Assign yourself'}
</Button>
</div>
</form>
</Popup>
)
}
</>;
}
......@@ -7,18 +7,25 @@ import './time-input.scss';
interface Props {
onChange: (state: number) => void;
initialTime?: number;
}
export default function TimeInput({ onChange: userOnChange }: Props) {
const [formatted, setFormatted] = useState('');
function getFormatted(hours: number) {
if (hours > 0) {
return formatDuration(durationFor(hours, 'hour'), 'second', 2, true);
} else {
return 'none';
}
}
export default function TimeInput({ onChange: userOnChange, initialTime }: Props) {
const [formatted, setFormatted] = useState(initialTime ? getFormatted(initialTime) : '');
const onChange = useCallback(event => {
const value = parseFloat(event.target.value);
userOnChange(value);
if (!Number.isNaN(value)) {
setFormatted(
formatDuration(durationFor(value, 'hour'), 'second', 2, true)
);
setFormatted(getFormatted(value));
} else {
setFormatted('');
}
......@@ -27,7 +34,7 @@ export default function TimeInput({ onChange: userOnChange }: Props) {
return (
<div className="time-field">
<label htmlFor="time">Time in hours</label>
<input type="number" name="time" min={0} onChange={onChange} />
<input name="time" min={0} onChange={onChange} defaultValue={initialTime} />
<span className="formatted">{formatted}</span>
</div>
);
......
......@@ -6,28 +6,18 @@
margin: 20px 0;
display: flex;
align-items: baseline;
border-radius: 15px;
color: s.$text;
background: s.$background-light;
.formatted {
flex: 0 0 auto;
content: 'min';
margin-left: 10px;
min-width: 64px;
min-width: 75px;
white-space: nowrap;
text-align: center;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type=number] {
-moz-appearance: textfield;
}
label {
&:after {
content: ' *';
......
import { Link } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router';
import { getTeam } from 'adapters/team';
......@@ -8,7 +8,7 @@ import { AssignedUser } from 'adapters/user';
import { StatusColors } from 'adapters/common';
import { getLoggedInUser } from 'adapters/auth';
import { getProject, Project } from 'adapters/project';
import { getTask, getTaskAssignees, Task, TaskAssignment } from 'adapters/task';
import { getTask, getTaskAssignees, Task, updateTask } from 'adapters/task';
import Tag from 'components/ui/Tag';
import LongText from 'components/ui/LongText';
......@@ -21,6 +21,7 @@ import TaskAssignees from './TaskAssignees';
import TaskComments from './TaskComments';
import './task-detail.scss';
import AssignForm from 'components/forms/AssignForm';
export interface Params {
taskId: string;
......@@ -31,11 +32,11 @@ export default function TaskDetail() {
const [project, setProject] = useState<Project>();
const [teamNames, setTeamNames] = useState<string[]>([]);
const [assignees, setAssignees] = useState<AssignedUser[]>([]);
const [assignment, setAssignment] = useState<TaskAssignment>();
const history = useHistory();
const { taskId } = useParams<Params>();
const userId = getLoggedInUser();
const assignment = task?.assigned.find(a => a.user === userId);
useEffect(() => {
getTask(taskId).then((task) => {
......@@ -47,11 +48,30 @@ export default function TaskDetail() {
.map(team => team.name)
);
});
getTaskAssignees(taskId).then(setAssignees);
setAssignment(task.assigned.find(a => a.user === userId))
}).catch(() => {});
getTaskAssignees(taskId).then(setAssignees);
}, [taskId, userId, history]);
const onAssign = useCallback((time: number) => {
const reloadData = () => {
getTask(taskId).then(setTask);
getTaskAssignees(taskId).then(setAssignees);
};
if (time > 0) {
updateTask(taskId, {
remove_assigned: [ userId ],
add_assigned: [{
user: userId,
time: time,
finished: assignment?.finished ?? false,
}],
}).then(reloadData);
} else {
updateTask(taskId, { remove_assigned: [ userId ] })
.then(reloadData);
}
}, [taskId, userId, assignment]);
if (task) {
return (
<div className={'tasks-detail-page theme-' + task.color}>
......@@ -80,6 +100,7 @@ export default function TaskDetail() {
</ButtonLink>
)
}
<AssignForm onAssign={onAssign} initialTime={assignment && assignment.time} />
<ButtonLink href={'/tasks/' + taskId + '/edit'} className="dark expanded">
Edit
</ButtonLink>
......
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