2020-04-10 04:40:22 +02:00
|
|
|
import React, { useState } from 'react';
|
|
|
|
import styled from 'styled-components/macro';
|
|
|
|
import { useParams } from 'react-router-dom';
|
2020-04-10 05:27:57 +02:00
|
|
|
import {
|
|
|
|
useFindProjectQuery,
|
|
|
|
useUpdateTaskNameMutation,
|
|
|
|
useCreateTaskMutation,
|
|
|
|
useDeleteTaskMutation,
|
|
|
|
useUpdateTaskLocationMutation,
|
2020-04-11 04:22:58 +02:00
|
|
|
useCreateTaskGroupMutation,
|
2020-04-10 05:27:57 +02:00
|
|
|
} from 'shared/generated/graphql';
|
2020-04-10 04:40:22 +02:00
|
|
|
|
|
|
|
import Navbar from 'App/Navbar';
|
|
|
|
import TopNavbar from 'App/TopNavbar';
|
|
|
|
import Lists from 'shared/components/Lists';
|
|
|
|
import QuickCardEditor from 'shared/components/QuickCardEditor';
|
2020-04-11 04:22:58 +02:00
|
|
|
import PopupMenu from 'shared/components/PopupMenu';
|
|
|
|
import ListActions from 'shared/components/ListActions';
|
2020-04-10 04:40:22 +02:00
|
|
|
|
|
|
|
interface ColumnState {
|
|
|
|
[key: string]: TaskGroup;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface TaskState {
|
2020-04-10 05:27:57 +02:00
|
|
|
[key: string]: Task;
|
2020-04-10 04:40:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
interface State {
|
|
|
|
columns: ColumnState;
|
|
|
|
tasks: TaskState;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface QuickCardEditorState {
|
|
|
|
isOpen: boolean;
|
|
|
|
left: number;
|
|
|
|
top: number;
|
2020-04-10 05:27:57 +02:00
|
|
|
task?: Task;
|
2020-04-10 04:40:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const MainContent = styled.div`
|
2020-04-10 18:31:29 +02:00
|
|
|
padding: 0 0 50px 80px;
|
2020-04-10 04:40:22 +02:00
|
|
|
height: 100%;
|
|
|
|
background: #262c49;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const Wrapper = styled.div`
|
|
|
|
font-size: 16px;
|
|
|
|
background-color: red;
|
|
|
|
`;
|
|
|
|
|
2020-04-10 18:31:29 +02:00
|
|
|
const TitleWrapper = styled.div`
|
|
|
|
margin-left: 38px;
|
|
|
|
margin-bottom: 15px;
|
|
|
|
`;
|
|
|
|
|
2020-04-10 04:40:22 +02:00
|
|
|
const Title = styled.span`
|
|
|
|
text-align: center;
|
|
|
|
font-size: 24px;
|
|
|
|
color: #fff;
|
|
|
|
`;
|
|
|
|
|
2020-04-10 18:31:29 +02:00
|
|
|
const Board = styled.div`
|
|
|
|
margin-left: 36px;
|
|
|
|
`;
|
|
|
|
|
2020-04-10 04:40:22 +02:00
|
|
|
interface ProjectParams {
|
|
|
|
projectId: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
const initialState: State = { tasks: {}, columns: {} };
|
2020-04-11 04:22:58 +02:00
|
|
|
const initialPopupState = { left: 0, top: 0, isOpen: false, taskGroupID: '' };
|
2020-04-10 04:40:22 +02:00
|
|
|
const initialQuickCardEditorState: QuickCardEditorState = { isOpen: false, top: 0, left: 0 };
|
|
|
|
|
|
|
|
const Project = () => {
|
|
|
|
const { projectId } = useParams<ProjectParams>();
|
|
|
|
const [listsData, setListsData] = useState(initialState);
|
2020-04-11 04:22:58 +02:00
|
|
|
const [popupData, setPopupData] = useState(initialPopupState);
|
2020-04-10 04:40:22 +02:00
|
|
|
const [quickCardEditor, setQuickCardEditor] = useState(initialQuickCardEditorState);
|
2020-04-10 05:27:57 +02:00
|
|
|
const [updateTaskLocation] = useUpdateTaskLocationMutation();
|
2020-04-11 04:22:58 +02:00
|
|
|
const [createTaskGroup] = useCreateTaskGroupMutation({
|
|
|
|
onCompleted: newTaskGroupData => {
|
|
|
|
const newListsData = {
|
|
|
|
...listsData,
|
|
|
|
columns: {
|
|
|
|
...listsData.columns,
|
|
|
|
[newTaskGroupData.createTaskGroup.taskGroupID]: {
|
|
|
|
taskGroupID: newTaskGroupData.createTaskGroup.taskGroupID,
|
|
|
|
name: newTaskGroupData.createTaskGroup.name,
|
|
|
|
position: newTaskGroupData.createTaskGroup.position,
|
|
|
|
tasks: [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
setListsData(newListsData);
|
|
|
|
},
|
|
|
|
});
|
2020-04-10 05:27:57 +02:00
|
|
|
const [createTask] = useCreateTaskMutation({
|
2020-04-10 04:40:22 +02:00
|
|
|
onCompleted: newTaskData => {
|
|
|
|
const newListsData = {
|
|
|
|
...listsData,
|
|
|
|
tasks: {
|
|
|
|
...listsData.tasks,
|
|
|
|
[newTaskData.createTask.taskID]: {
|
2020-04-11 04:22:58 +02:00
|
|
|
taskGroup: {
|
|
|
|
taskGroupID: newTaskData.createTask.taskGroup.taskGroupID,
|
|
|
|
},
|
2020-04-10 04:40:22 +02:00
|
|
|
taskID: newTaskData.createTask.taskID,
|
|
|
|
name: newTaskData.createTask.name,
|
|
|
|
position: newTaskData.createTask.position,
|
|
|
|
labels: [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
setListsData(newListsData);
|
|
|
|
},
|
|
|
|
});
|
2020-04-10 05:27:57 +02:00
|
|
|
const [deleteTask] = useDeleteTaskMutation({
|
2020-04-10 04:40:22 +02:00
|
|
|
onCompleted: deletedTask => {
|
|
|
|
const { [deletedTask.deleteTask.taskID]: removedTask, ...remainingTasks } = listsData.tasks;
|
|
|
|
const newListsData = {
|
|
|
|
...listsData,
|
|
|
|
tasks: remainingTasks,
|
|
|
|
};
|
|
|
|
setListsData(newListsData);
|
|
|
|
},
|
|
|
|
});
|
2020-04-10 05:27:57 +02:00
|
|
|
const [updateTaskName] = useUpdateTaskNameMutation({
|
2020-04-10 04:40:22 +02:00
|
|
|
onCompleted: newTaskData => {
|
|
|
|
const newListsData = {
|
|
|
|
...listsData,
|
|
|
|
tasks: {
|
|
|
|
...listsData.tasks,
|
|
|
|
[newTaskData.updateTaskName.taskID]: {
|
|
|
|
...listsData.tasks[newTaskData.updateTaskName.taskID],
|
|
|
|
name: newTaskData.updateTaskName.name,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
setListsData(newListsData);
|
|
|
|
},
|
|
|
|
});
|
2020-04-10 05:27:57 +02:00
|
|
|
const { loading, data } = useFindProjectQuery({
|
2020-04-10 04:40:22 +02:00
|
|
|
variables: { projectId },
|
|
|
|
onCompleted: newData => {
|
2020-04-10 22:31:12 +02:00
|
|
|
const newListsData: State = { tasks: {}, columns: {} };
|
2020-04-11 04:22:58 +02:00
|
|
|
newData.findProject.taskGroups.forEach(taskGroup => {
|
2020-04-10 04:40:22 +02:00
|
|
|
newListsData.columns[taskGroup.taskGroupID] = {
|
|
|
|
taskGroupID: taskGroup.taskGroupID,
|
|
|
|
name: taskGroup.name,
|
|
|
|
position: taskGroup.position,
|
|
|
|
tasks: [],
|
|
|
|
};
|
2020-04-11 04:22:58 +02:00
|
|
|
taskGroup.tasks.forEach(task => {
|
2020-04-10 04:40:22 +02:00
|
|
|
newListsData.tasks[task.taskID] = {
|
|
|
|
taskID: task.taskID,
|
2020-04-11 04:22:58 +02:00
|
|
|
taskGroup: {
|
|
|
|
taskGroupID: taskGroup.taskGroupID,
|
|
|
|
},
|
2020-04-10 04:40:22 +02:00
|
|
|
name: task.name,
|
|
|
|
position: task.position,
|
|
|
|
labels: [],
|
|
|
|
};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
setListsData(newListsData);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
const onCardDrop = (droppedTask: any) => {
|
|
|
|
updateTaskLocation({
|
|
|
|
variables: { taskID: droppedTask.taskID, taskGroupID: droppedTask.taskGroupID, position: droppedTask.position },
|
|
|
|
});
|
|
|
|
const newState = {
|
|
|
|
...listsData,
|
|
|
|
tasks: {
|
|
|
|
...listsData.tasks,
|
|
|
|
[droppedTask.taskID]: droppedTask,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
setListsData(newState);
|
|
|
|
};
|
|
|
|
const onListDrop = (droppedColumn: any) => {
|
|
|
|
const newState = {
|
|
|
|
...listsData,
|
|
|
|
columns: {
|
|
|
|
...listsData.columns,
|
|
|
|
[droppedColumn.taskGroupID]: droppedColumn,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
setListsData(newState);
|
|
|
|
};
|
|
|
|
const onCardCreate = (taskGroupID: string, name: string) => {
|
2020-04-11 04:22:58 +02:00
|
|
|
const taskGroupTasks = Object.values(listsData.tasks).filter(
|
|
|
|
(task: Task) => task.taskGroup.taskGroupID === taskGroupID,
|
|
|
|
);
|
2020-04-10 22:31:12 +02:00
|
|
|
let position = 65535;
|
2020-04-10 04:40:22 +02:00
|
|
|
if (taskGroupTasks.length !== 0) {
|
|
|
|
const [lastTask] = taskGroupTasks.sort((a: any, b: any) => a.position - b.position).slice(-1);
|
|
|
|
position = Math.ceil(lastTask.position) * 2 + 1;
|
|
|
|
}
|
|
|
|
|
2020-04-10 22:31:12 +02:00
|
|
|
createTask({ variables: { taskGroupID, name, position } });
|
2020-04-10 04:40:22 +02:00
|
|
|
};
|
|
|
|
const onQuickEditorOpen = (e: ContextMenuEvent) => {
|
2020-04-10 05:27:57 +02:00
|
|
|
const currentTask = Object.values(listsData.tasks).find(task => task.taskID === e.taskID);
|
2020-04-10 04:40:22 +02:00
|
|
|
setQuickCardEditor({
|
|
|
|
top: e.top,
|
|
|
|
left: e.left,
|
|
|
|
isOpen: true,
|
2020-04-10 05:27:57 +02:00
|
|
|
task: currentTask,
|
2020-04-10 04:40:22 +02:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
return <Wrapper>Loading</Wrapper>;
|
|
|
|
}
|
|
|
|
if (data) {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<Navbar />
|
|
|
|
<MainContent>
|
|
|
|
<TopNavbar />
|
2020-04-10 18:31:29 +02:00
|
|
|
<TitleWrapper>
|
|
|
|
<Title>{data.findProject.name}</Title>
|
|
|
|
</TitleWrapper>
|
|
|
|
<Board>
|
|
|
|
<Lists
|
|
|
|
onQuickEditorOpen={onQuickEditorOpen}
|
|
|
|
onCardCreate={onCardCreate}
|
|
|
|
{...listsData}
|
|
|
|
onCardDrop={onCardDrop}
|
|
|
|
onListDrop={onListDrop}
|
2020-04-11 04:22:58 +02:00
|
|
|
onCreateList={listName => {
|
|
|
|
const [lastColumn] = Object.values(listsData.columns)
|
|
|
|
.sort((a, b) => a.position - b.position)
|
|
|
|
.slice(-1);
|
|
|
|
let position = 65535;
|
|
|
|
if (lastColumn) {
|
|
|
|
position = lastColumn.position * 2 + 1;
|
|
|
|
}
|
|
|
|
createTaskGroup({ variables: { projectID: projectId, name: listName, position } });
|
|
|
|
}}
|
2020-04-10 18:31:29 +02:00
|
|
|
/>
|
|
|
|
</Board>
|
2020-04-10 04:40:22 +02:00
|
|
|
</MainContent>
|
|
|
|
{quickCardEditor.isOpen && (
|
|
|
|
<QuickCardEditor
|
2020-04-10 22:31:12 +02:00
|
|
|
isOpen
|
2020-04-10 05:27:57 +02:00
|
|
|
taskID={quickCardEditor.task ? quickCardEditor.task.taskID : ''}
|
2020-04-11 04:22:58 +02:00
|
|
|
taskGroupID={quickCardEditor.task ? quickCardEditor.task.taskGroup.taskGroupID : ''}
|
2020-04-10 04:40:22 +02:00
|
|
|
cardTitle={quickCardEditor.task ? quickCardEditor.task.name : ''}
|
|
|
|
onCloseEditor={() => setQuickCardEditor(initialQuickCardEditorState)}
|
2020-04-10 22:31:12 +02:00
|
|
|
onEditCard={(_listId: string, cardId: string, cardName: string) => {
|
|
|
|
updateTaskName({ variables: { taskID: cardId, name: cardName } });
|
|
|
|
}}
|
2020-04-10 04:40:22 +02:00
|
|
|
onOpenPopup={() => console.log()}
|
2020-04-10 22:31:12 +02:00
|
|
|
onArchiveCard={(_listId: string, cardId: string) => deleteTask({ variables: { taskID: cardId } })}
|
2020-04-10 04:40:22 +02:00
|
|
|
labels={[]}
|
|
|
|
top={quickCardEditor.top}
|
|
|
|
left={quickCardEditor.left}
|
|
|
|
/>
|
|
|
|
)}
|
2020-04-11 04:22:58 +02:00
|
|
|
{popupData.isOpen && (
|
|
|
|
<PopupMenu
|
|
|
|
title="List Actions"
|
|
|
|
top={popupData.top}
|
|
|
|
onClose={() => setPopupData(initialPopupState)}
|
|
|
|
left={popupData.left}
|
|
|
|
>
|
|
|
|
<ListActions taskGroupID={popupData.taskGroupID} />
|
|
|
|
</PopupMenu>
|
|
|
|
)}
|
2020-04-10 04:40:22 +02:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return <Wrapper>Error</Wrapper>;
|
|
|
|
};
|
|
|
|
|
|
|
|
export default Project;
|