Persist update on board drag and drop (#328)
* chore: move dnd lib comment aligned with import * feature: add onUpdate on board * chore: remove multi entity pipelines * feature: add pipelineProgressableType field * feature: fetch progressableType in board * feature: implement on update to persist progress change
This commit is contained in:
@ -4,9 +4,10 @@ import {
|
||||
Draggable,
|
||||
Droppable,
|
||||
OnDragEndResponder,
|
||||
} from '@hello-pangea/dnd';
|
||||
} 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 {
|
||||
BoardItemKey,
|
||||
Column,
|
||||
getOptimisticlyUpdatedBoard,
|
||||
Items,
|
||||
@ -17,8 +18,6 @@ import {
|
||||
StyledColumn,
|
||||
StyledColumnTitle,
|
||||
} from '../../ui/components/board/BoardColumn';
|
||||
// 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 { BoardItem } from '../../ui/components/board/BoardItem';
|
||||
import { NewButton } from '../../ui/components/board/BoardNewButton';
|
||||
|
||||
@ -27,19 +26,29 @@ import { BoardCard } from './BoardCard';
|
||||
type BoardProps = {
|
||||
initialBoard: Column[];
|
||||
items: Items;
|
||||
onUpdate?: (itemKey: BoardItemKey, columnId: Column['id']) => Promise<void>;
|
||||
};
|
||||
|
||||
export const Board = ({ initialBoard, items }: BoardProps) => {
|
||||
export const Board = ({ initialBoard, items, onUpdate }: BoardProps) => {
|
||||
const [board, setBoard] = useState<Column[]>(initialBoard);
|
||||
|
||||
const onDragEnd: OnDragEndResponder = useCallback(
|
||||
(result) => {
|
||||
async (result) => {
|
||||
const newBoard = getOptimisticlyUpdatedBoard(board, result);
|
||||
if (!newBoard) return;
|
||||
setBoard(newBoard);
|
||||
// TODO implement update board mutation
|
||||
try {
|
||||
const draggedEntityId = items[result.draggableId]?.id;
|
||||
const destinationColumnId = result.destination?.droppableId;
|
||||
draggedEntityId &&
|
||||
destinationColumnId &&
|
||||
onUpdate &&
|
||||
(await onUpdate(draggedEntityId, destinationColumnId));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
[board],
|
||||
[board, onUpdate, items],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@ -50,8 +50,9 @@ const StyledBoardCardBody = styled.div`
|
||||
`;
|
||||
|
||||
export const BoardCard = ({ item }: { item: Person | Company }) => {
|
||||
if (item.__typename === 'Person') return <PersonBoardCard person={item} />;
|
||||
if (item.__typename === 'Company') return <CompanyBoardCard company={item} />;
|
||||
if (item?.__typename === 'Person') return <PersonBoardCard person={item} />;
|
||||
if (item?.__typename === 'Company')
|
||||
return <CompanyBoardCard company={item} />;
|
||||
// @todo return card skeleton
|
||||
return null;
|
||||
};
|
||||
|
||||
@ -24,38 +24,49 @@ export const useBoard = () => {
|
||||
const pipelineStages = pipelines.data?.findManyPipeline[0].pipelineStages;
|
||||
const initialBoard: Column[] =
|
||||
pipelineStages?.map((pipelineStage) => ({
|
||||
id: pipelineStage.name,
|
||||
id: pipelineStage.id,
|
||||
title: pipelineStage.name,
|
||||
colorCode: pipelineStage.color,
|
||||
itemKeys:
|
||||
pipelineStage.pipelineProgresses?.map(
|
||||
(item) => `item-${item.progressableId}` as BoardItemKey,
|
||||
(item) => item.progressableId as BoardItemKey,
|
||||
) || [],
|
||||
})) || [];
|
||||
|
||||
const pipelineEntityIds = pipelineStages?.reduce(
|
||||
(acc, pipelineStage) => [
|
||||
...acc,
|
||||
...(pipelineStage.pipelineProgresses?.map(
|
||||
(item) => item.progressableId,
|
||||
) || []),
|
||||
...(pipelineStage.pipelineProgresses?.map((item) => ({
|
||||
entityId: item?.progressableId,
|
||||
pipelineProgressId: item?.id,
|
||||
})) || []),
|
||||
],
|
||||
[] as string[],
|
||||
[] as { entityId: string; pipelineProgressId: string }[],
|
||||
);
|
||||
|
||||
const pipelineEntityIdsMapper = (entityId: string) => {
|
||||
const pipelineProgressId = pipelineEntityIds?.find(
|
||||
(item) => item.entityId === entityId,
|
||||
)?.pipelineProgressId;
|
||||
|
||||
return pipelineProgressId;
|
||||
};
|
||||
|
||||
const pipelineEntityType: 'Person' | 'Company' | undefined =
|
||||
pipelineStages?.[0].pipelineProgresses?.[0].progressableType;
|
||||
pipelines.data?.findManyPipeline[0].pipelineProgressableType;
|
||||
|
||||
const query =
|
||||
pipelineEntityType === 'Person' ? useGetPeopleQuery : useGetCompaniesQuery;
|
||||
|
||||
const entitiesQueryResult = query({
|
||||
variables: { where: { id: { in: pipelineEntityIds } } },
|
||||
variables: {
|
||||
where: { id: { in: pipelineEntityIds?.map((item) => item.entityId) } },
|
||||
},
|
||||
});
|
||||
|
||||
const indexByIdReducer = (acc: Items, entity: { id: string }) => ({
|
||||
...acc,
|
||||
[`item-${entity.id}`]: entity,
|
||||
[entity.id]: entity,
|
||||
});
|
||||
|
||||
const items: Items | undefined = entitiesQueryResult.data
|
||||
@ -71,5 +82,6 @@ export const useBoard = () => {
|
||||
items,
|
||||
loading: pipelines.loading || entitiesQueryResult.loading,
|
||||
error: pipelines.error || entitiesQueryResult.error,
|
||||
pipelineEntityIdsMapper,
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,10 +2,12 @@ import { gql } from '@apollo/client';
|
||||
|
||||
export const GET_PIPELINES = gql`
|
||||
query GetPipelines {
|
||||
findManyPipeline(skip: 1) {
|
||||
findManyPipeline {
|
||||
id
|
||||
name
|
||||
pipelineProgressableType
|
||||
pipelineStages {
|
||||
id
|
||||
name
|
||||
color
|
||||
pipelineProgresses {
|
||||
@ -17,3 +19,14 @@ export const GET_PIPELINES = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const UPDATE_PIPELINE_STAGE = gql`
|
||||
mutation UpdateOnePipelineProgress($id: String, $pipelineStageId: String) {
|
||||
updateOnePipelineProgress(
|
||||
where: { id: $id }
|
||||
data: { pipelineStage: { connect: { id: $pipelineStageId } } }
|
||||
) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { DropResult } from '@hello-pangea/dnd';
|
||||
import { DropResult } 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
|
||||
|
||||
export const StyledBoard = styled.div`
|
||||
display: flex;
|
||||
@ -7,7 +7,7 @@ export const StyledBoard = styled.div`
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export type BoardItemKey = `item-${number | string}`;
|
||||
export type BoardItemKey = string;
|
||||
export type Item = any & { id: string };
|
||||
export interface Items {
|
||||
[key: string]: Item;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { DroppableProvided } from '@hello-pangea/dnd';
|
||||
import { DroppableProvided } 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
|
||||
|
||||
export const StyledColumn = styled.div`
|
||||
background-color: ${({ theme }) => theme.primaryBackground};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { DraggableProvided } from '@hello-pangea/dnd';
|
||||
import { DraggableProvided } 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
|
||||
|
||||
const StyledCard = styled.div`
|
||||
background-color: ${({ theme }) => theme.secondaryBackground};
|
||||
|
||||
Reference in New Issue
Block a user