From b98dd4d76ca8d4c884ed8e9b077989c8ed1282d7 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Fri, 3 Feb 2023 12:58:21 +0100 Subject: [PATCH] Project overview UI (#3034) --- .../src/component/project/Project/Project.tsx | 12 +- .../ProjectInfo/ChangeRequestsWidget.tsx | 75 +++++---- .../Project/ProjectInfo/HealthWidget.tsx | 106 +++++-------- .../ProjectInfo/LegacyHealthWidget.tsx | 75 +++++++++ .../LegacyProjectMembersWidget.tsx | 93 +++++++++++ .../Project/ProjectInfo/MetaWidget.tsx | 56 +++---- .../Project/ProjectInfo/ProjectInfo.styles.ts | 81 +--------- .../Project/ProjectInfo/ProjectInfo.tsx | 106 ++++++++++--- .../ProjectInfo/ProjectMembersWidget.tsx | 30 ++-- .../Project/ProjectInfo/ToggleTypesWidget.tsx | 21 ++- .../Project/ProjectInfo/WidgetFooterLink.tsx | 28 ++++ .../Project/ProjectStats/ProjectStats.tsx | 99 ++++++++---- .../Project/ProjectStats/StatusBox.tsx | 145 ++++++++---------- 13 files changed, 560 insertions(+), 367 deletions(-) create mode 100644 frontend/src/component/project/Project/ProjectInfo/LegacyHealthWidget.tsx create mode 100644 frontend/src/component/project/Project/ProjectInfo/LegacyProjectMembersWidget.tsx create mode 100644 frontend/src/component/project/Project/ProjectInfo/WidgetFooterLink.tsx diff --git a/frontend/src/component/project/Project/Project.tsx b/frontend/src/component/project/Project/Project.tsx index 7382d97e9b..027a449ec5 100644 --- a/frontend/src/component/project/Project/Project.tsx +++ b/frontend/src/component/project/Project/Project.tsx @@ -187,9 +187,11 @@ export const Project = () => { (
@@ -200,7 +202,7 @@ export const Project = () => { show={ - Description:{' '} + Description:  {project.description} @@ -210,7 +212,7 @@ export const Project = () => { /> - projectId:{' '} + projectId:  {projectId} @@ -219,7 +221,7 @@ export const Project = () => {
- } + )} /> diff --git a/frontend/src/component/project/Project/ProjectInfo/ChangeRequestsWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/ChangeRequestsWidget.tsx index 1f46be6b56..e86ddf3b79 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ChangeRequestsWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/ChangeRequestsWidget.tsx @@ -1,7 +1,6 @@ import { FC } from 'react'; import useLoading from 'hooks/useLoading'; -import { Link as RouterLink } from 'react-router-dom'; -import { Box, styled, Typography, Link } from '@mui/material'; +import { Box, styled, Typography } from '@mui/material'; import { IChangeRequest } from 'component/changeRequest/changeRequest.types'; import { @@ -10,17 +9,25 @@ import { StyledWidgetTitle, } from './ProjectInfo.styles'; import { useProjectChangeRequests } from 'hooks/api/getters/useProjectChangeRequests/useProjectChangeRequests'; +import { WidgetFooterLink } from './WidgetFooterLink'; interface IChangeRequestsWidgetProps { projectId: string; } +const StyledContentBox = styled(Box)(({ theme }) => ({ + display: 'flex', + flexWrap: 'wrap', + gap: theme.spacing(1.5), +})); + const StyledChangeBox = styled(Box)(({ theme }) => ({ + flex: 1, textAlign: 'left', padding: theme.spacing(1.5), - marginBottom: theme.spacing(1.5), borderRadius: theme.shape.borderRadiusMedium, alignItems: 'center', + minWidth: 175, })); const StyledChangeRequestStatusInfo = styled(Box)(({ theme }) => ({ @@ -42,8 +49,18 @@ const StyledInReviewCount = styled(StyledCount)(({ theme }) => ({ borderRadius: theme.shape.borderRadius, })); +const StyledSubtitle = styled(Typography)(({ theme }) => ({ + fontSize: theme.typography.body2.fontSize, + marginBottom: theme.spacing(0.5), +})); + const ChangeRequestsLabel = () => ( - + change requests ); @@ -63,33 +80,31 @@ export const ChangeRequestsWidget: FC = ({ return ( Open change requests - - theme.palette.success.light }} - > - To be applied - - {toBeApplied}{' '} - - - - theme.palette.secondary.light }} - > - To be reviewed - - {toBeReviewed}{' '} - - - - - + theme.palette.success.light }} > - View change requests - - + To be applied + + {toBeApplied}{' '} + + + + theme.palette.secondary.light }} + > + To be reviewed + + + {toBeReviewed} + {' '} + + + + + + View change requests + ); }; diff --git a/frontend/src/component/project/Project/ProjectInfo/HealthWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/HealthWidget.tsx index d31547b794..73e877ead9 100644 --- a/frontend/src/component/project/Project/ProjectInfo/HealthWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/HealthWidget.tsx @@ -1,16 +1,10 @@ -import { - StyledArrowIcon, - StyledCount, - StyledProjectInfoWidgetContainer, - StyledDivPercentageContainer, - StyledLink, - StyledParagraphEmphasizedText, - StyledWidgetTitle, - StyledSpanLinkText, -} from './ProjectInfo.styles'; +import { Box, styled } from '@mui/material'; import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle'; -import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; -import { Box, styled, Typography } from '@mui/material'; +import { + StyledProjectInfoWidgetContainer, + StyledWidgetTitle, +} from './ProjectInfo.styles'; +import { WidgetFooterLink } from './WidgetFooterLink'; interface IHealthWidgetProps { projectId: string; @@ -19,69 +13,43 @@ interface IHealthWidgetProps { stale?: number; } -const StyledWarning = styled('span')<{ active?: boolean }>( - ({ theme, active }) => ({ - color: active ? theme.palette.warning.dark : 'inherit', - }) -); +const StyledParagraphEmphasizedText = styled('p')(({ theme }) => ({ + fontSize: '1.5rem', + [theme.breakpoints.down('md')]: { + fontSize: theme.fontSizes.bodySize, + marginBottom: theme.spacing(4), + }, +})); -export const HealthWidget = ({ - projectId, - health, - total, - stale, -}: IHealthWidgetProps) => { - const { uiConfig } = useUiConfig(); +const StyledPercentageText = styled('p')(({ theme }) => ({ + fontSize: '1.5rem', + [theme.breakpoints.down('md')]: { + fontSize: theme.fontSizes.bodySize, + }, +})); - if (uiConfig?.flags?.newProjectOverview) { - return ( - - - Project health - - +export const HealthWidget = ({ projectId, health }: IHealthWidgetProps) => { + return ( + + Project health + theme.spacing(2), + }} + > + - + {health}% - - {total} toggles in total - - - - - {stale} - - {' '} - - potentially stale - - - - - View project health - - - - ); - } - - return ( - - - - - - Overall health rating - - - {health}% - - - view more - - + + + View project health + ); }; diff --git a/frontend/src/component/project/Project/ProjectInfo/LegacyHealthWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/LegacyHealthWidget.tsx new file mode 100644 index 0000000000..6a7e231543 --- /dev/null +++ b/frontend/src/component/project/Project/ProjectInfo/LegacyHealthWidget.tsx @@ -0,0 +1,75 @@ +import { Box, styled, Typography } from '@mui/material'; +import { Link } from 'react-router-dom'; +import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle'; +import { flexRow } from 'themes/themeStyles'; +import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; +import { StyledProjectInfoWidgetContainer } from './ProjectInfo.styles'; + +interface ILegacyHealthWidgetProps { + projectId: string; + health: number; + total?: number; + stale?: number; +} + +const StyledParagraphEmphasizedText = styled('p')(({ theme }) => ({ + fontSize: '1.5rem', + [theme.breakpoints.down('md')]: { + fontSize: theme.fontSizes.bodySize, + marginBottom: theme.spacing(4), + }, +})); + +const StyledDivPercentageContainer = styled('div')(() => ({ + display: 'flex', + justifyContent: 'center', +})); + +const StyledLink = styled(Link)(({ theme }) => ({ + textDecoration: 'none', + ...flexRow, + justifyContent: 'center', + color: theme.palette.primary.main, + [theme.breakpoints.down('md')]: { + position: 'absolute', + bottom: theme.spacing(1.5), + right: theme.spacing(1.5), + }, +})); + +const StyledSpanLinkText = styled('p')(({ theme }) => ({ + [theme.breakpoints.down('md')]: { + display: 'none', + }, +})); + +const StyledArrowIcon = styled(ArrowForwardIcon)(({ theme }) => ({ + color: theme.palette.primary.main, + marginLeft: theme.spacing(1), +})); + +/** + * @deprecated + */ +export const LegacyHealthWidget = ({ + projectId, + health, +}: ILegacyHealthWidgetProps) => ( + + + + + theme.spacing(2) }}> + Overall health rating + + theme.spacing(2.5) }}> + + {health}% + + + + view more + + + +); diff --git a/frontend/src/component/project/Project/ProjectInfo/LegacyProjectMembersWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/LegacyProjectMembersWidget.tsx new file mode 100644 index 0000000000..2692bd789a --- /dev/null +++ b/frontend/src/component/project/Project/ProjectInfo/LegacyProjectMembersWidget.tsx @@ -0,0 +1,93 @@ +import { Link } from 'react-router-dom'; +import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; +import { flexRow } from 'themes/themeStyles'; +import { styled } from '@mui/material'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; + +const StyledDivInfoContainer = styled('div')(({ theme }) => ({ + textAlign: 'center', + backgroundColor: theme.palette.background.paper, + borderRadius: theme.shape.borderRadiusLarge, + width: '100%', + padding: theme.spacing(3, 2, 3, 2), + [theme.breakpoints.down('md')]: { + ...flexRow, + flexDirection: 'column', + justifyContent: 'center', + fontSize: theme.fontSizes.smallBody, + position: 'relative', + padding: theme.spacing(1.5), + }, +})); + +const StyledParagraphSubtitle = styled('p')(({ theme }) => ({ + marginBottom: theme.spacing(2), +})); + +const StyledParagraphEmphasizedText = styled('p')(({ theme }) => ({ + fontSize: '1.5rem', + marginBottom: theme.spacing(2), + [theme.breakpoints.down('md')]: { + fontSize: theme.fontSizes.bodySize, + marginBottom: theme.spacing(4), + }, +})); + +const StyledSpanLinkText = styled('p')(({ theme }) => ({ + [theme.breakpoints.down('md')]: { + display: 'none', + }, +})); + +const StyledLink = styled(Link)(({ theme }) => ({ + textDecoration: 'none', + ...flexRow, + justifyContent: 'center', + color: theme.palette.primary.main, + [theme.breakpoints.down('md')]: { + position: 'absolute', + right: theme.spacing(1.5), + bottom: theme.spacing(1.5), + }, +})); + +const StyledArrowIcon = styled(ArrowForwardIcon)(({ theme }) => ({ + color: theme.palette.primary.main, + marginLeft: theme.spacing(1), +})); + +interface ILegacyProjectMembersWidgetProps { + projectId: string; + memberCount: number; +} + +/** + * @deprecated + */ +export const LegacyProjectMembersWidget = ({ + projectId, + memberCount, +}: ILegacyProjectMembersWidgetProps) => { + const { uiConfig } = useUiConfig(); + + let link = `/admin/users`; + + if (uiConfig?.versionInfo?.current?.enterprise) { + link = `/projects/${projectId}/settings/access`; + } + + return ( + + + Project members + + + {memberCount} + + + view more + + + + ); +}; diff --git a/frontend/src/component/project/Project/ProjectInfo/MetaWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/MetaWidget.tsx index 48210d3bf1..80c52bd8dc 100644 --- a/frontend/src/component/project/Project/ProjectInfo/MetaWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/MetaWidget.tsx @@ -1,12 +1,12 @@ import { FC } from 'react'; -import { Link as RouterLink } from 'react-router-dom'; -import { Box, styled, Typography, Link } from '@mui/material'; +import { styled, Typography } from '@mui/material'; import { StyledProjectInfoWidgetContainer, StyledWidgetTitle, } from './ProjectInfo.styles'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import { WidgetFooterLink } from './WidgetFooterLink'; interface IMetaWidgetProps { id?: string; @@ -35,35 +35,29 @@ export const MetaWidget: FC = ({ id, description }) => { {' '} {id || '__________'} - - - - Description:{' '} - - - {description} - - - } - elseShow={ - - - Add description - - - } - /> - + theme.spacing(1.5), + marginBottom: 0, + textAlign: 'left', + }} + > + {description} + + } + /> + + Add description + + } + /> ); }; diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts index e9d743ba5b..b05a619a9c 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts +++ b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts @@ -1,74 +1,23 @@ -import { Link } from 'react-router-dom'; -import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; -import { flexRow } from 'themes/themeStyles'; import { styled } from '@mui/material'; -export const StyledProjectInfoSidebarContainer = styled('div')(({ theme }) => ({ - ...flexRow, - width: '225px', - flexDirection: 'column', - gap: theme.spacing(2), - boxShadow: 'none', - [theme.breakpoints.down('md')]: { - flexDirection: 'row', - alignItems: 'stretch', - width: '100%', - marginBottom: theme.spacing(2), - }, -})); - -export const StyledDivPercentageContainer = styled('div')(({ theme }) => ({ - display: 'flex', - justifyContent: 'center', - margin: theme.spacing(2, 0), -})); - export const StyledProjectInfoWidgetContainer = styled('div')(({ theme }) => ({ margin: '0', textAlign: 'center', backgroundColor: theme.palette.background.paper, borderRadius: theme.shape.borderRadiusLarge, width: '100%', - padding: theme.spacing(3, 2, 3, 2), + minWidth: 225, + padding: theme.spacing(3), [theme.breakpoints.down('md')]: { - margin: theme.spacing(0, 1), - ...flexRow, + display: 'flex', flexDirection: 'column', - justifyContent: 'center', - fontSize: theme.fontSizes.smallBody, position: 'relative', padding: theme.spacing(1.5), - '&:first-of-type': { - marginLeft: '0', - }, - '&:last-of-type': { - marginRight: '0', - }, }, })); export const StyledWidgetTitle = styled('p')(({ theme }) => ({ - marginBottom: theme.spacing(2), -})); - -export const StyledParagraphGridRow = styled('div')(({ theme }) => ({ - display: 'grid', - gridGap: theme.spacing(1.5), - gridTemplateColumns: `${theme.spacing(2.25)} auto auto`, //20px auto auto - margin: theme.spacing(1, 0, 1, 0), - fontSize: theme.fontSizes.smallBody, - color: theme.palette.text.secondary, - textAlign: 'left', - alignItems: 'center', -})); - -export const StyledParagraphEmphasizedText = styled('p')(({ theme }) => ({ - fontSize: '1.5rem', - marginBottom: theme.spacing(2), - [theme.breakpoints.down('md')]: { - fontSize: theme.fontSizes.bodySize, - marginBottom: theme.spacing(4), - }, + marginBottom: theme.spacing(2.5), })); export const StyledCount = styled('span')(({ theme }) => ({ @@ -76,25 +25,3 @@ export const StyledCount = styled('span')(({ theme }) => ({ fontWeight: 'bold', color: theme.palette.text.primary, })); - -export const StyledSpanLinkText = styled('p')(({ theme }) => ({ - [theme.breakpoints.down('md')]: { - display: 'none', - }, -})); - -export const StyledLink = styled(Link)(({ theme }) => ({ - textDecoration: 'none', - ...flexRow, - justifyContent: 'center', - color: theme.palette.primary.main, - [theme.breakpoints.down('md')]: { - position: 'absolute', - bottom: theme.spacing(1.5), - }, -})); - -export const StyledArrowIcon = styled(ArrowForwardIcon)(({ theme }) => ({ - color: theme.palette.primary.main, - marginLeft: theme.spacing(1), -})); diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx index e3159641c8..bfa4844af5 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx @@ -1,14 +1,17 @@ +import { Box, styled, useMediaQuery, useTheme } from '@mui/material'; +import { ProjectStatsSchema } from 'openapi/models/projectStatsSchema'; import type { IFeatureToggleListItem } from 'interfaces/featureToggle'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { DEFAULT_PROJECT_ID } from 'hooks/api/getters/useDefaultProject/useDefaultProjectId'; -import { StyledProjectInfoSidebarContainer } from './ProjectInfo.styles'; import { HealthWidget } from './HealthWidget'; import { ToggleTypesWidget } from './ToggleTypesWidget'; import { MetaWidget } from './MetaWidget'; import { ProjectMembersWidget } from './ProjectMembersWidget'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; -import { ProjectStatsSchema } from 'openapi/models/projectStatsSchema'; import { ChangeRequestsWidget } from './ChangeRequestsWidget'; +import { flexRow } from 'themes/themeStyles'; +import { LegacyHealthWidget } from './LegacyHealthWidget'; +import { LegacyProjectMembersWidget } from './LegacyProjectMembersWidget'; interface IProjectInfoProps { id: string; @@ -19,6 +22,23 @@ interface IProjectInfoProps { stats: ProjectStatsSchema; } +const StyledProjectInfoSidebarContainer = styled(Box)(({ theme }) => ({ + ...flexRow, + width: '225px', + flexDirection: 'column', + gap: theme.spacing(2), + boxShadow: 'none', + [theme.breakpoints.down('md')]: { + display: 'grid', + width: '100%', + alignItems: 'stretch', + marginBottom: theme.spacing(2), + }, + [theme.breakpoints.down('sm')]: { + display: 'flex', + }, +})); + const ProjectInfo = ({ id, description, @@ -28,29 +48,74 @@ const ProjectInfo = ({ stats, }: IProjectInfoProps) => { const { uiConfig, isEnterprise } = useUiConfig(); + const theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); + + const showChangeRequestsWidget = isEnterprise(); + const showProjectMembersWidget = id !== DEFAULT_PROJECT_ID; + const fitMoreColumns = + (!showChangeRequestsWidget && !showProjectMembersWidget) || + (isSmallScreen && showChangeRequestsWidget && showProjectMembersWidget); + + if (!Boolean(uiConfig?.flags.newProjectOverview)) { + return ( + + ); + } return ( ); diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx index 89db931a6e..eba45e5ce8 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx @@ -1,10 +1,11 @@ import { - StyledLink, StyledProjectInfoWidgetContainer, - StyledSpanLinkText, + StyledWidgetTitle, } from './ProjectInfo.styles'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { StatusBox } from '../ProjectStats/StatusBox'; +import { WidgetFooterLink } from './WidgetFooterLink'; +import { Box } from '@mui/material'; interface IProjectMembersWidgetProps { projectId: string; @@ -26,20 +27,17 @@ export const ProjectMembersWidget = ({ } return ( - theme.spacing(0, 0, 3, 0) }} - > - - - - View all members - - + + Project members + + + + View all members ); }; diff --git a/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx index c0955320a7..10d6b7f5d6 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx @@ -4,7 +4,6 @@ import type { IFeatureToggleListItem } from 'interfaces/featureToggle'; import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons'; import { StyledCount, - StyledParagraphGridRow, StyledProjectInfoWidgetContainer, StyledWidgetTitle, } from './ProjectInfo.styles'; @@ -14,8 +13,10 @@ export interface IToggleTypesWidgetProps { features: IFeatureToggleListItem[]; } -const StyledTypeCount = styled(StyledCount)(() => ({ +const StyledTypeCount = styled(StyledCount)(({ theme }) => ({ marginLeft: 'auto', + fontWeight: theme.typography.fontWeightRegular, + color: theme.palette.text.secondary, })); interface IToggleTypeRowProps { @@ -23,10 +24,26 @@ interface IToggleTypeRowProps { Icon: OverridableComponent; count: number; } + +const StyledParagraphGridRow = styled('div')(({ theme }) => ({ + display: 'flex', + gap: theme.spacing(1.5), + width: '100%', + gridTemplateColumns: `${theme.spacing(2.5)} auto auto`, //20px auto auto + margin: theme.spacing(1, 0), + fontSize: theme.fontSizes.smallBody, + color: theme.palette.text.secondary, + alignItems: 'center', + [theme.breakpoints.down('md')]: { + margin: 0, + }, +})); + const ToggleTypesRow = ({ type, Icon, count }: IToggleTypeRowProps) => { const getTitleText = (str: string) => { return str.charAt(0).toUpperCase() + str.slice(1).replace('-', ' '); }; + return ( diff --git a/frontend/src/component/project/Project/ProjectInfo/WidgetFooterLink.tsx b/frontend/src/component/project/Project/ProjectInfo/WidgetFooterLink.tsx new file mode 100644 index 0000000000..00d169d357 --- /dev/null +++ b/frontend/src/component/project/Project/ProjectInfo/WidgetFooterLink.tsx @@ -0,0 +1,28 @@ +import { Link as RouterLink } from 'react-router-dom'; +import { Link, Typography } from '@mui/material'; +import { FC } from 'react'; + +interface IWidgetFooterLinkProps { + to: string; +} + +export const WidgetFooterLink: FC = ({ + children, + to, +}) => { + return ( + theme.spacing(2.5), + marginTop: 'auto', + justifySelf: 'flex-end', + }} + > + + {children} + + + ); +}; diff --git a/frontend/src/component/project/Project/ProjectStats/ProjectStats.tsx b/frontend/src/component/project/Project/ProjectStats/ProjectStats.tsx index b8e59de056..d0e83c9b3f 100644 --- a/frontend/src/component/project/Project/ProjectStats/ProjectStats.tsx +++ b/frontend/src/component/project/Project/ProjectStats/ProjectStats.tsx @@ -1,21 +1,39 @@ -import { Box, styled } from '@mui/material'; +import { Box, styled, Typography } from '@mui/material'; import { ProjectStatsSchema } from 'openapi/models'; import { object } from 'prop-types'; import { StatusBox } from './StatusBox'; const StyledBox = styled(Box)(({ theme }) => ({ padding: theme.spacing(0, 0, 2, 2), - display: 'flex', - justifyContent: 'space-between', + display: 'grid', + gap: theme.spacing(2), + gridTemplateColumns: 'repeat(4, 1fr)', flexWrap: 'wrap', + [theme.breakpoints.down('lg')]: { + gridTemplateColumns: 'repeat(2, 1fr)', + }, [theme.breakpoints.down('md')]: { - paddingLeft: 0, + padding: theme.spacing(0, 0, 2), }, [theme.breakpoints.down('sm')]: { flexDirection: 'column', }, })); +const StyledWidget = styled(Box)(({ theme }) => ({ + padding: theme.spacing(3), + backgroundColor: theme.palette.background.paper, + flex: 1, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + borderRadius: `${theme.shape.borderRadiusLarge}px`, + [theme.breakpoints.down('lg')]: { + padding: theme.spacing(2), + }, +})); + interface IProjectStatsProps { stats: ProjectStatsSchema; } @@ -47,32 +65,53 @@ export const ProjectStats = ({ stats }: IProjectStatsProps) => { return ( - - {' '} - - + + + + + theme.spacing(1), + }} + > + {avgTimeToProdCurrentWindow}{' '} + days + + } + change={calculatePercentage( + avgTimeToProdCurrentWindow, + avgTimeToProdPastWindow + )} + percentage + /> + + + + + + + ); }; diff --git a/frontend/src/component/project/Project/ProjectStats/StatusBox.tsx b/frontend/src/component/project/Project/ProjectStats/StatusBox.tsx index c602c6230a..40209cc461 100644 --- a/frontend/src/component/project/Project/ProjectStats/StatusBox.tsx +++ b/frontend/src/component/project/Project/ProjectStats/StatusBox.tsx @@ -1,80 +1,56 @@ -import { ArrowOutward, SouthEast } from '@mui/icons-material'; +import type { ReactNode } from 'react'; +import { CallMade, SouthEast } from '@mui/icons-material'; import { Box, Typography, styled } from '@mui/material'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { flexRow } from 'themes/themeStyles'; -const StyledBox = styled(Box)(({ theme }) => ({ - padding: theme.spacing(4, 2), - backgroundColor: theme.palette.background.paper, - minWidth: '24%', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - borderRadius: `${theme.shape.borderRadiusLarge}px`, - [theme.breakpoints.down('lg')]: { - minWidth: '49%', - padding: theme.spacing(2), - ':nth-child(n+3)': { - marginTop: theme.spacing(2), - }, - }, - [theme.breakpoints.down('sm')]: { - ':nth-child(n+2)': { - marginTop: theme.spacing(2), - }, - }, -})); - const StyledTypographyHeader = styled(Typography)(({ theme }) => ({ - marginBottom: theme.spacing(2), + marginBottom: theme.spacing(2.5), })); const StyledTypographyCount = styled(Typography)(({ theme }) => ({ fontSize: theme.fontSizes.largeHeader, - fontWeight: 'bold', })); const StyledBoxChangeContainer = styled(Box)(({ theme }) => ({ ...flexRow, flexDirection: 'column', alignItems: 'center', - marginLeft: theme.spacing(1.5), + marginLeft: theme.spacing(2.5), })); const StyledTypographySubtext = styled(Typography)(({ theme }) => ({ color: theme.palette.neutral.main, - fontSize: theme.fontSizes.smallBody, + fontSize: theme.typography.body2.fontSize, })); const StyledTypographyChange = styled(Typography)(({ theme }) => ({ marginLeft: theme.spacing(1), - fontSize: theme.fontSizes.smallBody, + fontSize: theme.typography.body1.fontSize, + fontWeight: theme.typography.fontWeightBold, })); interface IStatusBoxProps { - title: string; - boxText: string; + title?: string; + boxText: ReactNode; change: number; percentage?: boolean; - fullWidthBodyText?: boolean; } const resolveIcon = (change: number) => { if (change > 0) { return ( - + ); } - return ; + return ; }; const resolveColor = (change: number) => { if (change > 0) { - return 'success.main'; + return 'success.dark'; } - return 'error.main'; + return 'warning.dark'; }; export const StatusBox = ({ @@ -82,52 +58,51 @@ export const StatusBox = ({ boxText, change, percentage, - fullWidthBodyText, -}: IStatusBoxProps) => { - return ( - - {title} - - {boxText} - - ( + <> + {title}} + /> + + {boxText} + + + {resolveIcon(change)} + - {resolveIcon(change)} - - {change} - {percentage ? '%' : ''} - - - - this month - - - } - elseShow={ - - - No change - - - } - /> - - - ); -}; + {change > 0 ? '+' : ''} + {change} + {percentage ? '%' : ''} + + + + this month + + + } + elseShow={ + + + No change + + + } + /> + + +);