change: redesign task details modal
This commit is contained in:
parent
9d6c67f791
commit
5c3afaba7c
@ -7,6 +7,7 @@ import { useRouteMatch, useHistory } from 'react-router';
|
|||||||
import {
|
import {
|
||||||
useFindTaskQuery,
|
useFindTaskQuery,
|
||||||
useUpdateTaskDueDateMutation,
|
useUpdateTaskDueDateMutation,
|
||||||
|
useSetTaskCompleteMutation,
|
||||||
useAssignTaskMutation,
|
useAssignTaskMutation,
|
||||||
useUnassignTaskMutation,
|
useUnassignTaskMutation,
|
||||||
useSetTaskChecklistItemCompleteMutation,
|
useSetTaskChecklistItemCompleteMutation,
|
||||||
@ -108,6 +109,7 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { loading, data, refetch } = useFindTaskQuery({ variables: { taskID } });
|
const { loading, data, refetch } = useFindTaskQuery({ variables: { taskID } });
|
||||||
|
const [setTaskComplete] = useSetTaskCompleteMutation();
|
||||||
const [updateTaskDueDate] = useUpdateTaskDueDateMutation({
|
const [updateTaskDueDate] = useUpdateTaskDueDateMutation({
|
||||||
onCompleted: () => {
|
onCompleted: () => {
|
||||||
refetch();
|
refetch();
|
||||||
@ -136,7 +138,7 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal
|
<Modal
|
||||||
width={1040}
|
width={768}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
history.push(projectURL);
|
history.push(projectURL);
|
||||||
}}
|
}}
|
||||||
@ -146,6 +148,9 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
task={data.findTask}
|
task={data.findTask}
|
||||||
onTaskNameChange={onTaskNameChange}
|
onTaskNameChange={onTaskNameChange}
|
||||||
onTaskDescriptionChange={onTaskDescriptionChange}
|
onTaskDescriptionChange={onTaskDescriptionChange}
|
||||||
|
onToggleTaskComplete={task => {
|
||||||
|
setTaskComplete({ variables: { taskID: task.id, complete: !task.complete } });
|
||||||
|
}}
|
||||||
onDeleteTask={onDeleteTask}
|
onDeleteTask={onDeleteTask}
|
||||||
onChangeItemName={(itemID, itemName) => {
|
onChangeItemName={(itemID, itemName) => {
|
||||||
updateTaskChecklistItemName({ variables: { taskChecklistItemID: itemID, name: itemName } });
|
updateTaskChecklistItemName({ variables: { taskChecklistItemID: itemID, name: itemName } });
|
||||||
|
@ -46,6 +46,10 @@ export const Wrapper = styled.div<{ editorOpen: boolean }>`
|
|||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const AddListButton = styled(Button)`
|
||||||
|
padding: 6px 12px;
|
||||||
|
`;
|
||||||
|
|
||||||
export const Placeholder = styled.span`
|
export const Placeholder = styled.span`
|
||||||
color: #c2c6dc;
|
color: #c2c6dc;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -99,12 +103,6 @@ export const ListAddControls = styled.div`
|
|||||||
margin: 4px 0 0;
|
margin: 4px 0 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const AddListButton = styled(Button)`
|
|
||||||
float: left;
|
|
||||||
padding: 6px 12px;
|
|
||||||
border-radius: 3px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const CancelAdd = styled.div`
|
export const CancelAdd = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { Plus, Cross } from 'shared/icons';
|
import { Plus, Cross } from 'shared/icons';
|
||||||
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
||||||
|
import Button from 'shared/components/Button';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Container,
|
Container,
|
||||||
Wrapper,
|
Wrapper,
|
||||||
Placeholder,
|
Placeholder,
|
||||||
AddIconWrapper,
|
AddIconWrapper,
|
||||||
|
AddListButton,
|
||||||
ListNameEditor,
|
ListNameEditor,
|
||||||
ListAddControls,
|
ListAddControls,
|
||||||
CancelAdd,
|
CancelAdd,
|
||||||
AddListButton,
|
|
||||||
ListNameEditorWrapper,
|
ListNameEditorWrapper,
|
||||||
} from './Styles';
|
} from './Styles';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useRef } from 'react';
|
||||||
import styled, { css } from 'styled-components/macro';
|
import styled, { css } from 'styled-components/macro';
|
||||||
|
|
||||||
const Text = styled.span<{ fontSize: string }>`
|
const Text = styled.span<{ fontSize: string }>`
|
||||||
@ -109,7 +109,7 @@ type ButtonProps = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
type?: 'button' | 'submit';
|
type?: 'button' | 'submit';
|
||||||
className?: string;
|
className?: string;
|
||||||
onClick?: () => void;
|
onClick?: ($target: React.RefObject<HTMLButtonElement>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Button: React.FC<ButtonProps> = ({
|
const Button: React.FC<ButtonProps> = ({
|
||||||
@ -122,46 +122,68 @@ const Button: React.FC<ButtonProps> = ({
|
|||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
|
const $button = useRef<HTMLButtonElement>(null);
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (onClick) {
|
if (onClick) {
|
||||||
onClick();
|
onClick($button);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
switch (variant) {
|
switch (variant) {
|
||||||
case 'filled':
|
case 'filled':
|
||||||
return (
|
return (
|
||||||
<Filled type={type} onClick={handleClick} className={className} disabled={disabled} color={color}>
|
<Filled ref={$button} type={type} onClick={handleClick} className={className} disabled={disabled} color={color}>
|
||||||
<Text fontSize={fontSize}>{children}</Text>
|
<Text fontSize={fontSize}>{children}</Text>
|
||||||
</Filled>
|
</Filled>
|
||||||
);
|
);
|
||||||
case 'outline':
|
case 'outline':
|
||||||
return (
|
return (
|
||||||
<Outline type={type} onClick={handleClick} className={className} disabled={disabled} color={color}>
|
<Outline
|
||||||
|
ref={$button}
|
||||||
|
type={type}
|
||||||
|
onClick={handleClick}
|
||||||
|
className={className}
|
||||||
|
disabled={disabled}
|
||||||
|
color={color}
|
||||||
|
>
|
||||||
<Text fontSize={fontSize}>{children}</Text>
|
<Text fontSize={fontSize}>{children}</Text>
|
||||||
</Outline>
|
</Outline>
|
||||||
);
|
);
|
||||||
case 'flat':
|
case 'flat':
|
||||||
return (
|
return (
|
||||||
<Flat type={type} onClick={handleClick} className={className} disabled={disabled} color={color}>
|
<Flat ref={$button} type={type} onClick={handleClick} className={className} disabled={disabled} color={color}>
|
||||||
<Text fontSize={fontSize}>{children}</Text>
|
<Text fontSize={fontSize}>{children}</Text>
|
||||||
</Flat>
|
</Flat>
|
||||||
);
|
);
|
||||||
case 'lineDown':
|
case 'lineDown':
|
||||||
return (
|
return (
|
||||||
<LineDown type={type} onClick={handleClick} className={className} disabled={disabled} color={color}>
|
<LineDown
|
||||||
|
ref={$button}
|
||||||
|
type={type}
|
||||||
|
onClick={handleClick}
|
||||||
|
className={className}
|
||||||
|
disabled={disabled}
|
||||||
|
color={color}
|
||||||
|
>
|
||||||
<Text fontSize={fontSize}>{children}</Text>
|
<Text fontSize={fontSize}>{children}</Text>
|
||||||
<LineX color={color} />
|
<LineX color={color} />
|
||||||
</LineDown>
|
</LineDown>
|
||||||
);
|
);
|
||||||
case 'gradient':
|
case 'gradient':
|
||||||
return (
|
return (
|
||||||
<Gradient type={type} onClick={handleClick} className={className} disabled={disabled} color={color}>
|
<Gradient
|
||||||
|
ref={$button}
|
||||||
|
type={type}
|
||||||
|
onClick={handleClick}
|
||||||
|
className={className}
|
||||||
|
disabled={disabled}
|
||||||
|
color={color}
|
||||||
|
>
|
||||||
<Text fontSize={fontSize}>{children}</Text>
|
<Text fontSize={fontSize}>{children}</Text>
|
||||||
</Gradient>
|
</Gradient>
|
||||||
);
|
);
|
||||||
case 'relief':
|
case 'relief':
|
||||||
return (
|
return (
|
||||||
<Relief type={type} onClick={handleClick} className={className} disabled={disabled} color={color}>
|
<Relief ref={$button} type={type} onClick={handleClick} className={className} disabled={disabled} color={color}>
|
||||||
<Text fontSize={fontSize}>{children}</Text>
|
<Text fontSize={fontSize}>{children}</Text>
|
||||||
</Relief>
|
</Relief>
|
||||||
);
|
);
|
||||||
|
@ -6,6 +6,7 @@ const TaskDetailAssignee = styled.div`
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
|
float: left;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Wrapper = styled.div<{ size: number | string; bgColor: string | null; backgroundURL: string | null }>`
|
export const Wrapper = styled.div<{ size: number | string; bgColor: string | null; backgroundURL: string | null }>`
|
||||||
|
@ -49,16 +49,17 @@ export const TaskAction = styled.button`
|
|||||||
|
|
||||||
export const TaskDetailsWrapper = styled.div`
|
export const TaskDetailsWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0px 30px 60px;
|
padding: 0px 16px 60px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const TaskDetailsContent = styled.div`
|
export const TaskDetailsContent = styled.div`
|
||||||
width: 65%;
|
flex: 1;
|
||||||
padding-right: 50px;
|
padding-right: 8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const TaskDetailsSidebar = styled.div`
|
export const TaskDetailsSidebar = styled.div`
|
||||||
width: 35%;
|
width: 168px;
|
||||||
|
padding-left: 8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const TaskDetailsTitleWrapper = styled.div`
|
export const TaskDetailsTitleWrapper = styled.div`
|
||||||
@ -235,7 +236,13 @@ export const ProfileIcon = styled.div`
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const TaskDetailsAddMember = styled.div`
|
export const TaskDetailsAddMemberIcon = styled.div`
|
||||||
|
float: left;
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
background: ${mixin.darken('#262c49', 0.15)};
|
background: ${mixin.darken('#262c49', 0.15)};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -244,14 +251,6 @@ export const TaskDetailsAddMember = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const TaskDetailsAddMemberIcon = styled.div`
|
|
||||||
height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const TaskDetailLabels = styled.div`
|
export const TaskDetailLabels = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -292,11 +291,18 @@ export const TaskDetailsAddLabel = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const TaskDetailsAddLabelIcon = styled.div`
|
export const TaskDetailsAddLabelIcon = styled.div`
|
||||||
|
float: left;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: ${mixin.darken('#262c49', 0.15)};
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const NoDueDateLabel = styled.span`
|
export const NoDueDateLabel = styled.span`
|
||||||
@ -313,3 +319,69 @@ export const UnassignedLabel = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const ActionButtons = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ActionButtonsTitle = styled.h3`
|
||||||
|
color: rgba(${props => props.theme.colors.text.primary});
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ActionButton = styled(Button)`
|
||||||
|
margin-top: 8px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: rgba(${props => props.theme.colors.bg.primary}, 0.4);
|
||||||
|
text-align: left;
|
||||||
|
&:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
background: rgba(${props => props.theme.colors.bg.primary}, 0.6);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MetaDetails = styled.div`
|
||||||
|
margin-top: 8px;
|
||||||
|
display: flex;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TaskDueDateButton = styled(Button)`
|
||||||
|
height: 32px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: rgba(${props => props.theme.colors.bg.primary}, 0.4);
|
||||||
|
&:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
background: rgba(${props => props.theme.colors.bg.primary}, 0.6);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MetaDetail = styled.div`
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
margin: 0 16px 8px 0;
|
||||||
|
max-width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TaskDetailsSection = styled.div`
|
||||||
|
display: block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MetaDetailTitle = styled.h3`
|
||||||
|
color: rgba(${props => props.theme.colors.text.primary});
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
margin-top: 16px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
display: block;
|
||||||
|
line-height: 20px;
|
||||||
|
margin: 0 8px 4px 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MetaDetailContent = styled.div``;
|
||||||
|
@ -68,6 +68,7 @@ export const Default = () => {
|
|||||||
onMemberProfile={action('profile')}
|
onMemberProfile={action('profile')}
|
||||||
onOpenAddMemberPopup={action('open add member popup')}
|
onOpenAddMemberPopup={action('open add member popup')}
|
||||||
onAddItem={action('add item')}
|
onAddItem={action('add item')}
|
||||||
|
onToggleTaskComplete={action('toggle task complete')}
|
||||||
onToggleChecklistItem={action('toggle checklist item')}
|
onToggleChecklistItem={action('toggle checklist item')}
|
||||||
onOpenAddLabelPopup={action('open add label popup')}
|
onOpenAddLabelPopup={action('open add label popup')}
|
||||||
onOpenDueDatePopop={action('open due date popup')}
|
onOpenDueDatePopop={action('open due date popup')}
|
||||||
|
@ -7,15 +7,19 @@ import moment from 'moment';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
NoDueDateLabel,
|
NoDueDateLabel,
|
||||||
|
TaskDueDateButton,
|
||||||
UnassignedLabel,
|
UnassignedLabel,
|
||||||
TaskDetailsAddMember,
|
|
||||||
TaskGroupLabel,
|
TaskGroupLabel,
|
||||||
TaskGroupLabelName,
|
TaskGroupLabelName,
|
||||||
|
TaskDetailsSection,
|
||||||
TaskActions,
|
TaskActions,
|
||||||
TaskDetailsAddLabel,
|
TaskDetailsAddLabel,
|
||||||
TaskDetailsAddLabelIcon,
|
TaskDetailsAddLabelIcon,
|
||||||
TaskAction,
|
TaskAction,
|
||||||
TaskMeta,
|
TaskMeta,
|
||||||
|
ActionButtons,
|
||||||
|
ActionButton,
|
||||||
|
ActionButtonsTitle,
|
||||||
TaskHeader,
|
TaskHeader,
|
||||||
ProfileIcon,
|
ProfileIcon,
|
||||||
TaskDetailsContent,
|
TaskDetailsContent,
|
||||||
@ -37,6 +41,10 @@ import {
|
|||||||
TaskDetailAssignee,
|
TaskDetailAssignee,
|
||||||
TaskDetailAssignees,
|
TaskDetailAssignees,
|
||||||
TaskDetailsAddMemberIcon,
|
TaskDetailsAddMemberIcon,
|
||||||
|
MetaDetails,
|
||||||
|
MetaDetail,
|
||||||
|
MetaDetailTitle,
|
||||||
|
MetaDetailContent,
|
||||||
} from './Styles';
|
} from './Styles';
|
||||||
import Checklist from '../Checklist';
|
import Checklist from '../Checklist';
|
||||||
|
|
||||||
@ -127,6 +135,7 @@ type TaskDetailsProps = {
|
|||||||
onAddItem: (checklistID: string, name: string, position: number) => void;
|
onAddItem: (checklistID: string, name: string, position: number) => void;
|
||||||
onDeleteItem: (itemID: string) => void;
|
onDeleteItem: (itemID: string) => void;
|
||||||
onChangeItemName: (itemID: string, itemName: string) => void;
|
onChangeItemName: (itemID: string, itemName: string) => void;
|
||||||
|
onToggleTaskComplete: (task: Task) => void;
|
||||||
onToggleChecklistItem: (itemID: string, complete: boolean) => void;
|
onToggleChecklistItem: (itemID: string, complete: boolean) => void;
|
||||||
onOpenAddMemberPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
onOpenAddMemberPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||||
onOpenAddLabelPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
onOpenAddLabelPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||||
@ -138,6 +147,7 @@ type TaskDetailsProps = {
|
|||||||
const TaskDetails: React.FC<TaskDetailsProps> = ({
|
const TaskDetails: React.FC<TaskDetailsProps> = ({
|
||||||
task,
|
task,
|
||||||
onTaskNameChange,
|
onTaskNameChange,
|
||||||
|
onToggleTaskComplete,
|
||||||
onTaskDescriptionChange,
|
onTaskDescriptionChange,
|
||||||
onChangeItemName,
|
onChangeItemName,
|
||||||
onDeleteItem,
|
onDeleteItem,
|
||||||
@ -170,13 +180,14 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
const onUnassignedClick = () => {
|
const onUnassignedClick = () => {
|
||||||
onOpenAddMemberPopup(task, $unassignedRef);
|
onOpenAddMemberPopup(task, $unassignedRef);
|
||||||
};
|
};
|
||||||
const onAddMember = () => {
|
const onAddMember = ($target: React.RefObject<HTMLElement>) => {
|
||||||
onOpenAddMemberPopup(task, $addMemberRef);
|
onOpenAddMemberPopup(task, $target);
|
||||||
};
|
};
|
||||||
const $dueDateLabel = useRef<HTMLDivElement>(null);
|
const $dueDateLabel = useRef<HTMLDivElement>(null);
|
||||||
const $addLabelRef = useRef<HTMLDivElement>(null);
|
const $addLabelRef = useRef<HTMLDivElement>(null);
|
||||||
const onAddLabel = () => {
|
|
||||||
onOpenAddLabelPopup(task, $addLabelRef);
|
const onAddLabel = ($target: React.RefObject<HTMLElement>) => {
|
||||||
|
onOpenAddLabelPopup(task, $target);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -206,100 +217,111 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
</TaskHeader>
|
</TaskHeader>
|
||||||
<TaskDetailsWrapper>
|
<TaskDetailsWrapper>
|
||||||
<TaskDetailsContent>
|
<TaskDetailsContent>
|
||||||
<TaskDetailsLabel>Description</TaskDetailsLabel>
|
<MetaDetails>
|
||||||
{editorOpen ? (
|
{task.assigned && task.assigned.length !== 0 && (
|
||||||
<DetailsEditor
|
<MetaDetail>
|
||||||
description={description}
|
<MetaDetailTitle>MEMBERS</MetaDetailTitle>
|
||||||
onTaskDescriptionChange={newDescription => {
|
<MetaDetailContent>
|
||||||
setEditorOpen(false);
|
{task.assigned &&
|
||||||
setDescription(newDescription);
|
task.assigned.map(member => (
|
||||||
onTaskDescriptionChange(task, newDescription);
|
<TaskAssignee key={member.id} size={32} member={member} onMemberProfile={onMemberProfile} />
|
||||||
}}
|
))}
|
||||||
onCancel={() => {
|
<TaskDetailsAddMemberIcon ref={$addMemberRef} onClick={() => onAddMember($addMemberRef)}>
|
||||||
setEditorOpen(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<TaskContent description={description} onEditContent={handleClick} />
|
|
||||||
)}
|
|
||||||
{task.checklists &&
|
|
||||||
task.checklists
|
|
||||||
.slice()
|
|
||||||
.sort((a, b) => a.position - b.position)
|
|
||||||
.map(checklist => (
|
|
||||||
<Checklist
|
|
||||||
key={checklist.id}
|
|
||||||
name={checklist.name}
|
|
||||||
checklistID={checklist.id}
|
|
||||||
items={checklist.items}
|
|
||||||
onDeleteChecklist={() => {}}
|
|
||||||
onChangeName={() => {}}
|
|
||||||
onToggleItem={onToggleChecklistItem}
|
|
||||||
onDeleteItem={onDeleteItem}
|
|
||||||
onAddItem={n => {
|
|
||||||
if (task.checklists) {
|
|
||||||
let position = 1;
|
|
||||||
const lastChecklist = task.checklists.sort((a, b) => a.position - b.position)[-1];
|
|
||||||
if (lastChecklist) {
|
|
||||||
position = lastChecklist.position * 2 + 1;
|
|
||||||
}
|
|
||||||
onAddItem(checklist.id, n, position);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onChangeItemName={onChangeItemName}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</TaskDetailsContent>
|
|
||||||
<TaskDetailsSidebar>
|
|
||||||
<TaskDetailSectionTitle>Assignees</TaskDetailSectionTitle>
|
|
||||||
<TaskDetailAssignees>
|
|
||||||
{task.assigned && task.assigned.length === 0 ? (
|
|
||||||
<UnassignedLabel ref={$unassignedRef} onClick={onUnassignedClick}>
|
|
||||||
Unassigned
|
|
||||||
</UnassignedLabel>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{task.assigned &&
|
|
||||||
task.assigned.map(member => (
|
|
||||||
<TaskAssignee key={member.id} size={32} member={member} onMemberProfile={onMemberProfile} />
|
|
||||||
))}
|
|
||||||
<TaskDetailsAddMember ref={$addMemberRef} onClick={onAddMember}>
|
|
||||||
<TaskDetailsAddMemberIcon>
|
|
||||||
<Plus size={16} color="#c2c6dc" />
|
<Plus size={16} color="#c2c6dc" />
|
||||||
</TaskDetailsAddMemberIcon>
|
</TaskDetailsAddMemberIcon>
|
||||||
</TaskDetailsAddMember>
|
</MetaDetailContent>
|
||||||
</>
|
</MetaDetail>
|
||||||
)}
|
)}
|
||||||
</TaskDetailAssignees>
|
{task.labels.length !== 0 && (
|
||||||
<TaskDetailSectionTitle>Labels</TaskDetailSectionTitle>
|
<MetaDetail>
|
||||||
<TaskDetailLabels>
|
<MetaDetailTitle>LABELS</MetaDetailTitle>
|
||||||
{task.labels.map(label => {
|
<MetaDetailContent>
|
||||||
return (
|
{task.labels.map(label => {
|
||||||
<TaskLabelItem
|
return (
|
||||||
key={label.projectLabel.id}
|
<TaskLabelItem
|
||||||
label={label}
|
key={label.projectLabel.id}
|
||||||
onClick={$target => {
|
label={label}
|
||||||
onOpenAddLabelPopup(task, $target);
|
onClick={$target => {
|
||||||
}}
|
onOpenAddLabelPopup(task, $target);
|
||||||
/>
|
}}
|
||||||
);
|
/>
|
||||||
})}
|
);
|
||||||
<TaskDetailsAddLabel ref={$addLabelRef} onClick={onAddLabel}>
|
})}
|
||||||
<TaskDetailsAddLabelIcon>
|
<TaskDetailsAddLabelIcon ref={$addLabelRef} onClick={() => onAddLabel($addLabelRef)}>
|
||||||
<Plus size={16} color="#c2c6dc" />
|
<Plus size={16} color="#c2c6dc" />
|
||||||
</TaskDetailsAddLabelIcon>
|
</TaskDetailsAddLabelIcon>
|
||||||
</TaskDetailsAddLabel>
|
</MetaDetailContent>
|
||||||
</TaskDetailLabels>
|
</MetaDetail>
|
||||||
<TaskDetailSectionTitle>Due Date</TaskDetailSectionTitle>
|
)}
|
||||||
{task.dueDate ? (
|
{task.dueDate && (
|
||||||
<NoDueDateLabel ref={$dueDateLabel} onClick={() => onOpenDueDatePopop(task, $dueDateLabel)}>
|
<MetaDetail>
|
||||||
{moment(task.dueDate).format('MMM D [at] h:mm A')}
|
<MetaDetailTitle>DUE DATE</MetaDetailTitle>
|
||||||
</NoDueDateLabel>
|
<MetaDetailContent>
|
||||||
) : (
|
<TaskDueDateButton>{moment(task.dueDate).format('MMM D [at] h:mm A')}</TaskDueDateButton>
|
||||||
<NoDueDateLabel ref={$dueDateLabel} onClick={() => onOpenDueDatePopop(task, $dueDateLabel)}>
|
</MetaDetailContent>
|
||||||
No due date
|
</MetaDetail>
|
||||||
</NoDueDateLabel>
|
)}
|
||||||
)}
|
</MetaDetails>
|
||||||
|
|
||||||
|
<TaskDetailsSection>
|
||||||
|
<TaskDetailsLabel>Description</TaskDetailsLabel>
|
||||||
|
{editorOpen ? (
|
||||||
|
<DetailsEditor
|
||||||
|
description={description}
|
||||||
|
onTaskDescriptionChange={newDescription => {
|
||||||
|
setEditorOpen(false);
|
||||||
|
setDescription(newDescription);
|
||||||
|
onTaskDescriptionChange(task, newDescription);
|
||||||
|
}}
|
||||||
|
onCancel={() => {
|
||||||
|
setEditorOpen(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<TaskContent description={description} onEditContent={handleClick} />
|
||||||
|
)}
|
||||||
|
{task.checklists &&
|
||||||
|
task.checklists
|
||||||
|
.slice()
|
||||||
|
.sort((a, b) => a.position - b.position)
|
||||||
|
.map(checklist => (
|
||||||
|
<Checklist
|
||||||
|
key={checklist.id}
|
||||||
|
name={checklist.name}
|
||||||
|
checklistID={checklist.id}
|
||||||
|
items={checklist.items}
|
||||||
|
onDeleteChecklist={() => {}}
|
||||||
|
onChangeName={() => {}}
|
||||||
|
onToggleItem={onToggleChecklistItem}
|
||||||
|
onDeleteItem={onDeleteItem}
|
||||||
|
onAddItem={n => {
|
||||||
|
if (task.checklists) {
|
||||||
|
let position = 1;
|
||||||
|
const lastChecklist = task.checklists.sort((a, b) => a.position - b.position)[-1];
|
||||||
|
if (lastChecklist) {
|
||||||
|
position = lastChecklist.position * 2 + 1;
|
||||||
|
}
|
||||||
|
onAddItem(checklist.id, n, position);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onChangeItemName={onChangeItemName}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</TaskDetailsSection>
|
||||||
|
</TaskDetailsContent>
|
||||||
|
<TaskDetailsSidebar>
|
||||||
|
<ActionButtons>
|
||||||
|
<ActionButtonsTitle>ADD TO CARD</ActionButtonsTitle>
|
||||||
|
<ActionButton onClick={() => onToggleTaskComplete(task)}>
|
||||||
|
{task.complete ? 'Mark Incomplete' : 'Mark Complete'}
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton onClick={$target => onAddMember($target)}>Members</ActionButton>
|
||||||
|
<ActionButton onClick={$target => onAddLabel($target)}>Labels</ActionButton>
|
||||||
|
<ActionButton>Checklist</ActionButton>
|
||||||
|
<ActionButton onClick={$target => onOpenDueDatePopop(task, $target)}>Due Date</ActionButton>
|
||||||
|
<ActionButton>Attachment</ActionButton>
|
||||||
|
<ActionButton>Cover</ActionButton>
|
||||||
|
</ActionButtons>
|
||||||
</TaskDetailsSidebar>
|
</TaskDetailsSidebar>
|
||||||
</TaskDetailsWrapper>
|
</TaskDetailsWrapper>
|
||||||
</>
|
</>
|
||||||
|
@ -102,6 +102,17 @@ export type TaskGroup = {
|
|||||||
tasks: Array<Task>;
|
tasks: Array<Task>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ChecklistBadge = {
|
||||||
|
__typename?: 'ChecklistBadge';
|
||||||
|
complete: Scalars['Int'];
|
||||||
|
total: Scalars['Int'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TaskBadges = {
|
||||||
|
__typename?: 'TaskBadges';
|
||||||
|
checklist?: Maybe<ChecklistBadge>;
|
||||||
|
};
|
||||||
|
|
||||||
export type Task = {
|
export type Task = {
|
||||||
__typename?: 'Task';
|
__typename?: 'Task';
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
@ -115,6 +126,7 @@ export type Task = {
|
|||||||
assigned: Array<ProjectMember>;
|
assigned: Array<ProjectMember>;
|
||||||
labels: Array<TaskLabel>;
|
labels: Array<TaskLabel>;
|
||||||
checklists: Array<TaskChecklist>;
|
checklists: Array<TaskChecklist>;
|
||||||
|
badges: TaskBadges;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProjectsFilter = {
|
export type ProjectsFilter = {
|
||||||
@ -792,7 +804,7 @@ export type FindTaskQuery = (
|
|||||||
{ __typename?: 'Query' }
|
{ __typename?: 'Query' }
|
||||||
& { findTask: (
|
& { findTask: (
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'id' | 'name' | 'description' | 'dueDate' | 'position'>
|
& Pick<Task, 'id' | 'name' | 'description' | 'dueDate' | 'position' | 'complete'>
|
||||||
& { taskGroup: (
|
& { taskGroup: (
|
||||||
{ __typename?: 'TaskGroup' }
|
{ __typename?: 'TaskGroup' }
|
||||||
& Pick<TaskGroup, 'id'>
|
& Pick<TaskGroup, 'id'>
|
||||||
@ -1607,6 +1619,7 @@ export const FindTaskDocument = gql`
|
|||||||
description
|
description
|
||||||
dueDate
|
dueDate
|
||||||
position
|
position
|
||||||
|
complete
|
||||||
taskGroup {
|
taskGroup {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ query findTask($taskID: UUID!) {
|
|||||||
description
|
description
|
||||||
dueDate
|
dueDate
|
||||||
position
|
position
|
||||||
|
complete
|
||||||
taskGroup {
|
taskGroup {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user