diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e03c596358..bdae86da83 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -23,7 +23,7 @@ on: jobs: analyze: name: Analyze - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 permissions: actions: read contents: read @@ -32,6 +32,7 @@ jobs: strategy: fail-fast: false matrix: + node-version: [ 18.18.2 ] language: ['javascript'] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: @@ -41,6 +42,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 diff --git a/.github/workflows/infra-acceptance.yml b/.github/workflows/infra-acceptance.yml index 784245b443..10850a9cb9 100644 --- a/.github/workflows/infra-acceptance.yml +++ b/.github/workflows/infra-acceptance.yml @@ -10,7 +10,7 @@ jobs: trigger-acceptance-build: environment: Acceptance name: Call Azure Pipeline - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Azure Pipelines Action uses: Azure/pipelines@v1.2 diff --git a/.github/workflows/infra-develop.yml b/.github/workflows/infra-develop.yml index 659ee62c57..3615ca04a2 100644 --- a/.github/workflows/infra-develop.yml +++ b/.github/workflows/infra-develop.yml @@ -8,7 +8,7 @@ jobs: trigger-develop-build: environment: Development name: Call Azure Pipeline - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Azure Pipelines Action uses: Azure/pipelines@v1 diff --git a/.github/workflows/infra.yml b/.github/workflows/infra.yml index 91c7a95be0..ed78ceb791 100644 --- a/.github/workflows/infra.yml +++ b/.github/workflows/infra.yml @@ -8,7 +8,7 @@ on: jobs: build: name: Call Azure Pipeline - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Azure Pipelines Action uses: Azure/pipelines@v1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 66e036fc43..8fdf111530 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: pull_request jobs: init: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Cancel previous workflow uses: styfle/cancel-workflow-action@0.4.0 @@ -12,12 +12,20 @@ jobs: access_token: ${{ github.token }} lint: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 + strategy: + matrix: + node-version: [18.18.2] needs: init steps: - name: Check out repository uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn config get cacheFolder)" @@ -38,7 +46,10 @@ jobs: run: yarn lint compile: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 + strategy: + matrix: + node-version: [18.18.2] needs: init steps: - name: Get target branch name (pull request) @@ -49,6 +60,11 @@ jobs: - name: Check out repository uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn config get cacheFolder)" @@ -83,12 +99,20 @@ jobs: run: yarn typecheck test: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 + strategy: + matrix: + node-version: [18.18.2] needs: init steps: - name: Check out repository uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn config get cacheFolder)" @@ -118,7 +142,7 @@ jobs: run: yarn test:ci docker: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 needs: init if: contains(github.head_ref, 'release') steps: diff --git a/.github/workflows/sync-sanity-lokalize.yml b/.github/workflows/sync-sanity-lokalize.yml index 543224259c..e4f275ce5a 100644 --- a/.github/workflows/sync-sanity-lokalize.yml +++ b/.github/workflows/sync-sanity-lokalize.yml @@ -7,11 +7,19 @@ on: jobs: sync-after-feature: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 + strategy: + matrix: + node-version: [18.18.2] steps: - name: Check out repository uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn config get cacheFolder)" diff --git a/packages/app/.env.local.example b/packages/app/.env.local.example index 49fdd2b98b..ab27d61a66 100644 --- a/packages/app/.env.local.example +++ b/packages/app/.env.local.example @@ -16,3 +16,5 @@ SANITY_PREVIEW_SECRET= # set content of version string NEXT_PUBLIC_COMMIT_ID=n/a + +NEXT_PUBLIC_PHASE=develop \ No newline at end of file diff --git a/packages/app/schema/nl/deceased_cbs.json b/packages/app/schema/nl/deceased_cbs.json index 2266a29eee..afb85c6edb 100644 --- a/packages/app/schema/nl/deceased_cbs.json +++ b/packages/app/schema/nl/deceased_cbs.json @@ -24,13 +24,13 @@ "type": "integer" }, "expected": { - "type": "integer" + "type": ["integer", "null"] }, "expected_min": { - "type": "integer" + "type": ["integer", "null"] }, "expected_max": { - "type": "integer" + "type": ["integer", "null"] }, "date_start_unix": { "type": "integer" diff --git a/packages/app/src/components/aside/menu.tsx b/packages/app/src/components/aside/menu.tsx index cfa4f5fea6..010a90dfa9 100644 --- a/packages/app/src/components/aside/menu.tsx +++ b/packages/app/src/components/aside/menu.tsx @@ -1,19 +1,21 @@ -import css from '@styled-system/css'; -import { resolveHref } from 'next/dist/shared/lib/router/router'; -import { NextRouter, useRouter } from 'next/router'; -import { ReactNode } from 'react'; -import styled from 'styled-components'; -import { UrlObject } from 'url'; -import chevronUrl from '~/assets/chevron.svg'; -import { Box } from '~/components/base'; import { Anchor, Heading } from '~/components/typography'; -import { ExpandedSidebarMap, Layout } from '~/domain/layout/logic/types'; -import { space, SpaceValue } from '~/style/theme'; -import { colors } from '@corona-dashboard/common'; +import { AsideTitle } from './title'; import { asResponsiveArray } from '~/style/utils'; +import { Box } from '~/components/base'; +import { colors } from '@corona-dashboard/common'; +import { ExpandedSidebarMap, Layout } from '~/domain/layout/logic/types'; import { Link } from '~/utils/link'; +import { NextRouter, useRouter } from 'next/router'; +import { ReactNode } from 'react'; +import { resolveHref } from 'next/dist/shared/lib/router/router'; +import { space, SpaceValue } from '~/style/theme'; +import { UrlObject } from 'url'; import { useBreakpoints } from '~/utils/use-breakpoints'; -import { AsideTitle } from './title'; +import { useCollapsible } from '~/utils/use-collapsible'; +import chevronUrl from '~/assets/chevron.svg'; +import css from '@styled-system/css'; +import styled from 'styled-components'; +import { ArchivedPath, useArchivedPaths } from '~/utils/use-archived-paths'; type Url = UrlObject | string; @@ -21,7 +23,15 @@ export function MenuRenderer({ items }: { items: ExpandedSidebarMap }) { return ( <> {items.map((x) => - 'items' in x ? ( + 'items' in x && (x.key === 'archived_metrics' || x.title === 'Gearchiveerd') ? ( + + {x.items.map((item) => ( + // item includes key, ESLint gives a false positive here + // eslint-disable-next-line react/jsx-key + + ))} + + ) : 'items' in x ? ( {x.items.map((item) => ( // item includes key, ESLint gives a false positive here @@ -45,6 +55,32 @@ export function Menu({ children, spacing }: { children: ReactNode; spacing?: Spa ); } +export function CollapsibleCategoryMenu({ title, children, icon }: { children: ReactNode; title?: string; icon: ReactNode; key: string }) { + const router = useRouter(); + const archivedPaths = useArchivedPaths(); + const collapsible = useCollapsible({ isOpen: isCurrentRouteArchivedPage(router, archivedPaths) }); + return ( + + {title && icon && ( + <> + + + + + {icon} + {title} + + {collapsible.button()} + + + + {collapsible.content({children})} + + )} + + ); +} + export function CategoryMenu({ title, children, icon }: { children: ReactNode; title?: string; icon: ReactNode }) { return ( @@ -99,6 +135,25 @@ function isActivePath(router: NextRouter, href: Url) { return currentPath === hrefPath; } +function isCurrentRouteArchivedPage(router: NextRouter, archivedPaths: ArchivedPath) { + const currentPath = (router.asPath || '/').split('?')[0]; + const code = String(router.query.code); + + if (currentPath.includes('landelijk')) { + return Object.values(archivedPaths.nl).some((archivedPathFunction) => archivedPathFunction() === currentPath); + } + + if (currentPath.includes('gemeente')) { + return Object.values(archivedPaths.gm).some((archivedPathFunction) => archivedPathFunction(code) === currentPath); + } + + if (currentPath.includes('verantwoording')) { + return Object.values(archivedPaths.dataExplained).some((archivedPathFunction) => archivedPathFunction() === currentPath); + } + + return false; +} + const Unavailable = styled.span( css({ display: 'block', diff --git a/packages/app/src/components/time-series-chart/components/series.tsx b/packages/app/src/components/time-series-chart/components/series.tsx index c19e3b9e6d..26bc9490f8 100644 --- a/packages/app/src/components/time-series-chart/components/series.tsx +++ b/packages/app/src/components/time-series-chart/components/series.tsx @@ -115,6 +115,7 @@ function SeriesUnmemoized({ seriesConfig, seriesList fillOpacity={config.fillOpacity} getX={getX} getY={getY} + bandPadding={config.bandPadding} bounds={bounds} yScale={yScale} id={id} diff --git a/packages/app/src/components/time-series-chart/logic/series.ts b/packages/app/src/components/time-series-chart/logic/series.ts index 284021bbee..8bbbd580b2 100644 --- a/packages/app/src/components/time-series-chart/logic/series.ts +++ b/packages/app/src/components/time-series-chart/logic/series.ts @@ -123,6 +123,7 @@ export interface BarSeriesDefinition extends SeriesC shortLabel?: string; color: string; fillOpacity?: number; + bandPadding?: number; } export interface BarOutOfBoundsSeriesDefinition extends SeriesCommonDefinition { diff --git a/packages/app/src/pages/index.tsx b/packages/app/src/pages/index.tsx index 228ffd1b93..a6cfd1dd32 100644 --- a/packages/app/src/pages/index.tsx +++ b/packages/app/src/pages/index.tsx @@ -16,8 +16,9 @@ import { TopicalSectionHeader } from '~/domain/topical/components/topical-sectio import { TopicalThemeHeader } from '~/domain/topical/components/topical-theme-header'; import { Languages, SiteText } from '~/locale'; import { getArticleParts, getPagePartsQuery } from '~/queries/get-page-parts-query'; +import { getThermometerStructureQuery } from '~/queries/get-thermometer-structure-query'; import { getTopicalStructureQuery } from '~/queries/get-topical-structure-query'; -import { TopicalSanityData } from '~/queries/query-types'; +import { ThermometerConfig, 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'; @@ -40,17 +41,20 @@ export const getStaticProps = createGetStaticProps( const { content } = await createGetContent<{ parts: PagePartQueryResult; topicalStructure: TopicalSanityData; + thermometerStructure: ThermometerConfig; }>((context) => { const { locale } = context; return `{ "parts": ${getPagePartsQuery('topical_page')}, - "topicalStructure": ${getTopicalStructureQuery(locale)} + "topicalStructure": ${getTopicalStructureQuery(locale)}, + "thermometerStructure": ${getThermometerStructureQuery(locale)} }`; })(context); return { content: { articles: getArticleParts(content.parts.pageParts, 'topicalPageArticles')?.articles, topicalStructure: content.topicalStructure, + thermometerStructure: content.thermometerStructure, }, }; } @@ -59,9 +63,9 @@ export const getStaticProps = createGetStaticProps( const Home = (props: StaticProps) => { const { pageText, content, lastGenerated } = props; - const { topicalStructure } = content; + const { topicalStructure, thermometerStructure } = content; - const { topicalConfig, thermometer, kpiThemes, weeklySummary, advice } = topicalStructure; + const { topicalConfig, kpiThemes, weeklySummary, advice } = topicalStructure; const { textNl, textShared } = useDynamicLokalizeTexts(pageText, selectLokalizeTexts); @@ -77,7 +81,7 @@ const Home = (props: StaticProps) => { md: `repeat(3, 1fr)`, }; - const { currentSeverityLevel, currentSeverityLevelTexts } = getThermometerSeverityLevels(thermometer); + const { currentSeverityLevel, currentSeverityLevelTexts } = getThermometerSeverityLevels(thermometerStructure); return ( diff --git a/packages/app/src/pages/landelijk/corona-thermometer.tsx b/packages/app/src/pages/landelijk/corona-thermometer.tsx index da77d04556..c358e32c7f 100644 --- a/packages/app/src/pages/landelijk/corona-thermometer.tsx +++ b/packages/app/src/pages/landelijk/corona-thermometer.tsx @@ -1,33 +1,33 @@ +import { ArticleParts, LinkParts, PagePartQueryResult, RichTextParts } from '~/types/cms'; +import { Box } from '~/components/base'; +import { ChartTile, InView, PageInformationBlock, TileList, WarningTile } from '~/components'; import { colors } from '@corona-dashboard/common'; import { Coronathermometer } from '@corona-dashboard/icons'; +import { createGetContent, getLastGeneratedDate, getLokalizeTexts } from '~/static-props/get-data'; +import { getArticleParts, getDataExplainedParts, getFaqParts, getPagePartsQuery } from '~/queries/get-page-parts-query'; +import { getPageInformationHeaderContent } from '~/utils/get-page-information-header-content'; import { GetStaticPropsContext } from 'next'; -import styled from 'styled-components'; -import { ChartTile, InView, PageInformationBlock, TileList, WarningTile } from '~/components'; +import { getThermometerEvents, getThermometerStructureQuery } from '~/queries/get-thermometer-structure-query'; +import { getThermometerSeverityLevels } from '~/utils/get-thermometer-severity-level'; +import { getTimelineRangeDates } from '~/components/severity-indicator-tile/components/timeline/logic'; +import { IndicatorLevelDescription } from '~/domain/topical/components/indicator-level-description'; +import { Languages, SiteText } from '~/locale'; +import { Layout } from '~/domain/layout/layout'; +import { NlLayout } from '~/domain/layout/nl-layout'; import { PageArticlesTile } from '~/components/articles/page-articles-tile'; -import { Box } from '~/components/base'; import { PageFaqTile } from '~/components/page-faq-tile'; -import { getTimelineRangeDates } from '~/components/severity-indicator-tile/components/timeline/logic'; -import { Timeline } from '~/components/severity-indicator-tile/components/timeline/timeline'; +import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; 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 { Layout } from '~/domain/layout/layout'; -import { NlLayout } from '~/domain/layout/nl-layout'; -import { IndicatorLevelDescription } from '~/domain/topical/components/indicator-level-description'; -import { useIntl } from '~/intl'; -import { Languages, SiteText } from '~/locale'; -import { getArticleParts, getDataExplainedParts, getFaqParts, getPagePartsQuery } from '~/queries/get-page-parts-query'; -import { getThermometerEvents, 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 { StaticProps, createGetStaticProps } from '~/static-props/create-get-static-props'; +import { ThermometerConfig } from '~/queries/query-types'; +import { Timeline } from '~/components/severity-indicator-tile/components/timeline/timeline'; +import { TimelineMarker } from '~/components/time-series-chart/components/timeline'; import { useDynamicLokalizeTexts } from '~/utils/cms/use-dynamic-lokalize-texts'; -import { getPageInformationHeaderContent } from '~/utils/get-page-information-header-content'; -import { getThermometerSeverityLevels } from '~/utils/get-thermometer-severity-level'; -import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; +import { useIntl } from '~/intl'; +import styled from 'styled-components'; const selectLokalizeTexts = (siteText: SiteText) => ({ textNl: siteText.pages.corona_thermometer_page.nl, @@ -41,12 +41,12 @@ export const getStaticProps = createGetStaticProps( async (context: GetStaticPropsContext) => { const { content } = await createGetContent<{ parts: PagePartQueryResult; - topicalStructure: TopicalSanityData; + thermometerStructure: ThermometerConfig; }>((context) => { const { locale } = context; return `{ "parts": ${getPagePartsQuery('coronathermometer_page')}, - "topicalStructure": ${getTopicalStructureQuery(locale)} + "thermometerStructure": ${getThermometerStructureQuery(locale)} }`; })(context); return { @@ -54,7 +54,7 @@ export const getStaticProps = createGetStaticProps( articles: getArticleParts(content.parts.pageParts, 'coronathermometerPageArticles'), dataExplained: getDataExplainedParts(content.parts.pageParts, 'coronathermometerPageDataExplained'), faqs: getFaqParts(content.parts.pageParts, 'coronathermometerPageFAQs'), - topicalStructure: content.topicalStructure, + thermometerStructure: content.thermometerStructure, }, }; } @@ -63,9 +63,7 @@ export const getStaticProps = createGetStaticProps( const CoronaThermometer = (props: StaticProps) => { const { pageText, content, lastGenerated } = props; - const { topicalStructure } = content; - - const { thermometer } = topicalStructure; + const { thermometerStructure } = content; const { textNl } = useDynamicLokalizeTexts(pageText, selectLokalizeTexts); @@ -78,9 +76,9 @@ const CoronaThermometer = (props: StaticProps) => { const { commonTexts } = useIntl(); const { formatDateFromSeconds } = useIntl(); - const { currentSeverityLevel, currentSeverityLevelTexts } = getThermometerSeverityLevels(thermometer); + const { currentSeverityLevel, currentSeverityLevelTexts } = getThermometerSeverityLevels(thermometerStructure); - const thermometerEvents = getThermometerEvents(thermometer.timeline.ThermometerTimelineEvents, thermometer.thermometerLevels); + const thermometerEvents = getThermometerEvents(thermometerStructure.timeline.ThermometerTimelineEvents, thermometerStructure.thermometerLevels); const lastThermometerSetDate = formatDateFromSeconds(thermometerEvents.slice(-1)[0].end, 'weekday-long'); @@ -114,7 +112,7 @@ const CoronaThermometer = (props: StaticProps) => { {hasActiveWarningTile && } - + {currentSeverityLevelTexts && ( ) => { label: currentSeverityLevelTexts.label.toLowerCase(), }) } - title={thermometer.tileTitle} + title={thermometerStructure.tileTitle} label={currentSeverityLevelTexts.label} - sourceLabel={thermometer.sourceLabel} - datesLabel={thermometer.datesLabel} - levelDescription={thermometer.levelDescription} + sourceLabel={thermometerStructure.sourceLabel} + datesLabel={thermometerStructure.datesLabel} + levelDescription={thermometerStructure.levelDescription} /> {thermometerEvents && thermometerEvents.length && ( ) => { endDate={endDate} timelineEvents={thermometerEvents} labels={{ - heading: thermometer.timeline.title, - today: thermometer.timeline.todayLabel, - tooltipCurrentEstimation: thermometer.timeline.tooltipLabel, + heading: thermometerStructure.timeline.title, + today: thermometerStructure.timeline.todayLabel, + tooltipCurrentEstimation: thermometerStructure.timeline.tooltipLabel, }} legendItems={[ { - label: thermometer.timeline.legendLabel, + label: thermometerStructure.timeline.legendLabel, shape: 'custom', shapeComponent: , }, @@ -154,10 +152,10 @@ const CoronaThermometer = (props: StaticProps) => { )} - + {SEVERITY_LEVELS_LIST.map((severityLevel, index) => { - const indicatorTexts = thermometer.thermometerLevels.find((thermometerLevel) => thermometerLevel.level === severityLevel); + const indicatorTexts = thermometerStructure.thermometerLevels.find((thermometerLevel) => thermometerLevel.level === severityLevel); return ( indicatorTexts && ( diff --git a/packages/app/src/pages/landelijk/ziekenhuizen-in-beeld.tsx b/packages/app/src/pages/landelijk/ziekenhuizen-in-beeld.tsx index cb1bf25a23..bd377480e6 100644 --- a/packages/app/src/pages/landelijk/ziekenhuizen-in-beeld.tsx +++ b/packages/app/src/pages/landelijk/ziekenhuizen-in-beeld.tsx @@ -77,6 +77,8 @@ const HospitalsAndCarePage = (props: StaticProps) => { const [hospitalBedsOccupiedOverTimeTimeframe, setHospitalBedsOccupiedOverTimeTimeframe] = useState(TimeframeOption.THIRTY_DAYS); const [intensiveCareBedsTimeframe, setIntensiveCareBedsTimeframe] = useState(TimeframeOption.THIRTY_DAYS); + const gappedBarBandPaddingOverride = 0.4; + const bedsOccupiedOverTimeToggleItems: ChartTileToggleItem[] = [ { label: textNl.hospitals.chart_beds_occupied.toggle_label, @@ -156,110 +158,112 @@ const HospitalsAndCarePage = (props: StaticProps) => { ]} /> - {selectedBedsOccupiedOverTimeChart === 'beds_occupied_covid_hospital' && ( - setSelectedBedsOccupiedOverTimeChart(value), - }} - > - + {selectedBedsOccupiedOverTimeChart === 'beds_occupied_covid_hospital' && ( + setSelectedBedsOccupiedOverTimeChart(value), }} - values={lcpsHospitalWithoutRange} - timeframe={hospitalBedsOccupiedOverTimeTimeframe} - forceLegend - seriesConfig={[ - { - type: 'line', - metricProperty: 'beds_occupied_covid', - nonInteractive: true, - hideInLegend: true, - label: textNl.hospitals.chart_beds_occupied.legend_trend_label, - color: colors.primary, - }, - { - type: 'scatter-plot', - metricProperty: 'beds_occupied_covid', - label: textNl.hospitals.chart_beds_occupied.legend_dot_label, - color: colors.primary, - }, - ]} - dataOptions={{ - timespanAnnotations: [ + > + - - )} + { + type: 'bar', + metricProperty: 'beds_occupied_covid', + label: textNl.hospitals.chart_beds_occupied.legend_dot_label, + color: colors.primary, + bandPadding: gappedBarBandPaddingOverride, + }, + ]} + dataOptions={{ + timespanAnnotations: [ + { + start: data.hospital_lcps.values[0].date_unix, + end: new Date('1 June 2020').getTime() / 1000, + label: textNl.hospitals.chart_beds_occupied.legend_inaccurate_label, + shortLabel: commonTexts.common.incomplete, + }, + ], + timelineEvents: getTimelineEvents(content.elements.timeSeries, 'hospital_lcps', 'beds_occupied_covid'), + useDatesAsRange: false, + }} + /> + + )} - {selectedBedsOccupiedOverTimeChart === 'beds_occupied_covid_icu' && ( - setSelectedBedsOccupiedOverTimeChart(value), - }} - > - setSelectedBedsOccupiedOverTimeChart(value), }} - values={lcpsICWithoutRange} - timeframe={intensiveCareBedsTimeframe} - forceLegend - seriesConfig={[ - { - type: 'line', - metricProperty: 'beds_occupied_covid', - nonInteractive: true, - hideInLegend: true, - label: textNl.icu.chart_beds_occupied.legend_trend_label, - color: colors.primary, - }, - { - type: 'scatter-plot', - metricProperty: 'beds_occupied_covid', - label: textNl.icu.chart_beds_occupied.legend_dot_label, - color: colors.primary, - }, - ]} - dataOptions={{ - timespanAnnotations: [ + > + - - )} + { + type: 'bar', + metricProperty: 'beds_occupied_covid', + label: textNl.icu.chart_beds_occupied.legend_dot_label, + color: colors.primary, + bandPadding: gappedBarBandPaddingOverride, + }, + ]} + dataOptions={{ + timespanAnnotations: [ + { + start: data.intensive_care_lcps.values[0].date_unix, + end: new Date('1 June 2020').getTime() / 1000, + label: textNl.icu.chart_beds_occupied.legend_inaccurate_labels, + shortLabel: commonTexts.common.incomplete, + }, + ], + + timelineEvents: getTimelineEvents(content.elements.timeSeries, 'intensive_care_lcps', 'beds_occupied_covid'), + useDatesAsRange: false, + }} + /> + + )} + ) => { metricProperty: 'influx_covid_patients', label: textNl.hospitals.chart_patient_influx.legend_title_trend_label, color: colors.primary, + bandPadding: gappedBarBandPaddingOverride, }, ]} dataOptions={{ @@ -353,6 +358,7 @@ const HospitalsAndCarePage = (props: StaticProps) => { metricProperty: 'influx_covid_patients', label: textNl.icu.chart_patient_influx.legend_title_trend_label, color: colors.primary, + bandPadding: gappedBarBandPaddingOverride, }, ]} dataOptions={{ diff --git a/packages/app/src/queries/get-thermometer-structure-query.ts b/packages/app/src/queries/get-thermometer-structure-query.ts new file mode 100644 index 0000000000..cbdecd0b5f --- /dev/null +++ b/packages/app/src/queries/get-thermometer-structure-query.ts @@ -0,0 +1,51 @@ +import { SeverityIndicatorTimelineEventConfig } from '~/components/severity-indicator-tile/components/timeline/timeline'; +import { SeverityLevel } from '~/components/severity-indicator-tile/types'; +import { ThermometerLevel, ThermometerTimelineEvent } from './query-types'; + +export function getThermometerStructureQuery(locale: string) { + const query = `// groq + *[_type == 'coronaThermometer' && !(_id in path('drafts.**'))][0] + { + icon, + 'title': title.${locale}, + 'tileTitle':tileTitle.${locale}, + currentLevel, + 'thermometerLevels': thermometerLevels[]->{ + 'level': level, + 'label': label.${locale}, + 'description': description.${locale}, + }, + 'datesLabel': datesLabel.${locale}, + 'levelDescription': levelDescription.${locale}, + 'sourceLabel': sourceLabel.${locale}, + 'articleReference': articleReference.${locale}, + 'collapsibleTitle': collapsibleTitle.${locale}, + 'timeline': { + 'title': timeline.title.${locale}, + 'tooltipLabel': timeline.tooltipCurrentEstimationLabel.${locale}, + 'todayLabel': timeline.todayLabel.${locale}, + 'legendLabel': timeline.legendLabel.${locale}, + 'ThermometerTimelineEvents': timeline.thermometerTimelineEvents[]->{ + 'title': title.${locale}, + 'description': description.${locale}, + level, + date, + dateEnd + }, + }, + }`; + return query; +} + +export const getThermometerEvents = (thermometerEvents: ThermometerTimelineEvent[], thermometerLevels: ThermometerLevel[]) => + thermometerEvents.map((thermometerEvent) => { + const levelDetails = thermometerLevels.find((thermometerLevel) => thermometerLevel.level === (thermometerEvent.level as SeverityLevel)) as ThermometerLevel; + + return { + title: levelDetails.label, + description: levelDetails.description, + level: levelDetails.level, + start: new Date(thermometerEvent.date).getTime() / 1000, + end: new Date(thermometerEvent.dateEnd).getTime() / 1000, + }; + }); diff --git a/packages/app/src/queries/get-topical-structure-query.ts b/packages/app/src/queries/get-topical-structure-query.ts index 1f821563a4..fa680ab6c3 100644 --- a/packages/app/src/queries/get-topical-structure-query.ts +++ b/packages/app/src/queries/get-topical-structure-query.ts @@ -1,17 +1,17 @@ -import { ThermometerLevel, ThermometerTimelineEvent } from './query-types'; import { SeverityIndicatorTimelineEventConfig } from '~/components/severity-indicator-tile/components/timeline/timeline'; import { SeverityLevel } from '~/components/severity-indicator-tile/types'; +import { ThermometerLevel, ThermometerTimelineEvent } from './query-types'; export function getTopicalStructureQuery(locale: string) { const query = `// groq { - 'topicalConfig': *[ - _type == 'topicalPageConfig' && !(_id in path('drafts.**')) + 'topicalConfig': *[ + _type == 'topicalPageConfig' && !(_id in path('drafts.**')) ][0]{ 'title': title.${locale}, 'description': description.${locale} - }, - 'weeklySummary': *[ + }, + 'weeklySummary': *[ _type == 'weeklySummary' && !(_id in path('drafts.**')) ][0]{ 'title': title.${locale}, @@ -21,15 +21,14 @@ export function getTopicalStructureQuery(locale: string) { isThermometerMetric }, }, - 'kpiThemes': *[ - _type == 'themeCollection' && !(_id in path('drafts.**')) + 'kpiThemes': *[ + _type == 'themeCollection' && !(_id in path('drafts.**')) ][0]{ 'themes': themes[]->{ 'title':title.${locale}, themeIcon, 'linksLabelMobile': labelMobile.${locale}, 'linksLabelDesktop': labelDesktop.${locale}, - 'links':links[]->{ 'cta': { 'title': cta.title.${locale}, @@ -57,37 +56,6 @@ export function getTopicalStructureQuery(locale: string) { }, }, }, - 'thermometer': *[ - _type == 'thermometer' && !(_id in path('drafts.**')) - ][0]{ - icon, - 'title': title.${locale}, - 'tileTitle':tileTitle.${locale}, - currentLevel, - 'thermometerLevels': thermometerLevels[]->{ - 'level': level, - 'label': label.${locale}, - 'description': description.${locale}, - }, - 'datesLabel': datesLabel.${locale}, - 'levelDescription': levelDescription.${locale}, - 'sourceLabel': sourceLabel.${locale}, - 'articleReference': articleReference.${locale}, - 'collapsibleTitle': collapsibleTitle.${locale}, - 'timeline': { - 'title': timeline.title.${locale}, - 'tooltipLabel': timeline.tooltipCurrentEstimationLabel.${locale}, - 'todayLabel': timeline.todayLabel.${locale}, - 'legendLabel': timeline.legendLabel.${locale}, - 'ThermometerTimelineEvents': timeline.thermometerTimelineEvents[]->{ - 'title': title.${locale}, - 'description': description.${locale}, - level, - date, - dateEnd - }, - }, - }, 'advice': *[ _type == 'advice' && !(_id in path('drafts.**')) ][0]{ diff --git a/packages/app/src/utils/use-archived-paths.ts b/packages/app/src/utils/use-archived-paths.ts new file mode 100644 index 0000000000..6e08a46616 --- /dev/null +++ b/packages/app/src/utils/use-archived-paths.ts @@ -0,0 +1,20 @@ +import { getArchivedRoutes } from '@corona-dashboard/common'; +import { useMemo } from 'react'; + +export type ArchivedPath = ReturnType; + +/** + * A hook that return a memoized archived routes instance; + * + * The archived paths are used to determine the behaviour of the + * collapsible category menu in the sidebar. + * + * @returns + */ +export function useArchivedPaths() { + return useMemo(() => { + const archivedPaths = getArchivedRoutes(); + + return archivedPaths; + }, []); +} diff --git a/packages/cms/src/lokalize/key-mutations.csv b/packages/cms/src/lokalize/key-mutations.csv index a7c6419a8a..1bc76fe8c1 100644 --- a/packages/cms/src/lokalize/key-mutations.csv +++ b/packages/cms/src/lokalize/key-mutations.csv @@ -1 +1,3 @@ timestamp,action,key,document_id,move_to +2023-12-06T14:06:27.293Z,add,pages.hospitals_and_care_page.nl.icu.chart_beds_occupied.legend_inaccurate_labels,CFKdIPVDhosWzjhr2xUv19,__ +2023-12-06T14:06:27.294Z,delete,pages.hospitals_and_care_page.nl.icu.chart_beds_occupied.legend_inaccurate_label,PKXdxxxKAnTg0F1ZCrIxVz,__ diff --git a/packages/cms/src/schemas/documents/pages/corona-thermometer/index.ts b/packages/cms/src/schemas/documents/pages/corona-thermometer/index.ts new file mode 100644 index 0000000000..c9e17fdddb --- /dev/null +++ b/packages/cms/src/schemas/documents/pages/corona-thermometer/index.ts @@ -0,0 +1,126 @@ +import { defineArrayMember, defineField, defineType } from 'sanity'; +import { IconInput } from '../../../../components/icon-input'; +import { localeStringValidation } from '../../../../studio/validation/locale-validation'; +import { SEVERITY_LEVELS_LIST } from '../../../../studio/constants'; + +export const coronaThermometer = defineType({ + name: 'coronaThermometer', + type: 'object', + title: 'Corona Thermometer', + fieldsets: [ + { + title: 'De beschrijving boven de thermometer', + name: 'description', + description: 'Klik op het label om de velden te tonen.', + options: { + collapsible: true, + collapsed: true, + }, + }, + { + title: 'Artikel referentie', + name: 'artikel-referentie', + description: 'Klik op het label om de velden te tonen.', + options: { + collapsible: true, + collapsed: true, + }, + }, + { + title: 'Titel van standen informatie', + name: 'level-information', + description: 'Klik op het label om de velden te tonen.', + options: { + collapsible: true, + collapsed: true, + }, + }, + ], + fields: [ + defineField({ + title: 'Thermometer icoon', + name: 'icon', + type: 'string', + validation: (rule) => rule.required(), + components: { + input: IconInput, + }, + }), + defineField({ + title: 'De titel boven de thermometer', + name: 'title', + type: 'localeString', + validation: localeStringValidation((rule) => rule.required()), + }), + defineField({ + title: 'De beschrijving boven de thermometer', + name: 'subTitle', + type: 'localeRichContentBlock', + fieldset: 'description', + }), + defineField({ + title: 'De titel binnen de thermometer tegel', + name: 'tileTitle', + type: 'localeString', + }), + defineField({ + title: 'Huidige stand', + name: 'currentLevel', + type: 'number', + options: { + list: SEVERITY_LEVELS_LIST, + layout: 'dropdown', + }, + validation: (rule) => rule.required(), + }), + defineField({ + title: 'Standen', + name: 'thermometerLevels', + type: 'array', + of: [defineArrayMember({ type: 'reference', to: { type: 'thermometerLevel' } })], + validation: (rule) => rule.required().min(1), + }), + defineField({ + title: 'Datum tekst', + description: 'Van wanneer was deze stand', + name: 'datesLabel', + type: 'localeString', + }), + defineField({ + title: 'Huidige stand omschrijving', + description: 'De omschrijving specifiek voor de huidige thermometer stand bij de trendIcon', + name: 'levelDescription', + type: 'localeText', + validation: (rule) => rule.required(), + }), + defineField({ + title: 'Bron tekst', + name: 'sourceLabel', + type: 'localeString', + }), + defineField({ + title: 'Artikel referentie', + name: 'articleReference', + type: 'localeRichContentBlock', + fieldset: 'artikel-referentie', + }), + defineField({ + title: 'Titel van standen sectie', + name: 'collapsibleTitle', + type: 'localeString', + validation: localeStringValidation((rule) => rule.required()), + }), + defineField({ + title: 'Titel van standen informatie', + name: 'trendIcon', + type: 'thermometerTrendIcon', + fieldset: 'level-information', + }), + defineField({ + title: 'Tijdlijn', + name: 'timeline', + type: 'thermometerTimeline', + validation: (rule) => rule.required(), + }), + ], +}); diff --git a/packages/cms/src/schemas/documents/pages/homepage/thermometer-level.ts b/packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-level.ts similarity index 100% rename from packages/cms/src/schemas/documents/pages/homepage/thermometer-level.ts rename to packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-level.ts index 9829ccda26..bc8bdbbfbc 100644 --- a/packages/cms/src/schemas/documents/pages/homepage/thermometer-level.ts +++ b/packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-level.ts @@ -1,6 +1,6 @@ import { defineField, defineType } from 'sanity'; -import { SEVERITY_LEVELS_LIST, thermometerLevelPreviewMedia } from '../../../../studio/constants'; import { localeStringValidation } from '../../../../studio/validation/locale-validation'; +import { SEVERITY_LEVELS_LIST, thermometerLevelPreviewMedia } from '../../../../studio/constants'; export const thermometerLevel = defineType({ type: 'document', diff --git a/packages/cms/src/schemas/documents/pages/homepage/thermometer-timeline-event.ts b/packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-timeline-event.ts similarity index 100% rename from packages/cms/src/schemas/documents/pages/homepage/thermometer-timeline-event.ts rename to packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-timeline-event.ts index 9ba59e152f..b81b290db3 100644 --- a/packages/cms/src/schemas/documents/pages/homepage/thermometer-timeline-event.ts +++ b/packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-timeline-event.ts @@ -1,5 +1,5 @@ -import { defineField, defineType } from 'sanity'; import { DATE_FORMAT, SEVERITY_LEVELS_LIST, thermometerLevelPreviewMedia } from '../../../../studio/constants'; +import { defineField, defineType } from 'sanity'; export const thermometerTimelineEvent = defineType({ name: 'thermometerTimelineEvent', diff --git a/packages/cms/src/schemas/documents/pages/homepage/thermometer-timeline.ts b/packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-timeline.ts similarity index 100% rename from packages/cms/src/schemas/documents/pages/homepage/thermometer-timeline.ts rename to packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-timeline.ts diff --git a/packages/cms/src/schemas/documents/pages/homepage/thermometer-trend-icon.ts b/packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-trend-icon.ts similarity index 100% rename from packages/cms/src/schemas/documents/pages/homepage/thermometer-trend-icon.ts rename to packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer-trend-icon.ts diff --git a/packages/cms/src/schemas/documents/pages/homepage/thermometer.ts b/packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer.ts similarity index 100% rename from packages/cms/src/schemas/documents/pages/homepage/thermometer.ts rename to packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer.ts index 688f45a361..123e7ee2d7 100644 --- a/packages/cms/src/schemas/documents/pages/homepage/thermometer.ts +++ b/packages/cms/src/schemas/documents/pages/corona-thermometer/thermometer.ts @@ -1,7 +1,7 @@ import { defineArrayMember, defineField, defineType } from 'sanity'; import { IconInput } from '../../../../components/icon-input'; -import { SEVERITY_LEVELS_LIST } from '../../../../studio/constants'; import { localeStringValidation } from '../../../../studio/validation/locale-validation'; +import { SEVERITY_LEVELS_LIST } from '../../../../studio/constants'; export const thermometer = defineType({ type: 'object', diff --git a/packages/cms/src/schemas/index.ts b/packages/cms/src/schemas/index.ts index e34dd3613c..67d476d54f 100644 --- a/packages/cms/src/schemas/index.ts +++ b/packages/cms/src/schemas/index.ts @@ -1,53 +1,54 @@ -import { article } from './documents/article'; -import { lokalizeText } from './documents/lokalize-text'; -import { pageIdentifier } from './documents/page-identifier'; -import { articles } from './documents/page-parts/articles'; -import { dataExplained as dataExplainedParts } from './documents/page-parts/data-explained'; -import { faq as faqParts } from './documents/page-parts/faq'; -import { highlights } from './documents/page-parts/highlights'; -import { links } from './documents/page-parts/links'; import { about } from './documents/pages/about'; import { accessibility } from './documents/pages/accessibility'; +import { advice } from './documents/pages/homepage/advice'; +import { article } from './documents/article'; +import { articles } from './documents/page-parts/articles'; +import { block } from './locale/block'; import { contact } from './documents/pages/contact'; import { contactPageGroup } from './documents/pages/contact/group'; import { contactPageGroupItem } from './documents/pages/contact/item'; import { contactPageItemLink } from './documents/pages/contact/link'; +import { coronaThermometer } from './documents/pages/corona-thermometer'; import { dataExplained } from './documents/pages/data-explained'; +import { dataExplained as dataExplainedParts } from './documents/page-parts/data-explained'; import { dataExplainedGroups } from './documents/pages/data-explained/groups'; import { dataExplainedItem } from './documents/pages/data-explained/item'; import { faq } from './documents/pages/faq'; +import { faq as faqParts } from './documents/page-parts/faq'; import { faqGroups } from './documents/pages/faq/groups'; import { faqItem } from './documents/pages/faq/item'; +import { highlights } from './documents/page-parts/highlights'; import { homepage } from './documents/pages/homepage'; -import { advice } from './documents/pages/homepage/advice'; +import { image } from './locale/image'; +import { inlineBlock } from './objects/inline-block'; +import { inlineCollapsible } from './objects/inline-collapsible'; +import { link } from './objects/link'; +import { links } from './documents/page-parts/links'; +import { linkType } from './objects/link-type'; +import { lokalizeText } from './documents/lokalize-text'; +import { notFound } from './documents/pages/not-found'; +import { notFoundItem } from './documents/pages/not-found/item'; +import { notFoundLink } from './documents/pages/not-found/link'; +import { pageIdentifier } from './documents/page-identifier'; +import { richContentBlock } from './locale/rich-content-block'; +import { string } from './locale/string'; import { summary } from './documents/pages/homepage/summary'; import { summaryItem } from './documents/pages/homepage/summary-item'; +import { text } from './locale/text'; import { theme } from './documents/pages/homepage/theme'; import { themeCollection } from './documents/pages/homepage/theme-collection'; import { themeLink } from './documents/pages/homepage/theme-link'; import { themeTile } from './documents/pages/homepage/theme-tile'; import { themeTileConfig } from './documents/pages/homepage/theme-tile-config'; -import { thermometer } from './documents/pages/homepage/thermometer'; -import { thermometerLevel } from './documents/pages/homepage/thermometer-level'; -import { thermometerTimeline } from './documents/pages/homepage/thermometer-timeline'; -import { thermometerTimelineEvent } from './documents/pages/homepage/thermometer-timeline-event'; -import { thermometerTrendIcon } from './documents/pages/homepage/thermometer-trend-icon'; -import { notFound } from './documents/pages/not-found'; -import { notFoundItem } from './documents/pages/not-found/item'; -import { notFoundLink } from './documents/pages/not-found/link'; -import { trendIcon } from './documents/trend-icon'; -import { timeSeries } from './elements/time-series'; +import { thermometer } from './documents/pages/corona-thermometer/thermometer'; +import { thermometerLevel } from './documents/pages/corona-thermometer/thermometer-level'; +import { thermometerTimeline } from './documents/pages/corona-thermometer/thermometer-timeline'; +import { thermometerTimelineEvent } from './documents/pages/corona-thermometer/thermometer-timeline-event'; +import { thermometerTrendIcon } from './documents/pages/corona-thermometer/thermometer-trend-icon'; import { timelineEvent } from './elements/timeline-event'; import { timelineEventCollection } from './elements/timeline-event-collection'; -import { block } from './locale/block'; -import { image } from './locale/image'; -import { richContentBlock } from './locale/rich-content-block'; -import { string } from './locale/string'; -import { text } from './locale/text'; -import { inlineBlock } from './objects/inline-block'; -import { inlineCollapsible } from './objects/inline-collapsible'; -import { link } from './objects/link'; -import { linkType } from './objects/link-type'; +import { timeSeries } from './elements/time-series'; +import { trendIcon } from './documents/trend-icon'; const localeSpecificSchemas = [block, richContentBlock, string, text, image]; const richContentSchemas = [inlineBlock, inlineCollapsible]; @@ -57,6 +58,7 @@ const documentSchemas = [ contactPageGroup, contactPageGroupItem, contactPageItemLink, + coronaThermometer, dataExplainedGroups, dataExplainedItem, faqGroups, diff --git a/packages/cms/src/studio/desk-structure/corona-thermometer-structure-item.ts b/packages/cms/src/studio/desk-structure/corona-thermometer-structure-item.ts new file mode 100644 index 0000000000..d9c6f2d2bd --- /dev/null +++ b/packages/cms/src/studio/desk-structure/corona-thermometer-structure-item.ts @@ -0,0 +1,10 @@ +import { BsThermometer } from 'react-icons/bs'; +import { StructureBuilder } from 'sanity/desk'; + +export const coronaThermometerStructureItem = (S: StructureBuilder) => { + return S.listItem() + .id('coronaThermometerPage') + .title('Thermometer') + .icon(BsThermometer) + .child(S.document().title('Corona Thermometer').schemaType('coronaThermometer').documentId('coronaThermometer')); +}; diff --git a/packages/cms/src/studio/desk-structure/data-explained-structure-item.ts b/packages/cms/src/studio/desk-structure/data-explained-structure-item.ts index efbcd4d9c2..ed74e3b62c 100644 --- a/packages/cms/src/studio/desk-structure/data-explained-structure-item.ts +++ b/packages/cms/src/studio/desk-structure/data-explained-structure-item.ts @@ -1,6 +1,6 @@ +import { addStructureItem } from '../utils'; import { Bs123, BsBookHalf } from 'react-icons/bs'; import { StructureBuilder } from 'sanity/desk'; -import { addStructureItem } from '../utils'; export const dataExplainedStructureItem = (S: StructureBuilder) => { return S.listItem() diff --git a/packages/cms/src/studio/desk-structure/desk-structure.ts b/packages/cms/src/studio/desk-structure/desk-structure.ts index 7694f28a7c..b9fd74213c 100644 --- a/packages/cms/src/studio/desk-structure/desk-structure.ts +++ b/packages/cms/src/studio/desk-structure/desk-structure.ts @@ -1,7 +1,7 @@ -import { BsInfoCircle, BsMailbox, BsUniversalAccessCircle } from 'react-icons/bs'; -import { StructureBuilder, StructureResolverContext } from 'sanity/desk'; import { addStructureItem } from '../utils'; import { articlesStructureItem } from './articles-structure-item'; +import { BsInfoCircle, BsMailbox, BsUniversalAccessCircle, BsBarChart } from 'react-icons/bs'; +import { coronaThermometerStructureItem } from './corona-thermometer-structure-item'; import { dataExplainedStructureItem } from './data-explained-structure-item'; import { elementsStructureItem } from './elements-structure-item'; import { faqStructureItem } from './faq-structure-item'; @@ -10,28 +10,50 @@ import { lokalizeStructureItem } from './lokalize-structure-item'; import { notFoundPageStructureItem } from './not-found-page-structure-item'; import { pagePartsStructureItem } from './page-parts-structure-item'; import { pagesStructureItem } from './pages-structure-item'; +import { StructureBuilder, StructureResolverContext } from 'sanity/desk'; export const deskStructure = (S: StructureBuilder, context: StructureResolverContext) => S.list() .id('content') .title('Content') .items([ + homepageStructureItem(S), + S.divider(), pagesStructureItem(S, context), - lokalizeStructureItem(S, context), - elementsStructureItem(S, context), - addStructureItem(S, BsInfoCircle, 'Over dit dashboard', 'overDitDashboard'), - faqStructureItem(S), - dataExplainedStructureItem(S), - addStructureItem(S, BsUniversalAccessCircle, 'Toegankelijkheid', 'toegankelijkheid'), - addStructureItem(S, BsMailbox, 'Contact', 'contact'), - + S.divider(), + S.listItem() + .id('ContentPage') + .title("Dashboard content pagina's") + .child( + S.list() + .title("Pagina's") + .items([ + notFoundPageStructureItem(S), + addStructureItem(S, BsInfoCircle, 'Over dit dashboard', 'overDitDashboard'), + faqStructureItem(S), + addStructureItem(S, BsMailbox, 'Contact', 'contact'), + addStructureItem(S, BsUniversalAccessCircle, 'Toegankelijkheid', 'toegankelijkheid'), + dataExplainedStructureItem(S), + ]) + ), S.divider(), - homepageStructureItem(S), + pagePartsStructureItem(S), - notFoundPageStructureItem(S), + S.divider(), + S.listItem() + .id('GraphConfigs') + .title('Visuals configuratie') + .icon(BsBarChart) + .child( + S.list() + .title('Configuratie') + .items([coronaThermometerStructureItem(S), elementsStructureItem(S, context)]) + ), + S.divider(), + lokalizeStructureItem(S, context), + S.divider(), articlesStructureItem(S), - - pagePartsStructureItem(S), + S.divider(), ]); diff --git a/packages/cms/src/studio/desk-structure/elements-structure-item.ts b/packages/cms/src/studio/desk-structure/elements-structure-item.ts index d063070325..7add465f28 100644 --- a/packages/cms/src/studio/desk-structure/elements-structure-item.ts +++ b/packages/cms/src/studio/desk-structure/elements-structure-item.ts @@ -1,7 +1,7 @@ -import uniq from 'lodash/uniq'; import { BsBarChart, BsFolder, BsTags } from 'react-icons/bs'; import { map } from 'rxjs/operators'; import { StructureBuilder, StructureResolverContext } from 'sanity/desk'; +import uniq from 'lodash/uniq'; export const elementsStructureItem = (S: StructureBuilder, context: StructureResolverContext) => { const { documentStore } = context; diff --git a/packages/cms/src/studio/desk-structure/faq-structure-item.ts b/packages/cms/src/studio/desk-structure/faq-structure-item.ts index 5e92dde7d6..0c7a6504f2 100644 --- a/packages/cms/src/studio/desk-structure/faq-structure-item.ts +++ b/packages/cms/src/studio/desk-structure/faq-structure-item.ts @@ -1,6 +1,6 @@ +import { addStructureItem } from '../utils'; import { BsBookHalf, BsQuestionCircle } from 'react-icons/bs'; import { StructureBuilder } from 'sanity/desk'; -import { addStructureItem } from '../utils'; export const faqStructureItem = (S: StructureBuilder) => { return S.listItem() diff --git a/packages/cms/src/studio/desk-structure/homepage-structure-item.ts b/packages/cms/src/studio/desk-structure/homepage-structure-item.ts index 90541d4a38..389ee879f1 100644 --- a/packages/cms/src/studio/desk-structure/homepage-structure-item.ts +++ b/packages/cms/src/studio/desk-structure/homepage-structure-item.ts @@ -1,6 +1,6 @@ -import { BsCardList, BsCardText, BsGear, BsHouse, BsThermometer } from 'react-icons/bs'; -import { StructureBuilder } from 'sanity/desk'; import { addStructureItem } from '../utils'; +import { BsCardList, BsCardText, BsGear, BsHouse } from 'react-icons/bs'; +import { StructureBuilder } from 'sanity/desk'; export const homepageStructureItem = (S: StructureBuilder) => { return S.listItem() @@ -13,7 +13,6 @@ export const homepageStructureItem = (S: StructureBuilder) => { .items([ addStructureItem(S, BsGear, 'Samenvattingspagina configuratie', 'topicalPageConfig'), addStructureItem(S, BsCardList, 'Weeksamenvatting', 'weeklySummary'), - addStructureItem(S, BsThermometer, 'Thermometer', 'thermometer'), addStructureItem(S, BsCardText, "KPI thema's en tegels", 'themeCollection'), addStructureItem(S, BsCardText, 'Adviezen', 'advice'), ]) diff --git a/packages/cms/src/studio/desk-structure/lokalize-structure-item.ts b/packages/cms/src/studio/desk-structure/lokalize-structure-item.ts index 31de543672..1e43dfbd11 100644 --- a/packages/cms/src/studio/desk-structure/lokalize-structure-item.ts +++ b/packages/cms/src/studio/desk-structure/lokalize-structure-item.ts @@ -1,7 +1,7 @@ -import uniq from 'lodash/uniq'; import { BsFolder, BsTranslate } from 'react-icons/bs'; import { map } from 'rxjs/operators'; import { StructureBuilder, StructureResolverContext } from 'sanity/desk'; +import uniq from 'lodash/uniq'; export const lokalizeStructureItem = (S: StructureBuilder, context: StructureResolverContext) => { const { documentStore } = context; @@ -9,7 +9,7 @@ export const lokalizeStructureItem = (S: StructureBuilder, context: StructureRes return ( S.listItem() .id('lokalize') - .title('Lokalize') + .title('Lokalize keys') .icon(BsTranslate) // @ts-expect-error - The below code works like a charm and creates list items accordingly. // The old CMS would also face challenges here, but does not report this as such given the TS implementation. diff --git a/packages/cms/src/studio/desk-structure/pages-structure-item.ts b/packages/cms/src/studio/desk-structure/pages-structure-item.ts index e4a0495826..430ad9c06c 100644 --- a/packages/cms/src/studio/desk-structure/pages-structure-item.ts +++ b/packages/cms/src/studio/desk-structure/pages-structure-item.ts @@ -19,7 +19,7 @@ export const pagesStructureItem = (S: StructureBuilder, context: StructureResolv return ( S.listItem() .id('dashboard-paginas') - .title("Dashboard pagina's") + .title("Dashboard data pagina's") .icon(BsBook) // @ts-expect-error - The below code works like a charm and creates list items accordingly. // The old CMS would also face challenges here, but does not report this as such given the TS implementation. diff --git a/packages/common/src/data/reverse-router.ts b/packages/common/src/data/reverse-router.ts index 74caf6a4dc..b016029985 100644 --- a/packages/common/src/data/reverse-router.ts +++ b/packages/common/src/data/reverse-router.ts @@ -49,3 +49,48 @@ export function getReverseRouter(isMobile: boolean) { return reverseRouter; } + +export function getArchivedRoutes() { + /** + * Add the same keys that are part of the archived_metrics array + * in the nl-layout and gm-layout files + */ + + const archivedPaths = { + nl: { + nursing_home_care: () => '/landelijk/kwetsbare-groepen-70-plussers', + reproduction_number: () => '/landelijk/reproductiegetal', + corona_thermometer: () => '/landelijk/corona-thermometer', + compliance: () => '/landelijk/gedrag', + positive_tests: () => '/landelijk/positieve-testen', + disabled_care: () => '/landelijk/gehandicaptenzorg', + elderly_at_home: () => '/landelijk/thuiswonende-70-plussers', + coronamelder_app: () => '/landelijk/coronamelder', + infectious_people: () => '/landelijk/besmettelijke-mensen', + general_practitioner_suspicions: () => '/landelijk/klachten-bij-huisartsen', + }, + + gm: { + positive_tests: (code: string) => `/gemeente/${code}/positieve-testen`, + mortality: (code: string) => `/gemeente/${code}/sterfte`, + }, + + dataExplained: { + nursing_home_care: () => '/verantwoording/kwetsbare-groepen-en-70-plussers', + pressure_on_health_care: () => '/verantwoording/druk-op-de-zorg-verzuimcijfers-nza', + reproduction_number: () => '/verantwoording/reproductiegetal', + compliance: () => '/verantwoording/gedrag', + positive_tests: () => '/verantwoording/positieve-testen', + mortality: () => '/verantwoording/sterfte-rivm', + disabled_care: () => '/verantwoording/gehandicaptenzorg', + elderly_at_home: () => '/verantwoording/thuiswonende-70-plussers', + contact_research: () => '/verantwoording/bron-en-contactonderzoek-ggd-en', + coronamelder_app: () => '/verantwoording/coronamelder', + vaccinations: () => '/verantwoording/leveringen-en-voorraden-vaccins-and-vaccinatiebereidheid', + contagious_people: () => '/verantwoording/besmettelijke-mensen', + patients_with_complaints: () => '/verantwoording/patienten-met-klachten-bij-de-huisarts', + }, + } as const; + + return archivedPaths; +} diff --git a/packages/common/src/types/data.ts b/packages/common/src/types/data.ts index 8ea2185bf6..218c4c5cc0 100644 --- a/packages/common/src/types/data.ts +++ b/packages/common/src/types/data.ts @@ -1192,9 +1192,9 @@ export interface NlDeceasedCbs { } export interface NlDeceasedCbsValue { registered: number; - expected: number; - expected_min: number; - expected_max: number; + expected: number | null; + expected_min: number | null; + expected_max: number | null; date_start_unix: number; date_end_unix: number; date_of_insertion_unix: number;