From 86274a2d4ba9052c0ead3d291658d6a290e5bf73 Mon Sep 17 00:00:00 2001 From: Andrew Pazniak Date: Sat, 9 Apr 2022 10:11:29 +0200 Subject: [PATCH 1/3] Dashboard views have Aspects section --- .../DashboardSectionAspects.tsx | 34 ++++++++ .../common/cards/AspectCard/AspectCard.tsx | 6 +- .../composite/sections/ContextSection.tsx | 77 +++++++------------ .../composite/sections/ContextSectionIcon.tsx | 18 +++++ .../DashboardSection/DashboardColumn.tsx | 32 ++++++++ .../DashboardSection/DashboardSection.tsx | 34 ++++++++ .../ContributeTabContainerQueries.graphql | 8 +- .../challenge/ChallengePageContainer.tsx | 8 +- .../challenge/ChallengePageQueries.graphql | 3 + src/containers/hub/HubPage.graphql | 3 + src/containers/hub/HubPageContainer.tsx | 15 +++- src/hooks/generated/graphql.ts | 24 ++++-- src/models/graphql-schema.ts | 54 ++++++++++++- src/pages/Hub/HubDashboardPage.tsx | 1 + .../Challenge/ChallengeDashboardView.tsx | 23 +++--- src/views/Hub/HubDashboardView2.tsx | 31 ++++---- .../Opportunity/OpportunityDashboardView.tsx | 33 ++++---- 17 files changed, 292 insertions(+), 112 deletions(-) create mode 100644 src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx create mode 100644 src/components/composite/sections/ContextSectionIcon.tsx create mode 100644 src/components/composite/sections/DashboardSection/DashboardColumn.tsx create mode 100644 src/components/composite/sections/DashboardSection/DashboardSection.tsx diff --git a/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx b/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx new file mode 100644 index 0000000000..33118efb93 --- /dev/null +++ b/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx @@ -0,0 +1,34 @@ +import React, { FC } from 'react'; +import { useTranslation } from 'react-i18next'; +import DashboardSection from '../../sections/DashboardSection/DashboardSection'; +import AspectCard, { AspectCardAspect } from '../../common/cards/AspectCard/AspectCard'; +import { CardLayoutContainer, CardLayoutItem } from '../../../core/CardLayoutContainer/CardLayoutContainer'; + +interface DashboardSectionAspectsProps { + aspects: AspectCardAspect[]; + hubNameId?: string; + challengeNameId?: string; + opportunityNameId?: string; +} + +const DashboardSectionAspects: FC = ({ aspects, ...parentEntityIds }) => { + const { t } = useTranslation(); + + return ( + + + {aspects.slice(0, 2).map(aspect => ( + + + + ))} + + + ); +}; + +export default DashboardSectionAspects; diff --git a/src/components/composite/common/cards/AspectCard/AspectCard.tsx b/src/components/composite/common/cards/AspectCard/AspectCard.tsx index edcfbd082f..37d3ccf856 100644 --- a/src/components/composite/common/cards/AspectCard/AspectCard.tsx +++ b/src/components/composite/common/cards/AspectCard/AspectCard.tsx @@ -38,9 +38,9 @@ const Root = styled('div')(({ theme }) => ({ })); type NeededFields = 'id' | 'nameID' | 'displayName' | 'description' | 'type' | 'tagset'; -type AspectType = Pick & { bannerNarrow?: VisualUriFragment }; +export type AspectCardAspect = Pick & { bannerNarrow?: VisualUriFragment }; export interface AspectCardProps { - aspect?: AspectType; + aspect?: AspectCardAspect; hubNameId?: string; challengeNameId?: string; opportunityNameId?: string; @@ -56,7 +56,7 @@ const AspectCard: FC = ({ opportunityNameId, onDelete, }) => { - const { id, nameID = '', displayName = '', description = '', type = '', tagset } = (aspect || {}) as AspectType; + const { id, nameID = '', displayName = '', description = '', type = '', tagset } = (aspect || {}) as AspectCardAspect; const bannerNarrow = aspect?.bannerNarrow?.uri; return ( diff --git a/src/components/composite/sections/ContextSection.tsx b/src/components/composite/sections/ContextSection.tsx index 1606889609..65c8090cbb 100644 --- a/src/components/composite/sections/ContextSection.tsx +++ b/src/components/composite/sections/ContextSection.tsx @@ -2,16 +2,18 @@ import MenuBookIcon from '@mui/icons-material/MenuBook'; import PeopleAltIcon from '@mui/icons-material/PeopleAlt'; import PublicIcon from '@mui/icons-material/Public'; import SchoolIcon from '@mui/icons-material/School'; -import { Box, Grid, Typography } from '@mui/material'; +import { Grid, Typography } from '@mui/material'; import React, { FC, ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; import { Reference } from '../../../models/graphql-schema'; import Markdown from '../../core/Markdown'; import { SectionSpacer } from '../../core/Section/Section'; import SectionHeader from '../../core/Section/SectionHeader'; -import DashboardGenericSection from '../common/sections/DashboardGenericSection'; import TagsComponent from '../common/TagsComponent/TagsComponent'; import References from '../common/References/References'; +import DashboardSection from './DashboardSection/DashboardSection'; +import ContextSectionIcon from './ContextSectionIcon'; +import DashboardColumn from './DashboardSection/DashboardColumn'; export interface ContextSectionProps { contextId?: string; @@ -45,74 +47,51 @@ const ContextSection: FC = ({ return ( <> - - + } - headerSpacing={'none'} - options={{ collapsible: { maxHeight: 240 } }} + size="large" + collapsible > - - - + - - - } - options={{ collapsible: { maxHeight: 192 } }} + primaryAction={} + collapsible > - - - - + + + - - - } - options={{ collapsible: { maxHeight: 192 } }} + primaryAction={} + collapsible > - - - + - - - } - options={{ collapsible: { maxHeight: 192 } }} + primaryAction={} + collapsible > - - - + - - - } - options={{ collapsible: { maxHeight: 192 } }} + primaryAction={} + collapsible > - - + + ); diff --git a/src/components/composite/sections/ContextSectionIcon.tsx b/src/components/composite/sections/ContextSectionIcon.tsx new file mode 100644 index 0000000000..166863537e --- /dev/null +++ b/src/components/composite/sections/ContextSectionIcon.tsx @@ -0,0 +1,18 @@ +import React, { ComponentType, FC } from 'react'; +import { Box, SvgIconProps } from '@mui/material'; + +interface ComponentProps extends SvgIconProps {} + +interface ContextSectionIconProps { + component: ComponentType; +} + +const ContextSectionIcon: FC = ({ component: Component }) => { + return ( + + + + ); +}; + +export default ContextSectionIcon; diff --git a/src/components/composite/sections/DashboardSection/DashboardColumn.tsx b/src/components/composite/sections/DashboardSection/DashboardColumn.tsx new file mode 100644 index 0000000000..f513c03623 --- /dev/null +++ b/src/components/composite/sections/DashboardSection/DashboardColumn.tsx @@ -0,0 +1,32 @@ +import React, { cloneElement, FC, ReactElement } from 'react'; +import { SectionSpacer } from '../../../core/Section/Section'; +import { Grid, GridProps } from '@mui/material'; + +// TODO use ReactNode +type Child = ReactElement | false; +type ChildrenType = Child | Child[]; + +const insertSpacers = (children: ChildrenType) => { + const [firstChild, ...childrenTail] = React.Children.toArray(children) as ReactElement[]; + + return childrenTail.reduce( + (spacedChildren, child, i) => { + return [...spacedChildren, , cloneElement(child, { key: `item_${i + 1}` })]; + }, + [cloneElement(firstChild, { key: 'item_0' })] + ); +}; + +interface ContextSectionColumnProps extends Omit { + children: ChildrenType; +} + +const DashboardColumn: FC = ({ children }) => { + return ( + + {insertSpacers(children)} + + ); +}; + +export default DashboardColumn; diff --git a/src/components/composite/sections/DashboardSection/DashboardSection.tsx b/src/components/composite/sections/DashboardSection/DashboardSection.tsx new file mode 100644 index 0000000000..4ca97fa8f6 --- /dev/null +++ b/src/components/composite/sections/DashboardSection/DashboardSection.tsx @@ -0,0 +1,34 @@ +import React, { FC } from 'react'; +import DashboardGenericSection, { DashboardGenericSectionProps } from '../../common/sections/DashboardGenericSection'; + +type ContextSectionSectionSize = 'medium' | 'large'; + +interface ContextSectionSectionProps extends DashboardGenericSectionProps { + size?: ContextSectionSectionSize; + collapsible?: boolean; +} + +const maxHeightPerSize: Record = { + medium: 192, + large: 240, +}; + +const EMPTY = {}; + +const DashboardSection: FC = ({ + size = 'medium', + collapsible = false, + ...genericSectionProps +}) => { + const maxHeight = maxHeightPerSize[size]; + + return ( + + ); +}; + +export default DashboardSection; diff --git a/src/containers/ContributeTabContainer/ContributeTabContainerQueries.graphql b/src/containers/ContributeTabContainer/ContributeTabContainerQueries.graphql index 39b3836d42..3d10ee5edd 100644 --- a/src/containers/ContributeTabContainer/ContributeTabContainerQueries.graphql +++ b/src/containers/ContributeTabContainer/ContributeTabContainerQueries.graphql @@ -10,7 +10,7 @@ query HubAspects($hubNameId: UUID_NAMEID!) { hub(ID: $hubNameId) { id context { - ...ApsectsOnContext + ...AspectsOnContext } } } @@ -32,7 +32,7 @@ query ChallengeAspects($hubNameId: UUID_NAMEID!, $challengeNameId: UUID_NAMEID!) challenge(ID: $challengeNameId) { id context { - ...ApsectsOnContext + ...AspectsOnContext } } } @@ -55,13 +55,13 @@ query OpportunityAspects($hubNameId: UUID_NAMEID!, $opportunityNameId: UUID_NAME opportunity(ID: $opportunityNameId) { id context { - ...ApsectsOnContext + ...AspectsOnContext } } } } -fragment ApsectsOnContext on Context { +fragment AspectsOnContext on Context { id aspects { ...AspectCard diff --git a/src/containers/challenge/ChallengePageContainer.tsx b/src/containers/challenge/ChallengePageContainer.tsx index 9f2e218549..0bb62b8b22 100644 --- a/src/containers/challenge/ChallengePageContainer.tsx +++ b/src/containers/challenge/ChallengePageContainer.tsx @@ -7,7 +7,7 @@ import { useChallenge, useHub, useUserContext } from '../../hooks'; import { useChallengePageQuery } from '../../hooks/generated/graphql'; import { ContainerChildProps } from '../../models/container'; import { Discussion } from '../../models/discussion/discussion'; -import { AuthorizationPrivilege, ChallengeProfileFragment } from '../../models/graphql-schema'; +import { AspectCardFragment, AuthorizationPrivilege, ChallengeProfileFragment } from '../../models/graphql-schema'; import getActivityCount from '../../utils/get-activity-count'; import { ActivityType } from '../../models/constants'; @@ -17,6 +17,7 @@ export interface ChallengeContainerEntities { hubDisplayName: string; challenge?: ChallengeProfileFragment; activity: ActivityItem[]; + aspects: AspectCardFragment[]; permissions: { canEdit: boolean; communityReadAccess: boolean; @@ -33,6 +34,8 @@ export interface ChallengeContainerState { error?: ApolloError; } +const EMPTY = []; + export interface ChallengePageContainerProps extends ContainerChildProps {} @@ -81,6 +84,8 @@ export const ChallengePageContainer: FC = ({ childr ]; }, [_challenge]); + const aspects = _challenge?.hub.challenge.context?.aspects || EMPTY; + return ( <> {children( @@ -90,6 +95,7 @@ export const ChallengePageContainer: FC = ({ childr hubDisplayName: hub?.displayName || '', challenge: _challenge?.hub.challenge, activity, + aspects, permissions, isAuthenticated, isMember: user?.ofChallenge(challengeId) || false, diff --git a/src/containers/challenge/ChallengePageQueries.graphql b/src/containers/challenge/ChallengePageQueries.graphql index c20418065b..78a3659fb3 100644 --- a/src/containers/challenge/ChallengePageQueries.graphql +++ b/src/containers/challenge/ChallengePageQueries.graphql @@ -38,6 +38,9 @@ fragment ChallengeProfile on Challenge { visuals { ...VisualFull } + aspects { + ...AspectCard + } } community { id diff --git a/src/containers/hub/HubPage.graphql b/src/containers/hub/HubPage.graphql index a54bd6ccf1..8675f3a83f 100644 --- a/src/containers/hub/HubPage.graphql +++ b/src/containers/hub/HubPage.graphql @@ -35,6 +35,9 @@ fragment HubPage on Hub { anonymousReadAccess myPrivileges } + aspects { + ...AspectCard + } } community { id diff --git a/src/containers/hub/HubPageContainer.tsx b/src/containers/hub/HubPageContainer.tsx index 2bd669de4d..8dfe27683f 100644 --- a/src/containers/hub/HubPageContainer.tsx +++ b/src/containers/hub/HubPageContainer.tsx @@ -5,7 +5,12 @@ import { ActivityItem } from '../../components/composite/common/ActivityPanel/Ac import { useHub, useUserContext } from '../../hooks'; import { useHubPageQuery } from '../../hooks/generated/graphql'; import { ContainerChildProps } from '../../models/container'; -import { AuthorizationPrivilege, ChallengeCardFragment, HubPageFragment } from '../../models/graphql-schema'; +import { + AspectCardFragment, + AuthorizationPrivilege, + ChallengeCardFragment, + HubPageFragment, +} from '../../models/graphql-schema'; import getActivityCount from '../../utils/get-activity-count'; import { useDiscussionsContext } from '../../context/Discussions/DiscussionsProvider'; import { Discussion } from '../../models/discussion/discussion'; @@ -25,6 +30,7 @@ export interface HubContainerEntities { isGlobalAdmin: boolean; discussionList: Discussion[]; challenges: ChallengeCardFragment[]; + aspects: AspectCardFragment[]; } export interface HubContainerActions {} @@ -37,6 +43,8 @@ export interface HubContainerState { export interface HubPageContainerProps extends ContainerChildProps {} +const EMPTY = []; + export const HubPageContainer: FC = ({ children }) => { const { t } = useTranslation(); const { hubId, hubNameId, loading: loadingHub } = useHub(); @@ -85,7 +93,9 @@ export const HubPageContainer: FC = ({ children }) => { challengesReadAccess: isPrivate ? isMember || isGlobalAdmin : true, }; - const challenges = _hub?.hub?.challenges ?? []; + const challenges = _hub?.hub.challenges ?? EMPTY; + + const aspects = _hub?.hub.context?.aspects ?? EMPTY; return ( <> @@ -100,6 +110,7 @@ export const HubPageContainer: FC = ({ children }) => { isMember, isGlobalAdmin, challenges, + aspects, }, { loading: loadingHubQuery || loadingHub || loadingDiscussions, diff --git a/src/hooks/generated/graphql.ts b/src/hooks/generated/graphql.ts index 4a6a78033e..00b6c2bd79 100644 --- a/src/hooks/generated/graphql.ts +++ b/src/hooks/generated/graphql.ts @@ -795,8 +795,8 @@ export const AspectCardFragmentDoc = gql` } ${VisualUriFragmentDoc} `; -export const ApsectsOnContextFragmentDoc = gql` - fragment ApsectsOnContext on Context { +export const AspectsOnContextFragmentDoc = gql` + fragment AspectsOnContext on Context { id aspects { ...AspectCard @@ -1082,6 +1082,9 @@ export const ChallengeProfileFragmentDoc = gql` visuals { ...VisualFull } + aspects { + ...AspectCard + } } community { id @@ -1134,6 +1137,7 @@ export const ChallengeProfileFragmentDoc = gql` } ${OrganizationDetailsFragmentDoc} ${VisualFullFragmentDoc} + ${AspectCardFragmentDoc} ${ContextDetailsFragmentDoc} `; export const SimpleHubResultEntryFragmentDoc = gql` @@ -1263,6 +1267,9 @@ export const HubPageFragmentDoc = gql` anonymousReadAccess myPrivileges } + aspects { + ...AspectCard + } } community { id @@ -1284,6 +1291,7 @@ export const HubPageFragmentDoc = gql` } } ${VisualUriFragmentDoc} + ${AspectCardFragmentDoc} ${ChallengeCardFragmentDoc} `; export const OpportunityPageFragmentDoc = gql` @@ -9723,11 +9731,11 @@ export const HubAspectsDocument = gql` hub(ID: $hubNameId) { id context { - ...ApsectsOnContext + ...AspectsOnContext } } } - ${ApsectsOnContextFragmentDoc} + ${AspectsOnContextFragmentDoc} `; /** @@ -9849,12 +9857,12 @@ export const ChallengeAspectsDocument = gql` challenge(ID: $challengeNameId) { id context { - ...ApsectsOnContext + ...AspectsOnContext } } } } - ${ApsectsOnContextFragmentDoc} + ${AspectsOnContextFragmentDoc} `; /** @@ -9980,12 +9988,12 @@ export const OpportunityAspectsDocument = gql` opportunity(ID: $opportunityNameId) { id context { - ...ApsectsOnContext + ...AspectsOnContext } } } } - ${ApsectsOnContextFragmentDoc} + ${AspectsOnContextFragmentDoc} `; /** diff --git a/src/models/graphql-schema.ts b/src/models/graphql-schema.ts index 122c1b86c6..3875d7f29a 100644 --- a/src/models/graphql-schema.ts +++ b/src/models/graphql-schema.ts @@ -7450,7 +7450,7 @@ export type OpportunityAspectsQuery = { }; }; -export type ApsectsOnContextFragment = { +export type AspectsOnContextFragment = { __typename?: 'Context'; id: string; aspects?: @@ -8809,6 +8809,19 @@ export type ChallengePageQuery = { minWidth: number; }> | undefined; + aspects?: + | Array<{ + __typename?: 'Aspect'; + id: string; + nameID: string; + displayName: string; + type: string; + description: string; + banner?: { __typename?: 'Visual'; id: string; uri: string; name: string } | undefined; + bannerNarrow?: { __typename?: 'Visual'; id: string; uri: string; name: string } | undefined; + tagset?: { __typename?: 'Tagset'; id: string; name: string; tags: Array } | undefined; + }> + | undefined; } | undefined; community?: @@ -8940,6 +8953,19 @@ export type ChallengeProfileFragment = { minWidth: number; }> | undefined; + aspects?: + | Array<{ + __typename?: 'Aspect'; + id: string; + nameID: string; + displayName: string; + type: string; + description: string; + banner?: { __typename?: 'Visual'; id: string; uri: string; name: string } | undefined; + bannerNarrow?: { __typename?: 'Visual'; id: string; uri: string; name: string } | undefined; + tagset?: { __typename?: 'Tagset'; id: string; name: string; tags: Array } | undefined; + }> + | undefined; } | undefined; community?: @@ -9806,6 +9832,19 @@ export type HubPageQuery = { myPrivileges?: Array | undefined; } | undefined; + aspects?: + | Array<{ + __typename?: 'Aspect'; + id: string; + nameID: string; + displayName: string; + type: string; + description: string; + banner?: { __typename?: 'Visual'; id: string; uri: string; name: string } | undefined; + bannerNarrow?: { __typename?: 'Visual'; id: string; uri: string; name: string } | undefined; + tagset?: { __typename?: 'Tagset'; id: string; name: string; tags: Array } | undefined; + }> + | undefined; } | undefined; community?: @@ -9870,6 +9909,19 @@ export type HubPageFragment = { myPrivileges?: Array | undefined; } | undefined; + aspects?: + | Array<{ + __typename?: 'Aspect'; + id: string; + nameID: string; + displayName: string; + type: string; + description: string; + banner?: { __typename?: 'Visual'; id: string; uri: string; name: string } | undefined; + bannerNarrow?: { __typename?: 'Visual'; id: string; uri: string; name: string } | undefined; + tagset?: { __typename?: 'Tagset'; id: string; name: string; tags: Array } | undefined; + }> + | undefined; } | undefined; community?: diff --git a/src/pages/Hub/HubDashboardPage.tsx b/src/pages/Hub/HubDashboardPage.tsx index a77fb2725f..e36694d830 100644 --- a/src/pages/Hub/HubDashboardPage.tsx +++ b/src/pages/Hub/HubDashboardPage.tsx @@ -30,6 +30,7 @@ const HubDashboardPage: FC = ({ paths }) => { challenges={entities.challenges} discussions={entities.discussionList} members={entities?.hub?.community?.members as User[]} + aspects={entities.aspects} loading={state.loading} isMember={entities.isMember} communityReadAccess={entities.permissions.communityReadAccess} diff --git a/src/views/Challenge/ChallengeDashboardView.tsx b/src/views/Challenge/ChallengeDashboardView.tsx index 7fce4b4787..82cbac3b81 100644 --- a/src/views/Challenge/ChallengeDashboardView.tsx +++ b/src/views/Challenge/ChallengeDashboardView.tsx @@ -19,6 +19,8 @@ import OpportunityCard from '../../components/composite/common/cards/Opportunity import { CardLayoutContainer, CardLayoutItem } from '../../components/core/CardLayoutContainer/CardLayoutContainer'; import { getVisualBanner } from '../../utils/visuals.utils'; import { ActivityType, FEATURE_COMMUNICATIONS_DISCUSSIONS } from '../../models/constants'; +import DashboardColumn from '../../components/composite/sections/DashboardSection/DashboardColumn'; +import DashboardSectionAspects from '../../components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects'; const CHALLENGES_NUMBER_IN_SECTION = 2; const SPACING = 2; @@ -38,7 +40,7 @@ export const ChallengeDashboardView: FC = ({ entiti return entities.activity.find(({ type }) => type === ActivityType.Opportunity)?.count; }, [entities.activity]); - const { challenge, activity, isMember, discussions, permissions } = entities; + const { challenge, activity, isMember, discussions, permissions, aspects } = entities; const { loading } = state; @@ -59,7 +61,7 @@ export const ChallengeDashboardView: FC = ({ entiti return ( <> - + = ({ entiti - {communityReadAccess && ( <> - {isFeatureEnabled(FEATURE_COMMUNICATIONS_DISCUSSIONS) && ( @@ -88,13 +88,12 @@ export const ChallengeDashboardView: FC = ({ entiti )} )} - - + + - = ({ entiti ))} - {communityReadAccess && ( - <> - - - - )} - + + {communityReadAccess && } + ); diff --git a/src/views/Hub/HubDashboardView2.tsx b/src/views/Hub/HubDashboardView2.tsx index 68e6fd714e..8149ab835e 100644 --- a/src/views/Hub/HubDashboardView2.tsx +++ b/src/views/Hub/HubDashboardView2.tsx @@ -18,6 +18,9 @@ import ChallengeCard from '../../components/composite/common/cards/ChallengeCard import { CardLayoutContainer, CardLayoutItem } from '../../components/core/CardLayoutContainer/CardLayoutContainer'; import { ActivityType, FEATURE_COMMUNICATIONS_DISCUSSIONS } from '../../models/constants'; import { useConfig } from '../../hooks'; +import DashboardColumn from '../../components/composite/sections/DashboardSection/DashboardColumn'; +import DashboardSectionAspects from '../../components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects'; +import { AspectCardAspect } from '../../components/composite/common/cards/AspectCard/AspectCard'; export interface HubDashboardView2Props { title?: string; @@ -33,6 +36,7 @@ export interface HubDashboardView2Props { organization?: any; challenges: ChallengeCardFragment[]; members?: User[]; + aspects: AspectCardAspect[]; community?: any; loading: boolean; isMember?: boolean; @@ -54,6 +58,7 @@ const HubDashboardView2: FC = ({ organizationNameId, activity, discussions, + aspects, loading, isMember = false, communityReadAccess = false, @@ -71,7 +76,7 @@ const HubDashboardView2: FC = ({ return ( <> - + = ({ - {communityReadAccess && ( <> - {isFeatureEnabled(FEATURE_COMMUNICATIONS_DISCUSSIONS) && ( @@ -100,13 +103,12 @@ const HubDashboardView2: FC = ({ )} )} - - + + - {challengesReadAccess && ( = ({ navLink={'challenges'} > - {challenges.map((x, i) => ( - - + {challenges.map(challenge => ( + + ))} )} - {communityReadAccess && ( - <> - - - - )} - + + {communityReadAccess && } + ); }; + export default HubDashboardView2; diff --git a/src/views/Opportunity/OpportunityDashboardView.tsx b/src/views/Opportunity/OpportunityDashboardView.tsx index 7299d2eef3..5a42a4b56d 100644 --- a/src/views/Opportunity/OpportunityDashboardView.tsx +++ b/src/views/Opportunity/OpportunityDashboardView.tsx @@ -10,16 +10,19 @@ import DashboardOpportunityStatistics from '../../components/composite/common/se import DashboardUpdatesSection from '../../components/composite/common/sections/DashboardUpdatesSection'; import InterestModal from '../../components/composite/entities/Hub/InterestModal'; import Markdown from '../../components/core/Markdown'; -import { SectionSpacer } from '../../components/core/Section/Section'; -import { useOpportunity } from '../../hooks'; +import { useChallenge, useHub, useOpportunity } from '../../hooks'; import { Discussion } from '../../models/discussion/discussion'; import { OpportunityPageFragment, Reference, User } from '../../models/graphql-schema'; import { ViewProps } from '../../models/view'; import { getVisualBanner } from '../../utils/visuals.utils'; +import DashboardColumn from '../../components/composite/sections/DashboardSection/DashboardColumn'; +import DashboardSectionAspects from '../../components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects'; +import { AspectCardAspect } from '../../components/composite/common/cards/AspectCard/AspectCard'; const SPACING = 2; const PROJECTS_NUMBER_IN_SECTION = 2; +// TODO flat props export interface OpportunityDashboardViewEntities { opportunity: OpportunityPageFragment; activity: ActivityItem[]; @@ -33,6 +36,7 @@ export interface OpportunityDashboardViewEntities { incoming: OpportunityPageFragment['relations']; outgoing: OpportunityPageFragment['relations']; }; + aspects: AspectCardAspect[]; } export interface OpportunityDashboardViewActions { @@ -71,6 +75,8 @@ export interface OpportunityDashboardViewProps const OpportunityDashboardView: FC = ({ entities, state, options, actions }) => { const { t } = useTranslation(); + const { hubNameId } = useHub(); + const { challengeNameId } = useChallenge(); const { hubId } = useOpportunity(); const { opportunity } = entities; @@ -88,7 +94,7 @@ const OpportunityDashboardView: FC = ({ entities, return ( <> - + = ({ entities, - = ({ entities, /> {communityReadAccess && ( <> - {/* The discussions are not loaded, check OpportunityPageContainer if you try to enable them. */} {/* */} )} - - + + = ({ entities, })} - {communityReadAccess && ( - <> - - - - )} - + + {communityReadAccess && } + From b00385807148fa1612cee4d6b158443ba5902cc7 Mon Sep 17 00:00:00 2001 From: Andrew Pazniak Date: Wed, 13 Apr 2022 12:05:04 +0300 Subject: [PATCH 2/3] Getting subset of Aspects for Dashboard --- .../DashboardSectionAspects.tsx | 13 ++++++------- src/containers/challenge/ChallengePageContainer.tsx | 8 ++++++++ .../challenge/ChallengePageQueries.graphql | 2 +- src/containers/hub/HubPage.graphql | 2 +- src/containers/hub/HubPageContainer.tsx | 6 ++++++ src/containers/opportunity/OpportunityPage.graphql | 6 +++--- .../opportunity/OpportunityPageContainer.tsx | 8 ++++++++ src/hooks/generated/graphql.ts | 12 ++++++------ src/models/constants/common.constants.ts | 1 + src/models/graphql-schema.ts | 6 ++++-- src/pages/Hub/HubDashboardPage.tsx | 1 + src/views/Challenge/ChallengeDashboardView.tsx | 9 +++++++-- src/views/Hub/HubDashboardView2.tsx | 4 +++- src/views/Opportunity/OpportunityDashboardView.tsx | 2 ++ 14 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx b/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx index 33118efb93..7b898cc070 100644 --- a/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx +++ b/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx @@ -6,22 +6,21 @@ import { CardLayoutContainer, CardLayoutItem } from '../../../core/CardLayoutCon interface DashboardSectionAspectsProps { aspects: AspectCardAspect[]; + aspectsCount?: number; hubNameId?: string; challengeNameId?: string; opportunityNameId?: string; } -const DashboardSectionAspects: FC = ({ aspects, ...parentEntityIds }) => { +const DashboardSectionAspects: FC = ({ aspects, aspectsCount, ...parentEntityIds }) => { const { t } = useTranslation(); + const headerText = aspectsCount ? `${t('common.aspects')} (${aspectsCount})` : t('common.aspects'); + return ( - + - {aspects.slice(0, 2).map(aspect => ( + {aspects.map(aspect => ( diff --git a/src/containers/challenge/ChallengePageContainer.tsx b/src/containers/challenge/ChallengePageContainer.tsx index 0bb62b8b22..e7c357122a 100644 --- a/src/containers/challenge/ChallengePageContainer.tsx +++ b/src/containers/challenge/ChallengePageContainer.tsx @@ -18,6 +18,7 @@ export interface ChallengeContainerEntities { challenge?: ChallengeProfileFragment; activity: ActivityItem[]; aspects: AspectCardFragment[]; + aspectsCount: number | undefined; permissions: { canEdit: boolean; communityReadAccess: boolean; @@ -85,6 +86,12 @@ export const ChallengePageContainer: FC = ({ childr }, [_challenge]); const aspects = _challenge?.hub.challenge.context?.aspects || EMPTY; + const aspectsCount = useMemo(() => { + const stringValue = _challenge?.hub.challenge.activity?.find( + activity => activity.name === ActivityType.Aspect + )?.value; + return Number(stringValue); + }, [_challenge?.hub.challenge.activity]); return ( <> @@ -96,6 +103,7 @@ export const ChallengePageContainer: FC = ({ childr challenge: _challenge?.hub.challenge, activity, aspects, + aspectsCount, permissions, isAuthenticated, isMember: user?.ofChallenge(challengeId) || false, diff --git a/src/containers/challenge/ChallengePageQueries.graphql b/src/containers/challenge/ChallengePageQueries.graphql index 78a3659fb3..b53be917e2 100644 --- a/src/containers/challenge/ChallengePageQueries.graphql +++ b/src/containers/challenge/ChallengePageQueries.graphql @@ -38,7 +38,7 @@ fragment ChallengeProfile on Challenge { visuals { ...VisualFull } - aspects { + aspects(limit: 2, shuffle: true) { ...AspectCard } } diff --git a/src/containers/hub/HubPage.graphql b/src/containers/hub/HubPage.graphql index 8675f3a83f..3152b0a398 100644 --- a/src/containers/hub/HubPage.graphql +++ b/src/containers/hub/HubPage.graphql @@ -35,7 +35,7 @@ fragment HubPage on Hub { anonymousReadAccess myPrivileges } - aspects { + aspects(limit: 2, shuffle: true) { ...AspectCard } } diff --git a/src/containers/hub/HubPageContainer.tsx b/src/containers/hub/HubPageContainer.tsx index 8dfe27683f..755c3b6d01 100644 --- a/src/containers/hub/HubPageContainer.tsx +++ b/src/containers/hub/HubPageContainer.tsx @@ -31,6 +31,7 @@ export interface HubContainerEntities { discussionList: Discussion[]; challenges: ChallengeCardFragment[]; aspects: AspectCardFragment[]; + aspectsCount: number | undefined; } export interface HubContainerActions {} @@ -96,6 +97,10 @@ export const HubPageContainer: FC = ({ children }) => { const challenges = _hub?.hub.challenges ?? EMPTY; const aspects = _hub?.hub.context?.aspects ?? EMPTY; + const aspectsCount = useMemo(() => { + const stringValue = _hub?.hub.activity?.find(activity => activity.name === ActivityType.Aspect)?.value; + return Number(stringValue); + }, [_hub?.hub.activity]); return ( <> @@ -111,6 +116,7 @@ export const HubPageContainer: FC = ({ children }) => { isGlobalAdmin, challenges, aspects, + aspectsCount, }, { loading: loadingHubQuery || loadingHub || loadingDiscussions, diff --git a/src/containers/opportunity/OpportunityPage.graphql b/src/containers/opportunity/OpportunityPage.graphql index bce260a92c..a5751f9fef 100644 --- a/src/containers/opportunity/OpportunityPage.graphql +++ b/src/containers/opportunity/OpportunityPage.graphql @@ -50,12 +50,12 @@ fragment OpportunityPage on Opportunity { name uri } - aspects { - ...AspectCard - } visuals { ...VisualUri } + aspects(limit: 2, shuffle: true) { + ...AspectCard + } } # projects { diff --git a/src/containers/opportunity/OpportunityPageContainer.tsx b/src/containers/opportunity/OpportunityPageContainer.tsx index ec4ff12ed7..a6cadef741 100644 --- a/src/containers/opportunity/OpportunityPageContainer.tsx +++ b/src/containers/opportunity/OpportunityPageContainer.tsx @@ -18,6 +18,7 @@ import { import getActivityCount from '../../utils/get-activity-count'; import { replaceAll } from '../../utils/replaceAll'; import { buildAdminOpportunityUrl } from '../../utils/urlBuilders'; +import { ActivityType } from '../../models/constants'; export interface OpportunityContainerEntities { opportunity: OpportunityPageFragment; @@ -49,6 +50,7 @@ export interface OpportunityContainerEntities { }; discussions: Discussion[]; aspects: AspectCardFragment[]; + aspectsCount: number | undefined; } export interface OpportunityContainerActions { @@ -176,6 +178,11 @@ const OpportunityPageContainer: FC = ({ children return projectList; }, [projects, onProjectTransition, permissions.projectWrite, t]); + const aspectsCount = useMemo(() => { + const stringValue = _activity.find(activity => activity.name === ActivityType.Aspect)?.value; + return Number(stringValue); + }, [_activity]); + return ( <> {children( @@ -203,6 +210,7 @@ const OpportunityPageContainer: FC = ({ children }, discussions: [], //discussionList, aspects, + aspectsCount, }, { loading: loadingOpportunity, // || loadingDiscussions, diff --git a/src/hooks/generated/graphql.ts b/src/hooks/generated/graphql.ts index 00b6c2bd79..d5245164a8 100644 --- a/src/hooks/generated/graphql.ts +++ b/src/hooks/generated/graphql.ts @@ -1082,7 +1082,7 @@ export const ChallengeProfileFragmentDoc = gql` visuals { ...VisualFull } - aspects { + aspects(limit: 2, shuffle: true) { ...AspectCard } } @@ -1267,7 +1267,7 @@ export const HubPageFragmentDoc = gql` anonymousReadAccess myPrivileges } - aspects { + aspects(limit: 2, shuffle: true) { ...AspectCard } } @@ -1338,12 +1338,12 @@ export const OpportunityPageFragmentDoc = gql` name uri } - aspects { - ...AspectCard - } visuals { ...VisualUri } + aspects(limit: 2, shuffle: true) { + ...AspectCard + } } projects { id @@ -1363,8 +1363,8 @@ export const OpportunityPageFragmentDoc = gql` } } } - ${AspectCardFragmentDoc} ${VisualUriFragmentDoc} + ${AspectCardFragmentDoc} `; export const AssociatedOrganizationDetailsFragmentDoc = gql` fragment AssociatedOrganizationDetails on Organization { diff --git a/src/models/constants/common.constants.ts b/src/models/constants/common.constants.ts index 742665819c..124ec1a9fa 100644 --- a/src/models/constants/common.constants.ts +++ b/src/models/constants/common.constants.ts @@ -19,6 +19,7 @@ export enum ActivityType { Hub = 'hubs', Challenge = 'challenges', Relation = 'relations', + Aspect = 'aspects', } export const APPLICATION_STATE_NEW = 'new'; diff --git a/src/models/graphql-schema.ts b/src/models/graphql-schema.ts index 3875d7f29a..f645490efe 100644 --- a/src/models/graphql-schema.ts +++ b/src/models/graphql-schema.ts @@ -643,6 +643,8 @@ export type Context = { export type ContextAspectsArgs = { IDs?: InputMaybe>; + limit?: InputMaybe; + shuffle?: InputMaybe; }; export type ContextCanvasesArgs = { @@ -10026,6 +10028,7 @@ export type OpportunityPageQuery = { } | undefined; references?: Array<{ __typename?: 'Reference'; id: string; name: string; uri: string }> | undefined; + visuals?: Array<{ __typename?: 'Visual'; id: string; uri: string; name: string }> | undefined; aspects?: | Array<{ __typename?: 'Aspect'; @@ -10039,7 +10042,6 @@ export type OpportunityPageQuery = { tagset?: { __typename?: 'Tagset'; id: string; name: string; tags: Array } | undefined; }> | undefined; - visuals?: Array<{ __typename?: 'Visual'; id: string; uri: string; name: string }> | undefined; } | undefined; projects?: @@ -10108,6 +10110,7 @@ export type OpportunityPageFragment = { } | undefined; references?: Array<{ __typename?: 'Reference'; id: string; name: string; uri: string }> | undefined; + visuals?: Array<{ __typename?: 'Visual'; id: string; uri: string; name: string }> | undefined; aspects?: | Array<{ __typename?: 'Aspect'; @@ -10121,7 +10124,6 @@ export type OpportunityPageFragment = { tagset?: { __typename?: 'Tagset'; id: string; name: string; tags: Array } | undefined; }> | undefined; - visuals?: Array<{ __typename?: 'Visual'; id: string; uri: string; name: string }> | undefined; } | undefined; projects?: diff --git a/src/pages/Hub/HubDashboardPage.tsx b/src/pages/Hub/HubDashboardPage.tsx index e36694d830..e6a843128e 100644 --- a/src/pages/Hub/HubDashboardPage.tsx +++ b/src/pages/Hub/HubDashboardPage.tsx @@ -31,6 +31,7 @@ const HubDashboardPage: FC = ({ paths }) => { discussions={entities.discussionList} members={entities?.hub?.community?.members as User[]} aspects={entities.aspects} + aspectsCount={entities.aspectsCount} loading={state.loading} isMember={entities.isMember} communityReadAccess={entities.permissions.communityReadAccess} diff --git a/src/views/Challenge/ChallengeDashboardView.tsx b/src/views/Challenge/ChallengeDashboardView.tsx index 82cbac3b81..ce332663a5 100644 --- a/src/views/Challenge/ChallengeDashboardView.tsx +++ b/src/views/Challenge/ChallengeDashboardView.tsx @@ -40,7 +40,7 @@ export const ChallengeDashboardView: FC = ({ entiti return entities.activity.find(({ type }) => type === ActivityType.Opportunity)?.count; }, [entities.activity]); - const { challenge, activity, isMember, discussions, permissions, aspects } = entities; + const { challenge, activity, isMember, discussions, permissions, aspects, aspectsCount } = entities; const { loading } = state; @@ -108,7 +108,12 @@ export const ChallengeDashboardView: FC = ({ entiti ))} - + {communityReadAccess && } diff --git a/src/views/Hub/HubDashboardView2.tsx b/src/views/Hub/HubDashboardView2.tsx index 8149ab835e..f55b9f22b0 100644 --- a/src/views/Hub/HubDashboardView2.tsx +++ b/src/views/Hub/HubDashboardView2.tsx @@ -37,6 +37,7 @@ export interface HubDashboardView2Props { challenges: ChallengeCardFragment[]; members?: User[]; aspects: AspectCardAspect[]; + aspectsCount: number | undefined; community?: any; loading: boolean; isMember?: boolean; @@ -59,6 +60,7 @@ const HubDashboardView2: FC = ({ activity, discussions, aspects, + aspectsCount, loading, isMember = false, communityReadAccess = false, @@ -125,7 +127,7 @@ const HubDashboardView2: FC = ({ )} - + {communityReadAccess && } diff --git a/src/views/Opportunity/OpportunityDashboardView.tsx b/src/views/Opportunity/OpportunityDashboardView.tsx index 5a42a4b56d..288bedf557 100644 --- a/src/views/Opportunity/OpportunityDashboardView.tsx +++ b/src/views/Opportunity/OpportunityDashboardView.tsx @@ -37,6 +37,7 @@ export interface OpportunityDashboardViewEntities { outgoing: OpportunityPageFragment['relations']; }; aspects: AspectCardAspect[]; + aspectsCount: number | undefined; } export interface OpportunityDashboardViewActions { @@ -149,6 +150,7 @@ const OpportunityDashboardView: FC = ({ entities, Date: Wed, 13 Apr 2022 15:40:46 +0300 Subject: [PATCH 3/3] reviewers' comments addressed --- .../aspect/DashboardSectionAspects/DashboardSectionAspects.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx b/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx index 7b898cc070..c0623ec453 100644 --- a/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx +++ b/src/components/composite/aspect/DashboardSectionAspects/DashboardSectionAspects.tsx @@ -15,7 +15,8 @@ interface DashboardSectionAspectsProps { const DashboardSectionAspects: FC = ({ aspects, aspectsCount, ...parentEntityIds }) => { const { t } = useTranslation(); - const headerText = aspectsCount ? `${t('common.aspects')} (${aspectsCount})` : t('common.aspects'); + const headerText = + typeof aspectsCount === 'undefined' ? t('common.aspects') : `${t('common.aspects')} (${aspectsCount})`; return (