arch: move web folder into api & move api to top level

This commit is contained in:
Jordan Knott
2020-07-04 18:08:37 -05:00
parent eaffaa70df
commit e5d5e6da01
354 changed files with 20 additions and 1557 deletions

View File

@ -0,0 +1,101 @@
import React, { useState } from 'react';
import { action } from '@storybook/addon-actions';
import Lists from '.';
export default {
component: Lists,
title: 'Lists',
parameters: {
backgrounds: [
{ name: 'gray', value: '#262c49', default: true },
{ name: 'white', value: '#ffffff' },
],
},
};
const initialListsData = {
columns: {
'column-1': {
taskGroupID: 'column-1',
name: 'General',
taskIds: ['task-3', 'task-4', 'task-1', 'task-2'],
position: 1,
tasks: [],
},
'column-2': {
taskGroupID: 'column-2',
name: 'Development',
taskIds: [],
position: 2,
tasks: [],
},
},
tasks: {
'task-1': {
taskID: 'task-1',
taskGroup: { taskGroupID: 'column-1' },
name: 'Create roadmap',
position: 2,
labels: [],
},
'task-2': {
taskID: 'task-2',
taskGroup: { taskGroupID: 'column-1' },
position: 1,
name: 'Create authentication',
labels: [],
},
'task-3': {
taskID: 'task-3',
taskGroup: { taskGroupID: 'column-1' },
position: 3,
name: 'Create login',
labels: [],
},
'task-4': {
taskID: 'task-4',
taskGroup: { taskGroupID: 'column-1' },
position: 4,
name: 'Create plugins',
labels: [],
},
},
};
export const Default = () => {
const [listsData, setListsData] = useState(initialListsData);
const onCardDrop = (droppedTask: Task) => {
const newState = {
...listsData,
tasks: {
...listsData.tasks,
[droppedTask.id]: droppedTask,
},
};
setListsData(newState);
};
const onListDrop = (droppedColumn: any) => {
const newState = {
...listsData,
columns: {
...listsData.columns,
[droppedColumn.taskGroupID]: droppedColumn,
},
};
setListsData(newState);
};
return (
<Lists
taskGroups={[]}
onTaskClick={action('card click')}
onQuickEditorOpen={action('card composer open')}
onCreateTask={action('card create')}
onTaskDrop={onCardDrop}
onTaskGroupDrop={onListDrop}
onChangeTaskGroupName={action('change group name')}
onCreateTaskGroup={action('create list')}
onExtraMenuOpen={action('extra menu open')}
onCardMemberClick={action('card member click')}
/>
);
};

View File

@ -0,0 +1,48 @@
import styled from 'styled-components';
export const Container = styled.div`
flex: 1;
user-select: none;
white-space: nowrap;
margin-bottom: 8px;
overflow-x: auto;
overflow-y: hidden;
padding-bottom: 8px;
::-webkit-scrollbar {
height: 10px;
}
::-webkit-scrollbar-thumb {
background: #7367f0;
border-radius: 6px;
}
::-webkit-scrollbar-track {
background: #10163a;
border-radius: 6px;
}
`;
export const BoardContainer = styled.div`
position: relative;
overflow-y: auto;
outline: none;
flex-grow: 1;
`;
export const BoardWrapper = styled.div`
display: flex;
user-select: none;
white-space: nowrap;
margin-bottom: 8px;
overflow-x: auto;
overflow-y: hidden;
padding-bottom: 8px;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
`;
export default Container;

View File

@ -0,0 +1,228 @@
import React, { useState } from 'react';
import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd';
import List, { ListCards } from 'shared/components/List';
import Card from 'shared/components/Card';
import CardComposer from 'shared/components/CardComposer';
import AddList from 'shared/components/AddList';
import {
isPositionChanged,
getSortedDraggables,
getNewDraggablePosition,
getAfterDropDraggableList,
} from 'shared/utils/draggables';
import moment from 'moment';
import { Container, BoardContainer, BoardWrapper } from './Styles';
interface SimpleProps {
taskGroups: Array<TaskGroup>;
onTaskDrop: (task: Task, previousTaskGroupID: string) => void;
onTaskGroupDrop: (taskGroup: TaskGroup) => void;
onTaskClick: (task: Task) => void;
onCreateTask: (taskGroupID: string, name: string) => void;
onChangeTaskGroupName: (taskGroupID: string, name: string) => void;
onQuickEditorOpen: ($target: React.RefObject<HTMLElement>, taskID: string, taskGroupID: string) => void;
onCreateTaskGroup: (listName: string) => void;
onExtraMenuOpen: (taskGroupID: string, $targetRef: React.RefObject<HTMLElement>) => void;
onCardMemberClick: OnCardMemberClick;
}
const SimpleLists: React.FC<SimpleProps> = ({
taskGroups,
onTaskDrop,
onChangeTaskGroupName,
onTaskGroupDrop,
onTaskClick,
onCreateTask,
onQuickEditorOpen,
onCreateTaskGroup,
onExtraMenuOpen,
onCardMemberClick,
}) => {
const onDragEnd = ({ draggableId, source, destination, type }: DropResult) => {
if (typeof destination === 'undefined') return;
if (!isPositionChanged(source, destination)) return;
const isList = type === 'column';
const isSameList = destination.droppableId === source.droppableId;
let droppedDraggable: DraggableElement | null = null;
let beforeDropDraggables: Array<DraggableElement> | null = null;
if (isList) {
const droppedGroup = taskGroups.find(taskGroup => taskGroup.id === draggableId);
if (droppedGroup) {
droppedDraggable = {
id: draggableId,
position: droppedGroup.position,
};
beforeDropDraggables = getSortedDraggables(
taskGroups.map(taskGroup => {
return { id: taskGroup.id, position: taskGroup.position };
}),
);
if (droppedDraggable === null || beforeDropDraggables === null) {
throw new Error('before drop draggables is null');
}
const afterDropDraggables = getAfterDropDraggableList(
beforeDropDraggables,
droppedDraggable,
isList,
isSameList,
destination,
);
const newPosition = getNewDraggablePosition(afterDropDraggables, destination.index);
onTaskGroupDrop({
...droppedGroup,
position: newPosition,
});
} else {
throw { error: 'task group can not be found' };
}
} else {
const targetGroup = taskGroups.findIndex(
taskGroup => taskGroup.tasks.findIndex(task => task.id === draggableId) !== -1,
);
const droppedTask = taskGroups[targetGroup].tasks.find(task => task.id === draggableId);
if (droppedTask) {
droppedDraggable = {
id: draggableId,
position: droppedTask.position,
};
beforeDropDraggables = getSortedDraggables(
taskGroups[targetGroup].tasks.map(task => {
return { id: task.id, position: task.position };
}),
);
if (droppedDraggable === null || beforeDropDraggables === null) {
throw new Error('before drop draggables is null');
}
const afterDropDraggables = getAfterDropDraggableList(
beforeDropDraggables,
droppedDraggable,
isList,
isSameList,
destination,
);
const newPosition = getNewDraggablePosition(afterDropDraggables, destination.index);
const newTask = {
...droppedTask,
position: newPosition,
taskGroup: {
id: destination.droppableId,
},
};
onTaskDrop(newTask, droppedTask.taskGroup.id);
}
}
};
const [currentComposer, setCurrentComposer] = useState('');
return (
<BoardContainer>
<BoardWrapper>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable direction="horizontal" type="column" droppableId="root">
{provided => (
<Container {...provided.droppableProps} ref={provided.innerRef}>
{taskGroups
.slice()
.sort((a: any, b: any) => a.position - b.position)
.map((taskGroup: TaskGroup, index: number) => {
return (
<Draggable draggableId={taskGroup.id} key={taskGroup.id} index={index}>
{columnDragProvided => (
<Droppable type="tasks" droppableId={taskGroup.id}>
{(columnDropProvided, snapshot) => (
<List
name={taskGroup.name}
onOpenComposer={id => setCurrentComposer(id)}
isComposerOpen={currentComposer === taskGroup.id}
onSaveName={name => onChangeTaskGroupName(taskGroup.id, name)}
ref={columnDragProvided.innerRef}
wrapperProps={columnDragProvided.draggableProps}
headerProps={columnDragProvided.dragHandleProps}
onExtraMenuOpen={onExtraMenuOpen}
id={taskGroup.id}
key={taskGroup.id}
index={index}
>
<ListCards ref={columnDropProvided.innerRef} {...columnDropProvided.droppableProps}>
{taskGroup.tasks
.slice()
.sort((a: any, b: any) => a.position - b.position)
.map((task: Task, taskIndex: any) => {
return (
<Draggable key={task.id} draggableId={task.id} index={taskIndex}>
{taskProvided => {
return (
<Card
wrapperProps={{
...taskProvided.draggableProps,
...taskProvided.dragHandleProps,
}}
ref={taskProvided.innerRef}
taskID={task.id}
complete={task.complete ?? false}
taskGroupID={taskGroup.id}
description=""
labels={task.labels.map(label => label.projectLabel)}
dueDate={
task.dueDate
? {
isPastDue: false,
formattedDate: moment(task.dueDate).format('MMM D, YYYY'),
}
: undefined
}
title={task.name}
members={task.assigned}
onClick={() => {
onTaskClick(task);
}}
checklists={task.badges && task.badges.checklist}
onCardMemberClick={onCardMemberClick}
onContextMenu={onQuickEditorOpen}
/>
);
}}
</Draggable>
);
})}
{columnDropProvided.placeholder}
{currentComposer === taskGroup.id && (
<CardComposer
onClose={() => {
setCurrentComposer('');
}}
onCreateCard={name => {
onCreateTask(taskGroup.id, name);
}}
isOpen
/>
)}
</ListCards>
</List>
)}
</Droppable>
)}
</Draggable>
);
})}
<AddList
onSave={listName => {
onCreateTaskGroup(listName);
}}
/>
{provided.placeholder}
</Container>
)}
</Droppable>
</DragDropContext>
</BoardWrapper>
</BoardContainer>
);
};
export default SimpleLists;