Skip to content

Commit

Permalink
First round of refactor EntityBoards (#1067)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasbordeau authored Aug 4, 2023
1 parent 11e7266 commit c790cc5
Show file tree
Hide file tree
Showing 35 changed files with 515 additions and 416 deletions.
2 changes: 1 addition & 1 deletion front/src/modules/companies/__stories__/Board.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { MemoryRouter } from 'react-router-dom';
import { Meta, StoryObj } from '@storybook/react';

import { EntityBoard } from '@/pipeline/components/EntityBoard';
import { EntityBoard } from '@/ui/board/components/EntityBoard';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBoardOptions';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,18 @@
import { useEffect } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Meta, StoryObj } from '@storybook/react';

import { CompanyBoardCard } from '@/companies/components/CompanyBoardCard';
import { BoardCardIdContext } from '@/ui/board/states/BoardCardIdContext';
import { BoardColumnContext } from '@/ui/board/states/BoardColumnContext';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedPipelineProgressData } from '~/testing/mock-data/pipeline-progress';

import { defaultPipelineProgressOrderBy } from '../../pipeline/queries';
import { BoardCardContext } from '../../pipeline/states/BoardCardContext';
import { BoardColumnContext } from '../../pipeline/states/BoardColumnContext';
import { pipelineProgressIdScopedState } from '../../pipeline/states/pipelineProgressIdScopedState';
import { HooksCompanyBoard } from '../components/HooksCompanyBoard';
import { CompanyBoardContext } from '../states/CompanyBoardContext';

function HookLoadFakeBoardContextState() {
const [, setPipelineProgressId] = useRecoilScopedState(
pipelineProgressIdScopedState,
BoardCardContext,
);
const pipelineProgress = mockedPipelineProgressData[1];
useEffect(() => {
setPipelineProgressId(pipelineProgress?.id || '');
}, [pipelineProgress?.id, setPipelineProgressId]);
return <></>;
}

const meta: Meta<typeof CompanyBoardCard> = {
title: 'Modules/Companies/CompanyBoardCard',
component: CompanyBoardCard,
Expand All @@ -39,12 +24,11 @@ const meta: Meta<typeof CompanyBoardCard> = {
orderBy={defaultPipelineProgressOrderBy}
/>
<RecoilScope SpecificContext={BoardColumnContext}>
<RecoilScope SpecificContext={BoardCardContext}>
<HookLoadFakeBoardContextState />
<BoardCardIdContext.Provider value={mockedPipelineProgressData[1].id}>
<MemoryRouter>
<Story />
</MemoryRouter>
</RecoilScope>
</BoardCardIdContext.Provider>
</RecoilScope>
</RecoilScope>
),
Expand Down
28 changes: 13 additions & 15 deletions front/src/modules/companies/components/CompanyBoardCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode, useCallback } from 'react';
import { ReactNode, useCallback, useContext } from 'react';
import { getOperationName } from '@apollo/client/utilities';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
Expand All @@ -7,9 +7,8 @@ import { companyProgressesFamilyState } from '@/companies/states/companyProgress
import { PipelineProgressPointOfContactEditableField } from '@/pipeline/editable-field/components/PipelineProgressPointOfContactEditableField';
import { ProbabilityEditableField } from '@/pipeline/editable-field/components/ProbabilityEditableField';
import { GET_PIPELINE_PROGRESS, GET_PIPELINES } from '@/pipeline/queries';
import { BoardCardContext } from '@/pipeline/states/BoardCardContext';
import { pipelineProgressIdScopedState } from '@/pipeline/states/pipelineProgressIdScopedState';
import { selectedBoardCardsState } from '@/pipeline/states/selectedBoardCardsState';
import { BoardCardIdContext } from '@/ui/board/states/BoardCardIdContext';
import { selectedBoardCardIdsState } from '@/ui/board/states/selectedBoardCardIdsState';
import { EntityChipVariant } from '@/ui/chip/components/EntityChip';
import { DateEditableField } from '@/ui/editable-field/variants/components/DateEditableField';
import { NumberEditableField } from '@/ui/editable-field/variants/components/NumberEditableField';
Expand All @@ -19,7 +18,6 @@ import {
Checkbox,
CheckboxVariant,
} from '@/ui/input/checkbox/components/Checkbox';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { useUpdateOnePipelineProgressMutation } from '~/generated/graphql';
import { getLogoUrlFromDomainName } from '~/utils';

Expand Down Expand Up @@ -110,25 +108,25 @@ const StyledFieldContainer = styled.div`
export function CompanyBoardCard() {
const [updatePipelineProgress] = useUpdateOnePipelineProgressMutation();

const [pipelineProgressId] = useRecoilScopedState(
pipelineProgressIdScopedState,
BoardCardContext,
);
const boardCardId = useContext(BoardCardIdContext);

const [companyProgress] = useRecoilState(
companyProgressesFamilyState(pipelineProgressId || ''),
companyProgressesFamilyState(boardCardId ?? ''),
);
const { pipelineProgress, company } = companyProgress || {};
const { pipelineProgress, company } = companyProgress ?? {};

const [selectedBoardCards, setSelectedBoardCards] = useRecoilState(
selectedBoardCardsState,
selectedBoardCardIdsState,
);

const selected = selectedBoardCards.includes(pipelineProgressId || '');
const selected = selectedBoardCards.includes(boardCardId ?? '');

function setSelected(isSelected: boolean) {
if (isSelected) {
setSelectedBoardCards([...selectedBoardCards, pipelineProgressId || '']);
setSelectedBoardCards([...selectedBoardCards, boardCardId ?? '']);
} else {
setSelectedBoardCards(
selectedBoardCards.filter((id) => id !== pipelineProgressId),
selectedBoardCards.filter((id) => id !== boardCardId),
);
}
}
Expand Down
110 changes: 75 additions & 35 deletions front/src/modules/companies/components/HooksCompanyBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import {
CompanyProgress,
PipelineProgressForBoard,
} from '@/companies/types/CompanyProgress';
import { boardState } from '@/pipeline/states/boardState';
import { currentPipelineState } from '@/pipeline/states/currentPipelineState';
import { isBoardLoadedState } from '@/pipeline/states/isBoardLoadedState';
import { BoardPipelineStageColumn } from '@/ui/board/components/Board';
import { boardCardIdsByColumnIdFamilyState } from '@/ui/board/states/boardCardIdsByColumnIdFamilyState';
import { boardColumnsState } from '@/ui/board/states/boardColumnsState';
import { isBoardLoadedState } from '@/ui/board/states/isBoardLoadedState';
import { BoardColumnDefinition } from '@/ui/board/types/BoardColumnDefinition';
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
import { FilterDefinition } from '@/ui/filter-n-sort/types/FilterDefinition';
import { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIntoWhereClause';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import {
GetPipelineProgressQuery,
PipelineProgressableType,
PipelineProgressOrderByWithRelationInput as PipelineProgresses_Order_By,
} from '~/generated/graphql';
Expand All @@ -39,13 +41,52 @@ export function HooksCompanyBoard({
useInitializeCompanyBoardFilters({
availableFilters,
});
const [currentPipeline, setCurrentPipeline] =
useRecoilState(currentPipelineState);

const [board, setBoard] = useRecoilState(boardState);
const [currentPipeline] = useRecoilState(currentPipelineState);
const [, setBoardColumns] = useRecoilState(boardColumnsState);

const [, setIsBoardLoaded] = useRecoilState(isBoardLoadedState);

const updateBoardColumns = useRecoilCallback(
({ set, snapshot }) =>
(pipeline: Pipeline) => {
const currentPipeline = snapshot
.getLoadable(currentPipelineState)
.valueOrThrow();

const currentBoardColumns = snapshot
.getLoadable(boardColumnsState)
.valueOrThrow();

if (JSON.stringify(pipeline) !== JSON.stringify(currentPipeline)) {
set(currentPipelineState, pipeline);
}

const pipelineStages = pipeline?.pipelineStages ?? [];

const orderedPipelineStages = [...pipelineStages].sort((a, b) => {
if (!a.index || !b.index) return 0;
return a.index - b.index;
});

const newBoardColumns: BoardColumnDefinition[] =
orderedPipelineStages?.map((pipelineStage) => ({
id: pipelineStage.id,
title: pipelineStage.name,
colorCode: pipelineStage.color,
index: pipelineStage.index ?? 0,
}));

if (
JSON.stringify(currentBoardColumns) !==
JSON.stringify(newBoardColumns)
) {
setBoardColumns(newBoardColumns);
}
},
[],
);

useGetPipelinesQuery({
variables: {
where: {
Expand All @@ -54,23 +95,8 @@ export function HooksCompanyBoard({
},
onCompleted: async (data) => {
const pipeline = data?.findManyPipeline[0] as Pipeline;
setCurrentPipeline(pipeline);
const pipelineStages = pipeline?.pipelineStages;
const orderedPipelineStages = pipelineStages
? [...pipelineStages].sort((a, b) => {
if (!a.index || !b.index) return 0;
return a.index - b.index;
})
: [];
const initialBoard: BoardPipelineStageColumn[] =
orderedPipelineStages?.map((pipelineStage, i) => ({
pipelineStageId: pipelineStage.id,
title: pipelineStage.name,
colorCode: pipelineStage.color,
index: pipelineStage.index || 0,
pipelineProgressIds: board?.[i].pipelineProgressIds || [],
})) || [];
setBoard(initialBoard);

updateBoardColumns(pipeline);
},
});

Expand All @@ -89,25 +115,39 @@ export function HooksCompanyBoard({
};
}, [filters, pipelineStageIds]) as any;

const updateBoardCardIds = useRecoilCallback(
({ snapshot, set }) =>
(
pipelineProgresses: GetPipelineProgressQuery['findManyPipelineProgress'],
) => {
const boardColumns = snapshot
.getLoadable(boardColumnsState)
.valueOrThrow();

for (const boardColumn of boardColumns) {
const boardCardIds = pipelineProgresses
.filter(
(pipelineProgressToFilter) =>
pipelineProgressToFilter.pipelineStageId === boardColumn.id,
)
.map((pipelineProgress) => pipelineProgress.id);

set(boardCardIdsByColumnIdFamilyState(boardColumn.id), boardCardIds);
}
},
[],
);

const pipelineProgressesQuery = useGetPipelineProgressQuery({
variables: {
where: whereFilters,
orderBy,
},
onCompleted: (data) => {
const pipelineProgresses = data?.findManyPipelineProgress || [];
setBoard((board) =>
board?.map((boardPipelineStage) => ({
...boardPipelineStage,
pipelineProgressIds: pipelineProgresses
.filter(
(pipelineProgress) =>
pipelineProgress.pipelineStageId ===
boardPipelineStage.pipelineStageId,
)
.map((pipelineProgress) => pipelineProgress.id),
})),
);

updateBoardCardIds(pipelineProgresses);

setIsBoardLoaded(true);
},
});
Expand Down
69 changes: 32 additions & 37 deletions front/src/modules/companies/components/NewCompanyProgressButton.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { useCallback, useState } from 'react';
import { useCallback, useContext, useState } from 'react';
import { getOperationName } from '@apollo/client/utilities';
import { useRecoilState } from 'recoil';
import { useRecoilCallback, useRecoilState } from 'recoil';
import { v4 as uuidv4 } from 'uuid';

import { GET_PIPELINE_PROGRESS, GET_PIPELINES } from '@/pipeline/queries';
import { BoardColumnContext } from '@/pipeline/states/BoardColumnContext';
import { boardState } from '@/pipeline/states/boardState';
import { currentPipelineState } from '@/pipeline/states/currentPipelineState';
import { pipelineStageIdScopedState } from '@/pipeline/states/pipelineStageIdScopedState';
import { BoardPipelineStageColumn } from '@/ui/board/components/Board';
import { NewButton } from '@/ui/board/components/NewButton';
import { boardCardIdsByColumnIdFamilyState } from '@/ui/board/states/boardCardIdsByColumnIdFamilyState';
import { BoardColumnIdContext } from '@/ui/board/states/BoardColumnIdContext';
import { SingleEntitySelect } from '@/ui/input/relation-picker/components/SingleEntitySelect';
import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState';
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
Expand All @@ -21,12 +19,8 @@ import { useFilteredSearchCompanyQuery } from '../queries';

export function NewCompanyProgressButton() {
const [isCreatingCard, setIsCreatingCard] = useState(false);
const [board, setBoard] = useRecoilState(boardState);
const [pipeline] = useRecoilState(currentPipelineState);
const [pipelineStageId] = useRecoilScopedState(
pipelineStageIdScopedState,
BoardColumnContext,
);
const pipelineStageId = useContext(BoardColumnIdContext);

const {
goBackToPreviousHotkeyScope,
Expand All @@ -41,34 +35,35 @@ export function NewCompanyProgressButton() {
],
});

const handleEntitySelect = useCallback(
async (company: any) => {
if (!company) return;

setIsCreatingCard(false);
goBackToPreviousHotkeyScope();

const newUuid = uuidv4();
const newBoard = JSON.parse(JSON.stringify(board));
const destinationColumnIndex = newBoard.findIndex(
(column: BoardPipelineStageColumn) =>
column.pipelineStageId === pipelineStageId,
);
newBoard[destinationColumnIndex].pipelineProgressIds.push(newUuid);
setBoard(newBoard);
await createOneCompanyPipelineProgress({
variables: {
uuid: newUuid,
pipelineStageId: pipelineStageId || '',
pipelineId: pipeline?.id || '',
companyId: company.id || '',
},
});
},
const handleEntitySelect = useRecoilCallback(
({ set }) =>
async (company: any) => {
if (!company) return;

if (!pipelineStageId) throw new Error('pipelineStageId is not defined');

setIsCreatingCard(false);

goBackToPreviousHotkeyScope();

const newUuid = uuidv4();

set(boardCardIdsByColumnIdFamilyState(pipelineStageId), (oldValue) => [
...oldValue,
newUuid,
]);

await createOneCompanyPipelineProgress({
variables: {
uuid: newUuid,
pipelineStageId: pipelineStageId,
pipelineId: pipeline?.id ?? '',
companyId: company.id ?? '',
},
});
},
[
goBackToPreviousHotkeyScope,
board,
setBoard,
createOneCompanyPipelineProgress,
pipelineStageId,
pipeline?.id,
Expand Down
Loading

0 comments on commit c790cc5

Please sign in to comment.