feat: reorder kanban columns (#1699)
* kaban header options * gql codegn * moveColumn hook refactor * BoardColumnContext addition * saved board columns state * db call hook update * lint fix * state change first db call second * handleMoveTableColumn call * codegen lint fix * useMoveViewColumns hook * useBoardColumns db call addition * boardColumns state change from BoardHeader --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { Tag } from '@/ui/tag/components/Tag';
|
||||
import { ThemeColor } from '@/ui/theme/constants/colors';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
|
||||
import { BoardColumnContext } from '../contexts/BoardColumnContext';
|
||||
import { BoardColumnHotkeyScope } from '../types/BoardColumnHotkeyScope';
|
||||
|
||||
import { BoardColumnMenu } from './BoardColumnMenu';
|
||||
@ -53,28 +53,24 @@ const StyledNumChildren = styled.div`
|
||||
`;
|
||||
|
||||
export type BoardColumnProps = {
|
||||
color?: ThemeColor;
|
||||
title: string;
|
||||
onDelete?: (id: string) => void;
|
||||
onTitleEdit: (title: string, color: string) => void;
|
||||
totalAmount?: number;
|
||||
children: React.ReactNode;
|
||||
isFirstColumn: boolean;
|
||||
numChildren: number;
|
||||
stageId: string;
|
||||
};
|
||||
|
||||
export const BoardColumn = ({
|
||||
color,
|
||||
title,
|
||||
onDelete,
|
||||
onTitleEdit,
|
||||
totalAmount,
|
||||
children,
|
||||
isFirstColumn,
|
||||
numChildren,
|
||||
stageId,
|
||||
}: BoardColumnProps) => {
|
||||
const boardColumn = useContext(BoardColumnContext);
|
||||
|
||||
const [isBoardColumnMenuOpen, setIsBoardColumnMenuOpen] =
|
||||
React.useState(false);
|
||||
|
||||
@ -95,10 +91,18 @@ export const BoardColumn = ({
|
||||
setIsBoardColumnMenuOpen(false);
|
||||
};
|
||||
|
||||
if (!boardColumn) return <></>;
|
||||
|
||||
const { isFirstColumn, columnDefinition } = boardColumn;
|
||||
|
||||
return (
|
||||
<StyledColumn isFirstColumn={isFirstColumn}>
|
||||
<StyledHeader onClick={handleTitleClick}>
|
||||
<Tag color={color ?? 'gray'} text={title} />
|
||||
<StyledHeader>
|
||||
<Tag
|
||||
onClick={handleTitleClick}
|
||||
color={columnDefinition.colorCode ?? 'gray'}
|
||||
text={columnDefinition.title}
|
||||
/>
|
||||
{!!totalAmount && <StyledAmount>${totalAmount}</StyledAmount>}
|
||||
<StyledNumChildren>{numChildren}</StyledNumChildren>
|
||||
</StyledHeader>
|
||||
@ -107,8 +111,6 @@ export const BoardColumn = ({
|
||||
onClose={handleClose}
|
||||
onDelete={onDelete}
|
||||
onTitleEdit={onTitleEdit}
|
||||
title={title}
|
||||
color={color ?? 'gray'}
|
||||
stageId={stageId}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { useCallback, useContext, useRef, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
@ -7,50 +7,53 @@ import { useCreateCompanyProgress } from '@/companies/hooks/useCreateCompanyProg
|
||||
import { useFilteredSearchCompanyQuery } from '@/companies/hooks/useFilteredSearchCompanyQuery';
|
||||
import { StyledDropdownMenu } from '@/ui/dropdown/components/StyledDropdownMenu';
|
||||
import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer';
|
||||
import { IconPencil, IconPlus, IconTrash } from '@/ui/icon';
|
||||
import {
|
||||
IconArrowLeft,
|
||||
IconArrowRight,
|
||||
IconPencil,
|
||||
IconPlus,
|
||||
IconTrash,
|
||||
} from '@/ui/icon';
|
||||
import { SingleEntitySelect } from '@/ui/input/relation-picker/components/SingleEntitySelect';
|
||||
import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
|
||||
import { MenuItem } from '@/ui/menu-item/components/MenuItem';
|
||||
import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar';
|
||||
import { ThemeColor } from '@/ui/theme/constants/colors';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
import { BoardColumnContext } from '../contexts/BoardColumnContext';
|
||||
import { useBoardColumns } from '../hooks/useBoardColumns';
|
||||
import { boardColumnsState } from '../states/boardColumnsState';
|
||||
import { BoardColumnHotkeyScope } from '../types/BoardColumnHotkeyScope';
|
||||
|
||||
import { BoardColumnEditTitleMenu } from './BoardColumnEditTitleMenu';
|
||||
|
||||
const StyledMenuContainer = styled.div`
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
z-index: 1;
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
color: ThemeColor;
|
||||
type BoardColumnMenuProps = {
|
||||
onClose: () => void;
|
||||
onDelete?: (id: string) => void;
|
||||
onTitleEdit: (title: string, color: string) => void;
|
||||
stageId: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
type Menu = 'actions' | 'add' | 'title';
|
||||
|
||||
export const BoardColumnMenu = ({
|
||||
color,
|
||||
onClose,
|
||||
onDelete,
|
||||
onTitleEdit,
|
||||
stageId,
|
||||
title,
|
||||
}: OwnProps) => {
|
||||
}: BoardColumnMenuProps) => {
|
||||
const [currentMenu, setCurrentMenu] = useState('actions');
|
||||
const column = useContext(BoardColumnContext);
|
||||
|
||||
const [, setBoardColumns] = useRecoilState(boardColumnsState);
|
||||
|
||||
@ -58,6 +61,7 @@ export const BoardColumnMenu = ({
|
||||
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
const createCompanyProgress = useCreateCompanyProgress();
|
||||
const { handleMoveBoardColumn } = useBoardColumns();
|
||||
|
||||
const handleCompanySelected = (
|
||||
selectedCompany: EntityForSelect | null | undefined,
|
||||
@ -125,6 +129,26 @@ export const BoardColumnMenu = ({
|
||||
[],
|
||||
);
|
||||
|
||||
if (!column) return <></>;
|
||||
|
||||
const { isFirstColumn, isLastColumn, columnDefinition } = column;
|
||||
|
||||
const handleColumnMoveLeft = () => {
|
||||
closeMenu();
|
||||
if (isFirstColumn) {
|
||||
return;
|
||||
}
|
||||
handleMoveBoardColumn('left', columnDefinition);
|
||||
};
|
||||
|
||||
const handleColumnMoveRight = () => {
|
||||
closeMenu();
|
||||
if (isLastColumn) {
|
||||
return;
|
||||
}
|
||||
handleMoveBoardColumn('right', columnDefinition);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledMenuContainer ref={boardColumnMenuRef}>
|
||||
<StyledDropdownMenu data-select-disable>
|
||||
@ -135,6 +159,16 @@ export const BoardColumnMenu = ({
|
||||
LeftIcon={IconPencil}
|
||||
text="Rename"
|
||||
/>
|
||||
<MenuItem
|
||||
LeftIcon={IconArrowLeft}
|
||||
onClick={handleColumnMoveLeft}
|
||||
text="Move left"
|
||||
/>
|
||||
<MenuItem
|
||||
LeftIcon={IconArrowRight}
|
||||
onClick={handleColumnMoveRight}
|
||||
text="Move right"
|
||||
/>
|
||||
<MenuItem
|
||||
onClick={handleDelete}
|
||||
LeftIcon={IconTrash}
|
||||
@ -149,10 +183,10 @@ export const BoardColumnMenu = ({
|
||||
)}
|
||||
{currentMenu === 'title' && (
|
||||
<BoardColumnEditTitleMenu
|
||||
color={color}
|
||||
color={columnDefinition.colorCode ?? 'gray'}
|
||||
onClose={closeMenu}
|
||||
onTitleEdit={onTitleEdit}
|
||||
title={title}
|
||||
title={columnDefinition.title}
|
||||
/>
|
||||
)}
|
||||
{currentMenu === 'add' && (
|
||||
|
||||
@ -12,9 +12,12 @@ import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext';
|
||||
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
|
||||
|
||||
import { boardCardFieldsScopedState } from '../states/boardCardFieldsScopedState';
|
||||
import { boardColumnsState } from '../states/boardColumnsState';
|
||||
import { savedBoardCardFieldsFamilyState } from '../states/savedBoardCardFieldsFamilyState';
|
||||
import { savedBoardColumnsState } from '../states/savedBoardColumnsState';
|
||||
import { canPersistBoardCardFieldsScopedFamilySelector } from '../states/selectors/canPersistBoardCardFieldsScopedFamilySelector';
|
||||
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||
import { canPersistBoardColumnsSelector } from '../states/selectors/canPersistBoardColumnsSelector';
|
||||
import type { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||
import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey';
|
||||
import { BoardOptionsHotkeyScope } from '../types/BoardOptionsHotkeyScope';
|
||||
|
||||
@ -47,6 +50,8 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => {
|
||||
viewId: currentViewId,
|
||||
}),
|
||||
);
|
||||
const canPersistBoardColumns = useRecoilValue(canPersistBoardColumnsSelector);
|
||||
|
||||
const [boardCardFields, setBoardCardFields] = useRecoilScopedState(
|
||||
boardCardFieldsScopedState,
|
||||
BoardRecoilScopeContext,
|
||||
@ -55,7 +60,15 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => {
|
||||
savedBoardCardFieldsFamilyState(currentViewId),
|
||||
);
|
||||
|
||||
const handleViewBarReset = () => setBoardCardFields(savedBoardCardFields);
|
||||
const [boardColumns, setBoardColumns] = useRecoilState(boardColumnsState);
|
||||
const [, setSavedBoardColumns] = useRecoilState(savedBoardColumnsState);
|
||||
|
||||
const savedBoardColumns = useRecoilValue(savedBoardColumnsState);
|
||||
|
||||
const handleViewBarReset = () => {
|
||||
setBoardCardFields(savedBoardCardFields);
|
||||
setBoardColumns(savedBoardColumns);
|
||||
};
|
||||
|
||||
const handleViewSelect = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
@ -75,16 +88,21 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => {
|
||||
if (canPersistBoardCardFields) {
|
||||
setSavedBoardCardFields(boardCardFields);
|
||||
}
|
||||
if (canPersistBoardColumns) {
|
||||
setSavedBoardColumns(boardColumns);
|
||||
}
|
||||
|
||||
await onCurrentViewSubmit?.();
|
||||
};
|
||||
|
||||
const canPersistView = canPersistBoardCardFields || canPersistBoardColumns;
|
||||
|
||||
return (
|
||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
||||
<ViewBarContext.Provider
|
||||
value={{
|
||||
...viewBarContextProps,
|
||||
canPersistViewFields: canPersistBoardCardFields,
|
||||
canPersistViewFields: canPersistView,
|
||||
onCurrentViewSubmit: handleCurrentViewSubmit,
|
||||
onViewBarReset: handleViewBarReset,
|
||||
onViewSelect: handleViewSelect,
|
||||
|
||||
@ -2,13 +2,13 @@ import { useCallback, useRef } from 'react';
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import styled from '@emotion/styled';
|
||||
import { DragDropContext, OnDragEndResponder } 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
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { GET_PIPELINE_PROGRESS } from '@/pipeline/graphql/queries/getPipelineProgress';
|
||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||
import { BoardHeader } from '@/ui/board/components/BoardHeader';
|
||||
import { StyledBoard } from '@/ui/board/components/StyledBoard';
|
||||
import { BoardColumnIdContext } from '@/ui/board/contexts/BoardColumnIdContext';
|
||||
import { BoardColumnContext } from '@/ui/board/contexts/BoardColumnContext';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useListenClickOutsideByClassName } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
@ -54,7 +54,7 @@ export const EntityBoard = ({
|
||||
onColumnDelete,
|
||||
onEditColumnTitle,
|
||||
}: EntityBoardProps) => {
|
||||
const [boardColumns] = useRecoilState(boardColumnsState);
|
||||
const boardColumns = useRecoilValue(boardColumnsState);
|
||||
const setCardSelected = useSetCardSelected();
|
||||
|
||||
const [updatePipelineProgressStage] =
|
||||
@ -151,19 +151,26 @@ export const EntityBoard = ({
|
||||
<StyledBoard ref={boardRef}>
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
{sortedBoardColumns.map((column) => (
|
||||
<BoardColumnIdContext.Provider value={column.id} key={column.id}>
|
||||
<BoardColumnContext.Provider
|
||||
key={column.id}
|
||||
value={{
|
||||
id: column.id,
|
||||
columnDefinition: column,
|
||||
isFirstColumn: column.index === 0,
|
||||
isLastColumn: column.index === sortedBoardColumns.length - 1,
|
||||
}}
|
||||
>
|
||||
<RecoilScope
|
||||
CustomRecoilScopeContext={BoardColumnRecoilScopeContext}
|
||||
key={column.id}
|
||||
>
|
||||
<EntityBoardColumn
|
||||
boardOptions={boardOptions}
|
||||
column={column}
|
||||
onDelete={onColumnDelete}
|
||||
onTitleEdit={onEditColumnTitle}
|
||||
/>
|
||||
</RecoilScope>
|
||||
</BoardColumnIdContext.Provider>
|
||||
</BoardColumnContext.Provider>
|
||||
))}
|
||||
</DragDropContext>
|
||||
</StyledBoard>
|
||||
|
||||
@ -5,8 +5,7 @@ import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { BoardColumn } from '@/ui/board/components/BoardColumn';
|
||||
import { BoardCardIdContext } from '@/ui/board/contexts/BoardCardIdContext';
|
||||
import { BoardColumnIdContext } from '@/ui/board/contexts/BoardColumnIdContext';
|
||||
import { BoardColumnDefinition } from '@/ui/board/types/BoardColumnDefinition';
|
||||
import { BoardColumnContext } from '@/ui/board/contexts/BoardColumnContext';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
|
||||
import { boardCardIdsByColumnIdFamilyState } from '../states/boardCardIdsByColumnIdFamilyState';
|
||||
@ -29,13 +28,21 @@ const StyledColumnCardsContainer = styled.div`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
type BoardColumnCardsContainerProps = {
|
||||
children: React.ReactNode;
|
||||
droppableProvided: DroppableProvided;
|
||||
};
|
||||
|
||||
type EntityBoardColumnProps = {
|
||||
boardOptions: BoardOptions;
|
||||
onDelete?: (columnId: string) => void;
|
||||
onTitleEdit: (columnId: string, title: string, color: string) => void;
|
||||
};
|
||||
|
||||
const BoardColumnCardsContainer = ({
|
||||
children,
|
||||
droppableProvided,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
droppableProvided: DroppableProvided;
|
||||
}) => {
|
||||
}: BoardColumnCardsContainerProps) => {
|
||||
return (
|
||||
<StyledColumnCardsContainer
|
||||
ref={droppableProvided?.innerRef}
|
||||
@ -49,39 +56,34 @@ const BoardColumnCardsContainer = ({
|
||||
|
||||
export const EntityBoardColumn = ({
|
||||
boardOptions,
|
||||
column,
|
||||
onDelete,
|
||||
onTitleEdit,
|
||||
}: {
|
||||
boardOptions: BoardOptions;
|
||||
column: BoardColumnDefinition;
|
||||
onDelete?: (columnId: string) => void;
|
||||
onTitleEdit: (columnId: string, title: string, color: string) => void;
|
||||
}) => {
|
||||
const boardColumnId = useContext(BoardColumnIdContext) ?? '';
|
||||
}: EntityBoardColumnProps) => {
|
||||
const column = useContext(BoardColumnContext);
|
||||
|
||||
const boardColumnId = column?.id || '';
|
||||
|
||||
const boardColumnTotal = useRecoilValue(
|
||||
boardColumnTotalsFamilySelector(column.id),
|
||||
boardColumnTotalsFamilySelector(boardColumnId),
|
||||
);
|
||||
|
||||
const cardIds = useRecoilValue(
|
||||
boardCardIdsByColumnIdFamilyState(boardColumnId ?? ''),
|
||||
boardCardIdsByColumnIdFamilyState(boardColumnId),
|
||||
);
|
||||
|
||||
const handleTitleEdit = (title: string, color: string) => {
|
||||
onTitleEdit(boardColumnId, title, color);
|
||||
};
|
||||
|
||||
if (!column) return <></>;
|
||||
|
||||
return (
|
||||
<Droppable droppableId={column.id}>
|
||||
{(droppableProvided) => (
|
||||
<BoardColumn
|
||||
onTitleEdit={handleTitleEdit}
|
||||
onDelete={onDelete}
|
||||
title={column.title}
|
||||
color={column.colorCode}
|
||||
totalAmount={boardColumnTotal}
|
||||
isFirstColumn={column.index === 0}
|
||||
numChildren={cardIds.length}
|
||||
stageId={column.id}
|
||||
>
|
||||
|
||||
12
front/src/modules/ui/board/contexts/BoardColumnContext.ts
Normal file
12
front/src/modules/ui/board/contexts/BoardColumnContext.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||
|
||||
type BoardColumn = {
|
||||
id: string;
|
||||
columnDefinition: BoardColumnDefinition;
|
||||
isFirstColumn: boolean;
|
||||
isLastColumn: boolean;
|
||||
};
|
||||
|
||||
export const BoardColumnContext = createContext<BoardColumn | null>(null);
|
||||
@ -1,3 +0,0 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const BoardColumnIdContext = createContext<string | null>(null);
|
||||
53
front/src/modules/ui/board/hooks/useBoardColumns.ts
Normal file
53
front/src/modules/ui/board/hooks/useBoardColumns.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns';
|
||||
import { useUpdatePipelineStageMutation } from '~/generated/graphql';
|
||||
|
||||
import { boardColumnsState } from '../states/boardColumnsState';
|
||||
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||
|
||||
export const useBoardColumns = () => {
|
||||
const [boardColumns, setBoardColumns] = useRecoilState(boardColumnsState);
|
||||
|
||||
const { handleColumnMove } = useMoveViewColumns();
|
||||
|
||||
const [updatePipelineStageMutation] = useUpdatePipelineStageMutation();
|
||||
|
||||
const updatedPipelineStages = (stages: BoardColumnDefinition[]) => {
|
||||
if (!stages.length) return;
|
||||
|
||||
return Promise.all(
|
||||
stages.map((stage) =>
|
||||
updatePipelineStageMutation({
|
||||
variables: {
|
||||
data: {
|
||||
index: stage.index,
|
||||
},
|
||||
id: stage.id,
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
const persistBoardColumns = async () => {
|
||||
await updatedPipelineStages(boardColumns);
|
||||
};
|
||||
|
||||
const handleMoveBoardColumn = (
|
||||
direction: 'left' | 'right',
|
||||
column: BoardColumnDefinition,
|
||||
) => {
|
||||
const currentColumnArrayIndex = boardColumns.findIndex(
|
||||
(tableColumn) => tableColumn.id === column.id,
|
||||
);
|
||||
const columns = handleColumnMove(
|
||||
direction,
|
||||
currentColumnArrayIndex,
|
||||
boardColumns,
|
||||
);
|
||||
setBoardColumns(columns);
|
||||
};
|
||||
|
||||
return { handleMoveBoardColumn, persistBoardColumns };
|
||||
};
|
||||
@ -0,0 +1,8 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||
|
||||
export const savedBoardColumnsState = atom<BoardColumnDefinition[]>({
|
||||
key: 'savedBoardColumnsState',
|
||||
default: [],
|
||||
});
|
||||
@ -0,0 +1,12 @@
|
||||
import { selector } from 'recoil';
|
||||
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
import { boardColumnsState } from '../boardColumnsState';
|
||||
import { savedBoardColumnsState } from '../savedBoardColumnsState';
|
||||
|
||||
export const canPersistBoardColumnsSelector = selector<boolean>({
|
||||
key: 'canPersistBoardCardFieldsScopedFamilySelector',
|
||||
get: ({ get }) =>
|
||||
!isDeeplyEqual(get(boardColumnsState), get(savedBoardColumnsState)),
|
||||
});
|
||||
@ -22,11 +22,8 @@ export const TableColumnDropdownMenu = ({
|
||||
isLastColumn,
|
||||
primaryColumnKey,
|
||||
}: EntityTableHeaderOptionsProps) => {
|
||||
const {
|
||||
handleColumnVisibilityChange,
|
||||
handleColumnLeftMove,
|
||||
handleColumnRightMove,
|
||||
} = useTableColumns();
|
||||
const { handleColumnVisibilityChange, handleMoveTableColumn } =
|
||||
useTableColumns();
|
||||
|
||||
const { closeDropdownButton } = useDropdownButton({
|
||||
dropdownId: ColumnHeadDropdownId,
|
||||
@ -37,7 +34,7 @@ export const TableColumnDropdownMenu = ({
|
||||
if (isFirstColumn) {
|
||||
return;
|
||||
}
|
||||
handleColumnLeftMove(column);
|
||||
handleMoveTableColumn('left', column);
|
||||
};
|
||||
|
||||
const handleColumnMoveRight = () => {
|
||||
@ -45,7 +42,7 @@ export const TableColumnDropdownMenu = ({
|
||||
if (isLastColumn) {
|
||||
return;
|
||||
}
|
||||
handleColumnRightMove(column);
|
||||
handleMoveTableColumn('right', column);
|
||||
};
|
||||
|
||||
const handleColumnVisibility = () => {
|
||||
|
||||
@ -5,6 +5,7 @@ import { ViewFieldMetadata } from '@/ui/editable-field/types/ViewField';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
|
||||
import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns';
|
||||
|
||||
import { TableContext } from '../contexts/TableContext';
|
||||
import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||
@ -32,6 +33,8 @@ export const useTableColumns = () => {
|
||||
TableRecoilScopeContext,
|
||||
);
|
||||
|
||||
const { handleColumnMove } = useMoveViewColumns();
|
||||
|
||||
const handleColumnsChange = useCallback(
|
||||
async (columns: ColumnDefinition<ViewFieldMetadata>[]) => {
|
||||
setSavedTableColumns(columns);
|
||||
@ -71,54 +74,28 @@ export const useTableColumns = () => {
|
||||
[tableColumnsByKey, tableColumns, handleColumnsChange],
|
||||
);
|
||||
|
||||
const handleColumnMove = useCallback(
|
||||
async (direction: string, column: ColumnDefinition<ViewFieldMetadata>) => {
|
||||
const handleMoveTableColumn = useCallback(
|
||||
(
|
||||
direction: 'left' | 'right',
|
||||
column: ColumnDefinition<ViewFieldMetadata>,
|
||||
) => {
|
||||
const currentColumnArrayIndex = tableColumns.findIndex(
|
||||
(tableColumn) => tableColumn.key === column.key,
|
||||
);
|
||||
const targetColumnArrayIndex =
|
||||
direction === 'left'
|
||||
? currentColumnArrayIndex - 1
|
||||
: currentColumnArrayIndex + 1;
|
||||
const columns = handleColumnMove(
|
||||
direction,
|
||||
currentColumnArrayIndex,
|
||||
tableColumns,
|
||||
);
|
||||
|
||||
if (currentColumnArrayIndex >= 0) {
|
||||
const currentColumn = tableColumns[currentColumnArrayIndex];
|
||||
const targetColumn = tableColumns[targetColumnArrayIndex];
|
||||
|
||||
const newTableColumns = [...tableColumns];
|
||||
newTableColumns[currentColumnArrayIndex] = {
|
||||
...targetColumn,
|
||||
index: currentColumn.index,
|
||||
};
|
||||
newTableColumns[targetColumnArrayIndex] = {
|
||||
...currentColumn,
|
||||
index: targetColumn.index,
|
||||
};
|
||||
|
||||
await handleColumnsChange(newTableColumns);
|
||||
}
|
||||
setTableColumns(columns);
|
||||
},
|
||||
[tableColumns, handleColumnsChange],
|
||||
);
|
||||
|
||||
const handleColumnLeftMove = useCallback(
|
||||
(column: ColumnDefinition<ViewFieldMetadata>) => {
|
||||
handleColumnMove('left', column);
|
||||
},
|
||||
[handleColumnMove],
|
||||
);
|
||||
|
||||
const handleColumnRightMove = useCallback(
|
||||
(column: ColumnDefinition<ViewFieldMetadata>) => {
|
||||
handleColumnMove('right', column);
|
||||
},
|
||||
[handleColumnMove],
|
||||
[tableColumns, setTableColumns, handleColumnMove],
|
||||
);
|
||||
|
||||
return {
|
||||
handleColumnVisibilityChange,
|
||||
handleColumnLeftMove,
|
||||
handleColumnRightMove,
|
||||
handleMoveTableColumn,
|
||||
handleColumnReorder,
|
||||
handleColumnsChange,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user