bugfix: fix user checklist item toggle completion

This commit is contained in:
Jordan Knott
2020-07-13 16:21:37 -05:00
parent d8daa60729
commit 1e9813601e
4 changed files with 551 additions and 525 deletions

View File

@ -1,19 +1,19 @@
import React, { useState } from 'react';
import { action } from '@storybook/addon-actions';
import React, {useState} from 'react';
import {action} from '@storybook/addon-actions';
import BaseStyles from 'App/BaseStyles';
import NormalizeStyles from 'App/NormalizeStyles';
import { theme } from 'App/ThemeStyles';
import {theme} from 'App/ThemeStyles';
import produce from 'immer';
import styled, { ThemeProvider } from 'styled-components';
import Checklist, { ChecklistItem } from '.';
import styled, {ThemeProvider} from 'styled-components';
import Checklist, {ChecklistItem} from '.';
export default {
component: Checklist,
title: 'Checklist',
parameters: {
backgrounds: [
{ name: 'gray', value: '#f8f8f8', default: true },
{ name: 'white', value: '#ffffff' },
{name: 'gray', value: '#f8f8f8', default: true},
{name: 'white', value: '#ffffff'},
],
},
};
@ -138,6 +138,7 @@ export const Default = () => {
key={item.id}
wrapperProps={{}}
handleProps={{}}
checklistID='id'
itemID={item.id}
name={item.name}
complete={item.complete}

View File

@ -1,7 +1,7 @@
import React, { useState, useRef, useEffect } from 'react';
import React, {useState, useRef, useEffect} from 'react';
import styled from 'styled-components';
import { CheckSquare, Trash, Square, CheckSquareOutline, Clock, Cross, AccountPlus } from 'shared/icons';
import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd';
import {CheckSquare, Trash, Square, CheckSquareOutline, Clock, Cross, AccountPlus} from 'shared/icons';
import {DragDropContext, Droppable, Draggable, DropResult} from 'react-beautiful-dnd';
import {
isPositionChanged,
getSortedDraggables,
@ -81,7 +81,7 @@ const ChecklistProgressBar = styled.div`
overflow: hidden;
position: relative;
`;
const ChecklistProgressBarCurrent = styled.div<{ width: number }>`
const ChecklistProgressBarCurrent = styled.div<{width: number}>`
width: ${props => props.width}%;
background: rgba(${props => (props.width === 100 ? props.theme.colors.success : props.theme.colors.primary)});
bottom: 0;
@ -129,9 +129,10 @@ const ChecklistItemTextControls = styled.div`
padding: 6px 0;
width: 100%;
display: inline-flex;
align-items: center;
`;
const ChecklistItemText = styled.span<{ complete: boolean }>`
const ChecklistItemText = styled.span<{complete: boolean}>`
color: ${props => (props.complete ? '#5e6c84' : `rgba(${props.theme.colors.text.primary})`)};
${props => props.complete && 'text-decoration: line-through;'}
line-height: 20px;
@ -155,6 +156,11 @@ const ControlButton = styled.div`
padding: 4px 6px;
border-radius: 6px;
background-color: rgba(${props => props.theme.colors.bg.primary}, 0.8);
display: flex;
width: 32px;
height: 32px;
align-items: center;
justify-content: center;
&:hover {
background-color: rgba(${props => props.theme.colors.primary}, 1);
}
@ -206,7 +212,7 @@ const TrashButton = styled(Trash)`
fill: rgba(${props => props.theme.colors.text.primary});
`;
const ChecklistItemWrapper = styled.div<{ ref: any }>`
const ChecklistItemWrapper = styled.div<{ref: any}>`
user-select: none;
clear: both;
padding-left: 40px;
@ -216,6 +222,9 @@ const ChecklistItemWrapper = styled.div<{ ref: any }>`
transition-property: transform, opacity, height, padding, margin;
transition-duration: 0.14s;
transition-timing-function: ease-in;
& ${ControlButton}:last-child {
margin-right: 4px;
}
&:hover {
background-color: rgba(${props => props.theme.colors.bg.primary}, 0.4);
@ -274,18 +283,19 @@ const ChecklistNewItem = styled.div`
type ChecklistItemProps = {
itemID: string;
checklistID: string;
complete: boolean;
name: string;
onChangeName: (itemID: string, currentName: string) => void;
wrapperProps: any;
handleProps: any;
onToggleItem: (itemID: string, complete: boolean) => void;
onDeleteItem: (itemID: string) => void;
onDeleteItem: (checklistIDID: string, itemID: string) => void;
};
export const ChecklistItem = React.forwardRef(
(
{ itemID, complete, name, wrapperProps, handleProps, onChangeName, onToggleItem, onDeleteItem }: ChecklistItemProps,
{itemID, checklistID, complete, name, wrapperProps, handleProps, onChangeName, onToggleItem, onDeleteItem}: ChecklistItemProps,
$item,
) => {
const $editor = useRef<HTMLTextAreaElement>(null);
@ -309,8 +319,8 @@ export const ChecklistItem = React.forwardRef(
{complete ? (
<ChecklistItemCheckedIcon width={20} height={20} />
) : (
<ChecklistItemUncheckedIcon width={20} height={20} />
)}
<ChecklistItemUncheckedIcon width={20} height={20} />
)}
</ChecklistIcon>
{editting ? (
<>
@ -352,7 +362,7 @@ export const ChecklistItem = React.forwardRef(
onClick={e => {
e.stopPropagation();
setEditting(false);
onDeleteItem(itemID);
onDeleteItem(checklistID, itemID);
}}
>
<Trash width={16} height={16} />
@ -360,34 +370,34 @@ export const ChecklistItem = React.forwardRef(
</EditControls>
</>
) : (
<ChecklistItemDetails
onClick={() => {
setEditting(true);
}}
>
<ChecklistItemRow>
<ChecklistItemTextControls>
<ChecklistItemText complete={complete}>{name}</ChecklistItemText>
<ChecklistControls>
<ControlButton>
<AssignUserButton width={14} height={14} />
</ControlButton>
<ControlButton>
<ClockButton width={14} height={14} />
</ControlButton>
<ControlButton
onClick={e => {
e.stopPropagation();
onDeleteItem(itemID);
}}
>
<TrashButton width={14} height={14} />
</ControlButton>
</ChecklistControls>
</ChecklistItemTextControls>
</ChecklistItemRow>
</ChecklistItemDetails>
)}
<ChecklistItemDetails
onClick={() => {
setEditting(true);
}}
>
<ChecklistItemRow>
<ChecklistItemTextControls>
<ChecklistItemText complete={complete}>{name}</ChecklistItemText>
<ChecklistControls>
<ControlButton>
<AssignUserButton width={14} height={14} />
</ControlButton>
<ControlButton>
<ClockButton width={14} height={14} />
</ControlButton>
<ControlButton
onClick={e => {
e.stopPropagation();
onDeleteItem(checklistID, itemID);
}}
>
<TrashButton width={14} height={14} />
</ControlButton>
</ChecklistControls>
</ChecklistItemTextControls>
</ChecklistItemRow>
</ChecklistItemDetails>
)}
</ChecklistItemWrapper>
);
},
@ -397,7 +407,7 @@ type AddNewItemProps = {
onAddItem: (name: string) => void;
};
const AddNewItem: React.FC<AddNewItemProps> = ({ onAddItem }) => {
const AddNewItem: React.FC<AddNewItemProps> = ({onAddItem}) => {
const $editor = useRef<HTMLTextAreaElement>(null);
const $wrapper = useRef<HTMLDivElement>(null);
const [currentName, setCurrentName] = useState('');
@ -454,8 +464,8 @@ const AddNewItem: React.FC<AddNewItemProps> = ({ onAddItem }) => {
</EditControls>
</>
) : (
<NewItemButton onClick={() => setEditting(true)}>Add an item</NewItemButton>
)}
<NewItemButton onClick={() => setEditting(true)}>Add an item</NewItemButton>
)}
</ChecklistNewItem>
);
};
@ -467,7 +477,7 @@ type ChecklistTitleEditorProps = {
};
const ChecklistTitleEditor = React.forwardRef(
({ name, onChangeName, onCancel }: ChecklistTitleEditorProps, $name: any) => {
({name, onChangeName, onCancel}: ChecklistTitleEditorProps, $name: any) => {
const [currentName, setCurrentName] = useState(name);
return (
<>
@ -515,7 +525,7 @@ type ChecklistProps = {
onChangeItemName: (itemID: string, currentName: string) => void;
wrapperProps: any;
handleProps: any;
onDeleteItem: (itemID: string) => void;
onDeleteItem: (checklistID: string, itemID: string) => void;
onAddItem: (itemName: string) => void;
items: Array<TaskChecklistItem>;
};
@ -569,21 +579,21 @@ const Checklist = React.forwardRef(
}}
/>
) : (
<WindowChecklistTitle {...handleProps}>
<WindowTitleText onClick={() => setEditting(true)}>{name}</WindowTitleText>
<WindowOptions>
<DeleteButton
onClick={$target => {
onDeleteChecklist($target, checklistID);
}}
color="danger"
variant="outline"
>
Delete
<WindowChecklistTitle {...handleProps}>
<WindowTitleText onClick={() => setEditting(true)}>{name}</WindowTitleText>
<WindowOptions>
<DeleteButton
onClick={$target => {
onDeleteChecklist($target, checklistID);
}}
color="danger"
variant="outline"
>
Delete
</DeleteButton>
</WindowOptions>
</WindowChecklistTitle>
)}
</WindowOptions>
</WindowChecklistTitle>
)}
</WindowTitle>
<ChecklistProgress>
<ChecklistProgressPercent>{`${percent}%`}</ChecklistProgressPercent>

View File

@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from 'react';
import { Bin, Cross, Plus } from 'shared/icons';
import React, {useState, useRef, useEffect} from 'react';
import {Bin, Cross, Plus} from 'shared/icons';
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
import ReactMarkdown from 'react-markdown';
@ -9,7 +9,7 @@ import {
getNewDraggablePosition,
getAfterDropDraggableList,
} from 'shared/utils/draggables';
import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd';
import {DragDropContext, Droppable, Draggable, DropResult} from 'react-beautiful-dnd';
import TaskAssignee from 'shared/components/TaskAssignee';
import moment from 'moment';
@ -54,7 +54,7 @@ import {
MetaDetailTitle,
MetaDetailContent,
} from './Styles';
import Checklist, { ChecklistItem, ChecklistItems } from '../Checklist';
import Checklist, {ChecklistItem, ChecklistItems} from '../Checklist';
import styled from 'styled-components';
const ChecklistContainer = styled.div``;
@ -69,7 +69,7 @@ type TaskLabelProps = {
onClick: ($target: React.RefObject<HTMLElement>) => void;
};
const TaskLabelItem: React.FC<TaskLabelProps> = ({ label, onClick }) => {
const TaskLabelItem: React.FC<TaskLabelProps> = ({label, onClick}) => {
const $label = useRef<HTMLDivElement>(null);
return (
<TaskDetailLabel
@ -84,14 +84,14 @@ const TaskLabelItem: React.FC<TaskLabelProps> = ({ label, onClick }) => {
);
};
const TaskContent: React.FC<TaskContentProps> = ({ description, onEditContent }) => {
const TaskContent: React.FC<TaskContentProps> = ({description, onEditContent}) => {
return description === '' ? (
<TaskDetailsAddDetailsButton onClick={onEditContent}>Add a more detailed description</TaskDetailsAddDetailsButton>
) : (
<TaskDetailsMarkdown onClick={onEditContent}>
<ReactMarkdown source={description} />
</TaskDetailsMarkdown>
);
<TaskDetailsMarkdown onClick={onEditContent}>
<ReactMarkdown source={description} />
</TaskDetailsMarkdown>
);
};
type DetailsEditorProps = {
@ -144,7 +144,7 @@ type TaskDetailsProps = {
onTaskDescriptionChange: (task: Task, newDescription: string) => void;
onDeleteTask: (task: Task) => void;
onAddItem: (checklistID: string, name: string, position: number) => void;
onDeleteItem: (itemID: string) => void;
onDeleteItem: (checklistID: string, itemID: string) => void;
onChangeItemName: (itemID: string, itemName: string) => void;
onToggleTaskComplete: (task: Task) => void;
onToggleChecklistItem: (itemID: string, complete: boolean) => void;
@ -214,7 +214,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
onOpenAddLabelPopup(task, $target);
};
const onDragEnd = ({ draggableId, source, destination, type }: DropResult) => {
const onDragEnd = ({draggableId, source, destination, type}: DropResult) => {
if (typeof destination === 'undefined') return;
if (!isPositionChanged(source, destination)) return;
@ -233,7 +233,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
};
beforeDropDraggables = getSortedDraggables(
task.checklists.map(checklist => {
return { id: checklist.id, position: checklist.position };
return {id: checklist.id, position: checklist.position};
}),
);
if (droppedDraggable === null || beforeDropDraggables === null) {
@ -249,9 +249,9 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
const newPosition = getNewDraggablePosition(afterDropDraggables, destination.index);
console.log(droppedGroup);
console.log(`positiion: ${newPosition}`);
onChecklistDrop({ ...droppedGroup, position: newPosition });
onChecklistDrop({...droppedGroup, position: newPosition});
} else {
throw { error: 'task group can not be found' };
throw {error: 'task group can not be found'};
}
} else {
const targetChecklist = task.checklists.findIndex(
@ -266,7 +266,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
};
beforeDropDraggables = getSortedDraggables(
task.checklists[targetChecklist].items.map(item => {
return { id: item.id, position: item.position };
return {id: item.id, position: item.position};
}),
);
if (droppedDraggable === null || beforeDropDraggables === null) {
@ -379,8 +379,8 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
}}
/>
) : (
<TaskContent description={description} onEditContent={handleClick} />
)}
<TaskContent description={description} onEditContent={handleClick} />
)}
<DragDropContext onDragEnd={onDragEnd}>
<Droppable direction="vertical" type="checklist" droppableId="root">
{dropProvided => (
@ -430,6 +430,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
<ChecklistItem
key={item.id}
itemID={item.id}
checklistID={item.taskChecklistID}
ref={itemDrop.innerRef}
wrapperProps={itemDrop.draggableProps}
handleProps={itemDrop.dragHandleProps}
@ -437,7 +438,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
complete={item.complete}
onDeleteItem={onDeleteItem}
onChangeName={onChangeItemName}
onToggleItem={() => {}}
onToggleItem={(itemID, complete) => onToggleChecklistItem(item.id, complete)}
/>
)}
</Draggable>