From bf6fb0ba7088c8233d434afb24c183b9e294db4f Mon Sep 17 00:00:00 2001 From: Sammy Teillet Date: Wed, 14 Jun 2023 10:37:44 +0200 Subject: [PATCH] 282 on opportunities page data pipeline + companies + people is fetched from be (#285) * feature: get pipelines columns from backend * feature: display item not found instead of crashing * feature: add BoardCard component * feature: display items from the backend * refactor: extract useBoard in a hook * refactor: export only loading and error from useBoard * refactor: create var pipelineStage * feature: implement support for Company boards --- front/src/generated/graphql.tsx | 49 ++++++++++++ .../opportunities/components/Board.tsx | 14 ++-- .../opportunities/components/BoardCard.tsx | 5 ++ .../modules/opportunities/hooks/useBoard.ts | 75 +++++++++++++++++++ .../modules/opportunities/queries/index.ts | 19 +++++ .../src/modules/ui/components/board/Board.tsx | 4 +- .../src/pages/opportunities/Opportunities.tsx | 11 ++- 7 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 front/src/modules/opportunities/components/BoardCard.tsx create mode 100644 front/src/modules/opportunities/hooks/useBoard.ts create mode 100644 front/src/modules/opportunities/queries/index.ts diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx index d0b299b25d..0ad4da3fef 100644 --- a/front/src/generated/graphql.tsx +++ b/front/src/generated/graphql.tsx @@ -1159,6 +1159,11 @@ export type DeleteCompaniesMutationVariables = Exact<{ export type DeleteCompaniesMutation = { __typename?: 'Mutation', deleteManyCompany: { __typename?: 'AffectedRows', count: number } }; +export type GetPipelinesQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetPipelinesQuery = { __typename?: 'Query', findManyPipeline: Array<{ __typename?: 'Pipeline', id: string, name: string, pipelineStages?: Array<{ __typename?: 'PipelineStage', name: string, color: string, pipelineProgresses?: Array<{ __typename?: 'PipelineProgress', id: string, associableType: PipelineProgressableType, associableId: string }> | null }> | null }> }; + export type GetPeopleQueryVariables = Exact<{ orderBy?: InputMaybe | PersonOrderByWithRelationInput>; where?: InputMaybe; @@ -1623,6 +1628,50 @@ export function useDeleteCompaniesMutation(baseOptions?: Apollo.MutationHookOpti export type DeleteCompaniesMutationHookResult = ReturnType; export type DeleteCompaniesMutationResult = Apollo.MutationResult; export type DeleteCompaniesMutationOptions = Apollo.BaseMutationOptions; +export const GetPipelinesDocument = gql` + query GetPipelines { + findManyPipeline(skip: 1) { + id + name + pipelineStages { + name + color + pipelineProgresses { + id + associableType + associableId + } + } + } +} + `; + +/** + * __useGetPipelinesQuery__ + * + * To run a query within a React component, call `useGetPipelinesQuery` and pass it any options that fit your needs. + * When your component renders, `useGetPipelinesQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetPipelinesQuery({ + * variables: { + * }, + * }); + */ +export function useGetPipelinesQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetPipelinesDocument, options); + } +export function useGetPipelinesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetPipelinesDocument, options); + } +export type GetPipelinesQueryHookResult = ReturnType; +export type GetPipelinesLazyQueryHookResult = ReturnType; +export type GetPipelinesQueryResult = Apollo.QueryResult; export const GetPeopleDocument = gql` query GetPeople($orderBy: [PersonOrderByWithRelationInput!], $where: PersonWhereInput, $limit: Int) { people: findManyPerson(orderBy: $orderBy, where: $where, take: $limit) { diff --git a/front/src/modules/opportunities/components/Board.tsx b/front/src/modules/opportunities/components/Board.tsx index aeab002504..2159a8cc5f 100644 --- a/front/src/modules/opportunities/components/Board.tsx +++ b/front/src/modules/opportunities/components/Board.tsx @@ -22,6 +22,8 @@ import { import { BoardItem } from '../../ui/components/board/BoardItem'; import { NewButton } from '../../ui/components/board/BoardNewButton'; +import { BoardCard } from './BoardCard'; + type BoardProps = { initialBoard: Column[]; items: Items; @@ -41,8 +43,8 @@ export const Board = ({ initialBoard, items }: BoardProps) => { ); return ( - - + + {board.map((column) => ( {(droppableProvided) => ( @@ -59,7 +61,9 @@ export const Board = ({ initialBoard, items }: BoardProps) => { > {(draggableProvided) => ( -

{items[itemKey].content}

+ + {items[itemKey]?.id || 'Item not found'} +
)} @@ -70,7 +74,7 @@ export const Board = ({ initialBoard, items }: BoardProps) => { )}
))} -
-
+ + ); }; diff --git a/front/src/modules/opportunities/components/BoardCard.tsx b/front/src/modules/opportunities/components/BoardCard.tsx new file mode 100644 index 0000000000..c7982172f5 --- /dev/null +++ b/front/src/modules/opportunities/components/BoardCard.tsx @@ -0,0 +1,5 @@ +import styled from '@emotion/styled'; + +export const BoardCard = styled.p` + color: ${(props) => props.theme.text80}; +`; diff --git a/front/src/modules/opportunities/hooks/useBoard.ts b/front/src/modules/opportunities/hooks/useBoard.ts new file mode 100644 index 0000000000..3832f83468 --- /dev/null +++ b/front/src/modules/opportunities/hooks/useBoard.ts @@ -0,0 +1,75 @@ +import { + GetCompaniesQuery, + GetPeopleQuery, + useGetCompaniesQuery, + useGetPeopleQuery, + useGetPipelinesQuery, +} from '../../../generated/graphql'; +import { BoardItemKey, Column, Items } from '../../ui/components/board/Board'; + +type Entities = GetCompaniesQuery | GetPeopleQuery; + +function isGetCompaniesQuery( + entities: Entities, +): entities is GetCompaniesQuery { + return (entities as GetCompaniesQuery).companies !== undefined; +} + +function isGetPeopleQuery(entities: Entities): entities is GetPeopleQuery { + return (entities as GetPeopleQuery).people !== undefined; +} + +export const useBoard = () => { + const pipelines = useGetPipelinesQuery(); + const pipelineStages = pipelines.data?.findManyPipeline[0].pipelineStages; + const initialBoard: Column[] = + pipelineStages?.map((pipelineStage) => ({ + id: pipelineStage.name, + title: pipelineStage.name, + colorCode: pipelineStage.color, + itemKeys: + pipelineStage.pipelineProgresses?.map( + (item) => `item-${item.associableId}` as BoardItemKey, + ) || [], + })) || []; + + const pipelineEntityIds = pipelineStages?.reduce( + (acc, pipelineStage) => [ + ...acc, + ...(pipelineStage.pipelineProgresses?.map((item) => item.associableId) || + []), + ], + [] as string[], + ); + + const pipelineEntityType: 'Person' | 'Company' | undefined = + pipelineStages?.[0].pipelineProgresses?.[0].associableType; + console.log(pipelineEntityType); + + const query = + pipelineEntityType === 'Person' ? useGetPeopleQuery : useGetCompaniesQuery; + + const entitiesQueryResult = query({ + variables: { where: { id: { in: pipelineEntityIds } } }, + }); + + const indexByIdReducer = (acc: Items, entity: { id: string }) => ({ + ...acc, + [`item-${entity.id}`]: entity, + }); + + const items: Items | undefined = entitiesQueryResult.data + ? isGetCompaniesQuery(entitiesQueryResult.data) + ? entitiesQueryResult.data.companies.reduce(indexByIdReducer, {} as Items) + : isGetPeopleQuery(entitiesQueryResult.data) + ? entitiesQueryResult.data.people.reduce(indexByIdReducer, {} as Items) + : undefined + : undefined; + + return { + initialBoard, + items, + loading: pipelines.loading || entitiesQueryResult.loading, + error: pipelines.error || entitiesQueryResult.error, + }; +}; diff --git a/front/src/modules/opportunities/queries/index.ts b/front/src/modules/opportunities/queries/index.ts new file mode 100644 index 0000000000..c5fe91469e --- /dev/null +++ b/front/src/modules/opportunities/queries/index.ts @@ -0,0 +1,19 @@ +import { gql } from '@apollo/client'; + +export const GET_PIPELINES = gql` + query GetPipelines { + findManyPipeline(skip: 1) { + id + name + pipelineStages { + name + color + pipelineProgresses { + id + associableType + associableId + } + } + } + } +`; diff --git a/front/src/modules/ui/components/board/Board.tsx b/front/src/modules/ui/components/board/Board.tsx index 3ae911eb73..d99e095e69 100644 --- a/front/src/modules/ui/components/board/Board.tsx +++ b/front/src/modules/ui/components/board/Board.tsx @@ -7,10 +7,10 @@ export const StyledBoard = styled.div` height: 100%; `; -export type BoardItemKey = `item-${number}`; +export type BoardItemKey = `item-${number | string}`; export interface Item { id: string; - content: string; + content?: string; } export interface Items { [key: string]: Item; diff --git a/front/src/pages/opportunities/Opportunities.tsx b/front/src/pages/opportunities/Opportunities.tsx index 45c238caca..8994508768 100644 --- a/front/src/pages/opportunities/Opportunities.tsx +++ b/front/src/pages/opportunities/Opportunities.tsx @@ -2,13 +2,16 @@ import { IconTarget } from '@/ui/icons/index'; import { WithTopBarContainer } from '@/ui/layout/containers/WithTopBarContainer'; import { AppPage } from '~/AppPage'; -import { - initialBoard, - items, -} from '../../modules/opportunities/components/__stories__/mock-data'; import { Board } from '../../modules/opportunities/components/Board'; +import { useBoard } from '../../modules/opportunities/hooks/useBoard'; export function Opportunities() { + const { initialBoard, items, loading, error } = useBoard(); + + if (loading) return
Loading...
; + if (error) return
Error...
; + if (!initialBoard || !items) + return
Initial board or items not found
; return ( }>