91c8068db1
* Enable column edition, and fix ordering * Move queries to services * Add total amounts for board columns * Refactor totals selector as a family * Fix 0-index issue * Lint * Rename selector * Remove useless header * Address PR comments * Optimistically update board column names
122 lines
3.7 KiB
TypeScript
122 lines
3.7 KiB
TypeScript
import { useEffect } from 'react';
|
|
import styled from '@emotion/styled';
|
|
import { Droppable, DroppableProvided } from '@hello-pangea/dnd';
|
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
|
|
|
import { BoardCardContext } from '@/pipeline-progress/states/BoardCardContext';
|
|
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
|
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
|
import { BoardPipelineStageColumn } from '@/ui/board/components/Board';
|
|
import { BoardColumn } from '@/ui/board/components/BoardColumn';
|
|
import { useUpdatePipelineStageMutation } from '~/generated/graphql';
|
|
|
|
import { BoardColumnContext } from '../states/BoardColumnContext';
|
|
import { boardColumnTotalsFamilySelector } from '../states/boardColumnTotalsFamilySelector';
|
|
import { boardState } from '../states/boardState';
|
|
import { pipelineStageIdScopedState } from '../states/pipelineStageIdScopedState';
|
|
import { BoardOptions } from '../types/BoardOptions';
|
|
|
|
import { EntityBoardCard } from './EntityBoardCard';
|
|
|
|
const StyledPlaceholder = styled.div`
|
|
min-height: 1px;
|
|
`;
|
|
|
|
const StyledNewCardButtonContainer = styled.div`
|
|
padding-bottom: ${({ theme }) => theme.spacing(40)};
|
|
`;
|
|
|
|
const BoardColumnCardsContainer = ({
|
|
children,
|
|
droppableProvided,
|
|
}: {
|
|
children: React.ReactNode;
|
|
droppableProvided: DroppableProvided;
|
|
}) => {
|
|
return (
|
|
<div
|
|
ref={droppableProvided?.innerRef}
|
|
{...droppableProvided?.droppableProps}
|
|
>
|
|
{children}
|
|
<StyledPlaceholder>{droppableProvided?.placeholder}</StyledPlaceholder>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export function EntityBoardColumn({
|
|
column,
|
|
boardOptions,
|
|
}: {
|
|
column: BoardPipelineStageColumn;
|
|
boardOptions: BoardOptions;
|
|
}) {
|
|
const [board, setBoard] = useRecoilState(boardState);
|
|
const [pipelineStageId, setPipelineStageId] = useRecoilScopedState(
|
|
pipelineStageIdScopedState,
|
|
BoardColumnContext,
|
|
);
|
|
const boardColumnTotal = useRecoilValue(
|
|
boardColumnTotalsFamilySelector(column.pipelineStageId),
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (pipelineStageId !== column.pipelineStageId) {
|
|
setPipelineStageId(column.pipelineStageId);
|
|
}
|
|
}, [column, setPipelineStageId, pipelineStageId]);
|
|
|
|
const [updatePipelineStage] = useUpdatePipelineStageMutation();
|
|
function handleEditColumnTitle(value: string) {
|
|
updatePipelineStage({
|
|
variables: {
|
|
id: pipelineStageId,
|
|
name: value,
|
|
},
|
|
});
|
|
setBoard([
|
|
...(board || []).map((pipelineStage) => {
|
|
if (pipelineStage.pipelineStageId === pipelineStageId) {
|
|
return {
|
|
...pipelineStage,
|
|
name: value,
|
|
};
|
|
}
|
|
return pipelineStage;
|
|
}),
|
|
]);
|
|
}
|
|
|
|
return (
|
|
<Droppable droppableId={column.pipelineStageId}>
|
|
{(droppableProvided) => (
|
|
<BoardColumn
|
|
onTitleEdit={handleEditColumnTitle}
|
|
title={column.title}
|
|
colorCode={column.colorCode}
|
|
pipelineStageId={column.pipelineStageId}
|
|
totalAmount={boardColumnTotal}
|
|
>
|
|
<BoardColumnCardsContainer droppableProvided={droppableProvided}>
|
|
{column.pipelineProgressIds.map((pipelineProgressId, index) => (
|
|
<RecoilScope
|
|
SpecificContext={BoardCardContext}
|
|
key={pipelineProgressId}
|
|
>
|
|
<EntityBoardCard
|
|
index={index}
|
|
pipelineProgressId={pipelineProgressId}
|
|
boardOptions={boardOptions}
|
|
/>
|
|
</RecoilScope>
|
|
))}
|
|
</BoardColumnCardsContainer>
|
|
<StyledNewCardButtonContainer>
|
|
<RecoilScope>{boardOptions.newCardComponent}</RecoilScope>
|
|
</StyledNewCardButtonContainer>
|
|
</BoardColumn>
|
|
)}
|
|
</Droppable>
|
|
);
|
|
}
|