diff --git a/front/src/modules/companies/board/components/CompanyBoard.tsx b/front/src/modules/companies/board/components/CompanyBoard.tsx index f95640b6a..330b0fe58 100644 --- a/front/src/modules/companies/board/components/CompanyBoard.tsx +++ b/front/src/modules/companies/board/components/CompanyBoard.tsx @@ -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 ( { + persistViewFields(mapBoardFieldDefinitionsToViewFields(fields)); + }, }} > []) => void; }>({ BoardRecoilScopeContext: createContext(null), + onFieldsChange: () => {}, }); diff --git a/front/src/modules/companies/utils/mapBoardFieldDefinitionsToViewFields.ts b/front/src/modules/companies/utils/mapBoardFieldDefinitionsToViewFields.ts new file mode 100644 index 000000000..b417fb72e --- /dev/null +++ b/front/src/modules/companies/utils/mapBoardFieldDefinitionsToViewFields.ts @@ -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[], +): ViewField[] => { + return fieldsDefinitions.map( + (fieldDefinition): ViewField => ({ + id: fieldDefinition.viewFieldId || '', + fieldMetadataId: fieldDefinition.fieldMetadataId, + size: 0, + position: fieldDefinition.position, + isVisible: fieldDefinition.isVisible ?? true, + definition: fieldDefinition, + }), + ); +}; diff --git a/front/src/modules/ui/layout/board/components/BoardOptionsDropdownContent.tsx b/front/src/modules/ui/layout/board/components/BoardOptionsDropdownContent.tsx index 472862def..7362eae0d 100644 --- a/front/src/modules/ui/layout/board/components/BoardOptionsDropdownContent.tsx +++ b/front/src/modules/ui/layout/board/components/BoardOptionsDropdownContent.tsx @@ -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 && } diff --git a/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts b/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts index 35cc98415..d19ddc1f7 100644 --- a/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts +++ b/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts @@ -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, 'size' | 'position'>, ) => { @@ -26,5 +35,27 @@ export const useBoardCardFields = () => { ); }; - return { handleFieldVisibilityChange }; + const handleFieldsChange = useCallback( + async (fields: BoardFieldDefinition[]) => { + setSavedBoardCardFields(fields); + setBoardCardFields(fields); + + await onFieldsChange?.(fields); + }, + [setBoardCardFields, setSavedBoardCardFields, onFieldsChange], + ); + + const handleFieldsReorder = useCallback( + async (fields: BoardFieldDefinition[]) => { + const updatedFields = fields.map((column, index) => ({ + ...column, + position: index, + })); + + await handleFieldsChange(updatedFields); + }, + [handleFieldsChange], + ); + + return { handleFieldVisibilityChange, handleFieldsReorder }; }; diff --git a/front/src/modules/ui/layout/board/states/selectors/visibleBoardCardFieldsScopedSelector.ts b/front/src/modules/ui/layout/board/states/selectors/visibleBoardCardFieldsScopedSelector.ts index e4ce74ea3..669c2ba22 100644 --- a/front/src/modules/ui/layout/board/states/selectors/visibleBoardCardFieldsScopedSelector.ts +++ b/front/src/modules/ui/layout/board/states/selectors/visibleBoardCardFieldsScopedSelector.ts @@ -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), }); diff --git a/front/src/modules/ui/layout/board/types/BoardFieldDefinition.ts b/front/src/modules/ui/layout/board/types/BoardFieldDefinition.ts index 951b98447..543f3b6df 100644 --- a/front/src/modules/ui/layout/board/types/BoardFieldDefinition.ts +++ b/front/src/modules/ui/layout/board/types/BoardFieldDefinition.ts @@ -5,4 +5,5 @@ export type BoardFieldDefinition = FieldDefinition & { position: number; isVisible?: boolean; + viewFieldId?: string; }; diff --git a/front/src/modules/views/types/ViewField.ts b/front/src/modules/views/types/ViewField.ts index 536796da9..6d510c008 100644 --- a/front/src/modules/views/types/ViewField.ts +++ b/front/src/modules/views/types/ViewField.ts @@ -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; + definition: + | ColumnDefinition + | BoardFieldDefinition; };