diff --git a/frontend/src/Projects/Project/Details/index.tsx b/frontend/src/Projects/Project/Details/index.tsx index ab999ea..2147a2e 100644 --- a/frontend/src/Projects/Project/Details/index.tsx +++ b/frontend/src/Projects/Project/Details/index.tsx @@ -1,26 +1,26 @@ -import React, {useState, useContext, useEffect} from 'react'; +import React, { useState, useContext, useEffect } from 'react'; import Modal from 'shared/components/Modal'; import TaskDetails from 'shared/components/TaskDetails'; -import PopupMenu, {Popup, usePopup} from 'shared/components/PopupMenu'; +import PopupMenu, { Popup, usePopup } from 'shared/components/PopupMenu'; import MemberManager from 'shared/components/MemberManager'; -import {useRouteMatch, useHistory} from 'react-router'; +import { useRouteMatch, useHistory } from 'react-router'; import { - useDeleteTaskChecklistMutation, - useUpdateTaskChecklistNameMutation, - useUpdateTaskChecklistItemLocationMutation, - useCreateTaskChecklistMutation, - useFindTaskQuery, - useUpdateTaskDueDateMutation, - useSetTaskCompleteMutation, - useAssignTaskMutation, - useUnassignTaskMutation, - useSetTaskChecklistItemCompleteMutation, - useUpdateTaskChecklistLocationMutation, - useDeleteTaskChecklistItemMutation, - useUpdateTaskChecklistItemNameMutation, - useCreateTaskChecklistItemMutation, - FindTaskDocument, - FindTaskQuery, + useDeleteTaskChecklistMutation, + useUpdateTaskChecklistNameMutation, + useUpdateTaskChecklistItemLocationMutation, + useCreateTaskChecklistMutation, + useFindTaskQuery, + useUpdateTaskDueDateMutation, + useSetTaskCompleteMutation, + useAssignTaskMutation, + useUnassignTaskMutation, + useSetTaskChecklistItemCompleteMutation, + useUpdateTaskChecklistLocationMutation, + useDeleteTaskChecklistItemMutation, + useUpdateTaskChecklistItemNameMutation, + useCreateTaskChecklistItemMutation, + FindTaskDocument, + FindTaskQuery, } from 'shared/generated/graphql'; import UserIDContext from 'App/context'; import MiniProfile from 'shared/components/MiniProfile'; @@ -29,27 +29,27 @@ import produce from 'immer'; import styled from 'styled-components'; import Button from 'shared/components/Button'; import Input from 'shared/components/Input'; -import {useForm} from 'react-hook-form'; +import { useForm } from 'react-hook-form'; import updateApolloCache from 'shared/utils/cache'; const calculateChecklistBadge = (checklists: Array) => { - const total = checklists.reduce((prev: any, next: any) => { - return ( - prev + - next.items.reduce((innerPrev: any, _item: any) => { - return innerPrev + 1; - }, 0) + const total = checklists.reduce((prev: any, next: any) => { + return ( + prev + + next.items.reduce((innerPrev: any, _item: any) => { + return innerPrev + 1; + }, 0) + ); + }, 0); + const complete = checklists.reduce( + (prev: any, next: any) => + prev + + next.items.reduce((innerPrev: any, item: any) => { + return innerPrev + (item.complete ? 1 : 0); + }, 0), + 0, ); - }, 0); - const complete = checklists.reduce( - (prev: any, next: any) => - prev + - next.items.reduce((innerPrev: any, item: any) => { - return innerPrev + (item.complete ? 1 : 0); - }, 0), - 0, - ); - return {total, complete}; + return { total, complete }; }; const DeleteChecklistButton = styled(Button)` @@ -58,7 +58,7 @@ const DeleteChecklistButton = styled(Button)` margin-top: 8px; `; type CreateChecklistData = { - name: string; + name: string; }; const CreateChecklistForm = styled.form` display: flex; @@ -80,423 +80,437 @@ const InputError = styled.span` font-size: 12px; `; type CreateChecklistPopupProps = { - onCreateChecklist: (data: CreateChecklistData) => void; + onCreateChecklist: (data: CreateChecklistData) => void; }; -const CreateChecklistPopup: React.FC = ({onCreateChecklist}) => { - const {register, handleSubmit, errors} = useForm(); - const createUser = (data: CreateChecklistData) => { - onCreateChecklist(data); - }; - console.log(errors); - return ( - - - Create - - ); +const CreateChecklistPopup: React.FC = ({ onCreateChecklist }) => { + const { register, handleSubmit, errors } = useForm(); + const createUser = (data: CreateChecklistData) => { + onCreateChecklist(data); + }; + console.log(errors); + return ( + + + Create + + ); }; type DetailsProps = { - taskID: string; - projectURL: string; - onTaskNameChange: (task: Task, newName: string) => void; - onTaskDescriptionChange: (task: Task, newDescription: string) => void; - onDeleteTask: (task: Task) => void; - onOpenAddLabelPopup: (task: Task, $targetRef: React.RefObject) => void; - availableMembers: Array; - refreshCache: () => void; + taskID: string; + projectURL: string; + onTaskNameChange: (task: Task, newName: string) => void; + onTaskDescriptionChange: (task: Task, newDescription: string) => void; + onDeleteTask: (task: Task) => void; + onOpenAddLabelPopup: (task: Task, $targetRef: React.RefObject) => void; + availableMembers: Array; + refreshCache: () => void; }; -const initialMemberPopupState = {taskID: '', isOpen: false, top: 0, left: 0}; +const initialMemberPopupState = { taskID: '', isOpen: false, top: 0, left: 0 }; const Details: React.FC = ({ - projectURL, - taskID, - onTaskNameChange, - onTaskDescriptionChange, - onDeleteTask, - onOpenAddLabelPopup, - availableMembers, - refreshCache, + projectURL, + taskID, + onTaskNameChange, + onTaskDescriptionChange, + onDeleteTask, + onOpenAddLabelPopup, + availableMembers, + refreshCache, }) => { - const {userID} = useContext(UserIDContext); - const {showPopup, hidePopup} = usePopup(); - const history = useHistory(); - const match = useRouteMatch(); - const [currentMemberTask, setCurrentMemberTask] = useState(''); - const [memberPopupData, setMemberPopupData] = useState(initialMemberPopupState); - const [updateTaskChecklistLocation] = useUpdateTaskChecklistLocationMutation(); - const [updateTaskChecklistItemLocation] = useUpdateTaskChecklistItemLocationMutation({ - update: (client, response) => { - updateApolloCache( - client, - FindTaskDocument, - cache => - produce(cache, draftCache => { - const {prevChecklistID, checklistID, checklistItem} = response.data.updateTaskChecklistItemLocation; - console.log(`${checklistID} !== ${prevChecklistID}`); - if (checklistID !== prevChecklistID) { - const oldIdx = cache.findTask.checklists.findIndex(c => c.id === prevChecklistID); - const newIdx = cache.findTask.checklists.findIndex(c => c.id === checklistID); - console.log(`oldIdx ${oldIdx} newIdx ${newIdx}`); - if (oldIdx > -1 && newIdx > -1) { - const item = cache.findTask.checklists[oldIdx].items.find(item => item.id === checklistItem.id); - console.log(item); - if (item) { - draftCache.findTask.checklists[oldIdx].items = cache.findTask.checklists[oldIdx].items.filter( - i => i.id !== checklistItem.id, - ); - draftCache.findTask.checklists[newIdx].items.push({ - ...item, - position: checklistItem.position, - taskChecklistID: checklistID, - }); - } - } - } - }), - {taskID}, - ); - }, - }); - const [setTaskChecklistItemComplete] = useSetTaskChecklistItemCompleteMutation({ - update: client => { - updateApolloCache( - client, - FindTaskDocument, - cache => - produce(cache, draftCache => { - const {complete, total} = calculateChecklistBadge(draftCache.findTask.checklists); - draftCache.findTask.badges.checklist = { - __typename: 'ChecklistBadge', - complete, - total, - }; - }), - {taskID}, - ); - }, - }); - const [deleteTaskChecklist] = useDeleteTaskChecklistMutation({ - update: (client, deleteData) => { - updateApolloCache( - client, - FindTaskDocument, - cache => - produce(cache, draftCache => { - const {checklists} = cache.findTask; - console.log(deleteData) - draftCache.findTask.checklists = checklists.filter(c => c.id !== deleteData.data.deleteTaskChecklist.taskChecklist.id); - const {complete, total} = calculateChecklistBadge(draftCache.findTask.checklists); - draftCache.findTask.badges.checklist = { - __typename: 'ChecklistBadge', - complete, - total, - }; - if (complete === 0 && total === 0) { - draftCache.findTask.badges.checklist = null; - } - }), - {taskID}, - ); - }, - }); - const [updateTaskChecklistItemName] = useUpdateTaskChecklistItemNameMutation(); - const [createTaskChecklist] = useCreateTaskChecklistMutation({ - update: (client, createData) => { - updateApolloCache( - client, - FindTaskDocument, - cache => - produce(cache, draftCache => { - const item = createData.data.createTaskChecklist; - draftCache.findTask.checklists.push({...item}); - }), - {taskID}, - ); - }, - }); - const [updateTaskChecklistName] = useUpdateTaskChecklistNameMutation(); - const [deleteTaskChecklistItem] = useDeleteTaskChecklistItemMutation({ - update: (client, deleteData) => { - updateApolloCache( - client, - FindTaskDocument, - cache => - produce(cache, draftCache => { - const item = deleteData.data.deleteTaskChecklistItem.taskChecklistItem; - const targetIdx = cache.findTask.checklists.findIndex(c => c.id === item.taskChecklistID) - if (targetIdx > -1) { - draftCache.findTask.checklists[targetIdx].items = cache.findTask.checklists[targetIdx].items.filter(c => item.id !== c.id); - } - const {complete, total} = calculateChecklistBadge(draftCache.findTask.checklists); - draftCache.findTask.badges.checklist = { - __typename: 'ChecklistBadge', - complete, - total, - }; - }), - {taskID}, - ); - }, - }); - const [createTaskChecklistItem] = useCreateTaskChecklistItemMutation({ - update: (client, newTaskItem) => { - updateApolloCache( - client, - FindTaskDocument, - cache => - produce(cache, draftCache => { - const item = newTaskItem.data.createTaskChecklistItem; - const {checklists} = cache.findTask; - const idx = checklists.findIndex(c => c.id === item.taskChecklistID); - if (idx !== -1) { - draftCache.findTask.checklists[idx].items.push({...item}); - const {complete, total} = calculateChecklistBadge(draftCache.findTask.checklists); - draftCache.findTask.badges.checklist = { - __typename: 'ChecklistBadge', - complete, - total, - }; - } - }), - {taskID}, - ); - }, - }); - const {loading, data, refetch} = useFindTaskQuery({variables: {taskID}}); - const [setTaskComplete] = useSetTaskCompleteMutation(); - const [updateTaskDueDate] = useUpdateTaskDueDateMutation({ - onCompleted: () => { - refetch(); - refreshCache(); - }, - }); - const [assignTask] = useAssignTaskMutation({ - onCompleted: () => { - refetch(); - refreshCache(); - }, - }); - const [unassignTask] = useUnassignTaskMutation({ - onCompleted: () => { - refetch(); - refreshCache(); - }, - }); - if (loading) { - return
loading
; - } - if (!data) { - return
loading
; - } - return ( - <> - { - history.push(projectURL); - }} - renderContent={() => { - return ( - { - updateTaskChecklistLocation({ - variables: {checklistID: checklist.id, position: checklist.position}, - - optimisticResponse: { - __typename: 'Mutation', - updateTaskChecklistLocation: { - __typename: 'UpdateTaskChecklistLocationPayload', - checklist: { - __typename: 'TaskChecklist', - position: checklist.position, - id: checklist.id, - }, - }, - }, - }); - }} - onChecklistItemDrop={(prevChecklistID, checklistID, checklistItem) => { - updateTaskChecklistItemLocation({ - variables: {checklistID, checklistItemID: checklistItem.id, position: checklistItem.position}, - - optimisticResponse: { - __typename: 'Mutation', - updateTaskChecklistItemLocation: { - __typename: 'UpdateTaskChecklistItemLocationPayload', - prevChecklistID, - checklistID, - checklistItem: { - __typename: 'TaskChecklistItem', - position: checklistItem.position, - id: checklistItem.id, - taskChecklistID: checklistID, - }, - }, - }, - }); - }} - onTaskNameChange={onTaskNameChange} - onTaskDescriptionChange={onTaskDescriptionChange} - onToggleTaskComplete={task => { - setTaskComplete({variables: {taskID: task.id, complete: !task.complete}}); - }} - onDeleteTask={onDeleteTask} - onChangeItemName={(itemID, itemName) => { - updateTaskChecklistItemName({variables: {taskChecklistItemID: itemID, name: itemName}}); - }} - onCloseModal={() => history.push(projectURL)} - onChangeChecklistName={(checklistID, newName) => { - updateTaskChecklistName({variables: {taskChecklistID: checklistID, name: newName}}); - }} - onDeleteItem={itemID => { - deleteTaskChecklistItem({variables: {taskChecklistItemID: itemID}}); - }} - onToggleChecklistItem={(itemID, complete) => { - setTaskChecklistItemComplete({ - variables: {taskChecklistItemID: itemID, complete}, - optimisticResponse: { - __typename: 'Mutation', - setTaskChecklistItemComplete: { - __typename: 'TaskChecklistItem', - id: itemID, - complete, - }, - }, - }); - }} - onAddItem={(taskChecklistID, name, position) => { - createTaskChecklistItem({variables: {taskChecklistID, name, position}}); - }} - onMemberProfile={($targetRef, memberID) => { - const member = data.findTask.assigned.find(m => m.id === memberID); - if (member) { - showPopup( - $targetRef, - {}} tab={0}> - { - unassignTask({variables: {taskID: data.findTask.id, userID: userID ?? ''}}); - }} - /> - , - ); - } - }} - onOpenAddMemberPopup={(task, $targetRef) => { - showPopup( - $targetRef, - {}}> - { - if (isActive) { - assignTask({variables: {taskID: data.findTask.id, userID: userID ?? ''}}); - } else { - unassignTask({variables: {taskID: data.findTask.id, userID: userID ?? ''}}); + const { userID } = useContext(UserIDContext); + const { showPopup, hidePopup } = usePopup(); + const history = useHistory(); + const match = useRouteMatch(); + const [currentMemberTask, setCurrentMemberTask] = useState(''); + const [memberPopupData, setMemberPopupData] = useState(initialMemberPopupState); + const [updateTaskChecklistLocation] = useUpdateTaskChecklistLocationMutation(); + const [updateTaskChecklistItemLocation] = useUpdateTaskChecklistItemLocationMutation({ + update: (client, response) => { + updateApolloCache( + client, + FindTaskDocument, + cache => + produce(cache, draftCache => { + const { prevChecklistID, checklistID, checklistItem } = response.data.updateTaskChecklistItemLocation; + console.log(`${checklistID} !== ${prevChecklistID}`); + if (checklistID !== prevChecklistID) { + const oldIdx = cache.findTask.checklists.findIndex(c => c.id === prevChecklistID); + const newIdx = cache.findTask.checklists.findIndex(c => c.id === checklistID); + console.log(`oldIdx ${oldIdx} newIdx ${newIdx}`); + if (oldIdx > -1 && newIdx > -1) { + const item = cache.findTask.checklists[oldIdx].items.find(item => item.id === checklistItem.id); + console.log(item); + if (item) { + draftCache.findTask.checklists[oldIdx].items = cache.findTask.checklists[oldIdx].items.filter( + i => i.id !== checklistItem.id, + ); + draftCache.findTask.checklists[newIdx].items.push({ + ...item, + position: checklistItem.position, + taskChecklistID: checklistID, + }); + } + } } - }} - /> - , - ); - }} - onOpenAddLabelPopup={onOpenAddLabelPopup} - onOpenAddChecklistPopup={(_task, $target) => { - showPopup( - $target, - { - hidePopup(); - }} - > - { - let position = 65535; - console.log(data.findTask.checklists); - if (data.findTask.checklists) { - const [lastChecklist] = data.findTask.checklists.slice(-1); - console.log(`lastCheclist ${lastChecklist}`); - if (lastChecklist) { - position = lastChecklist.position * 2 + 1; - } + }), + { taskID }, + ); + }, + }); + const [setTaskChecklistItemComplete] = useSetTaskChecklistItemCompleteMutation({ + update: client => { + updateApolloCache( + client, + FindTaskDocument, + cache => + produce(cache, draftCache => { + const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists); + draftCache.findTask.badges.checklist = { + __typename: 'ChecklistBadge', + complete, + total, + }; + }), + { taskID }, + ); + }, + }); + const [deleteTaskChecklist] = useDeleteTaskChecklistMutation({ + update: (client, deleteData) => { + updateApolloCache( + client, + FindTaskDocument, + cache => + produce(cache, draftCache => { + const { checklists } = cache.findTask; + console.log(deleteData) + draftCache.findTask.checklists = checklists.filter(c => c.id !== deleteData.data.deleteTaskChecklist.taskChecklist.id); + const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists); + draftCache.findTask.badges.checklist = { + __typename: 'ChecklistBadge', + complete, + total, + }; + if (complete === 0 && total === 0) { + draftCache.findTask.badges.checklist = null; } - createTaskChecklist({ - variables: { - taskID: data.findTask.id, - name: checklistData.name, - position, - }, - }); - hidePopup(); - }} - /> - , - ); - }} - onDeleteChecklist={($target, checklistID) => { - showPopup( - $target, - hidePopup()}> -

Deleting a checklist is permanent and there is no way to get it back.

- { - deleteTaskChecklist({variables: {taskChecklistID: checklistID}}); - hidePopup(); - }} - > - Delete Checklist + }), + { taskID }, + ); + }, + }); + const [updateTaskChecklistItemName] = useUpdateTaskChecklistItemNameMutation(); + const [createTaskChecklist] = useCreateTaskChecklistMutation({ + update: (client, createData) => { + updateApolloCache( + client, + FindTaskDocument, + cache => + produce(cache, draftCache => { + const item = createData.data.createTaskChecklist; + draftCache.findTask.checklists.push({ ...item }); + }), + { taskID }, + ); + }, + }); + const [updateTaskChecklistName] = useUpdateTaskChecklistNameMutation(); + const [deleteTaskChecklistItem] = useDeleteTaskChecklistItemMutation({ + update: (client, deleteData) => { + updateApolloCache( + client, + FindTaskDocument, + cache => + produce(cache, draftCache => { + const item = deleteData.data.deleteTaskChecklistItem.taskChecklistItem; + const targetIdx = cache.findTask.checklists.findIndex(c => c.id === item.taskChecklistID) + if (targetIdx > -1) { + draftCache.findTask.checklists[targetIdx].items = cache.findTask.checklists[targetIdx].items.filter(c => item.id !== c.id); + } + const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists); + draftCache.findTask.badges.checklist = { + __typename: 'ChecklistBadge', + complete, + total, + }; + }), + { taskID }, + ); + }, + }); + const [createTaskChecklistItem] = useCreateTaskChecklistItemMutation({ + update: (client, newTaskItem) => { + updateApolloCache( + client, + FindTaskDocument, + cache => + produce(cache, draftCache => { + const item = newTaskItem.data.createTaskChecklistItem; + const { checklists } = cache.findTask; + const idx = checklists.findIndex(c => c.id === item.taskChecklistID); + if (idx !== -1) { + draftCache.findTask.checklists[idx].items.push({ ...item }); + const { complete, total } = calculateChecklistBadge(draftCache.findTask.checklists); + draftCache.findTask.badges.checklist = { + __typename: 'ChecklistBadge', + complete, + total, + }; + } + }), + { taskID }, + ); + }, + }); + const { loading, data, refetch } = useFindTaskQuery({ variables: { taskID } }); + const [setTaskComplete] = useSetTaskCompleteMutation(); + const [updateTaskDueDate] = useUpdateTaskDueDateMutation({ + onCompleted: () => { + refetch(); + refreshCache(); + }, + }); + const [assignTask] = useAssignTaskMutation({ + onCompleted: () => { + refetch(); + refreshCache(); + }, + }); + const [unassignTask] = useUnassignTaskMutation({ + onCompleted: () => { + refetch(); + refreshCache(); + }, + }); + if (loading) { + return
loading
; + } + if (!data) { + return
loading
; + } + return ( + <> + { + history.push(projectURL); + }} + renderContent={() => { + return ( + { + updateTaskChecklistLocation({ + variables: { checklistID: checklist.id, position: checklist.position }, + + optimisticResponse: { + __typename: 'Mutation', + updateTaskChecklistLocation: { + __typename: 'UpdateTaskChecklistLocationPayload', + checklist: { + __typename: 'TaskChecklist', + position: checklist.position, + id: checklist.id, + }, + }, + }, + }); + }} + onChecklistItemDrop={(prevChecklistID, checklistID, checklistItem) => { + updateTaskChecklistItemLocation({ + variables: { checklistID, checklistItemID: checklistItem.id, position: checklistItem.position }, + + optimisticResponse: { + __typename: 'Mutation', + updateTaskChecklistItemLocation: { + __typename: 'UpdateTaskChecklistItemLocationPayload', + prevChecklistID, + checklistID, + checklistItem: { + __typename: 'TaskChecklistItem', + position: checklistItem.position, + id: checklistItem.id, + taskChecklistID: checklistID, + }, + }, + }, + }); + }} + onTaskNameChange={onTaskNameChange} + onTaskDescriptionChange={onTaskDescriptionChange} + onToggleTaskComplete={task => { + setTaskComplete({ variables: { taskID: task.id, complete: !task.complete } }); + }} + onDeleteTask={onDeleteTask} + onChangeItemName={(itemID, itemName) => { + updateTaskChecklistItemName({ variables: { taskChecklistItemID: itemID, name: itemName } }); + }} + onCloseModal={() => history.push(projectURL)} + onChangeChecklistName={(checklistID, newName) => { + updateTaskChecklistName({ variables: { taskChecklistID: checklistID, name: newName } }); + }} + onDeleteItem={(checklistID, itemID) => { + deleteTaskChecklistItem({ + variables: { taskChecklistItemID: itemID }, + optimisticResponse: { + __typename: 'Mutation', + deleteTaskChecklistItem: { + __typename: 'DeleteTaskChecklistItemPayload', + ok: true, + taskChecklistItem: { + __typename: 'TaskChecklistItem', + id: itemID, + taskChecklistID: checklistID, + } + } + } + }); + }} + onToggleChecklistItem={(itemID, complete) => { + setTaskChecklistItemComplete({ + variables: { taskChecklistItemID: itemID, complete }, + optimisticResponse: { + __typename: 'Mutation', + setTaskChecklistItemComplete: { + __typename: 'TaskChecklistItem', + id: itemID, + complete, + }, + }, + }); + }} + onAddItem={(taskChecklistID, name, position) => { + createTaskChecklistItem({ variables: { taskChecklistID, name, position } }); + }} + onMemberProfile={($targetRef, memberID) => { + const member = data.findTask.assigned.find(m => m.id === memberID); + if (member) { + showPopup( + $targetRef, + { }} tab={0}> + { + unassignTask({ variables: { taskID: data.findTask.id, userID: userID ?? '' } }); + }} + /> + , + ); + } + }} + onOpenAddMemberPopup={(task, $targetRef) => { + showPopup( + $targetRef, + { }}> + { + if (isActive) { + assignTask({ variables: { taskID: data.findTask.id, userID: userID ?? '' } }); + } else { + unassignTask({ variables: { taskID: data.findTask.id, userID: userID ?? '' } }); + } + }} + /> + , + ); + }} + onOpenAddLabelPopup={onOpenAddLabelPopup} + onOpenAddChecklistPopup={(_task, $target) => { + showPopup( + $target, + { + hidePopup(); + }} + > + { + let position = 65535; + console.log(data.findTask.checklists); + if (data.findTask.checklists) { + const [lastChecklist] = data.findTask.checklists.slice(-1); + console.log(`lastCheclist ${lastChecklist}`); + if (lastChecklist) { + position = lastChecklist.position * 2 + 1; + } + } + createTaskChecklist({ + variables: { + taskID: data.findTask.id, + name: checklistData.name, + position, + }, + }); + hidePopup(); + }} + /> + , + ); + }} + onDeleteChecklist={($target, checklistID) => { + showPopup( + $target, + hidePopup()}> +

Deleting a checklist is permanent and there is no way to get it back.

+ { + deleteTaskChecklist({ variables: { taskChecklistID: checklistID } }); + hidePopup(); + }} + > + Delete Checklist -
, - ); - }} - onOpenDueDatePopop={(task, $targetRef) => { - showPopup( - $targetRef, - { - hidePopup(); - }} - > - { - updateTaskDueDate({variables: {taskID: t.id, dueDate: null}}); - hidePopup(); - }} - onDueDateChange={(t, newDueDate) => { - updateTaskDueDate({variables: {taskID: t.id, dueDate: newDueDate}}); - hidePopup(); - }} - onCancel={() => {}} - /> - , - ); - }} +
, + ); + }} + onOpenDueDatePopop={(task, $targetRef) => { + showPopup( + $targetRef, + { + hidePopup(); + }} + > + { + updateTaskDueDate({ variables: { taskID: t.id, dueDate: null } }); + hidePopup(); + }} + onDueDateChange={(t, newDueDate) => { + updateTaskDueDate({ variables: { taskID: t.id, dueDate: newDueDate } }); + hidePopup(); + }} + onCancel={() => { }} + /> + , + ); + }} + /> + ); + }} /> - ); - }} - /> - - ); + + ); }; export default Details; diff --git a/frontend/src/shared/components/Checklist/Checklist.stories.tsx b/frontend/src/shared/components/Checklist/Checklist.stories.tsx index 923ae95..feb19c5 100644 --- a/frontend/src/shared/components/Checklist/Checklist.stories.tsx +++ b/frontend/src/shared/components/Checklist/Checklist.stories.tsx @@ -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} diff --git a/frontend/src/shared/components/Checklist/index.tsx b/frontend/src/shared/components/Checklist/index.tsx index 5cfe9d5..0301de4 100644 --- a/frontend/src/shared/components/Checklist/index.tsx +++ b/frontend/src/shared/components/Checklist/index.tsx @@ -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(null); @@ -309,8 +319,8 @@ export const ChecklistItem = React.forwardRef( {complete ? ( ) : ( - - )} + + )} {editting ? ( <> @@ -352,7 +362,7 @@ export const ChecklistItem = React.forwardRef( onClick={e => { e.stopPropagation(); setEditting(false); - onDeleteItem(itemID); + onDeleteItem(checklistID, itemID); }} > @@ -360,34 +370,34 @@ export const ChecklistItem = React.forwardRef( ) : ( - { - setEditting(true); - }} - > - - - {name} - - - - - - - - { - e.stopPropagation(); - onDeleteItem(itemID); - }} - > - - - - - - - )} + { + setEditting(true); + }} + > + + + {name} + + + + + + + + { + e.stopPropagation(); + onDeleteItem(checklistID, itemID); + }} + > + + + + + + + )} ); }, @@ -397,7 +407,7 @@ type AddNewItemProps = { onAddItem: (name: string) => void; }; -const AddNewItem: React.FC = ({ onAddItem }) => { +const AddNewItem: React.FC = ({onAddItem}) => { const $editor = useRef(null); const $wrapper = useRef(null); const [currentName, setCurrentName] = useState(''); @@ -454,8 +464,8 @@ const AddNewItem: React.FC = ({ onAddItem }) => { ) : ( - setEditting(true)}>Add an item - )} + setEditting(true)}>Add an item + )} ); }; @@ -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; }; @@ -569,21 +579,21 @@ const Checklist = React.forwardRef( }} /> ) : ( - - setEditting(true)}>{name} - - { - onDeleteChecklist($target, checklistID); - }} - color="danger" - variant="outline" - > - Delete + + setEditting(true)}>{name} + + { + onDeleteChecklist($target, checklistID); + }} + color="danger" + variant="outline" + > + Delete - - - )} + + + )} {`${percent}%`} diff --git a/frontend/src/shared/components/TaskDetails/index.tsx b/frontend/src/shared/components/TaskDetails/index.tsx index 5f55d72..d8a4a11 100644 --- a/frontend/src/shared/components/TaskDetails/index.tsx +++ b/frontend/src/shared/components/TaskDetails/index.tsx @@ -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) => void; }; -const TaskLabelItem: React.FC = ({ label, onClick }) => { +const TaskLabelItem: React.FC = ({label, onClick}) => { const $label = useRef(null); return ( = ({ label, onClick }) => { ); }; -const TaskContent: React.FC = ({ description, onEditContent }) => { +const TaskContent: React.FC = ({description, onEditContent}) => { return description === '' ? ( Add a more detailed description ) : ( - - - - ); + + + + ); }; 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 = ({ 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 = ({ }; 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 = ({ 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 = ({ }; 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 = ({ }} /> ) : ( - - )} + + )} {dropProvided => ( @@ -430,6 +430,7 @@ const TaskDetails: React.FC = ({ = ({ complete={item.complete} onDeleteItem={onDeleteItem} onChangeName={onChangeItemName} - onToggleItem={() => {}} + onToggleItem={(itemID, complete) => onToggleChecklistItem(item.id, complete)} /> )}