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

Fixed the display of long task descriptions

parent ce34f19d
No related branches found
No related tags found
No related merge requests found
import { ReactNode, useState } from 'react';
import { User } from 'adapters/user';
import Popup from 'components/ui/Popup';
import TeamMember, { TeamMemberProps } from 'components/ui/TeamMember';
import UserComponent from 'components/ui/User';
import { DropDownItem } from 'components/navigation/Dropdown';
import './member-list.scss';
import './user-list.scss';
interface Props {
members: TeamMemberProps[];
interface Props<T extends User> {
users: T[];
addContent?: ReactNode
info?: (user: T) => string;
settings?: (user: T) => DropDownItem[];
}
export default function MemberList({ members, addContent }: Props) {
export default function UserList<T extends User>({ users, addContent, info, settings }: Props<T>) {
const [showAdd, setShowAdd] = useState(false);
return (
<>
......@@ -29,8 +34,13 @@ export default function MemberList({ members, addContent }: Props) {
</div>
}
{members.length > 0 ? members.map((member) => (
<TeamMember key={member.user.id} {...member} />
{users.length > 0 ? users.map((user) => (
<UserComponent
key={user.id}
user={user}
info={info}
settings={settings}
/>
)) : (
<div>No user found.</div>
)}
......
......@@ -64,6 +64,8 @@
.description-container {
margin-top: 20px;
max-height: 3rem;
overflow: hidden;
}
.assignee-list {
......
......@@ -4,31 +4,31 @@ import { User } from 'adapters/user';
import Avatar from 'components/ui/Avatar';
import Dropdown, { DropDownItem } from 'components/navigation/Dropdown';
import './team-member.scss';
import './user.scss';
export interface TeamMemberProps {
user: User;
info: string;
settings?: DropDownItem[]
export interface UserProps<T extends User> {
user: T;
info?: (user: T) => string;
settings?: (user: T) => DropDownItem[];
}
export default function TeamMember({ user, info, settings }: TeamMemberProps) {
export default function UserComponent<T extends User>({ user, info, settings }: UserProps<T>) {
return (
<div className="team-member-item">
<Avatar user={user} />
<div className="details">
<div className="name">{user.realname ?? user.username}</div>
<div className="info">{info}</div>
<div className="info">{info?.(user)}</div>
</div>
{
settings &&
<Dropdown items={settings} position="right">
<div className="settings">
<span className="material-icons icon">
expand_more
</span>
</div>
</Dropdown>
<Dropdown items={settings(user)} position="right">
<div className="settings">
<span className="material-icons icon">
expand_more
</span>
</div>
</Dropdown>
}
</div>
);
......
import MemberList from 'components/layout/MemberList';
import { AssignedUser } from 'adapters/user';
import UserList from 'components/layout/UserList';
import LoadingScreen from 'components/ui/LoadingScreen';
import { TeamMemberProps } from 'components/ui/TeamMember';
interface Props {
assignees: TeamMemberProps[]
assignees: AssignedUser[]
}
export default function TaskAssignees({ assignees }: Props) {
......@@ -12,7 +13,12 @@ export default function TaskAssignees({ assignees }: Props) {
<section className="task-assignees-section">
{
assignees
? <MemberList members={assignees} />
? (
<UserList
users={assignees}
info={user => user.time + " min"}
/>
)
: <LoadingScreen />
}
</section>
......
......@@ -4,7 +4,7 @@ import { useHistory, useParams } from 'react-router';
import { getTeam } from 'adapters/team';
import { StatusColors } from 'adapters/common';
import { getCurrentUser } from 'adapters/user';
import { AssignedUser } from 'adapters/user';
import { getProject, Project } from 'adapters/project';
import { getTask, getTaskAssignees, Task, TaskAssignment } from 'adapters/task';
......@@ -13,102 +13,107 @@ import Tabs from 'components/navigation/Tabs';
import DetailGrid from 'components/layout/DetailGrid';
import LoadingScreen from 'components/ui/LoadingScreen';
import ButtonLink from 'components/navigation/ButtonLink';
import { TeamMemberProps } from 'components/ui/TeamMember';
import TaskAssignees from './TaskAssignees';
import TaskComments from './TaskComments';
import './task-detail.scss';
import {getLoggedInUser} from 'adapters/auth';
export interface Params {
taskId: string;
}
export default function TaskDetail() {
const [more, setMore] = useState(false);
const [task, setTask] = useState<Task>();
const [project, setProject] = useState<Project>();
const [teamNames, setTeamNames] = useState<string[]>([]);
const [assignees, setAssignees] = useState<TeamMemberProps[]>([]);
const [assignees, setAssignees] = useState<AssignedUser[]>([]);
const [assignment, setAssignment] = useState<TaskAssignment>();
const history = useHistory();
const { taskId } = useParams<Params>();
const userId = getLoggedInUser();
useEffect(() => {
getTask(taskId).then((task) => {
setTask(task);
getProject(task.project).then((project) => {
getProject(task.project).then(async (project) => {
setProject(project);
project.teams.forEach((teamId) =>
getTeam(teamId).then((team) => {
setTeamNames(state => [...state, team.name])
}
));
setTeamNames(
(await Promise.all(project.teams.map(getTeam)))
.map(team => team.name)
);
});
getTaskAssignees(taskId).then(assignees =>
setAssignees(assignees.map(assignee => ({
user: assignee,
info: assignee.time.toString() + ' min'
})))
);
getCurrentUser().then((user) =>
setAssignment(task.assigned.find(a => a.user === user.id))
);
getTaskAssignees(taskId).then(setAssignees);
setAssignment(task.assigned.find(a => a.user === userId))
}).catch(() => history.goBack());
}, [taskId, history]);
return (
task
? (
<div className={'tasks-detail-page theme-' + StatusColors.get(task.status)}>
<span className="material-icons back-btn" onClick={history.goBack} >
arrow_back
</span>
<div className="content-container">
<Tag label={task.status} color={StatusColors.get(task.status)} />
<h1>{task.name}</h1>
<div className="description-container">
<p>
{task.text}
</p>
</div>
<h2>
Details
</h2>
<DetailGrid
details={[
{ icon: 'folder', title: 'Project', label: project?.name ?? 'Loading...' },
{ icon: 'group', title: 'Teams', label: teamNames.join(', ') }
]}
/>
if (task) {
return (
<div className={'tasks-detail-page theme-' + StatusColors.get(task.status)}>
<span className="material-icons back-btn" onClick={history.goBack} >
arrow_back
</span>
<div className="content-container">
<Tag label={task.status} color={StatusColors.get(task.status)} />
<h1>{task.name}</h1>
<div className="description-container">
{
assignment && !assignment.finished && (
<ButtonLink href={'/tasks/' + taskId + '/start'} className="expanded">
Start working
</ButtonLink>
)
(task.text.length < 300)
? <p>{task.text}</p>
: (more
? <>
<p>{task.text}</p>
<a onClick={() => setMore(false)}>less</a>
</>
: <>
<p>{task.text.substr(0, 300) + '... '}</p>
<a onClick={() => setMore(true)}>more</a>
</>
)
}
<ButtonLink href={'/tasks/' + taskId + '/edit'} className="dark expanded">
Edit
</ButtonLink>
<Tabs
tabs={[
{
label: 'Assignees',
route: '/tasks/' + taskId,
component: <TaskAssignees assignees={assignees} />
},
{
label: 'Comments',
route: '/tasks/' + taskId + '/comments',
component: <TaskComments taskId={taskId} />
}
]}
/>
</div>
<h2>
Details
</h2>
<DetailGrid
details={[
{ icon: 'folder', title: 'Project', label: project?.name ?? 'Loading...' },
{ icon: 'group', title: 'Teams', label: teamNames.join(', ') }
]}
/>
{
assignment && !assignment.finished && (
<ButtonLink href={'/tasks/' + taskId + '/start'} className="expanded">
Start working
</ButtonLink>
)
}
<ButtonLink href={'/tasks/' + taskId + '/edit'} className="dark expanded">
Edit
</ButtonLink>
<Tabs
tabs={[
{
label: 'Assignees',
route: '/tasks/' + taskId,
component: <TaskAssignees assignees={assignees} />
},
{
label: 'Comments',
route: '/tasks/' + taskId + '/comments',
component: <TaskComments taskId={taskId} />
}
]}
/>
</div>
)
: <LoadingScreen />
);
</div>
)
} else {
return <LoadingScreen />
}
}
......@@ -17,6 +17,7 @@
}
.tasks-container {
margin-top: 20px;
margin-bottom: 60px;
.task {
......
......@@ -5,7 +5,7 @@ import { getTeamRoles, Team, TeamMember, TeamRole } from 'adapters/team';
import RoleForm from 'components/forms/RoleForm';
import MemberForm from 'components/forms/MemberForm';
import MemberList from 'components/layout/MemberList';
import UserList from 'components/layout/UserList';
import LoadingScreen from 'components/ui/LoadingScreen';
import './teams-members.scss';
......@@ -27,22 +27,9 @@ export default function TeamsMembers({ members, team }: Props) {
{
roles
? (
<MemberList
members={members.map(member => ({
user: member,
info: member.role.name,
settings: [{
label: 'Edit role',
popupContent: (
<RoleForm
setRoles={setRoles}
roles={roles}
team={team}
member={member}
/>
)
}]
}))}
<UserList
users={members}
info={member => member.role.name}
addContent={
<MemberForm
setRoles={setRoles}
......@@ -50,6 +37,17 @@ export default function TeamsMembers({ members, team }: Props) {
team={team}
/>
}
settings={member => [{
label: 'Edit role',
popupContent: (
<RoleForm
setRoles={setRoles}
roles={roles}
team={team}
member={member}
/>
)
}]}
/>
)
: <LoadingScreen />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment