Skip to content

Commit

Permalink
Add Callouts preview accordion on SubspacesList default subspace temp…
Browse files Browse the repository at this point in the history
…late selector (#7325)

* Add Callouts preview accordion on SubspacesList default subspace template selector

* usememo

* memoize the Description component

---------

Co-authored-by: Valentin Yanakiev <[email protected]>
  • Loading branch information
ccanos and valentinyanakiev committed Dec 13, 2024
1 parent e6bc6de commit 42b3f96
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 104 deletions.
17 changes: 17 additions & 0 deletions src/core/apollo/generated/apollo-hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17767,6 +17767,23 @@ export const AdminSpaceSubspacesPageDocument = gql`
}
collaboration {
id
callouts {
id
type
sortOrder
framing {
id
profile {
id
displayName
description
flowStateTagset: tagset(tagsetName: FLOW_STATE) {
id
tags
}
}
}
}
innovationFlow {
id
profile {
Expand Down
17 changes: 17 additions & 0 deletions src/core/apollo/generated/graphql-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23021,6 +23021,23 @@ export type AdminSpaceSubspacesPageQuery = {
| {
__typename?: 'Collaboration';
id: string;
callouts: Array<{
__typename?: 'Callout';
id: string;
type: CalloutType;
sortOrder: number;
framing: {
__typename?: 'CalloutFraming';
id: string;
profile: {
__typename?: 'Profile';
id: string;
displayName: string;
description: string;
flowStateTagset?: { __typename?: 'Tagset'; id: string; tags: Array<string> } | undefined;
};
};
}>;
innovationFlow: {
__typename?: 'InnovationFlow';
id: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { memo, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Accordion, AccordionDetails, AccordionSummary, Box, styled } from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import RoundedIcon from '@/core/ui/icon/RoundedIcon';
import { gutters } from '@/core/ui/grid/utils';
import { CalloutType } from '@/core/apollo/generated/graphql-schema';
import WrapperMarkdown from '@/core/ui/markdown/WrapperMarkdown';
import { Text, CaptionSmall } from '@/core/ui/typography';
import { getCalloutTypeIcon } from '@/domain/collaboration/callout/calloutCard/calloutIcons';
import WhiteboardPreview from '@/domain/collaboration/whiteboard/WhiteboardPreview/WhiteboardPreview';

type CalloutPreview = {
id: string;
type: CalloutType;
framing: {
profile: {
displayName: string;
description?: string;
flowStateTagset?: {
tags: string[];
};
};
whiteboard?: {
profile: {
preview?: {
uri: string;
};
};
};
};
sortOrder: number;
};

export interface InnovationFlowCalloutsPreviewProps {
selectedState: string | undefined;
callouts: CalloutPreview[] | undefined;
loading?: boolean;
}

const StyledAccordion = styled(Accordion)(({ theme }) => ({
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadius,
marginBottom: gutters(1)(theme),
boxShadow: 'none',
}));

const CalloutDescription = memo(({ callout }: { callout: CalloutPreview }) => {
const { t } = useTranslation();

switch (callout.type) {
case CalloutType.Whiteboard:
case CalloutType.WhiteboardCollection:
if (callout.framing.whiteboard?.profile.preview?.uri) {
return (
<WhiteboardPreview
whiteboard={callout.framing.whiteboard}
displayName={callout.framing.profile.displayName}
/>
);
}
return null;
default:
return callout.framing.profile.description?.trim() ? (
<WrapperMarkdown>{callout.framing.profile.description}</WrapperMarkdown>
) : (
<CaptionSmall>{t('common.noDescription')}</CaptionSmall>
);
}
});

const InnovationFlowCalloutsPreview = ({ callouts, selectedState, loading }: InnovationFlowCalloutsPreviewProps) => {
const [selectedCallout, setSelectedCallout] = useState<string | false>(false);
const handleSelectedCalloutChange = (calloutId: string) => (_event, isExpanded: boolean) =>
setSelectedCallout(isExpanded ? calloutId : false);

const visibleCallouts = useMemo(() => {
return callouts
?.filter(
callout =>
selectedState &&
callout.framing.profile.flowStateTagset?.tags &&
callout.framing.profile.flowStateTagset?.tags.includes(selectedState)
)
.sort((a, b) => a.sortOrder - b.sortOrder);
}, [callouts, selectedState]);

return (
<>
{!loading && visibleCallouts && (
<Box>
{visibleCallouts.map(callout => {
return (
<StyledAccordion
key={callout.id}
expanded={selectedCallout === callout.id}
onChange={handleSelectedCalloutChange(callout.id)}
>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<RoundedIcon
size="small"
component={getCalloutTypeIcon({ type: callout.type, contributionPolicy: undefined })}
/>
<Text marginLeft={gutters()}>{callout.framing.profile.displayName}</Text>
</AccordionSummary>
<AccordionDetails>
{selectedCallout === callout.id && <CalloutDescription callout={callout} />}
</AccordionDetails>
</StyledAccordion>
);
})}
</Box>
)}
</>
);
};

export default InnovationFlowCalloutsPreview;
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ query AdminSpaceSubspacesPage($spaceId: UUID_NAMEID!) {
}
collaboration {
id
callouts {
id
type
sortOrder
framing {
id
profile {
id
displayName
description
flowStateTagset: tagset(tagsetName: FLOW_STATE) {
id
tags
}
}
}
}
innovationFlow {
id
profile {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { AuthorizationPrivilege, TemplateDefaultType, TemplateType } from '@/cor
import { CollaborationTemplateFormSubmittedValues } from '@/domain/templates/components/Forms/CollaborationTemplateForm';
import { useCreateCollaborationTemplate } from '@/domain/templates/hooks/useCreateCollaborationTemplate';
import { useSubspaceCreation } from '@/domain/shared/utils/useSubspaceCreation/useSubspaceCreation';
import InnovationFlowCalloutsPreview from '@/domain/collaboration/callout/CalloutsPreview/InnovationFlowCalloutsPreview';

export const SubspaceListView = () => {
const { t } = useTranslation();
Expand Down Expand Up @@ -226,7 +227,14 @@ export const SubspaceListView = () => {
<InnovationFlowStates
states={defaultSubspaceTemplate.template.collaboration?.innovationFlow.states}
selectedState={selectedState}
onSelectState={state => setSelectedState(state.displayName)}
onSelectState={state =>
setSelectedState(currentState => (currentState === state.displayName ? undefined : state.displayName))
}
/>
<InnovationFlowCalloutsPreview
callouts={defaultSubspaceTemplate.template.collaboration?.callouts}
selectedState={selectedState}
loading={loading}
/>
</>
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,12 @@
import { Accordion, AccordionDetails, AccordionSummary, Box, styled } from '@mui/material';
import { FC, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { Box } from '@mui/material';
import PageContentBlock from '@/core/ui/content/PageContentBlock';
import Loading from '@/core/ui/loading/Loading';
import { InnovationFlowState } from '@/domain/collaboration/InnovationFlow/InnovationFlow';
import InnovationFlowChips from '@/domain/collaboration/InnovationFlow/InnovationFlowVisualizers/InnovationFlowChips';
import { CalloutType } from '@/core/apollo/generated/graphql-schema';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { Text, CaptionSmall } from '@/core/ui/typography';
import { useTranslation } from 'react-i18next';
import { getCalloutTypeIcon } from '@/domain/collaboration/callout/calloutCard/calloutIcons';
import WrapperMarkdown from '@/core/ui/markdown/WrapperMarkdown';
import RoundedIcon from '@/core/ui/icon/RoundedIcon';
import { gutters } from '@/core/ui/grid/utils';
import WhiteboardPreview from '@/domain/collaboration/whiteboard/WhiteboardPreview/WhiteboardPreview';

interface CalloutPreview {
id: string;
type: CalloutType;
framing: {
profile: {
displayName: string;
description?: string;
flowStateTagset?: {
tags: string[];
};
};
whiteboard?: {
profile: {
preview?: {
uri: string;
};
};
};
};
sortOrder: number;
}
import InnovationFlowCalloutsPreview, {
InnovationFlowCalloutsPreviewProps,
} from '../../../collaboration/callout/CalloutsPreview/InnovationFlowCalloutsPreview';

interface CollaborationTemplatePreviewProps {
loading?: boolean;
Expand All @@ -43,46 +15,13 @@ interface CollaborationTemplatePreviewProps {
innovationFlow?: {
states: InnovationFlowState[];
};
callouts?: CalloutPreview[];
callouts?: InnovationFlowCalloutsPreviewProps['callouts'];
};
};
}

const StyledAccordion = styled(Accordion)(({ theme }) => ({
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadius,
marginBottom: gutters(1)(theme),
boxShadow: 'none',
}));

const CalloutDescription = ({ callout }: { callout: CalloutPreview }) => {
const { t } = useTranslation();

switch (callout.type) {
case CalloutType.Whiteboard:
if (callout.framing.whiteboard?.profile.preview?.uri) {
return (
<Box display="flex" justifyContent="center">
<WhiteboardPreview
whiteboard={callout.framing.whiteboard}
displayName={callout.framing.profile.displayName}
/>
</Box>
);
}
return null;
default:
return callout.framing.profile.description?.trim() ? (
<WrapperMarkdown>{callout.framing.profile.description}</WrapperMarkdown>
) : (
<CaptionSmall>{t('common.noDescription')}</CaptionSmall>
);
}
};

const CollaborationTemplatePreview: FC<CollaborationTemplatePreviewProps> = ({ template, loading }) => {
const CollaborationTemplatePreview = ({ template, loading }: CollaborationTemplatePreviewProps) => {
const [selectedState, setSelectedState] = useState<string | undefined>(undefined);
const [selectedCallout, setSelectedCallout] = useState<string | false>(false);
const templateStates = template?.collaboration?.innovationFlow?.states ?? [];

useEffect(() => {
Expand All @@ -96,9 +35,6 @@ const CollaborationTemplatePreview: FC<CollaborationTemplatePreviewProps> = ({ t
}
}, [selectedState, templateStates]);

const handleSelectedCalloutChange = (calloutId: string) => (_event, isExpanded: boolean) =>
setSelectedCallout(isExpanded ? calloutId : false);

useEffect(() => {
if (!selectedState && templateStates.length > 0) {
setSelectedState(templateStates[0]?.displayName);
Expand All @@ -119,38 +55,11 @@ const CollaborationTemplatePreview: FC<CollaborationTemplatePreviewProps> = ({ t
onSelectState={state => setSelectedState(state.displayName)}
/>
)}
{!loading && template?.collaboration?.callouts && (
<Box>
{template?.collaboration?.callouts
.filter(
callout =>
selectedState &&
callout.framing.profile.flowStateTagset?.tags &&
callout.framing.profile.flowStateTagset?.tags.includes(selectedState)
)
.sort((a, b) => a.sortOrder - b.sortOrder)
.map(callout => {
return (
<StyledAccordion
key={callout.id}
expanded={selectedCallout === callout.id}
onChange={handleSelectedCalloutChange(callout.id)}
>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<RoundedIcon
size="small"
component={getCalloutTypeIcon({ type: callout.type, contributionPolicy: undefined })}
/>
<Text marginLeft={gutters()}>{callout.framing.profile.displayName}</Text>
</AccordionSummary>
<AccordionDetails>
<CalloutDescription callout={callout} />
</AccordionDetails>
</StyledAccordion>
);
})}
</Box>
)}
<InnovationFlowCalloutsPreview
callouts={template?.collaboration?.callouts}
selectedState={selectedState}
loading={loading}
/>
</PageContentBlock>
);
};
Expand Down

0 comments on commit 42b3f96

Please sign in to comment.