diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx new file mode 100644 index 000000000..a8aaaa97b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx @@ -0,0 +1,68 @@ +import { useRef } from 'react'; +import styled from '@emotion/styled'; +import { DragDropContext } 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 { RecordBoardColumn } from '@/object-record/record-board/record-board-column/components/RecordBoardColumn'; +import { RecordBoardScope } from '@/object-record/record-board/scopes/RecordBoardScope'; +import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; +import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; + +export type RecordBoardProps = { + recordBoardId: string; +}; + +const StyledContainer = styled.div` + border-top: 1px solid ${({ theme }) => theme.border.color.light}; + display: flex; + flex: 1; + flex-direction: row; + margin-left: ${({ theme }) => theme.spacing(2)}; + margin-right: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledWrapper = styled.div` + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + position: relative; + width: 100%; +`; + +const StyledBoardHeader = styled.div` + position: relative; + z-index: 1; +`; + +export const RecordBoard = ({ recordBoardId }: RecordBoardProps) => { + const boardRef = useRef(null); + + return ( + {}} + onFieldsChange={() => {}} + > + + + + + {}}> + {[].map((column) => ( + + ))} + + + + {}} + /> + + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/contexts/RecordBoardColumnContext.ts b/packages/twenty-front/src/modules/object-record/record-board/contexts/RecordBoardColumnContext.ts new file mode 100644 index 000000000..bd19cd033 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/contexts/RecordBoardColumnContext.ts @@ -0,0 +1,11 @@ +import { createContext } from 'react'; + +import { BoardColumnDefinition } from '@/object-record/record-board-deprecated/types/BoardColumnDefinition'; + +type RecordBoardColumnContextProps = { + id: string; + columnDefinition: BoardColumnDefinition; +}; + +export const RecordBoardColumnContext = + createContext(null); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx new file mode 100644 index 000000000..e7f037b7d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx @@ -0,0 +1,59 @@ +import styled from '@emotion/styled'; +import { Droppable } from '@hello-pangea/dnd'; + +import { RecordBoardColumnContext } from '@/object-record/record-board/contexts/RecordBoardColumnContext'; +import { RecordBoardColumnCardsContainer } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer'; +import { BoardCardIdContext } from '@/object-record/record-board-deprecated/contexts/BoardCardIdContext'; +import { BoardColumnDefinition } from '@/object-record/record-board-deprecated/types/BoardColumnDefinition'; + +const StyledColumn = styled.div<{ isFirstColumn: boolean }>` + background-color: ${({ theme }) => theme.background.primary}; + border-left: 1px solid + ${({ theme, isFirstColumn }) => + isFirstColumn ? 'none' : theme.border.color.light}; + display: flex; + flex-direction: column; + max-width: 200px; + min-width: 200px; + + padding: ${({ theme }) => theme.spacing(2)}; + position: relative; +`; + +type RecordBoardColumnProps = { + recordBoardColumnId: string; + columnDefinition: BoardColumnDefinition; +}; + +export const RecordBoardColumn = ({ + recordBoardColumnId, + columnDefinition, +}: RecordBoardColumnProps) => { + const isFirstColumn = columnDefinition.position === 0; + + return ( + + + {(droppableProvided) => ( + + + {[].map((cardId, _index) => ( + + ))} + + + )} + + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx new file mode 100644 index 000000000..157a5d6f2 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import styled from '@emotion/styled'; +import { DroppableProvided } from '@hello-pangea/dnd'; + +const StyledPlaceholder = styled.div` + min-height: 1px; +`; + +const StyledColumnCardsContainer = styled.div` + display: flex; + flex: 1; + flex-direction: column; +`; + +type RecordBoardColumnCardsContainerProps = { + children: React.ReactNode; + droppableProvided: DroppableProvided; +}; + +export const RecordBoardColumnCardsContainer = ({ + children, + droppableProvided, +}: RecordBoardColumnCardsContainerProps) => { + return ( + + {children} + {droppableProvided?.placeholder} + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/scopes/RecordBoardScope.tsx b/packages/twenty-front/src/modules/object-record/record-board/scopes/RecordBoardScope.tsx new file mode 100644 index 000000000..58ab59ec0 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/scopes/RecordBoardScope.tsx @@ -0,0 +1,32 @@ +import { ReactNode } from 'react'; + +import { FieldDefinition } from '@/object-record/field/types/FieldDefinition'; +import { FieldMetadata } from '@/object-record/field/types/FieldMetadata'; +import { RecordBoardScopeInternalContext } from '@/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext'; +import { RecordBoardColumnDefinition } from '@/object-record/record-board/types/RecordBoardColumnDefinition'; + +type RecordBoardScopeProps = { + children: ReactNode; + recordBoardScopeId: string; + onFieldsChange: (fields: FieldDefinition[]) => void; + onColumnsChange: (column: RecordBoardColumnDefinition[]) => void; +}; + +export const RecordBoardScope = ({ + children, + recordBoardScopeId, + onColumnsChange, + onFieldsChange, +}: RecordBoardScopeProps) => { + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext.ts b/packages/twenty-front/src/modules/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext.ts new file mode 100644 index 000000000..7b5b10dc6 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext.ts @@ -0,0 +1,13 @@ +import { FieldDefinition } from '@/object-record/field/types/FieldDefinition'; +import { FieldMetadata } from '@/object-record/field/types/FieldMetadata'; +import { RecordBoardColumnDefinition } from '@/object-record/record-board/types/RecordBoardColumnDefinition'; +import { StateScopeMapKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/StateScopeMapKey'; +import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; + +type RecordBoardDeprecatedScopeInternalContextProps = StateScopeMapKey & { + onFieldsChange: (fields: FieldDefinition[]) => void; + onColumnsChange: (column: RecordBoardColumnDefinition[]) => void; +}; + +export const RecordBoardScopeInternalContext = + createScopeInternalContext(); diff --git a/packages/twenty-front/src/modules/object-record/record-board/types/RecordBoardColumnDefinition.ts b/packages/twenty-front/src/modules/object-record/record-board/types/RecordBoardColumnDefinition.ts new file mode 100644 index 000000000..a2ce4a32f --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/types/RecordBoardColumnDefinition.ts @@ -0,0 +1,8 @@ +import { ThemeColor } from '@/ui/theme/constants/colors'; + +export type RecordBoardColumnDefinition = { + id: string; + title: string; + position: number; + colorCode?: ThemeColor; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx new file mode 100644 index 000000000..1eb73a407 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx @@ -0,0 +1,14 @@ +import { RecordBoard } from '@/object-record/record-board/components/RecordBoard'; + +type RecordIndexBoardContainerProps = { + recordBoardId: string; + viewBarId: string; + objectNamePlural: string; + createRecord: () => Promise; +}; + +export const RecordIndexBoardContainer = ({ + recordBoardId, +}: RecordIndexBoardContainerProps) => { + return ; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainerEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainerEffect.tsx new file mode 100644 index 000000000..95dac6191 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainerEffect.tsx @@ -0,0 +1,11 @@ +type RecordIndexBoardContainerEffectProps = { + objectNamePlural: string; + recordBoardId: string; + viewBarId: string; +}; + +export const RecordIndexBoardContainerEffect = ( + _props: RecordIndexBoardContainerEffectProps, +) => { + return <>; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx index 5a4dbc325..7b4c99b92 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx @@ -5,8 +5,10 @@ import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCom import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; +import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer'; import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer'; -import { RecordIndexViewInitEffect } from '@/object-record/record-index/components/RecordIndexViewInitEffect'; +import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect'; +import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect'; import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { TableOptionsDropdown } from '@/object-record/record-table/options/components/TableOptionsDropdown'; @@ -22,6 +24,7 @@ const StyledContainer = styled.div` display: flex; flex-direction: column; height: 100%; + width: 100%; overflow: auto; padding-left: ${({ theme }) => theme.table.horizontalCellPadding}; `; @@ -98,19 +101,41 @@ export const RecordIndexContainer = ({ setRecordIndexViewType(viewType); }} /> + {recordIndexViewType === ViewType.Table && ( - + <> + + + + )} + {recordIndexViewType === ViewType.Kanban && ( + <> + + + )} - ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx index 4cdd942bb..1de72a2bc 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx @@ -1,7 +1,6 @@ import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { RecordUpdateHookParams } from '@/object-record/field/contexts/FieldContext'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; -import { RecordTableEffect } from '@/object-record/record-index/components/RecordTableEffect'; import { RecordTableActionBar } from '@/object-record/record-table/action-bar/components/RecordTableActionBar'; import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers'; import { RecordTableContextMenu } from '@/object-record/record-table/context-menu/components/RecordTableContextMenu'; @@ -36,11 +35,6 @@ export const RecordIndexTableContainer = ({ return ( <> - { +}; + +export const RecordIndexTableContainerEffect = ({ + objectNamePlural, + recordTableId, + viewBarId, +}: RecordIndexTableContainerEffectProps) => { const { setAvailableTableColumns, setOnEntityCountChange, diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexViewInitEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexViewBarEffect.tsx similarity index 92% rename from packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexViewInitEffect.tsx rename to packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexViewBarEffect.tsx index 8a93fd16c..31a4447b2 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexViewInitEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexViewBarEffect.tsx @@ -5,13 +5,15 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useViewBar } from '@/views/hooks/useViewBar'; -export const RecordIndexViewInitEffect = ({ - objectNamePlural, - viewBarId, -}: { +type RecordIndexViewBarEffectProps = { objectNamePlural: string; viewBarId: string; -}) => { +}; + +export const RecordIndexViewBarEffect = ({ + objectNamePlural, + viewBarId, +}: RecordIndexViewBarEffectProps) => { const { objectNameSingular } = useObjectNameSingularFromPlural({ objectNamePlural, });