Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

Commit

Permalink
COR-1660-archive-thermometer (#4818)
Browse files Browse the repository at this point in the history
* Update topical weekly summary to support link

* Remove thermometer from frontpage

* feat(COR-1660): Sanity summary-item schema fix for description field type

* feat(COR-1660): Summary items with lokalize keys

* feat(COR-1660): First block of the archived page

* add page information block and warning

* Add dataexplained and faq links to pageinfo header

* Add FAQ and articles section

* Add automatically set state to last thermometer setting

* feat(COR-1660): PR comment resolution

* feat(COR-1660): Sanity schema adjustment

---------

Co-authored-by: beek <[email protected]>
Co-authored-by: VWSCoronaDashboard <[email protected]>
Co-authored-by: VWSCoronaDashboard30 <[email protected]>
  • Loading branch information
4 people authored Jul 18, 2023
1 parent 1657602 commit 77d92ce
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { asResponsiveArray } from '~/style/utils';
import { BaseTile } from '~/queries/query-types';
import { getFilenameToIconName } from '~/utils';
import { TOPICAL_SEVERITY_INDICATOR_TILE_MAX_WIDTH } from '../severity-indicator-tile/constants';
import { RichContent } from '../cms/rich-content';

interface TopicalWeeklySummaryTileProps {
label: string | undefined;
Expand All @@ -35,8 +36,8 @@ export const TopicalWeeklySummaryTile = ({ label, level, title, summaryItems }:
<Box minWidth="25px" height="25px">
<DynamicIcon width="25px" name={getFilenameToIconName(summaryItem.tileIcon) as TopicalIcon} />
</Box>
<Box>
<InlineText>{summaryItem.description}</InlineText>
<Box display="flex">
<RichContent blocks={summaryItem.description} />
{summaryItem.isThermometerMetric && label && (
<InlineText css={css({ whiteSpace: 'nowrap' })}>
<SeverityIndicatorLevel level={level}>{level}</SeverityIndicatorLevel>
Expand All @@ -53,7 +54,7 @@ export const TopicalWeeklySummaryTile = ({ label, level, title, summaryItems }:
};

const SeverityIndicatorLevel = styled.span`
margin: 0 ${space[1]};
margin: 0 ${space[2]};
background-color: ${({ level }: { level: SeverityLevel }) => getSeverityColor(level as SeverityLevels)};
border-radius: 50%;
color: ${colors.white};
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/domain/layout/logic/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type GmCategoryKeys = SharedCategoryKeys | 'archived_metrics';
export type NlItemKeys =
| 'compliance'
| 'coronamelder_app'
| 'corona_thermometer'
| 'disabled_care'
| 'elderly_at_home'
| 'general_practitioner_suspicions'
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/domain/layout/logic/use-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const mapCategoriesToIcons = {
const mapKeysToReverseRouter = {
compliance: 'gedrag',
coronamelder_app: 'coronamelder',
corona_thermometer: 'coronaThermometer',
current_advices: 'geldendeAdviezen',
disabled_care: 'gehandicaptenzorg',
elderly_at_home: 'thuiswonendeOuderen',
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/domain/layout/nl-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export function NlLayout(props: NlLayoutProps) {
[
'nursing_home_care',
'reproduction_number',
'corona_thermometer',
'compliance',
'positive_tests',
'disabled_care',
Expand Down
95 changes: 5 additions & 90 deletions packages/app/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,30 @@
import { colors } from '@corona-dashboard/common';
import { IconName as TopicalIcon } from '@corona-dashboard/icons/src/icon-name2filename';
import { css } from '@styled-system/css';
import { GetStaticPropsContext } from 'next';
import styled from 'styled-components';
import { isPresent } from 'ts-is-present';
import { Box, Spacer } from '~/components/base';
import { RichContent } from '~/components/cms/rich-content';
import { CollapsibleSection } from '~/components/collapsible';
import { MaxWidth } from '~/components/max-width';
import { getTimelineRangeDates } from '~/components/severity-indicator-tile/components/timeline/logic';
import { Timeline } from '~/components/severity-indicator-tile/components/timeline/timeline';
import { SEVERITY_LEVELS_LIST, TOPICAL_SEVERITY_INDICATOR_TILE_MAX_WIDTH } from '~/components/severity-indicator-tile/constants';
import { SeverityIndicatorTile } from '~/components/severity-indicator-tile/severity-indicator-tile';
import { SeverityLevel, SeverityLevels } from '~/components/severity-indicator-tile/types';
import { TimelineMarker } from '~/components/time-series-chart/components/timeline';
import { TOPICAL_SEVERITY_INDICATOR_TILE_MAX_WIDTH } from '~/components/severity-indicator-tile/constants';
import { TopicalWeeklySummaryTile } from '~/components/weekly-summary/topical-weekly-summary-tile';
import { Layout } from '~/domain/layout';
import { Advice } from '~/domain/topical/components/advice';
import { IndicatorLevelDescription } from '~/domain/topical/components/indicator-level-description';
import { TopicalArticlesList } from '~/domain/topical/components/topical-article-list';
import { TopicalHeader } from '~/domain/topical/components/topical-header';
import { TopicalTile } from '~/domain/topical/components/topical-kpi-tile/topical-tile';
import { TopicalLinksList } from '~/domain/topical/components/topical-links-list';
import { TopicalSectionHeader } from '~/domain/topical/components/topical-section-header';
import { TopicalThemeHeader } from '~/domain/topical/components/topical-theme-header';
import { TrendIcon } from '~/domain/topical/types';
import { Languages, SiteText } from '~/locale';
import { getArticleParts, getPagePartsQuery } from '~/queries/get-page-parts-query';
import { getThermometerEvents, getTopicalStructureQuery } from '~/queries/get-topical-structure-query';
import { getTopicalStructureQuery } from '~/queries/get-topical-structure-query';
import { TopicalSanityData } from '~/queries/query-types';
import { StaticProps, createGetStaticProps } from '~/static-props/create-get-static-props';
import { createGetContent, getLastGeneratedDate, getLokalizeTexts } from '~/static-props/get-data';
import { space } from '~/style/theme';
import { ArticleParts, LinkParts, PagePartQueryResult, RichTextParts } from '~/types/cms';
import { getFilenameToIconName, replaceVariablesInText } from '~/utils';
import { useDynamicLokalizeTexts } from '~/utils/cms/use-dynamic-lokalize-texts';
import { getThermometerSeverityLevels } from '~/utils/get-thermometer-severity-level';

const selectLokalizeTexts = (siteText: SiteText) => ({
textNl: siteText.pages.topical_page.nl,
Expand Down Expand Up @@ -87,12 +77,7 @@ const Home = (props: StaticProps<typeof getStaticProps>) => {
md: `repeat(3, 1fr)`,
};

const currentSeverityLevel = thermometer.currentLevel as unknown as SeverityLevels;
const currentSeverityLevelTexts = thermometer.thermometerLevels.find((thermometerLevel) => thermometerLevel.level === currentSeverityLevel);

const thermometerEvents = getThermometerEvents(thermometer.timeline.ThermometerTimelineEvents, thermometer.thermometerLevels);

const { startDate, endDate } = getTimelineRangeDates(thermometerEvents);
const { currentSeverityLevel, currentSeverityLevelTexts } = getThermometerSeverityLevels(thermometer);

return (
<Layout {...metadata} lastGenerated={lastGenerated}>
Expand All @@ -110,70 +95,8 @@ const Home = (props: StaticProps<typeof getStaticProps>) => {
<Box paddingX={{ _: space[3], sm: space[4] }} maxWidth={TOPICAL_SEVERITY_INDICATOR_TILE_MAX_WIDTH}>
<TopicalHeader description={topicalConfig.description} />
</Box>
{currentSeverityLevelTexts && (
<Box marginY={space[5]} paddingX={{ _: space[3], sm: space[4] }} maxWidth={TOPICAL_SEVERITY_INDICATOR_TILE_MAX_WIDTH}>
<TopicalThemeHeader title={thermometer.title} subtitle={thermometer.subTitle} icon={getFilenameToIconName(thermometer.icon) as TopicalIcon} />

<SeverityIndicatorTile
level={currentSeverityLevel}
description={
currentSeverityLevelTexts.description &&
replaceVariablesInText(currentSeverityLevelTexts.description, {
label: currentSeverityLevelTexts.label.toLowerCase(),
})
}
title={thermometer.tileTitle}
label={currentSeverityLevelTexts.label}
sourceLabel={thermometer.sourceLabel}
datesLabel={thermometer.datesLabel}
levelDescription={thermometer.levelDescription}
trendIcon={thermometer.trendIcon as TrendIcon}
/>

{thermometerEvents && thermometerEvents.length && (
<Timeline
startDate={startDate}
endDate={endDate}
timelineEvents={thermometerEvents}
labels={{
heading: thermometer.timeline.title,
today: thermometer.timeline.todayLabel,
tooltipCurrentEstimation: thermometer.timeline.tooltipLabel,
}}
legendItems={[
{
label: thermometer.timeline.legendLabel,
shape: 'custom',
shapeComponent: <TimelineMarker color={colors.gray6} />,
},
]}
/>
)}

<Box marginY={{ _: space[3], md: space[4] }} borderBottom={'1px solid'} borderBottomColor={colors.gray3}>
<CollapsibleSection summary={thermometer.collapsibleTitle} textColor={colors.black} borderColor={colors.gray3}>
<Box marginY={space[3]}>
<OrderedList>
{SEVERITY_LEVELS_LIST.map((severityLevel, index) => {
const indicatorTexts = thermometer.thermometerLevels.find((thermometerLevel) => thermometerLevel.level === severityLevel);
return (
indicatorTexts && (
<IndicatorLevelDescription
key={index}
level={indicatorTexts.level as SeverityLevel}
label={indicatorTexts.label}
description={indicatorTexts.description}
/>
)
);
})}
</OrderedList>
</Box>
</CollapsibleSection>
</Box>
<RichContent blocks={thermometer.articleReference} />
</Box>
)}
<Spacer marginBottom={space[5]} />

<Box spacing={{ _: 5, md: 6 }} paddingX={{ _: space[3], sm: space[4] }}>
{kpiThemes.themes.map((theme) => {
Expand Down Expand Up @@ -245,12 +168,4 @@ const Home = (props: StaticProps<typeof getStaticProps>) => {
);
};

const OrderedList = styled.ol(
css({
listStyleType: 'none',
margin: '0',
padding: '0',
})
);

export default Home;
195 changes: 195 additions & 0 deletions packages/app/src/pages/landelijk/corona-thermometer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import { Languages, SiteText } from '~/locale';
import { colors } from '@corona-dashboard/common';
import styled from 'styled-components';
import { Box } from '~/components/base';
import { GetStaticPropsContext } from 'next';
import { getTimelineRangeDates } from '~/components/severity-indicator-tile/components/timeline/logic';
import { Timeline } from '~/components/severity-indicator-tile/components/timeline/timeline';
import { SEVERITY_LEVELS_LIST, TOPICAL_SEVERITY_INDICATOR_TILE_MAX_WIDTH } from '~/components/severity-indicator-tile/constants';
import { SeverityIndicatorTile } from '~/components/severity-indicator-tile/severity-indicator-tile';
import { SeverityLevel } from '~/components/severity-indicator-tile/types';
import { TimelineMarker } from '~/components/time-series-chart/components/timeline';
import { IndicatorLevelDescription } from '~/domain/topical/components/indicator-level-description';
import { TrendIcon } from '~/domain/topical/types';
import { getThermometerEvents, getTopicalStructureQuery } from '~/queries/get-topical-structure-query';
import { StaticProps, createGetStaticProps } from '~/static-props/create-get-static-props';
import { createGetContent, getLastGeneratedDate, getLokalizeTexts } from '~/static-props/get-data';
import { ArticleParts, LinkParts, PagePartQueryResult, RichTextParts } from '~/types/cms';
import { TopicalSanityData } from '~/queries/query-types';
import { getArticleParts, getDataExplainedParts, getFaqParts, getPagePartsQuery } from '~/queries/get-page-parts-query';
import { Layout } from '~/domain/layout/layout';
import { NlLayout } from '~/domain/layout/nl-layout';
import { ChartTile, InView, PageInformationBlock, TileList, WarningTile } from '~/components';
import { useDynamicLokalizeTexts } from '~/utils/cms/use-dynamic-lokalize-texts';
import { space } from '~/style/theme';
import { Coronathermometer } from '@corona-dashboard/icons';
import { useIntl } from '~/intl';
import { replaceVariablesInText } from '~/utils/replace-variables-in-text';
import { getPageInformationHeaderContent } from '~/utils/get-page-information-header-content';
import { PageFaqTile } from '~/components/page-faq-tile';
import { PageArticlesTile } from '~/components/articles/page-articles-tile';
import { getThermometerSeverityLevels } from '~/utils/get-thermometer-severity-level';

const selectLokalizeTexts = (siteText: SiteText) => ({
textNl: siteText.pages.corona_thermometer_page.nl,
});

type LokalizeTexts = ReturnType<typeof selectLokalizeTexts>;

export const getStaticProps = createGetStaticProps(
({ locale }: { locale: keyof Languages }) => getLokalizeTexts(selectLokalizeTexts, locale),
getLastGeneratedDate,
async (context: GetStaticPropsContext) => {
const { content } = await createGetContent<{
parts: PagePartQueryResult<ArticleParts | LinkParts | RichTextParts>;
topicalStructure: TopicalSanityData;
}>((context) => {
const { locale } = context;
return `{
"parts": ${getPagePartsQuery('coronathermometer_page')},
"topicalStructure": ${getTopicalStructureQuery(locale)}
}`;
})(context);
return {
content: {
articles: getArticleParts(content.parts.pageParts, 'coronathermometerPageArticles'),
dataExplained: getDataExplainedParts(content.parts.pageParts, 'coronathermometerPageDataExplained'),
faqs: getFaqParts(content.parts.pageParts, 'coronathermometerPageFAQs'),
topicalStructure: content.topicalStructure,
},
};
}
);

const CoronaThermometer = (props: StaticProps<typeof getStaticProps>) => {
const { pageText, content, lastGenerated } = props;

const { topicalStructure } = content;

const { thermometer } = topicalStructure;

const { textNl } = useDynamicLokalizeTexts<LokalizeTexts>(pageText, selectLokalizeTexts);

const metadata = {
...textNl.metadata,
title: textNl.metadata.title,
description: textNl.metadata.description,
};

const { commonTexts } = useIntl();
const { formatDateFromSeconds } = useIntl();

const { currentSeverityLevel, currentSeverityLevelTexts } = getThermometerSeverityLevels(thermometer);

const thermometerEvents = getThermometerEvents(thermometer.timeline.ThermometerTimelineEvents, thermometer.thermometerLevels);

const lastThermometerSetDate = formatDateFromSeconds(thermometerEvents.slice(-1)[0].end, 'weekday-long');

const { startDate, endDate } = getTimelineRangeDates(thermometerEvents);

const hasActiveWarningTile = !!textNl.pagina.belangrijk_bericht;

return (
<Layout {...metadata} lastGenerated={lastGenerated}>
<NlLayout>
<TileList>
<PageInformationBlock
category={commonTexts.sidebar.categories.archived_metrics.title}
title={textNl.pagina.titel}
description={textNl.pagina.description}
icon={<Coronathermometer aria-hidden="true" />}
metadata={{
datumsText: replaceVariablesInText(textNl.pagina.dates, {
current_state: currentSeverityLevel,
end_date: lastThermometerSetDate,
}),
dateOrRange: endDate,
dateOfInsertionUnix: endDate,
dataSources: [textNl.bronnen.rivm],
}}
pageInformationHeader={getPageInformationHeaderContent({
dataExplained: content.dataExplained,
faq: content.faqs,
})}
/>

{hasActiveWarningTile && <WarningTile isFullWidth message={textNl.pagina.belangrijk_bericht} variant="informational"></WarningTile>}

<ChartTile title={thermometer.title} disableFullscreen>
{currentSeverityLevelTexts && (
<Box maxWidth={TOPICAL_SEVERITY_INDICATOR_TILE_MAX_WIDTH}>
<SeverityIndicatorTile
level={currentSeverityLevel}
description={
currentSeverityLevelTexts.description &&
replaceVariablesInText(currentSeverityLevelTexts.description, {
label: currentSeverityLevelTexts.label.toLowerCase(),
})
}
title={thermometer.tileTitle}
label={currentSeverityLevelTexts.label}
sourceLabel={thermometer.sourceLabel}
datesLabel={thermometer.datesLabel}
levelDescription={thermometer.levelDescription}
trendIcon={thermometer.trendIcon as TrendIcon}
/>
{thermometerEvents && thermometerEvents.length && (
<Timeline
startDate={startDate}
endDate={endDate}
timelineEvents={thermometerEvents}
labels={{
heading: thermometer.timeline.title,
today: thermometer.timeline.todayLabel,
tooltipCurrentEstimation: thermometer.timeline.tooltipLabel,
}}
legendItems={[
{
label: thermometer.timeline.legendLabel,
shape: 'custom',
shapeComponent: <TimelineMarker color={colors.gray6} />,
},
]}
/>
)}
</Box>
)}
</ChartTile>

<ChartTile title={thermometer.collapsibleTitle} disableFullscreen>
<OrderedList>
{SEVERITY_LEVELS_LIST.map((severityLevel, index) => {
const indicatorTexts = thermometer.thermometerLevels.find((thermometerLevel) => thermometerLevel.level === severityLevel);
return (
indicatorTexts && (
<IndicatorLevelDescription key={index} level={indicatorTexts.level as SeverityLevel} label={indicatorTexts.label} description={indicatorTexts.description} />
)
);
})}
</OrderedList>
</ChartTile>

{content.faqs && content.faqs.questions?.length > 0 && <PageFaqTile questions={content.faqs.questions} title={content.faqs.sectionTitle}></PageFaqTile>}

{content.articles && content.articles.articles?.length > 0 && (
<InView rootMargin="400px">
<PageArticlesTile articles={content.articles.articles} title={content.articles.sectionTitle}></PageArticlesTile>
</InView>
)}
</TileList>
</NlLayout>
</Layout>
);
};

const OrderedList = styled.ol`
margin-top: ${space[4]};
padding: 0;
list-style-type: none;
li:last-child div {
margin: 0;
}
`;

export default CoronaThermometer;
2 changes: 1 addition & 1 deletion packages/app/src/queries/query-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface TopicalSanityData {
advice: Advice;
}

interface ThermometerConfig {
export interface ThermometerConfig {
icon: TopicalIcon;
title: string;
subTitle: PortableTextEntry[] | null;
Expand Down
Loading

0 comments on commit 77d92ce

Please sign in to comment.