From 31571b8d1392031ce88de6004636c2ba67a500c1 Mon Sep 17 00:00:00 2001 From: NatSquared Date: Wed, 26 Jun 2024 15:53:23 -0700 Subject: [PATCH 1/7] DESENG-634: Update engagement cards; add suggested engagements block --- CHANGELOG.MD | 9 + .../common/Indicators/StatusChip.tsx | 12 +- .../new/view/EngagementDescription.tsx | 43 ++-- .../new/view/EngagementSurveyBlock.tsx | 57 ++--- .../new/view/SuggestedEngagements.tsx | 194 +++++++----------- .../components/engagement/new/view/index.tsx | 16 +- .../src/components/landing/EngagementTile.tsx | 189 ++++++++++------- .../src/components/landing/FilterDrawer.tsx | 14 +- .../components/landing/LandingComponent.tsx | 15 +- .../components/landing/MetadataFilterChip.tsx | 8 +- met-web/src/components/landing/TileBlock.tsx | 50 +++-- .../src/components/landing/TileSkeleton.tsx | 42 +++- met-web/src/routes/UnauthenticatedRoutes.tsx | 2 +- met-web/src/styles/Theme.ts | 10 +- 14 files changed, 360 insertions(+), 301 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 459c164c4..ab11f90fc 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,3 +1,12 @@ +## June 26, 2024 + +- **Feature** Redesigned Engagement Cards & added Suggested Engagements to the engagement page + - Redesigned the engagement cards to match the new design system + - Added a new section to the engagement page to display suggested engagements + - Engagement cards now take you to the "new look" route + - Tweaks to the engagement list page layout + - Minor tweaks to the engagement view page layout + ## June 24, 2024 - **Feature** Add a new survey block to the engagement page [🎟️ DESENG-633](https://citz-gdx.atlassian.net/browse/DESENG-633) diff --git a/met-web/src/components/common/Indicators/StatusChip.tsx b/met-web/src/components/common/Indicators/StatusChip.tsx index 5a0a697f8..6d4efb1c9 100644 --- a/met-web/src/components/common/Indicators/StatusChip.tsx +++ b/met-web/src/components/common/Indicators/StatusChip.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Chip as MuiChip, Skeleton } from '@mui/material'; +import { Chip as MuiChip, Skeleton, useTheme } from '@mui/material'; import { colors } from '..'; import { SubmissionStatus } from 'constants/engagementStatus'; @@ -24,8 +24,10 @@ export const getStatusFromStatusId = (statusId: SubmissionStatus): StatusText => } }; -export const EngagementStatusChip: React.FC = ({ label: customLabel, statusId: status, invert }) => { +export const EngagementStatusChip: React.FC = ({ label: customLabel, statusId: status }) => { const statusText = getStatusFromStatusId(status); + const theme = useTheme(); + const invert = theme.palette.mode === 'dark'; return ( = ({ label: customLabel, alignItems: 'center', gap: '10px', flexShrink: 0, - borderWidth: '1px', + border: '2px solid', borderColor: 'transparent', borderRadius: '24px', + boxSizing: 'border-box', '&>.MuiChip-label': { padding: '4px 16px', fontSize: '14px', fontWeight: 700, lineHeight: '16px', + position: 'relative', + bottom: '1px', }, '&.status-chip-open': { backgroundColor: colors.surface.blue[80], color: colors.type.inverted.primary, '&.status-chip-invert': { backgroundColor: 'transparent', - borderWidth: '2px', borderColor: colors.surface.white, }, }, diff --git a/met-web/src/components/engagement/new/view/EngagementDescription.tsx b/met-web/src/components/engagement/new/view/EngagementDescription.tsx index fcdc726a6..612bac541 100644 --- a/met-web/src/components/engagement/new/view/EngagementDescription.tsx +++ b/met-web/src/components/engagement/new/view/EngagementDescription.tsx @@ -82,26 +82,29 @@ export const EngagementDescription = () => { - - }> - - - {(resolvedWidgets: Widget[]) => { - const widget = resolvedWidgets?.[0]; - return widget && ; - }} - - - - + }> + + + {(resolvedWidgets: Widget[]) => { + const widget = resolvedWidgets?.[0]; + if (widget) + return ( + + ; + + ); + }} + + + diff --git a/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx b/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx index 17139d44c..455232a32 100644 --- a/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx +++ b/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx @@ -2,7 +2,7 @@ import React, { Suspense } from 'react'; import { Button } from 'components/common/Input'; import { Box, Grid, Skeleton, ThemeProvider } from '@mui/material'; import { colors } from 'components/common'; -import { Await, useLoaderData, useParams } from 'react-router-dom'; +import { Await, Link, useLoaderData, useParams } from 'react-router-dom'; import { Engagement } from 'models/engagement'; import { SubmissionStatus } from 'constants/engagementStatus'; import { getStatusFromStatusId } from 'components/common/Indicators/StatusChip'; @@ -104,7 +104,7 @@ export const EngagementSurveyBlock = () => { item sx={{ width: { xs: '100%', md: '47.5%' }, - display: 'flex', + display: statusBlock?.block_text ? 'flex' : 'none', flexDirection: 'column', minHeight: '120px', marginBottom: '48px', @@ -116,12 +116,14 @@ export const EngagementSurveyBlock = () => { toolbarHidden editorState={getEditorStateFromRaw(statusBlock?.block_text ?? '')} /> - handleCloseEmailModal()} - /> + + handleCloseEmailModal()} + /> + - } + iconPosition="right" + href={ + isLoggedIn + ? `/engagements/${engagement.id}/dashboard/public` + : `/engagements/${engagement.id}/dashboard/public/${language}` + } + LinkComponent={({ children, href, ...props }) => ( + + {children} + + )} > - - + {translate('buttonText.viewFeedback')} + @@ -164,7 +165,7 @@ export const EngagementSurveyBlock = () => { item sx={{ width: { xs: '100%', md: '47.5%' }, - display: 'flex', + display: widget ? 'flex' : 'none', minHeight: '360px', marginBottom: '48px', }} diff --git a/met-web/src/components/engagement/new/view/SuggestedEngagements.tsx b/met-web/src/components/engagement/new/view/SuggestedEngagements.tsx index 9ec720cd4..21f896c45 100644 --- a/met-web/src/components/engagement/new/view/SuggestedEngagements.tsx +++ b/met-web/src/components/engagement/new/view/SuggestedEngagements.tsx @@ -1,143 +1,89 @@ -import React, { useEffect } from 'react'; -import { Box, Grid, MobileStepper, ThemeProvider } from '@mui/material'; +import React, { Suspense } from 'react'; +import { Box, Grid } from '@mui/material'; import { TileSkeleton } from 'components/landing/TileSkeleton'; import { getEngagements } from 'services/engagementService'; import { Engagement } from 'models/engagement'; import EngagementTile from 'components/landing/EngagementTile'; -import { RepeatedGrid } from 'components/common'; import { Header2 } from 'components/common/Typography'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faArrowLeft, faChevronLeft, faChevronRight } from '@fortawesome/pro-regular-svg-icons'; -import { Button } from 'components/common/Input'; +import { faArrowLeft } from '@fortawesome/pro-regular-svg-icons'; import { Link } from 'components/common/Navigation'; -import { useLoaderData } from 'react-router-dom'; -import { engagementMetadata } from '../../../../../tests/unit/components/factory'; +import { Await, useLoaderData } from 'react-router-dom'; +import { RepeatedGrid } from 'components/common'; export const SuggestedEngagements = () => { - const [suggestedEngagements, setSuggestedEngagements] = React.useState([] as Engagement[]); - const [totalEngagements, setTotalEngagements] = React.useState(3); - const [page, setPage] = React.useState(0); - const [pageLength, setPageLength] = React.useState(3); - const [isLoading, setIsLoading] = React.useState(true); const { engagement } = useLoaderData() as { engagement: Promise }; - const allEngagementsPromise = getEngagements({ size: 13, page: 1, include_banner_url: true }); - - const handleResize = () => { - if (window.innerWidth < 930) { - setPageLength(1); - } else if (window.innerWidth < 1500) { - setPageLength(2); - if (page > 5) { - setPage(5); - } - } else if (window.innerWidth < 1800) { - setPageLength(3); - if (page > 3) { - setPage(3); - } - } else { - setPageLength(4); - if (page > 4) { - setPage(4); - } - } - }; - useEffect(() => { - handleResize(); - window.addEventListener('resize', handleResize); - return () => window.removeEventListener('resize', handleResize); - }, [page]); - - useEffect(() => { - const fetchData = async () => { - try { - // preload all 12 suggested engagements to keep things snappy - // a 13th engagement is loaded in case one of the 12 is the current engagement - const currentEngagement = await engagement; - const allEngagements = await allEngagementsPromise; - const filteredEngagements = allEngagements.items - .filter((engagement) => engagement.id !== currentEngagement.id) - .slice(0, 12) - .map((value) => ({ value, sort: Math.random() })) - .sort((a, b) => a.sort - b.sort) - .map(({ value }) => value); - setSuggestedEngagements(filteredEngagements); - setTotalEngagements(allEngagements.total); - setIsLoading(false); - } catch (error) { - console.error('Error fetching suggested engagements:', error); - } - }; - setPage(0); - fetchData(); - }, [engagement]); - - const pages = Math.ceil((totalEngagements - 1) / pageLength); - const engagementSlice = suggestedEngagements.slice(page * pageLength, (page + 1) * pageLength); + const suggestedEngagementsPromise = getEngagements({ size: 5, page: 1, include_banner_url: true }).then( + async (response) => { + const currentEngagement = await engagement; + return response.items + .filter((engagement) => engagement.id !== currentEngagement.id) + .slice(0, 4) + .map((value) => ({ value, sort: Math.random() })) + .sort((a, b) => a.sort - b.sort) + .map(({ value }) => value); + }, + ); return (
- - + + You may also be interested in - - - {isLoading - ? Array.from({ length: 3 }).map((_, index) => ( - - - - )) - : engagementSlice.map((engagement, index) => ( - - - - ))} - - - theme.palette.primary.main as string, - }, - }, - }} - /> - - + + {(engagements: Engagement[]) => + engagements.map((engagement, index) => { + return ( + + + + ); + }) + } + + + + + theme.palette.text.primary, textDecoration: 'none' }}> All engagements diff --git a/met-web/src/components/engagement/new/view/index.tsx b/met-web/src/components/engagement/new/view/index.tsx index f1246d9b7..95c9b0e70 100644 --- a/met-web/src/components/engagement/new/view/index.tsx +++ b/met-web/src/components/engagement/new/view/index.tsx @@ -3,15 +3,19 @@ import { EngagementHero } from './EngagementHero'; import { EngagementDescription } from './EngagementDescription'; import { EngagementContentTabs } from './EngagementContentTabs'; import { EngagementSurveyBlock } from './EngagementSurveyBlock'; +import { SuggestedEngagements } from './SuggestedEngagements'; export const ViewEngagement = () => { return ( -
- - - - -
+ <> +
+ + + + +
+ + ); }; diff --git a/met-web/src/components/landing/EngagementTile.tsx b/met-web/src/components/landing/EngagementTile.tsx index 5a0d5f638..5af031191 100644 --- a/met-web/src/components/landing/EngagementTile.tsx +++ b/met-web/src/components/landing/EngagementTile.tsx @@ -1,21 +1,20 @@ import React, { useEffect, useState } from 'react'; -import Card from '@mui/material/Card'; -import CardActions from '@mui/material/CardActions'; -import CardContent from '@mui/material/CardContent'; -import CardMedia from '@mui/material/CardMedia'; +import { Card, CardContent, CardMedia, CardActionArea, ThemeProvider } from '@mui/material'; import { Engagement } from 'models/engagement'; -import { Box, Stack } from '@mui/material'; -import { MetBodyOld, MetHeader4, MetLabel, MetParagraphOld } from 'components/common'; +import { Box, Grid } from '@mui/material'; import { getEngagement } from 'services/engagementService'; -import { If, Then, When } from 'react-if'; import dayjs from 'dayjs'; -import { EngagementStatusChip } from 'components/engagement/status'; -import { SubmissionStatus } from 'constants/engagementStatus'; +import { EngagementStatusChip } from 'components/common/Indicators/StatusChip'; import { TileSkeleton } from './TileSkeleton'; import { getSlugByEngagementId } from 'services/engagementSlugService'; import { getBaseUrl } from 'helper'; import { useAppTranslation } from 'hooks'; -import { Button } from 'components/common/Input/Button'; +import { Link } from 'components/common/Navigation'; +import { BodyText, EyebrowText } from 'components/common/Typography'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faArrowRight } from '@fortawesome/pro-regular-svg-icons'; +import { colors, elevations, globalFocusVisible } from 'components/common'; +import { BaseTheme, DarkTheme } from 'styles/Theme'; interface EngagementTileProps { passedEngagement?: Engagement; @@ -26,9 +25,15 @@ const EngagementTile = ({ passedEngagement, engagementId }: EngagementTileProps) const [loadedEngagement, setLoadedEngagement] = useState(passedEngagement || null); const [isLoadingEngagement, setIsLoadingEngagement] = useState(true); const [slug, setSlug] = useState(''); - const dateFormat = 'MMM DD, YYYY'; + const [isHovered, setIsHovered] = useState(false); + const [isFocused, setIsFocused] = useState(false); + const [isActive, setIsActive] = useState(false); + const startDate = dayjs(loadedEngagement?.start_date); + const endDate = dayjs(loadedEngagement?.end_date); + const dateFormat = 'MMMM DD, YYYY'; + const semanticDateFormat = 'YYYY-MM-DD'; const languagePath = `/${sessionStorage.getItem('languageId')}`; - const engagementPath = `/${slug}`; + const engagementPath = `/new-look/${slug}`; const engagementUrl = `${getBaseUrl()}${engagementPath}${languagePath}`; const loadEngagement = async () => { @@ -76,78 +81,104 @@ const EngagementTile = ({ passedEngagement, engagementId }: EngagementTileProps) } if (!loadedEngagement) { - return {translate('landingPage.tile.error')}; + return {translate('landingPage.tile.error')}; } - const { name, end_date, start_date, description, banner_url, submission_status } = loadedEngagement; - const EngagementDate = `${dayjs(start_date).format(dateFormat)} to ${dayjs(end_date).format(dateFormat)}`; - - const handleClick = (event: React.MouseEvent) => { - event.stopPropagation(); - window.location.href = engagementUrl; - }; + const { name, banner_url } = loadedEngagement; return ( - { - window.location.href = engagementUrl; - }} - > - - - - - - {name} - - {description} - - - - {EngagementDate} - - - {translate('landingPage.tile.status')} - - - - - - - - - - + + setIsHovered(true)} + onMouseLeave={() => { + setIsHovered(false); + setIsActive(false); + }} + onFocus={() => setIsFocused(true)} + onBlur={() => setIsFocused(false)} + onMouseDown={() => setIsActive(true)} + onMouseUp={() => setIsActive(false)} + className={isActive ? 'active' : ''} + sx={{ + borderRadius: '24px', + width: '320px', + cursor: 'pointer', + '&:hover': { + boxShadow: elevations.hover, + background: colors.surface.blue[90], + }, + '&.active': { + boxShadow: elevations.pressed, + background: colors.surface.blue[100], + }, + '&:focus': { + boxShadow: elevations.hover, + background: colors.surface.blue[90], + }, + '&:focus-visible': { + boxShadow: globalFocusVisible + elevations.hover, + background: colors.surface.blue[90], + }, + }} > - - - - - - + + {Boolean(banner_url) && } + + + + {name} + + + + + + + + + + + {' '} + to + + + + + + + + + + + ); }; diff --git a/met-web/src/components/landing/FilterDrawer.tsx b/met-web/src/components/landing/FilterDrawer.tsx index 864a6440e..de463d9fe 100644 --- a/met-web/src/components/landing/FilterDrawer.tsx +++ b/met-web/src/components/landing/FilterDrawer.tsx @@ -1,11 +1,12 @@ import React, { useContext, useMemo } from 'react'; import { LandingContext } from './LandingContext'; -import { SwipeableDrawer, IconButton, Typography, Stack, Button, Grid, useTheme, useMediaQuery } from '@mui/material'; +import { SwipeableDrawer, IconButton, Typography, Stack, Grid, useTheme, useMediaQuery } from '@mui/material'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faXmark } from '@fortawesome/pro-regular-svg-icons/faXmark'; import { MetadataFilterChip } from './MetadataFilterChip'; import { EngagementDisplayStatus } from 'constants/engagementStatus'; import { useAppTranslation } from 'hooks'; +import { Button } from 'components/common/Input'; const FilterDrawer = () => { const { searchFilters, setSearchFilters, setPage, metadataFilters, clearFilters, drawerOpened, setDrawerOpened } = @@ -59,7 +60,7 @@ const FilterDrawer = () => { PaperProps={{ sx: { width: isSmallScreen ? '100%' : '50%', - background: theme.palette.primary.main, + background: theme.palette.background.default, color: 'white', padding: '3em', }, @@ -139,10 +140,9 @@ const FilterDrawer = () => { diff --git a/met-web/src/components/landing/LandingComponent.tsx b/met-web/src/components/landing/LandingComponent.tsx index 8d600ebbb..7d4b789f3 100644 --- a/met-web/src/components/landing/LandingComponent.tsx +++ b/met-web/src/components/landing/LandingComponent.tsx @@ -1,7 +1,6 @@ import React from 'react'; -import { Grid } from '@mui/material'; +import { Grid, ThemeProvider } from '@mui/material'; import { Banner } from 'components/banner/Banner'; -import { MetHeader1Old, MetParagraphOld } from 'components/common'; import TileBlock from './TileBlock'; import { Container } from '@mui/system'; import LandingPageBanner from 'assets/images/LandingPageBanner.png'; @@ -9,13 +8,17 @@ import FilterBlock from './FilterBlock'; import FilterDrawer from './FilterDrawer'; import { TenantState } from 'reduxSlices/tenantSlice'; import { useAppSelector } from '../../hooks'; +import { BodyText, Header1 } from 'components/common/Typography'; +import { DarkTheme } from 'styles/Theme'; const LandingComponent = () => { const tenant: TenantState = useAppSelector((state) => state.tenant); return ( - + + + { rowSpacing={2} > - {tenant.title} + {tenant.title} - {tenant.description} + {tenant.description} - + diff --git a/met-web/src/components/landing/MetadataFilterChip.tsx b/met-web/src/components/landing/MetadataFilterChip.tsx index 72b3d8cd3..8a27d3c6a 100644 --- a/met-web/src/components/landing/MetadataFilterChip.tsx +++ b/met-web/src/components/landing/MetadataFilterChip.tsx @@ -24,7 +24,11 @@ export const MetadataFilterChip = ({ .replace('{0}', name) .replace('{1}', selectionHint)} color="default" - avatar={selected ? : undefined} + avatar={ + selected ? ( + + ) : undefined + } variant={selected ? 'filled' : 'outlined'} onClick={onClick} sx={{ @@ -36,7 +40,7 @@ export const MetadataFilterChip = ({ borderColor: selected ? '#053662' : '#D8EAFD', borderRadius: '2em', backgroundColor: selected ? '#D8EAFD' : 'transparent', - color: selected ? theme.palette.primary.main : 'white', + color: selected ? theme.palette.primary.light : 'white', fontSize: '16px', '&.MuiChip-clickable:hover': { backgroundColor: selected ? '#F1F8FE' : '#1E5189', diff --git a/met-web/src/components/landing/TileBlock.tsx b/met-web/src/components/landing/TileBlock.tsx index d7a75b7a9..f3ff9f6d9 100644 --- a/met-web/src/components/landing/TileBlock.tsx +++ b/met-web/src/components/landing/TileBlock.tsx @@ -16,14 +16,26 @@ const TileBlock = () => { - + @@ -34,9 +46,9 @@ const TileBlock = () => { { - {engagements.map((engagement) => { + {engagements.map((engagement, index) => { return ( - + diff --git a/met-web/src/components/landing/TileSkeleton.tsx b/met-web/src/components/landing/TileSkeleton.tsx index b17b02c86..ee017d929 100644 --- a/met-web/src/components/landing/TileSkeleton.tsx +++ b/met-web/src/components/landing/TileSkeleton.tsx @@ -1,6 +1,44 @@ import React from 'react'; -import { Skeleton } from '@mui/material'; +import { Card, CardActionArea, CardContent, Grid, Skeleton } from '@mui/material'; +import { EyebrowText, BodyText } from 'components/common/Typography'; +import { StatusChipSkeleton } from 'components/common/Indicators/StatusChip'; +import { colors } from 'styles/Theme'; export const TileSkeleton = () => { - return ; + return ( + + + + + + + + + + + + + + + + + Feb 02, 2022 to + + + + + Feb 02, 2022 + + + + + + + + ); }; diff --git a/met-web/src/routes/UnauthenticatedRoutes.tsx b/met-web/src/routes/UnauthenticatedRoutes.tsx index 7ac1f2697..b0945847a 100644 --- a/met-web/src/routes/UnauthenticatedRoutes.tsx +++ b/met-web/src/routes/UnauthenticatedRoutes.tsx @@ -26,7 +26,7 @@ const RedirectLoginWrapper = withLanguageParam(RedirectLogin); const UnauthenticatedRoutes = () => { return ( <> - } /> + } /> } /> } /> diff --git a/met-web/src/styles/Theme.ts b/met-web/src/styles/Theme.ts index 79b593af2..8569543dc 100644 --- a/met-web/src/styles/Theme.ts +++ b/met-web/src/styles/Theme.ts @@ -1,3 +1,4 @@ +import { Contrast } from '@mui/icons-material'; import { PaletteMode, createTheme } from '@mui/material'; export const colors = { type: { @@ -289,8 +290,9 @@ export const DarkPalette = { mode: 'dark' as PaletteMode, primary: { main: colors.surface.white, - light: colors.surface.blue[10], - dark: colors.surface.blue[20], + light: colors.surface.blue[90], + dark: colors.surface.blue[100], + contrastText: colors.type.inverted.primary, }, secondary: { main: colors.surface.gold.bc, @@ -299,7 +301,7 @@ export const DarkPalette = { }, background: { default: colors.surface.blue[90], - paper: colors.surface.gray[110], + paper: colors.surface.blue[90], }, hover: { light: colors.surface.blue[10], @@ -321,7 +323,7 @@ export const DarkTheme = createTheme({ MuiPaper: { styleOverrides: { root: { - backgroundColor: colors.surface.gray[110], + backgroundColor: DarkPalette.background.paper, }, }, }, From 7d5387cf002a86d6b82ccce3c05c9e4c9732663a Mon Sep 17 00:00:00 2001 From: NatSquared Date: Wed, 26 Jun 2024 16:06:12 -0700 Subject: [PATCH 2/7] Fix SonarCloud issues --- CHANGELOG.MD | 2 +- .../src/components/common/Indicators/StatusChip.tsx | 1 - .../engagement/new/view/EngagementSurveyBlock.tsx | 12 ++++++------ met-web/src/components/landing/EngagementTile.tsx | 3 +-- met-web/src/styles/Theme.ts | 1 - 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index ab11f90fc..703f59297 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,6 +1,6 @@ ## June 26, 2024 -- **Feature** Redesigned Engagement Cards & added Suggested Engagements to the engagement page +- **Feature** Redesigned Engagement Cards & added Suggested Engagements to the engagement page [🎟️ DESENG-634](https://citz-gdx.atlassian.net/browse/DESENG-634) - Redesigned the engagement cards to match the new design system - Added a new section to the engagement page to display suggested engagements - Engagement cards now take you to the "new look" route diff --git a/met-web/src/components/common/Indicators/StatusChip.tsx b/met-web/src/components/common/Indicators/StatusChip.tsx index 6d4efb1c9..3ae08476c 100644 --- a/met-web/src/components/common/Indicators/StatusChip.tsx +++ b/met-web/src/components/common/Indicators/StatusChip.tsx @@ -5,7 +5,6 @@ import { SubmissionStatus } from 'constants/engagementStatus'; export interface ChipProps { label?: string; - invert?: boolean; statusId: SubmissionStatus; } diff --git a/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx b/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx index 455232a32..1c7aa1d0a 100644 --- a/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx +++ b/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx @@ -2,7 +2,7 @@ import React, { Suspense } from 'react'; import { Button } from 'components/common/Input'; import { Box, Grid, Skeleton, ThemeProvider } from '@mui/material'; import { colors } from 'components/common'; -import { Await, Link, useLoaderData, useParams } from 'react-router-dom'; +import { Await, Link, LinkProps, useLoaderData, useParams } from 'react-router-dom'; import { Engagement } from 'models/engagement'; import { SubmissionStatus } from 'constants/engagementStatus'; import { getStatusFromStatusId } from 'components/common/Indicators/StatusChip'; @@ -31,6 +31,10 @@ const gridContainerStyles = { flexDirection: { xs: 'column', md: 'row' }, }; +const LinkRenderer: React.ElementType = ({ href, ...props }: Omit & { href: string }) => ( + +); + export const EngagementSurveyBlock = () => { const { engagement, widgets } = useLoaderData() as { engagement: Promise; widgets: Promise }; const surveyBlockContents = Promise.all([engagement, widgets]); @@ -149,11 +153,7 @@ export const EngagementSurveyBlock = () => { ? `/engagements/${engagement.id}/dashboard/public` : `/engagements/${engagement.id}/dashboard/public/${language}` } - LinkComponent={({ children, href, ...props }) => ( - - {children} - - )} + LinkComponent={LinkRenderer} > {translate('buttonText.viewFeedback')} diff --git a/met-web/src/components/landing/EngagementTile.tsx b/met-web/src/components/landing/EngagementTile.tsx index 5af031191..3b60faa9e 100644 --- a/met-web/src/components/landing/EngagementTile.tsx +++ b/met-web/src/components/landing/EngagementTile.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useState } from 'react'; -import { Card, CardContent, CardMedia, CardActionArea, ThemeProvider } from '@mui/material'; +import { Box, Grid, Card, CardContent, CardMedia, CardActionArea, ThemeProvider } from '@mui/material'; import { Engagement } from 'models/engagement'; -import { Box, Grid } from '@mui/material'; import { getEngagement } from 'services/engagementService'; import dayjs from 'dayjs'; import { EngagementStatusChip } from 'components/common/Indicators/StatusChip'; diff --git a/met-web/src/styles/Theme.ts b/met-web/src/styles/Theme.ts index 8569543dc..2b566eb15 100644 --- a/met-web/src/styles/Theme.ts +++ b/met-web/src/styles/Theme.ts @@ -1,4 +1,3 @@ -import { Contrast } from '@mui/icons-material'; import { PaletteMode, createTheme } from '@mui/material'; export const colors = { type: { From 0c23d977d566970c27bb0470feaa8c4079b585cc Mon Sep 17 00:00:00 2001 From: NatSquared Date: Wed, 26 Jun 2024 16:46:15 -0700 Subject: [PATCH 3/7] update unit tests --- .../landingPage/LandingPage.test.tsx | 246 +++++++++++------- 1 file changed, 146 insertions(+), 100 deletions(-) diff --git a/met-web/tests/unit/components/landingPage/LandingPage.test.tsx b/met-web/tests/unit/components/landingPage/LandingPage.test.tsx index dfa0f6c6c..ed4761a4a 100644 --- a/met-web/tests/unit/components/landingPage/LandingPage.test.tsx +++ b/met-web/tests/unit/components/landingPage/LandingPage.test.tsx @@ -6,6 +6,7 @@ import { setupEnv } from '../setEnvVars'; import { LandingContext } from 'components/landing/LandingContext'; import * as reactRedux from 'react-redux'; import { openEngagement, closedEngagement } from '../factory'; +import { RouterProvider, createMemoryRouter } from 'react-router-dom'; const MOCK_TENANT = { title: 'Mock Tenant', @@ -74,27 +75,36 @@ describe('Landing page tests', () => { test('LandingComponent is rendered correctly with engagements listed', async () => { render( - + + + ), }, - metadataFilters: [], - clearFilters: jest.fn(), - drawerOpened: false, - setDrawerOpened: jest.fn(), - setSearchFilters: jest.fn(), - setPage: jest.fn(), - page: 1, - engagements: [openEngagement, closedEngagement], - loadingEngagements: false, - totalEngagements: 0, - }} - > - - , + ])} + />, ); await waitFor(() => { @@ -120,27 +130,36 @@ describe('Landing page tests', () => { const setSearchFiltersMock = jest.fn(); render( - + + + ), }, - metadataFilters: [], - clearFilters: jest.fn(), - drawerOpened: false, - setDrawerOpened: jest.fn(), - setSearchFilters: setSearchFiltersMock, - setPage: jest.fn(), - page: 1, - engagements: [], - loadingEngagements: false, - totalEngagements: 0, - }} - > - - , + ])} + />, ); const searchInput = screen.getByPlaceholderText('landing.filters.searchPlaceholder'); @@ -155,27 +174,36 @@ describe('Landing page tests', () => { const setSearchFiltersMock = jest.fn(); render( - + + + ), }, - metadataFilters: [], - clearFilters: jest.fn(), - drawerOpened: false, - setDrawerOpened: jest.fn(), - setSearchFilters: setSearchFiltersMock, - setPage: jest.fn(), - page: 1, - engagements: [], - loadingEngagements: false, - totalEngagements: 0, - }} - > - - , + ])} + />, ); // Find all elements with role "button" @@ -202,27 +230,36 @@ describe('Landing page tests', () => { const setDrawerOpenedMock = jest.fn(); render( - + + + ), }, - metadataFilters: [], - clearFilters: jest.fn(), - drawerOpened: false, - setDrawerOpened: setDrawerOpenedMock, - setSearchFilters: jest.fn(), - setPage: jest.fn(), - page: 1, - engagements: [], - loadingEngagements: false, - totalEngagements: 0, - }} - > - - , + ])} + />, ); const filterButton = screen.getByText('landing.filters.drawer.openButton'); @@ -246,27 +283,36 @@ describe('Landing page tests', () => { const setDrawerOpenedMock = jest.fn(); render( - + + + ), }, - metadataFilters: [], - clearFilters: jest.fn(), - drawerOpened: false, - setDrawerOpened: setDrawerOpenedMock, - setSearchFilters: jest.fn(), - setPage: jest.fn(), - page: 1, - engagements: [], - loadingEngagements: false, - totalEngagements: 0, - }} - > - - , + ])} + />, ); expect(screen.getByTestId('NoResultsHeader')).toBeInTheDocument(); From 4b8b2ee5c4fae543458407d87637703e3607fcc1 Mon Sep 17 00:00:00 2001 From: NatSquared Date: Wed, 26 Jun 2024 16:55:01 -0700 Subject: [PATCH 4/7] Remove "any" typing --- .../components/engagement/new/view/EngagementSurveyBlock.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx b/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx index 1c7aa1d0a..4a79b3bb7 100644 --- a/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx +++ b/met-web/src/components/engagement/new/view/EngagementSurveyBlock.tsx @@ -31,9 +31,7 @@ const gridContainerStyles = { flexDirection: { xs: 'column', md: 'row' }, }; -const LinkRenderer: React.ElementType = ({ href, ...props }: Omit & { href: string }) => ( - -); +const LinkRenderer = ({ href, ...props }: Omit & { href: string }) => ; export const EngagementSurveyBlock = () => { const { engagement, widgets } = useLoaderData() as { engagement: Promise; widgets: Promise }; From 4285e2af9a16c5e7fca194b503fffaf0bb212354 Mon Sep 17 00:00:00 2001 From: NatSquared Date: Thu, 27 Jun 2024 12:42:13 -0700 Subject: [PATCH 5/7] Address review comments --- .../src/components/common/Navigation/Link.tsx | 7 +- .../components/common/Typography/Headers.tsx | 3 + .../new/view/EngagementSurveyBlock.tsx | 7 +- .../components/engagement/new/view/index.tsx | 2 +- .../src/components/landing/EngagementTile.tsx | 179 ++++++++++-------- .../src/components/landing/TileSkeleton.tsx | 10 +- 6 files changed, 121 insertions(+), 87 deletions(-) diff --git a/met-web/src/components/common/Navigation/Link.tsx b/met-web/src/components/common/Navigation/Link.tsx index 64b4bfad9..0309781b2 100644 --- a/met-web/src/components/common/Navigation/Link.tsx +++ b/met-web/src/components/common/Navigation/Link.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Link as MuiLink, LinkProps as MuiLinkProps } from '@mui/material'; -import { NavLink } from 'react-router-dom'; +import { LinkProps, NavLink } from 'react-router-dom'; import { colors } from '..'; interface FocusableNavLinkProps extends MuiLinkProps { @@ -59,3 +59,8 @@ export const Link: React.FC = ({ ); }; + +/* Adapter for elements expecting Mui's Link component, allowing them to use react-router's Link component */ +export const RouterLinkRenderer = ({ href, ...props }: Omit & { href: string }) => ( + +); diff --git a/met-web/src/components/common/Typography/Headers.tsx b/met-web/src/components/common/Typography/Headers.tsx index 0bd963171..ad0be5d21 100644 --- a/met-web/src/components/common/Typography/Headers.tsx +++ b/met-web/src/components/common/Typography/Headers.tsx @@ -45,15 +45,18 @@ export const Header2 = ({ children, decorated = false, weight, + component, ...props }: { children: React.ReactNode; decorated?: boolean; weight?: 'bold' | 'regular' | 'thin'; + component?: React.ElementType; } & TypographyProps) => { return ( & { href: string }) => ; - export const EngagementSurveyBlock = () => { const { engagement, widgets } = useLoaderData() as { engagement: Promise; widgets: Promise }; const surveyBlockContents = Promise.all([engagement, widgets]); @@ -151,7 +150,7 @@ export const EngagementSurveyBlock = () => { ? `/engagements/${engagement.id}/dashboard/public` : `/engagements/${engagement.id}/dashboard/public/${language}` } - LinkComponent={LinkRenderer} + LinkComponent={RouterLinkRenderer} > {translate('buttonText.viewFeedback')} diff --git a/met-web/src/components/engagement/new/view/index.tsx b/met-web/src/components/engagement/new/view/index.tsx index 95c9b0e70..a591f4777 100644 --- a/met-web/src/components/engagement/new/view/index.tsx +++ b/met-web/src/components/engagement/new/view/index.tsx @@ -13,8 +13,8 @@ export const ViewEngagement = () => { + - ); }; diff --git a/met-web/src/components/landing/EngagementTile.tsx b/met-web/src/components/landing/EngagementTile.tsx index 3b60faa9e..8e00fb940 100644 --- a/met-web/src/components/landing/EngagementTile.tsx +++ b/met-web/src/components/landing/EngagementTile.tsx @@ -8,12 +8,12 @@ import { TileSkeleton } from './TileSkeleton'; import { getSlugByEngagementId } from 'services/engagementSlugService'; import { getBaseUrl } from 'helper'; import { useAppTranslation } from 'hooks'; -import { Link } from 'components/common/Navigation'; -import { BodyText, EyebrowText } from 'components/common/Typography'; +import { BodyText, Header2 } from 'components/common/Typography'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faArrowRight } from '@fortawesome/pro-regular-svg-icons'; -import { colors, elevations, globalFocusVisible } from 'components/common'; +import { colors, elevations, globalFocusShadow } from 'components/common'; import { BaseTheme, DarkTheme } from 'styles/Theme'; +import { RouterLinkRenderer } from 'components/common/Navigation/Link'; interface EngagementTileProps { passedEngagement?: Engagement; @@ -80,16 +80,47 @@ const EngagementTile = ({ passedEngagement, engagementId }: EngagementTileProps) } if (!loadedEngagement) { - return {translate('landingPage.tile.error')}; + return {translate('landingPage.tile.error')}; } const { name, banner_url } = loadedEngagement; return ( - - - + + + setIsHovered(true)} onMouseLeave={() => { setIsHovered(false); @@ -99,85 +130,77 @@ const EngagementTile = ({ passedEngagement, engagementId }: EngagementTileProps) onBlur={() => setIsFocused(false)} onMouseDown={() => setIsActive(true)} onMouseUp={() => setIsActive(false)} - className={isActive ? 'active' : ''} + LinkComponent={RouterLinkRenderer} + href={engagementUrl} sx={{ - borderRadius: '24px', - width: '320px', - cursor: 'pointer', - '&:hover': { - boxShadow: elevations.hover, - background: colors.surface.blue[90], - }, - '&.active': { - boxShadow: elevations.pressed, - background: colors.surface.blue[100], - }, - '&:focus': { - boxShadow: elevations.hover, - background: colors.surface.blue[90], - }, '&:focus-visible': { - boxShadow: globalFocusVisible + elevations.hover, - background: colors.surface.blue[90], + // focus visible styling is applied by the parent Card component + border: 'none', + outline: 'none', + boxShadow: 'none', + padding: 'unset', + margin: 'unset', }, }} > - - {Boolean(banner_url) && } - - } + + + - - {name} - - - - - - - - - - - {' '} - to - - - - - + {name} + +
+
+ + + + + + + {' '} + to + + + + - - - - - + + + + + + // ); }; diff --git a/met-web/src/components/landing/TileSkeleton.tsx b/met-web/src/components/landing/TileSkeleton.tsx index ee017d929..a2fd8e8fa 100644 --- a/met-web/src/components/landing/TileSkeleton.tsx +++ b/met-web/src/components/landing/TileSkeleton.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Card, CardActionArea, CardContent, Grid, Skeleton } from '@mui/material'; -import { EyebrowText, BodyText } from 'components/common/Typography'; +import { Header2, BodyText } from 'components/common/Typography'; import { StatusChipSkeleton } from 'components/common/Indicators/StatusChip'; import { colors } from 'styles/Theme'; @@ -10,16 +10,20 @@ export const TileSkeleton = () => { - - + From 37748817d54274452b8db99b826fb6e22b1c3b2e Mon Sep 17 00:00:00 2001 From: NatSquared Date: Thu, 27 Jun 2024 12:43:56 -0700 Subject: [PATCH 6/7] Update ARIA labelling --- .../components/engagement/new/view/SuggestedEngagements.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/met-web/src/components/engagement/new/view/SuggestedEngagements.tsx b/met-web/src/components/engagement/new/view/SuggestedEngagements.tsx index 21f896c45..d42f7ddfd 100644 --- a/met-web/src/components/engagement/new/view/SuggestedEngagements.tsx +++ b/met-web/src/components/engagement/new/view/SuggestedEngagements.tsx @@ -26,9 +26,9 @@ export const SuggestedEngagements = () => { ); return ( -
+
- + You may also be interested in Date: Thu, 27 Jun 2024 13:25:51 -0700 Subject: [PATCH 7/7] Remove commented code --- met-web/src/components/landing/EngagementTile.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/met-web/src/components/landing/EngagementTile.tsx b/met-web/src/components/landing/EngagementTile.tsx index 8e00fb940..ff7a07648 100644 --- a/met-web/src/components/landing/EngagementTile.tsx +++ b/met-web/src/components/landing/EngagementTile.tsx @@ -86,7 +86,6 @@ const EngagementTile = ({ passedEngagement, engagementId }: EngagementTileProps) const { name, banner_url } = loadedEngagement; return ( - // - // ); };