First round of refactor EntityBoards (#1067)
This commit is contained in:
@ -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';
|
||||
|
||||
@ -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,
|
||||
@ -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>
|
||||
),
|
||||
|
||||
@ -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';
|
||||
@ -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';
|
||||
@ -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';
|
||||
|
||||
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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';
|
||||
@ -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: {
|
||||
@ -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);
|
||||
},
|
||||
});
|
||||
|
||||
@ -89,6 +115,29 @@ 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,
|
||||
@ -96,18 +145,9 @@ export function HooksCompanyBoard({
|
||||
},
|
||||
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);
|
||||
},
|
||||
});
|
||||
|
||||
@ -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';
|
||||
@ -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,
|
||||
@ -41,34 +35,35 @@ export function NewCompanyProgressButton() {
|
||||
],
|
||||
});
|
||||
|
||||
const handleEntitySelect = useCallback(
|
||||
async (company: any) => {
|
||||
if (!company) return;
|
||||
const handleEntitySelect = useRecoilCallback(
|
||||
({ set }) =>
|
||||
async (company: any) => {
|
||||
if (!company) return;
|
||||
|
||||
setIsCreatingCard(false);
|
||||
goBackToPreviousHotkeyScope();
|
||||
if (!pipelineStageId) throw new Error('pipelineStageId is not defined');
|
||||
|
||||
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 || '',
|
||||
},
|
||||
});
|
||||
},
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user