Skip to content

Commit

Permalink
Refactor kanban new card creation (#8339)
Browse files Browse the repository at this point in the history
On the kanban page, the record creation was changed a few weeks ago to
enable creation on top / bottom of the columns.

However, this introduced a glitch (missing background opacity). While
fixing it, I have refactored the component structure to:
- separate "New" button from the Empty record card
  • Loading branch information
charlesBochet authored Nov 5, 2024
1 parent be8141c commit 84b0b78
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { useRecordBoardStates } from '@/object-record/record-board/hooks/interna
import { RecordBoardColumnCardContainerSkeletonLoader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader';
import { RecordBoardColumnCardsMemo } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsMemo';
import { RecordBoardColumnFetchMoreLoader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnFetchMoreLoader';
import { RecordBoardColumnNewButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewButton';
import { RecordBoardColumnNewOpportunityButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunityButton';
import { RecordBoardColumnNewOpportunity } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunity';
import { RecordBoardColumnNewRecord } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecord';
import { RecordBoardColumnNewRecordButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecordButton';
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
import { useIsOpportunitiesCompanyFieldDisabled } from '@/object-record/record-board/record-board-column/hooks/useIsOpportunitiesCompanyFieldDisabled';
import { getNumberOfCardsPerColumnForSkeletonLoading } from '@/object-record/record-board/record-board-column/utils/getNumberOfCardsPerColumnForSkeletonLoading';
Expand Down Expand Up @@ -74,6 +75,33 @@ export const RecordBoardColumnCardsContainer = ({
// eslint-disable-next-line react/jsx-props-no-spreading
{...droppableProvided?.droppableProps}
>
<Draggable
draggableId={`new-${columnDefinition.id}-top`}
index={-1}
isDragDisabled={true}
>
{(draggableProvided) => (
<div
ref={draggableProvided?.innerRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...draggableProvided?.draggableProps}
>
{objectMetadataItem.nameSingular ===
CoreObjectNameSingular.Opportunity &&
!isOpportunitiesCompanyFieldDisabled ? (
<RecordBoardColumnNewOpportunity
columnId={columnDefinition.id}
position="first"
/>
) : (
<RecordBoardColumnNewRecord
columnId={columnDefinition.id}
position="first"
/>
)}
</div>
)}
</Draggable>
{isRecordIndexBoardColumnLoading ? (
Array.from(
{
Expand All @@ -98,7 +126,7 @@ export const RecordBoardColumnCardsContainer = ({
)}
<RecordBoardColumnFetchMoreLoader />
<Draggable
draggableId={`new-${columnDefinition.id}`}
draggableId={`new-${columnDefinition.id}-bottom`}
index={recordIds.length}
isDragDisabled={true}
>
Expand All @@ -108,16 +136,23 @@ export const RecordBoardColumnCardsContainer = ({
// eslint-disable-next-line react/jsx-props-no-spreading
{...draggableProvided?.draggableProps}
>
{objectMetadataItem.nameSingular ===
CoreObjectNameSingular.Opportunity &&
!isOpportunitiesCompanyFieldDisabled ? (
<RecordBoardColumnNewOpportunity
columnId={columnDefinition.id}
position="last"
/>
) : (
<RecordBoardColumnNewRecord
columnId={columnDefinition.id}
position="last"
/>
)}
<StyledNewButtonContainer>
{objectMetadataItem.nameSingular ===
CoreObjectNameSingular.Opportunity &&
!isOpportunitiesCompanyFieldDisabled ? (
<RecordBoardColumnNewOpportunityButton
columnId={columnDefinition.id}
/>
) : (
<RecordBoardColumnNewButton columnId={columnDefinition.id} />
)}
<RecordBoardColumnNewRecordButton
columnId={columnDefinition.id}
/>
</StyledNewButtonContainer>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import styled from '@emotion/styled';
import { useContext, useState } from 'react';
import { IconDotsVertical, IconPlus, LightIconButton, Tag } from 'twenty-ui';

import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
import { RecordBoardCard } from '@/object-record/record-board/record-board-card/components/RecordBoardCard';
import { RecordBoardColumnDropdownMenu } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnDropdownMenu';
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
import { useColumnNewCardActions } from '@/object-record/record-board/record-board-column/hooks/useColumnNewCardActions';
import { useIsOpportunitiesCompanyFieldDisabled } from '@/object-record/record-board/record-board-column/hooks/useIsOpportunitiesCompanyFieldDisabled';
import { RecordBoardColumnHotkeyScope } from '@/object-record/record-board/types/BoardColumnHotkeyScope';
import { RecordGroupDefinitionType } from '@/object-record/record-group/types/RecordGroupDefinition';
import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { IconDotsVertical, IconPlus, LightIconButton, Tag } from 'twenty-ui';

const StyledHeader = styled.div`
align-items: center;
Expand Down Expand Up @@ -102,12 +100,9 @@ export const RecordBoardColumnHeader = () => {

const boardColumnTotal = 0;

const {
newRecord,
handleNewButtonClick,
handleCreateSuccess,
handleEntitySelect,
} = useColumnNewCardActions(columnDefinition?.id ?? '');
const { handleNewButtonClick } = useColumnNewCardActions(
columnDefinition?.id ?? '',
);

const { isOpportunitiesCompanyFieldDisabled } =
useIsOpportunitiesCompanyFieldDisabled();
Expand Down Expand Up @@ -173,26 +168,6 @@ export const RecordBoardColumnHeader = () => {
stageId={columnDefinition.id}
/>
)}
{newRecord?.isCreating &&
newRecord.position === 'first' &&
(newRecord.isOpportunity ? (
<SingleEntitySelect
disableBackgroundBlur
onCancel={() => handleCreateSuccess('first', columnDefinition.id)}
onEntitySelected={(company) =>
company && handleEntitySelect('first', company)
}
relationObjectNameSingular={CoreObjectNameSingular.Company}
relationPickerScopeId="relation-picker"
selectedRelationRecordIds={[]}
/>
) : (
<RecordBoardCard
isCreating={true}
onCreateSuccess={() => handleCreateSuccess('first')}
position="first"
/>
))}
</StyledColumn>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import styled from '@emotion/styled';

import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
import { recordBoardNewRecordByColumnIdSelector } from '@/object-record/record-board/states/selectors/recordBoardNewRecordByColumnIdSelector';
import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
import { useRecoilValue } from 'recoil';

const StyledCompanyPickerContainer = styled.div`
align-items: center;
align-self: baseline;
background-color: ${({ theme }) => theme.background.primary};
border: none;
border-radius: ${({ theme }) => theme.border.radius.sm};
color: ${({ theme }) => theme.font.color.tertiary};
cursor: pointer;
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
`;

export const RecordBoardColumnNewOpportunity = ({
columnId,
position,
}: {
columnId: string;
position: 'last' | 'first';
}) => {
const newRecord = useRecoilValue(
recordBoardNewRecordByColumnIdSelector({
familyKey: columnId,
scopeId: columnId,
}),
);
const { handleCreateSuccess, handleEntitySelect } = useAddNewCard();

return (
<>
{newRecord.isCreating && newRecord.position === position && (
<StyledCompanyPickerContainer>
<SingleEntitySelect
disableBackgroundBlur
onCancel={() => handleCreateSuccess(position, columnId, false)}
onEntitySelected={(company) =>
company ? handleEntitySelect(position, company) : null
}
relationObjectNameSingular={CoreObjectNameSingular.Company}
relationPickerScopeId="relation-picker"
selectedRelationRecordIds={[]}
/>
</StyledCompanyPickerContainer>
)}
</>
);
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { RecordBoardCard } from '@/object-record/record-board/record-board-card/components/RecordBoardCard';
import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
import { recordBoardNewRecordByColumnIdSelector } from '@/object-record/record-board/states/selectors/recordBoardNewRecordByColumnIdSelector';
import { useRecoilValue } from 'recoil';

export const RecordBoardColumnNewRecord = ({
columnId,
position,
}: {
columnId: string;
position: 'first' | 'last';
}) => {
const newRecord = useRecoilValue(
recordBoardNewRecordByColumnIdSelector({
familyKey: columnId,
scopeId: columnId,
}),
);
const { handleCreateSuccess } = useAddNewCard();

return (
<>
{newRecord.isCreating && newRecord.position === position && (
<RecordBoardCard
isCreating={true}
onCreateSuccess={() => handleCreateSuccess(position)}
position={position}
/>
)}
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { RecordBoardCard } from '@/object-record/record-board/record-board-card/components/RecordBoardCard';
import { useColumnNewCardActions } from '@/object-record/record-board/record-board-column/hooks/useColumnNewCardActions';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
Expand All @@ -15,34 +14,20 @@ const StyledNewButton = styled.button`
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
padding: ${({ theme }) => theme.spacing(1)};
&:hover {
background-color: ${({ theme }) => theme.background.tertiary};
}
`;

export const RecordBoardColumnNewButton = ({
export const RecordBoardColumnNewRecordButton = ({
columnId,
}: {
columnId: string;
}) => {
const theme = useTheme();

const { newRecord, handleNewButtonClick, handleCreateSuccess } =
useColumnNewCardActions(columnId);

if (
newRecord.isCreating &&
newRecord.position === 'last' &&
!newRecord.isOpportunity
) {
return (
<RecordBoardCard
isCreating={true}
onCreateSuccess={() => handleCreateSuccess('last')}
position="last"
/>
);
}
const { handleNewButtonClick } = useColumnNewCardActions(columnId);

return (
<StyledNewButton onClick={() => handleNewButtonClick('last', false)}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
import { recordBoardNewRecordByColumnIdSelector } from '@/object-record/record-board/states/selectors/recordBoardNewRecordByColumnIdSelector';
import { useRecoilValue } from 'recoil';

export const useColumnNewCardActions = (columnId: string) => {
Expand All @@ -12,15 +11,7 @@ export const useColumnNewCardActions = (columnId: string) => {
(field) => field.isLabelIdentifier,
);

const { handleAddNewCardClick, handleCreateSuccess, handleEntitySelect } =
useAddNewCard();

const newRecord = useRecoilValue(
recordBoardNewRecordByColumnIdSelector({
familyKey: columnId,
scopeId: columnId,
}),
);
const { handleAddNewCardClick } = useAddNewCard();

const handleNewButtonClick = (
position: 'first' | 'last',
Expand All @@ -36,9 +27,6 @@ export const useColumnNewCardActions = (columnId: string) => {
};

return {
newRecord,
handleNewButtonClick,
handleCreateSuccess,
handleEntitySelect,
};
};

0 comments on commit 84b0b78

Please sign in to comment.