Refactor/inplace input (#541)
* wip * Changed all other components * Removed console log * Console.log * lint * Removed internal state * Fix * Lint
This commit is contained in:
55
front/src/modules/ui/board/components/Board.tsx
Normal file
55
front/src/modules/ui/board/components/Board.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { DropResult } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
|
||||
|
||||
export const StyledBoard = styled.div`
|
||||
border-radius: ${({ theme }) => theme.spacing(2)};
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: calc(100%);
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export type Column = {
|
||||
id: string;
|
||||
title: string;
|
||||
colorCode?: string;
|
||||
itemKeys: string[];
|
||||
};
|
||||
|
||||
export function getOptimisticlyUpdatedBoard(
|
||||
board: Column[],
|
||||
result: DropResult,
|
||||
) {
|
||||
const newBoard = JSON.parse(JSON.stringify(board));
|
||||
const { destination, source } = result;
|
||||
if (!destination) return;
|
||||
const sourceColumnIndex = newBoard.findIndex(
|
||||
(column: Column) => column.id === source.droppableId,
|
||||
);
|
||||
const sourceColumn = newBoard[sourceColumnIndex];
|
||||
const destinationColumnIndex = newBoard.findIndex(
|
||||
(column: Column) => column.id === destination.droppableId,
|
||||
);
|
||||
const destinationColumn = newBoard[destinationColumnIndex];
|
||||
if (!destinationColumn || !sourceColumn) return;
|
||||
const sourceItems = sourceColumn.itemKeys;
|
||||
const destinationItems = destinationColumn.itemKeys;
|
||||
|
||||
const [removed] = sourceItems.splice(source.index, 1);
|
||||
destinationItems.splice(destination.index, 0, removed);
|
||||
|
||||
const newSourceColumn = {
|
||||
...sourceColumn,
|
||||
itemKeys: sourceItems,
|
||||
};
|
||||
|
||||
const newDestinationColumn = {
|
||||
...destinationColumn,
|
||||
itemKeys: destinationItems,
|
||||
};
|
||||
|
||||
newBoard.splice(sourceColumnIndex, 1, newSourceColumn);
|
||||
newBoard.splice(destinationColumnIndex, 1, newDestinationColumn);
|
||||
return newBoard;
|
||||
}
|
||||
36
front/src/modules/ui/board/components/BoardColumn.tsx
Normal file
36
front/src/modules/ui/board/components/BoardColumn.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const StyledColumn = styled.div`
|
||||
background-color: ${({ theme }) => theme.background.primary};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 200px;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
export const StyledColumnTitle = styled.h3`
|
||||
color: ${({ color }) => color};
|
||||
font-family: 'Inter';
|
||||
font-size: ${({ theme }) => theme.font.size.md};
|
||||
font-style: normal;
|
||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||
line-height: ${({ theme }) => theme.text.lineHeight};
|
||||
margin: 0;
|
||||
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
colorCode?: string;
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export function BoardColumn({ colorCode, title, children }: OwnProps) {
|
||||
return (
|
||||
<StyledColumn>
|
||||
<StyledColumnTitle color={colorCode}>• {title}</StyledColumnTitle>
|
||||
{children}
|
||||
</StyledColumn>
|
||||
);
|
||||
}
|
||||
37
front/src/modules/ui/board/components/NewButton.tsx
Normal file
37
front/src/modules/ui/board/components/NewButton.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconPlus } from '@/ui/icons/index';
|
||||
|
||||
const StyledButton = styled.button`
|
||||
align-items: center;
|
||||
align-self: baseline;
|
||||
background-color: ${({ theme }) => theme.background.primary};
|
||||
border: none;
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
justify-content: center;
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
|
||||
&:hover {
|
||||
background-color: ${({ theme }) => theme.background.secondary};
|
||||
}
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
export function NewButton({ onClick }: OwnProps) {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledButton onClick={onClick}>
|
||||
<IconPlus size={theme.icon.size.md} />
|
||||
New
|
||||
</StyledButton>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
import { DropResult } from '@hello-pangea/dnd';
|
||||
|
||||
import { getOptimisticlyUpdatedBoard } from '../Board';
|
||||
|
||||
describe('getOptimisticlyUpdatedBoard', () => {
|
||||
it('should return a new board with the updated cell', () => {
|
||||
const initialColumn1: string[] = ['item-1', 'item-2', 'item-3'];
|
||||
const initialColumn2: string[] = ['item-4', 'item-5'];
|
||||
|
||||
const finalColumn1: string[] = ['item-2', 'item-3'];
|
||||
const finalColumn2: string[] = ['item-4', 'item-1', 'item-5'];
|
||||
|
||||
const dropResult = {
|
||||
source: {
|
||||
droppableId: 'column-1',
|
||||
index: 0,
|
||||
},
|
||||
destination: {
|
||||
droppableId: 'column-2',
|
||||
index: 1,
|
||||
},
|
||||
} as DropResult;
|
||||
|
||||
const initialBoard = [
|
||||
{
|
||||
id: 'column-1',
|
||||
title: 'My Column',
|
||||
itemKeys: initialColumn1,
|
||||
},
|
||||
{
|
||||
id: 'column-2',
|
||||
title: 'My Column',
|
||||
itemKeys: initialColumn2,
|
||||
},
|
||||
];
|
||||
|
||||
const updatedBoard = getOptimisticlyUpdatedBoard(initialBoard, dropResult);
|
||||
|
||||
const finalBoard = [
|
||||
{
|
||||
id: 'column-1',
|
||||
title: 'My Column',
|
||||
itemKeys: finalColumn1,
|
||||
},
|
||||
{
|
||||
id: 'column-2',
|
||||
title: 'My Column',
|
||||
itemKeys: finalColumn2,
|
||||
},
|
||||
];
|
||||
|
||||
expect(updatedBoard).toEqual(finalBoard);
|
||||
expect(updatedBoard).not.toBe(initialBoard);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user