Create board fields reorder (#2639)

* wip

* fields reorder works but fields are not yet persisted

* fields are persisted

* modify according to comments
This commit is contained in:
bosiraphael 2023-11-22 14:46:18 +01:00 committed by GitHub
parent 532e4342ec
commit 85646a8072
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 90 additions and 8 deletions

View File

@ -1,6 +1,7 @@
import styled from '@emotion/styled';
import { BoardContext } from '@/companies/states/contexts/BoardContext';
import { mapBoardFieldDefinitionsToViewFields } from '@/companies/utils/mapBoardFieldDefinitionsToViewFields';
import { BoardOptionsDropdown } from '@/ui/layout/board/components/BoardOptionsDropdown';
import { BoardOptionsDropdownId } from '@/ui/layout/board/components/constants/BoardOptionsDropdownId';
import {
@ -10,6 +11,7 @@ import {
import { EntityBoardActionBar } from '@/ui/layout/board/components/EntityBoardActionBar';
import { EntityBoardContextMenu } from '@/ui/layout/board/components/EntityBoardContextMenu';
import { ViewBar } from '@/views/components/ViewBar';
import { useViewFields } from '@/views/hooks/internal/useViewFields';
import { ViewScope } from '@/views/scopes/ViewScope';
import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBoardOptions';
@ -36,6 +38,8 @@ export const CompanyBoard = ({
}: CompanyBoardProps) => {
const viewScopeId = 'company-board-view';
const { persistViewFields } = useViewFields(viewScopeId);
return (
<ViewScope
viewScopeId={viewScopeId}
@ -47,6 +51,9 @@ export const CompanyBoard = ({
<BoardContext.Provider
value={{
BoardRecoilScopeContext: CompanyBoardRecoilScopeContext,
onFieldsChange: (fields) => {
persistViewFields(mapBoardFieldDefinitionsToViewFields(fields));
},
}}
>
<ViewBar

View File

@ -1,9 +1,13 @@
import { createContext } from 'react';
import { RecoilScopeContext } from '@/types/RecoilScopeContext';
import { BoardFieldDefinition } from '@/ui/layout/board/types/BoardFieldDefinition';
import { FieldMetadata } from '@/ui/object/field/types/FieldMetadata';
export const BoardContext = createContext<{
BoardRecoilScopeContext: RecoilScopeContext;
onFieldsChange: (fields: BoardFieldDefinition<FieldMetadata>[]) => void;
}>({
BoardRecoilScopeContext: createContext<string | null>(null),
onFieldsChange: () => {},
});

View File

@ -0,0 +1,18 @@
import { BoardFieldDefinition } from '@/ui/layout/board/types/BoardFieldDefinition';
import { FieldMetadata } from '@/ui/object/field/types/FieldMetadata';
import { ViewField } from '@/views/types/ViewField';
export const mapBoardFieldDefinitionsToViewFields = (
fieldsDefinitions: BoardFieldDefinition<FieldMetadata>[],
): ViewField[] => {
return fieldsDefinitions.map(
(fieldDefinition): ViewField => ({
id: fieldDefinition.viewFieldId || '',
fieldMetadataId: fieldDefinition.fieldMetadataId,
size: 0,
position: fieldDefinition.position,
isVisible: fieldDefinition.isVisible ?? true,
definition: fieldDefinition,
}),
);
};

View File

@ -1,4 +1,5 @@
import { useContext, useRef, useState } from 'react';
import { useCallback, useContext, useRef, useState } from 'react';
import { OnDragEndResponder } from '@hello-pangea/dnd';
import { useRecoilState, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { v4 } from 'uuid';
@ -107,10 +108,26 @@ export const BoardOptionsDropdownContent = ({
setCurrentMenu(menu);
};
const { handleFieldVisibilityChange } = useBoardCardFields();
const { handleFieldVisibilityChange, handleFieldsReorder } =
useBoardCardFields();
const { closeDropdown } = useDropdown();
const handleReorderField: OnDragEndResponder = useCallback(
(result) => {
if (!result.destination) {
return;
}
const reorderFields = [...visibleBoardCardFields];
const [removed] = reorderFields.splice(result.source.index - 1, 1);
reorderFields.splice(result.destination.index - 1, 0, removed);
handleFieldsReorder(reorderFields);
},
[handleFieldsReorder, visibleBoardCardFields],
);
useScopedHotkeys(
Key.Escape,
() => {
@ -209,6 +226,7 @@ export const BoardOptionsDropdownContent = ({
fields={visibleBoardCardFields}
onVisibilityChange={handleFieldVisibilityChange}
isDraggable={true}
onDragEnd={handleReorderField}
/>
)}
{hasVisibleFields && hasHiddenFields && <DropdownMenuSeparator />}

View File

@ -1,3 +1,7 @@
import { useCallback } from 'react';
import { savedBoardCardFieldsFamilyState } from '@/ui/layout/board/states/savedBoardCardFieldsFamilyState';
import { BoardFieldDefinition } from '@/ui/layout/board/types/BoardFieldDefinition';
import { FieldMetadata } from '@/ui/object/field/types/FieldMetadata';
import { ColumnDefinition } from '@/ui/object/record-table/types/ColumnDefinition';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
@ -7,13 +11,18 @@ import { boardCardFieldsScopedState } from '../states/boardCardFieldsScopedState
import { useBoardContext } from './useBoardContext';
export const useBoardCardFields = () => {
const { BoardRecoilScopeContext } = useBoardContext();
const { BoardRecoilScopeContext, onFieldsChange } = useBoardContext();
const [, setBoardCardFields] = useRecoilScopedState(
boardCardFieldsScopedState,
BoardRecoilScopeContext,
);
const [, setSavedBoardCardFields] = useRecoilScopedState(
savedBoardCardFieldsFamilyState,
BoardRecoilScopeContext,
);
const handleFieldVisibilityChange = (
field: Omit<ColumnDefinition<FieldMetadata>, 'size' | 'position'>,
) => {
@ -26,5 +35,27 @@ export const useBoardCardFields = () => {
);
};
return { handleFieldVisibilityChange };
const handleFieldsChange = useCallback(
async (fields: BoardFieldDefinition<FieldMetadata>[]) => {
setSavedBoardCardFields(fields);
setBoardCardFields(fields);
await onFieldsChange?.(fields);
},
[setBoardCardFields, setSavedBoardCardFields, onFieldsChange],
);
const handleFieldsReorder = useCallback(
async (fields: BoardFieldDefinition<FieldMetadata>[]) => {
const updatedFields = fields.map((column, index) => ({
...column,
position: index,
}));
await handleFieldsChange(updatedFields);
},
[handleFieldsChange],
);
return { handleFieldVisibilityChange, handleFieldsReorder };
};

View File

@ -7,7 +7,7 @@ export const visibleBoardCardFieldsScopedSelector = selectorFamily({
get:
(scopeId: string) =>
({ get }) =>
get(boardCardFieldsScopedState(scopeId)).filter(
(field) => field.isVisible,
),
get(boardCardFieldsScopedState(scopeId))
.filter((field) => field.isVisible)
.sort((a, b) => a.position - b.position),
});

View File

@ -5,4 +5,5 @@ export type BoardFieldDefinition<T extends FieldMetadata> =
FieldDefinition<T> & {
position: number;
isVisible?: boolean;
viewFieldId?: string;
};

View File

@ -1,3 +1,4 @@
import { BoardFieldDefinition } from '@/ui/layout/board/types/BoardFieldDefinition';
import { FieldMetadata } from '@/ui/object/field/types/FieldMetadata';
import { ColumnDefinition } from '@/ui/object/record-table/types/ColumnDefinition';
@ -7,5 +8,7 @@ export type ViewField = {
position: number;
isVisible: boolean;
size: number;
definition: ColumnDefinition<FieldMetadata>;
definition:
| ColumnDefinition<FieldMetadata>
| BoardFieldDefinition<FieldMetadata>;
};