diff --git a/packages/app/src/components/article-teaser.tsx b/packages/app/src/components/article-teaser.tsx deleted file mode 100644 index 16e95e1ce5..0000000000 --- a/packages/app/src/components/article-teaser.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import css from '@styled-system/css'; -import { ReactNode } from 'react'; -import styled from 'styled-components'; -import { ArrowIconRight } from '~/components/arrow-icon'; -import { useIntl } from '~/intl'; -import { spacingStyle } from '~/style/functions/spacing'; -import { Article, Block, ImageBlock } from '~/types/cms'; -import { Link } from '~/utils/link'; -import { BackgroundImage } from './background-image'; -import { Box } from './base'; -import { Anchor, Heading, Text, BoldText } from './typography'; - -export type ArticleSummary = Pick; - -type ArticleTeaserProps = { - title: string; - slug: string; - summary: Block; - cover: ImageBlock; - coverSizes: string[][]; -}; - -export function ArticleTeaser(props: ArticleTeaserProps) { - const { title, slug, summary, cover, coverSizes } = props; - const { commonTexts } = useIntl(); - - return ( - - - {cover.asset && ( - - - - )} - - - {title} - - {summary} - - - - - ); -} - -const ZoomContainer = styled(ZoomContainerUnstyled)``; - -function ZoomContainerUnstyled({ children, height, className }: { height: string; children: ReactNode; className?: string }) { - return ( - - {children} - - ); -} - -const StyledArticleTeaser = styled(Anchor)( - css({ - minHeight: '26rem', - overflow: 'hidden', - textDecoration: 'none', - color: 'black', - ...spacingStyle(3), - - [`${ZoomContainer}, ${Heading}`]: { - transitionProperty: 'transform, color', - transitionDuration: '500ms, 250ms', - transitionTimingFunction: 'ease-out', - willChange: 'transform, color', - }, - - '&:hover, &:focus': { - [ZoomContainer]: { - transitionDuration: '200ms, 250ms', - transitionTimingFunction: 'ease-in-out', - transform: 'scale(1.04)', - }, - [Heading]: { color: 'blue8' }, - }, - }) -); - -function Arrow() { - return ( - - - - ); -} diff --git a/packages/app/src/components/article-detail.tsx b/packages/app/src/components/articles/article-detail.tsx similarity index 85% rename from packages/app/src/components/article-detail.tsx rename to packages/app/src/components/articles/article-detail.tsx index 8e4004ae4e..5b15e62cc4 100644 --- a/packages/app/src/components/article-detail.tsx +++ b/packages/app/src/components/articles/article-detail.tsx @@ -1,22 +1,24 @@ +import { colors } from '@corona-dashboard/common'; import { css } from '@styled-system/css'; import styled from 'styled-components'; import { ArrowIconLeft } from '~/components/arrow-icon'; import { Box } from '~/components/base'; import { ContentBlock } from '~/components/cms/content-block'; -import { Heading, InlineText, Anchor } from '~/components/typography'; +import { Anchor, Heading, InlineText } from '~/components/typography'; import { ArticleCategoryType } from '~/domain/topical/common/categories'; import { useIntl } from '~/intl'; import { SiteText } from '~/locale'; +import { space } from '~/style/theme'; import { Article } from '~/types/cms'; +import { replaceComponentsInText } from '~/utils'; import { Link } from '~/utils/link'; import { mergeAdjacentKpiBlocks } from '~/utils/merge-adjacent-kpi-blocks'; -import { ContentImage } from './cms/content-image'; -import { RichContent } from './cms/rich-content'; -import { LinkWithIcon } from './link-with-icon'; -import { PublicationDate } from './publication-date'; import { useBreakpoints } from '~/utils/use-breakpoints'; -import { colors } from '@corona-dashboard/common'; -import { space } from '~/style/theme'; +import { ContentImage } from '../cms/content-image'; +import { RichContent } from '../cms/rich-content'; +import { LinkWithIcon } from '../link-with-icon'; +import { PublicationDate } from '../publication-date'; + interface ArticleDetailProps { article: Article; text: SiteText['pages']['topical_page']['shared']; @@ -43,9 +45,19 @@ export function ArticleDetail({ article, text }: ArticleDetailProps) { {article.title} - + + - + + {article.updatedDate && ( + <> + + | + + {replaceComponentsInText(commonTexts.article_detail.articles_updated_date, { date: })} + + )} + diff --git a/packages/app/src/components/articles/article-teaser.tsx b/packages/app/src/components/articles/article-teaser.tsx new file mode 100644 index 0000000000..be920ddf1e --- /dev/null +++ b/packages/app/src/components/articles/article-teaser.tsx @@ -0,0 +1,137 @@ +import { colors } from '@corona-dashboard/common'; +import { ChevronRight } from '@corona-dashboard/icons'; +import styled from 'styled-components'; +import { useIntl } from '~/intl'; +import { mediaQueries, radii, space } from '~/style/theme'; +import { Article, ArticleMainCategory, ArticlePublishedDate, ArticleUpdatedDate, Block, ImageBlock } from '~/types/cms'; +import { Link } from '~/utils/link'; +import { BackgroundImage } from '../background-image'; +import { Box } from '../base'; +import { Anchor, Heading, Text } from '../typography'; +import { ArticleUpdateOrPublishingDate } from './article-update-or-publishing-date'; + +export type ArticleSummary = Pick; + +interface ArticleTeaserImageProps { + image: ImageBlock; + sizes: string[][]; +} + +const ArticleTeaserImage = ({ image, sizes }: ArticleTeaserImageProps) => { + return ( +
+ +
+ ); +}; + +interface ArticleTeaserProps { + cover: ImageBlock; + coverSizes: string[][]; + mainCategory: ArticleMainCategory | null; + publicationDate: ArticlePublishedDate; + slug: string; + summary: Block; + title: string; + updatedDate: ArticleUpdatedDate; +} + +export const ArticleTeaser = ({ title, slug, summary, cover, coverSizes, mainCategory, publicationDate, updatedDate }: ArticleTeaserProps) => { + const { commonTexts } = useIntl(); + + return ( +
+ + + {cover.asset && } + + + {mainCategory && {commonTexts.article_teaser.categories[mainCategory]}} + + + {title} + + + + {summary} + + + + + + + + +
+ ); +}; + +const ArticleTeaserContent = styled.div` + display: flex; + flex-direction: column; + height: 100%; + padding: ${space[3]} ${space[3]} 0 ${space[3]}; + + & > * { + margin-bottom: ${space[3]}; + } +`; + +const ArticleTeaserCard = styled(Anchor)` + border: 1px solid ${colors.gray3}; + border-radius: ${radii[2]}px; + color: ${colors.black}; + cursor: pointer; + display: flex; + flex-direction: column; + height: 100%; + margin-bottom: ${space[4]}; + min-height: 26rem; + overflow: hidden; + text-decoration: none; + + @media ${mediaQueries.xs} { + margin-bottom: 0; + } + + .article-teaser-image { + flex-shrink: 0; + height: 200px; + overflow: hidden; + position: relative; + } + + .article-teaser-image, + ${Heading} { + transition: transform 500ms, color 250ms ease-out; + will-change: transform, color; + } + + &:hover, + &:focus { + .article-teaser-image { + transform: scale(1.04); + transition: transform 200ms, color 250ms ease-in-out; + } + + ${Heading} { + color: ${colors.blue8}; + } + } +`; + +const ArticleCTA = styled.strong` + align-items: center; + color: ${colors.blue8}; + display: flex; + justify-content: end; + + svg { + height: 10px; + margin: 3px 3px 0; + width: 10px; + } +`; diff --git a/packages/app/src/components/articles/article-update-or-publishing-date.tsx b/packages/app/src/components/articles/article-update-or-publishing-date.tsx new file mode 100644 index 0000000000..18ff183d41 --- /dev/null +++ b/packages/app/src/components/articles/article-update-or-publishing-date.tsx @@ -0,0 +1,37 @@ +import { colors } from '@corona-dashboard/common'; +import { useIntl } from '~/intl'; +import { ArticleMainCategory, ArticlePublishedDate, ArticleUpdatedDate } from '~/types/cms'; +import { replaceComponentsInText } from '~/utils/replace-components-in-text'; +import { Box } from '../base/box'; +import { PublicationDate } from '../publication-date'; +import { InlineText } from '../typography'; +import { getDateToUse } from './logic/get-date-to-use'; + +interface ArticlePublishingDateProps { + mainCategory: ArticleMainCategory | null; + publishedDate: ArticlePublishedDate; + updatedDate: ArticleUpdatedDate; +} + +export const ArticleUpdateOrPublishingDate = ({ publishedDate, updatedDate, mainCategory }: ArticlePublishingDateProps) => { + const { commonTexts } = useIntl(); + const { publishedOrUpdatedDate, isUpdatedAfterPublishing } = getDateToUse(publishedDate, updatedDate, mainCategory); + + if (isUpdatedAfterPublishing) { + return ( + + + {replaceComponentsInText(commonTexts.article_teaser.articles_updated_date, { + date: , + })} + + + ); + } + + return ( + + + + ); +}; diff --git a/packages/app/src/components/articles/articles-list.tsx b/packages/app/src/components/articles/articles-list.tsx new file mode 100644 index 0000000000..82131f1087 --- /dev/null +++ b/packages/app/src/components/articles/articles-list.tsx @@ -0,0 +1,88 @@ +import { colors } from '@corona-dashboard/common'; +import styled from 'styled-components'; +import { ArticleSummary, ArticleTeaser } from '~/components/articles/article-teaser'; +import { Box } from '~/components/base'; +import { BoldText } from '~/components/typography'; +import { ArticleCategoryType, allPossibleArticleCategories } from '~/domain/topical/common/categories'; +import { useIntl } from '~/intl'; +import { mediaQueries, space } from '~/style/theme'; +import { replaceVariablesInText } from '~/utils'; +import { getCategories } from './logic/get-categories'; +import { getDateToUse } from './logic/get-date-to-use'; + +interface ArticlesListProps { + articleList: ArticleSummary[]; + currentCategory: ArticleCategoryType; +} + +export const ArticlesList = ({ articleList, currentCategory }: ArticlesListProps) => { + const { commonTexts } = useIntl(); + + const articleListPerCategory = articleList.filter((item) => { + const categories = getCategories(item); + return categories.includes(currentCategory); + }); + + const articleListForDisplay = currentCategory === allPossibleArticleCategories[0] ? articleList : articleListPerCategory; + + // Articles are grouped by year. + const articleListPerYear = articleListForDisplay.reduce((object: Record, currentArticle) => { + const { publicationDate, updatedDate, mainCategory } = currentArticle; + const { publishedOrUpdatedDate } = getDateToUse(publicationDate, updatedDate, mainCategory); + const yearOfPublishingOrUpdate = new Date(publishedOrUpdatedDate).getFullYear(); + + // Create a key for a given year if it does not already contain that key. + if (!Object.hasOwnProperty.call(object, yearOfPublishingOrUpdate)) { + object[yearOfPublishingOrUpdate] = []; + } + + object[yearOfPublishingOrUpdate].push(currentArticle); + + return object; + }, {}); + + const articleTeasers = Object.keys(articleListPerYear) + // Articles list sorted by year to show the latest year first. + .sort((a, b) => parseFloat(b) - parseFloat(a)) + .map((yearKey, index) => ( +
+ + {replaceVariablesInText(commonTexts.article_list.articles_per_year, { year: yearKey })} + + + + {articleListPerYear[yearKey].map((article) => ( + + ))} + +
+ )); + + return ( + + {articleTeasers} + + ); +}; + +const ArticlesGrid = styled.div` + @media ${mediaQueries.sm} { + display: grid; + gap: ${space[4]}; + grid-template-columns: repeat(3, 1fr); + padding-inline: ${space[1]}; + } +`; diff --git a/packages/app/src/components/articles/logic/get-categories.ts b/packages/app/src/components/articles/logic/get-categories.ts new file mode 100644 index 0000000000..5cea4e2e9d --- /dev/null +++ b/packages/app/src/components/articles/logic/get-categories.ts @@ -0,0 +1,3 @@ +import { ArticleSummary } from '../article-teaser'; + +export const getCategories = (item: ArticleSummary) => [...(item.categories && item.categories.length ? item.categories : []), item.mainCategory ? item.mainCategory : '']; diff --git a/packages/app/src/components/articles/logic/get-date-to-use.ts b/packages/app/src/components/articles/logic/get-date-to-use.ts new file mode 100644 index 0000000000..a4b41d6c89 --- /dev/null +++ b/packages/app/src/components/articles/logic/get-date-to-use.ts @@ -0,0 +1,19 @@ +import { ArticleMainCategory, ArticlePublishedDate, ArticleUpdatedDate } from '~/types/cms'; + +export const getDateToUse = (publishedDate: ArticlePublishedDate, updatedDate: ArticleUpdatedDate, mainCategory: ArticleMainCategory | null) => { + if (!updatedDate || mainCategory === 'news') { + return { + publishedOrUpdatedDate: publishedDate, + isUpdatedAfterPublishing: false, + }; + } + + const dateOfUpdate = new Date(updatedDate); + const dateOfPublishing = new Date(publishedDate); + const isUpdatedAfterPublishing = dateOfUpdate > dateOfPublishing; + + return { + publishedOrUpdatedDate: mainCategory && mainCategory === 'knowledge' && isUpdatedAfterPublishing ? updatedDate : publishedDate, + isUpdatedAfterPublishing, + }; +}; diff --git a/packages/app/src/components/page-articles-tile.tsx b/packages/app/src/components/articles/page-articles-tile.tsx similarity index 72% rename from packages/app/src/components/page-articles-tile.tsx rename to packages/app/src/components/articles/page-articles-tile.tsx index f3b2fb4f41..ec80b2a0da 100644 --- a/packages/app/src/components/page-articles-tile.tsx +++ b/packages/app/src/components/articles/page-articles-tile.tsx @@ -1,23 +1,22 @@ import { colors } from '@corona-dashboard/common'; +import { ChevronRight } from '@corona-dashboard/icons'; +import styled, { css } from 'styled-components'; +import { useIntl } from '~/intl'; import { getImageProps } from '~/lib/sanity'; import { fontWeights, mediaQueries, radii, space } from '~/style/theme'; -import { Box } from './base'; -import { ChartTile } from './chart-tile'; -import { SanityImage } from './cms/sanity-image'; -import { Anchor, BoldText, Text } from './typography'; -import { Link } from '~/utils/link'; -import styled, { css } from 'styled-components'; -import { PublicationDate } from './publication-date'; -import { ChevronRight } from '@corona-dashboard/icons'; import { Article } from '~/types/cms'; -import { useIntl } from '~/intl'; +import { Link } from '~/utils/link'; +import { Box } from '../base'; +import { ChartTile } from '../chart-tile'; +import { SanityImage } from '../cms/sanity-image'; +import { Anchor, BoldText, InlineText, Text } from '../typography'; +import { ArticleUpdateOrPublishingDate } from './article-update-or-publishing-date'; interface PageArticlesTileProps { articles: Article[]; title: string; } -// TODO: this should be moved to the /articles/ directory, as picked up in COR-1601 export const PageArticlesTile = ({ articles, title }: PageArticlesTileProps) => { const { commonTexts } = useIntl(); @@ -30,17 +29,18 @@ export const PageArticlesTile = ({ articles, title }: PageArticlesTileProps) => - +
{article.title} - - {/* TODO: this should be updated after COR-1601 implements publicationDate vs updateDate logic */} - {article.mainCategory && `${commonTexts.article_teaser.categories[article.mainCategory]} · `} - - - + + + {article.mainCategory && `${commonTexts.article_teaser.categories[article.mainCategory]} · `} + + + +
- {article.summary} + {article.summary} {commonTexts.article_teaser.read_more} @@ -74,10 +74,17 @@ const Grid = styled(Box)` const ArticleCard = styled(Anchor)` border-radius: ${radii[2]}px; border: 1px solid ${colors.gray3}; - display: grid; + display: flex; + flex-direction: column; gap: ${space[2]}; height: 100%; padding: ${space[3]}; + + ${Text} { + align-items: end; + display: flex; + flex-grow: 1; + } `; const ArticleCardHeader = styled(Box)` diff --git a/packages/app/src/components/page-information-block/components/articles.tsx b/packages/app/src/components/page-information-block/components/articles.tsx index e05a46e5a5..18820572f7 100644 --- a/packages/app/src/components/page-information-block/components/articles.tsx +++ b/packages/app/src/components/page-information-block/components/articles.tsx @@ -2,7 +2,7 @@ import css from '@styled-system/css'; import { Fragment } from 'react'; import styled from 'styled-components'; import { ChevronRight } from '@corona-dashboard/icons'; -import { ArticleSummary } from '~/components/article-teaser'; +import { ArticleSummary } from '~/components/articles/article-teaser'; import { Box } from '~/components/base'; import { SanityImage } from '~/components/cms/sanity-image'; import { Anchor, InlineText, Text } from '~/components/typography'; diff --git a/packages/app/src/components/publication-date.tsx b/packages/app/src/components/publication-date.tsx index 9feb211e00..e27a57c40b 100644 --- a/packages/app/src/components/publication-date.tsx +++ b/packages/app/src/components/publication-date.tsx @@ -2,10 +2,15 @@ import { useIntl } from '~/intl'; type PublicationDateProps = { date: string; + className?: string; }; -export function PublicationDate({ date }: PublicationDateProps) { +export function PublicationDate({ date, className }: PublicationDateProps) { const { formatDate } = useIntl(); - return ; + return ( + + ); } diff --git a/packages/app/src/domain/articles/articles-overview-list.tsx b/packages/app/src/domain/articles/articles-overview-list.tsx deleted file mode 100644 index 7060b2eec3..0000000000 --- a/packages/app/src/domain/articles/articles-overview-list.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import css from '@styled-system/css'; -import styled from 'styled-components'; -import { isDefined } from 'ts-is-present'; -import { ArticleSummary, ArticleTeaser } from '~/components/article-teaser'; -import { Box, Spacer } from '~/components/base'; -import { articleCategory, ArticleCategoryType } from '~/domain/topical/common/categories'; -import { space } from '~/style/theme'; -import { asResponsiveArray } from '~/style/utils'; - -type ArticlesOverviewListProps = { - articleSummaries?: ArticleSummary[]; - hideLink?: boolean; - currentCategory?: ArticleCategoryType; -}; - -export function ArticlesOverviewList({ articleSummaries, currentCategory }: ArticlesOverviewListProps) { - if (!articleSummaries || articleSummaries.length === 0) { - return null; - } - - return ( - - {articleSummaries - .filter(({ categories }) => { - if (!isDefined(categories) || currentCategory === articleCategory[0]) return true; - - return categories.includes(currentCategory); - }) - .map((summary) => ( - - - - - ))} - - ); -} - -export const ArticleBox = styled.div( - css({ - width: asResponsiveArray({ - _: '100%', - sm: 'calc(50% - 16px)', - md: 'calc(1 / 3 * 100% - 32px)', - lg: 'calc(1 / 3 * 100% - 32px)', - }), - '&:nth-child(even)': { - marginLeft: asResponsiveArray({ sm: space[4], md: '0' }), - }, - '&:nth-child(3n+2)': { - marginX: asResponsiveArray({ md: '48px' }), - }, - '& > *': { - height: '100%', - }, - }) -); diff --git a/packages/app/src/domain/topical/common/categories.ts b/packages/app/src/domain/topical/common/categories.ts index 11a8960e66..40d43e569e 100644 --- a/packages/app/src/domain/topical/common/categories.ts +++ b/packages/app/src/domain/topical/common/categories.ts @@ -1,4 +1,4 @@ -export const articleCategory = [ +export const allPossibleArticleCategories = [ '__alles', 'knowledge', 'news', @@ -11,4 +11,4 @@ export const articleCategory = [ 'gedrag', ] as const; -export type ArticleCategoryType = typeof articleCategory[number]; +export type ArticleCategoryType = typeof allPossibleArticleCategories[number]; diff --git a/packages/app/src/domain/topical/components/topical-article-list.tsx b/packages/app/src/domain/topical/components/topical-article-list.tsx index 197dadbaa3..88243d0d05 100644 --- a/packages/app/src/domain/topical/components/topical-article-list.tsx +++ b/packages/app/src/domain/topical/components/topical-article-list.tsx @@ -1,4 +1,4 @@ -import { ArticleSummary } from '~/components/article-teaser'; +import { ArticleSummary } from '~/components/articles/article-teaser'; import { Box } from '~/components/base'; import { SiteText } from '~/locale'; import { TopicalArticleTeaser } from './topical-article-teaser'; diff --git a/packages/app/src/pages/artikelen/[slug].tsx b/packages/app/src/pages/artikelen/[slug].tsx index 7778a66e5f..5e2d1f87e3 100644 --- a/packages/app/src/pages/artikelen/[slug].tsx +++ b/packages/app/src/pages/artikelen/[slug].tsx @@ -1,19 +1,12 @@ import { useRouter } from 'next/router'; import { useMemo } from 'react'; -import { ArticleDetail } from '~/components/article-detail'; +import { ArticleDetail } from '~/components/articles/article-detail'; import { Box } from '~/components/base'; import { Layout } from '~/domain/layout/layout'; import { getClient, getImageSrc } from '~/lib/sanity'; import { Languages, SiteText } from '~/locale'; -import { - createGetStaticProps, - StaticProps, -} from '~/static-props/create-get-static-props'; -import { - createGetContent, - getLastGeneratedDate, - getLokalizeTexts, -} from '~/static-props/get-data'; +import { createGetStaticProps, StaticProps } from '~/static-props/create-get-static-props'; +import { createGetContent, getLastGeneratedDate, getLokalizeTexts } from '~/static-props/get-data'; import { Article, Block, RichContentBlock } from '~/types/cms'; import { assert } from '~/utils/assert'; import { useDynamicLokalizeTexts } from '~/utils/cms/use-dynamic-lokalize-texts'; @@ -48,16 +41,12 @@ export async function getStaticPaths() { } export const getStaticProps = createGetStaticProps( - ({ locale }: { locale: keyof Languages }) => - getLokalizeTexts(selectLokalizeTexts, locale), + ({ locale }: { locale: keyof Languages }) => getLokalizeTexts(selectLokalizeTexts, locale), getLastGeneratedDate, createGetContent
((context) => { const { locale } = context; - assert( - context?.params?.slug, - `[${getStaticProps.name}:artikelen] Slug required to retrieve article` - ); + assert(context?.params?.slug, `[${getStaticProps.name}:artikelen] Slug required to retrieve article`); return `*[_type == 'article' && slug.current == '${context.params.slug}']{ ..., "slug": slug.current, @@ -88,10 +77,7 @@ const ArticleDetailPage = (props: StaticProps) => { const { content, lastGenerated, pageText } = props; const { locale = 'nl' } = useRouter(); - const { textTopicalPageShared } = useDynamicLokalizeTexts( - pageText, - selectLokalizeTexts - ); + const { textTopicalPageShared } = useDynamicLokalizeTexts(pageText, selectLokalizeTexts); const { cover } = content; const { asset } = cover; @@ -105,17 +91,10 @@ const ArticleDetailPage = (props: StaticProps) => { twitterImage: imgPath, }; - const breadcrumbsData = useMemo( - () => ({ [props.content.slug.current]: props.content.title }), - [props.content.slug, props.content.title] - ); + const breadcrumbsData = useMemo(() => ({ [props.content.slug.current]: props.content.title }), [props.content.slug, props.content.title]); return ( - + @@ -126,10 +105,7 @@ const ArticleDetailPage = (props: StaticProps) => { export default ArticleDetailPage; function getTitle(title: string, locale: string) { - const suffix = - locale === 'nl' - ? 'Dashboard Coronavirus | Rijksoverheid.nl' - : 'Dashboard Coronavirus | Government.nl'; + const suffix = locale === 'nl' ? 'Dashboard Coronavirus | Rijksoverheid.nl' : 'Dashboard Coronavirus | Government.nl'; return `${title} | ${suffix}`; } diff --git a/packages/app/src/pages/artikelen/index.tsx b/packages/app/src/pages/artikelen/index.tsx index f66924a9ed..1b098fb83c 100644 --- a/packages/app/src/pages/artikelen/index.tsx +++ b/packages/app/src/pages/artikelen/index.tsx @@ -1,24 +1,23 @@ -import { css } from '@styled-system/css'; +import { colors } from '@corona-dashboard/common'; import { useRouter } from 'next/router'; import { useCallback, useMemo } from 'react'; import styled from 'styled-components'; -import { isPresent } from 'ts-is-present'; -import { ArticleSummary } from '~/components/article-teaser'; +import { ArticleSummary } from '~/components/articles/article-teaser'; import { Box } from '~/components/base'; import { MaxWidth } from '~/components/max-width'; import { RichContentSelect } from '~/components/rich-content-select'; import { Heading, InlineText, Text } from '~/components/typography'; -import { ArticlesOverviewList } from '~/domain/articles/articles-overview-list'; +import { ArticlesList } from '~/components/articles/articles-list'; import { Layout } from '~/domain/layout/layout'; -import { articleCategory, ArticleCategoryType } from '~/domain/topical/common/categories'; +import { ArticleCategoryType, allPossibleArticleCategories } from '~/domain/topical/common/categories'; import { useIntl } from '~/intl'; import { Languages, SiteText } from '~/locale'; -import { createGetStaticProps, StaticProps } from '~/static-props/create-get-static-props'; +import { StaticProps, createGetStaticProps } from '~/static-props/create-get-static-props'; import { createGetContent, getLastGeneratedDate, getLokalizeTexts } from '~/static-props/get-data'; -import { asResponsiveArray } from '~/style/utils'; -import { useBreakpoints } from '~/utils/use-breakpoints'; +import { mediaQueries, space } from '~/style/theme'; import { useDynamicLokalizeTexts } from '~/utils/cms/use-dynamic-lokalize-texts'; -import { space } from '~/style/theme'; +import { useBreakpoints } from '~/utils/use-breakpoints'; +import { getCategories } from '~/components/articles/logic/get-categories'; const selectLokalizeTexts = (siteText: SiteText) => ({ textShared: siteText.pages.topical_page.shared, @@ -40,70 +39,67 @@ export const getStaticProps = createGetStaticProps( "cover": { ...cover, "asset": cover.asset-> - } + }, + publicationDate, + mainCategory, + updatedDate, }`; }) ); -const ArticlesOverview = (props: StaticProps) => { - const { pageText, content, lastGenerated } = props; +const Articles = (props: StaticProps) => { + const { pageText, lastGenerated, content } = props; const { commonTexts } = useIntl(); + const { textShared } = useDynamicLokalizeTexts(pageText, selectLokalizeTexts); const router = useRouter(); const breakpoints = useBreakpoints(); - const { textShared } = useDynamicLokalizeTexts(pageText, selectLokalizeTexts); - const articleCategories = useMemo(() => { - /** - * Find all the categories that are currently being used in articles, - * to later check if we still need it for the menu items. - */ - const availableCategories: string[] = ['__alles', ...new Set(content.map((item) => item.categories).flat())].filter(isPresent); - - return articleCategory - .map((id) => { - const label = textShared.secties.artikelen.categorie_filters[id]; - - return { - label, - value: id, - }; - }) - .filter((item) => availableCategories.includes(item.value)); + // Find all categories currently active on published articles. Used later to filter out items from the cateogry menu which are not used. + const availableCategoriesWithDuplicates = content.map((item) => getCategories(item)).flat(); + const availableCategoriesWithoutDuplicates = new Set(availableCategoriesWithDuplicates); + const allAvailableCategories: string[] = ['__alles', ...availableCategoriesWithoutDuplicates].filter(Boolean); + const filteredArticleCategoryList = allPossibleArticleCategories.filter((item) => allAvailableCategories.includes(item)); + + const articleCategoriesWithLabels = filteredArticleCategoryList.map((item) => { + return { + label: textShared.secties.artikelen.categorie_filters[item], + value: item, + }; + }); + + return articleCategoriesWithLabels; }, [content, textShared.secties.artikelen.categorie_filters]); - const selectOptions = useMemo( - () => - articleCategories.map((category) => ({ + const narrowScreenDropdownConfig = useMemo(() => { + const config = articleCategories.map((category) => { + return { ...category, content: ( {category.label} ), - })), - [articleCategories] - ); + }; + }); + + return config; + }, [articleCategories]); const handleCategoryFilter = useCallback( - function setNewParam(item: ArticleCategoryType) { - router.replace( - { - pathname: '/artikelen', - query: { categorie: item }, - }, - undefined, - { shallow: true } - ); + (item: ArticleCategoryType) => { + router.replace({ pathname: '/artikelen', query: { category: item } }, undefined, { shallow: true }); }, [router] ); - const currentCategory = (articleCategory.includes(router.query.categorie as ArticleCategoryType) ? router.query.categorie : articleCategory[0]) as ArticleCategoryType; + const currentCategory = ( + allPossibleArticleCategories.includes(router.query.category as ArticleCategoryType) ? router.query.category : allPossibleArticleCategories[0] + ) as ArticleCategoryType; return ( - + @@ -116,7 +112,7 @@ const ArticlesOverview = (props: StaticProps) => { {breakpoints.lg ? ( {articleCategories.map((category, index) => ( - handleCategoryFilter(category.value)}> + handleCategoryFilter(category.value)} role="button"> {category.label} @@ -125,92 +121,93 @@ const ArticlesOverview = (props: StaticProps) => { ))} ) : ( - + handleCategoryFilter(item.value)} + visuallyHiddenLabel /> - + )} - + {content && content.length && } ); }; -export default ArticlesOverview; - -const OrderedList = styled.ol( - css({ - overflow: 'hidden', - position: 'relative', - display: 'flex', - justifyContent: 'space-around', - borderTop: '1px solid', - borderBottom: '1px solid', - borderColor: 'gray3', - margin: '0', - marginY: space[4], - padding: '0', - listStyleType: 'none', - }) -); - -const ListItem = styled.li<{ isActive: boolean }>((x) => - css({ - position: 'relative', - paddingY: space[3], - height: '100%', - transition: 'transform 0.2s', - cursor: 'pointer', - - '&:after': { - content: '""', - display: 'block', - position: 'absolute', - left: '0', - bottom: '0', - height: '5px', - width: `calc(100%)`, - backgroundColor: 'blue8', - transform: `translateY(${x.isActive ? 0 : '6px'})`, - transition: 'transform 0.2s', - }, - - span: { - // Regular text - ':nth-of-type(1)': { - opacity: x.isActive ? 0 : 1, - }, - - // Bold text - ':nth-of-type(2)': { - opacity: x.isActive ? 1 : 0, - }, - }, - - ':hover': { - '&:after': { - transform: `translateY(0)`, - }, - }, - }) -); +export default Articles; + +const NarrowScreenDropDownContainer = styled.div` + margin-top: ${space[3]}; + margin-bottom: ${space[4]}; + width: 100%; + + select { + width: 100%; + max-width: 25rem; + + @media ${mediaQueries.xs} { + max-width: 23rem; + } + } +`; + +const OrderedList = styled.ol` + border-bottom: 1px solid ${colors.gray3}; + border-top: 1px solid ${colors.gray3}; + display: flex; + justify-content: space-around; + list-style-type: none; + margin: ${space[4]} 0; + overflow: hidden; + padding: 0; + position: relative; +`; + +interface ListItem { + isActive: boolean; +} + +const ListItem = styled.li` + cursor: pointer; + height: 100%; + padding-block: ${space[3]}; + position: relative; + transition: transform 0.2s; + + &::after { + background-color: ${colors.blue8}; + bottom: 0; + content: ''; + display: block; + height: 5px; + left: 0; + position: absolute; + transform: translateY(${({ isActive }) => (isActive ? 0 : '6px')}); + transition: transform 0.2s; + width: 100%; + } + + span { + // Regular text + &:nth-of-type(1) { + opacity: ${({ isActive }) => (isActive ? 0 : 1)}; + } + + // Bold text + &:nth-of-type(2) { + opacity: ${({ isActive }) => (isActive ? 1 : 0)}; + } + } + + &:hover::after { + transform: translateY(0); + } +`; /* * Since we are using a justify-content: space around for positioning the elements, @@ -218,28 +215,24 @@ const ListItem = styled.li<{ isActive: boolean }>((x) => * Here we draw a identical text on top and switch them once the item is active. * It has a aria hidden label and is pure cosmetic for this use case. */ -const BoldText = styled.span( - css({ - position: 'absolute', - top: '0', - left: '50%', - fontWeight: 'bold', - opacity: 0, - whiteSpace: 'nowrap', - transform: 'translateX(-50%)', - }) -); - -const StyledButton = styled.button( - css({ - all: 'unset', - position: 'relative', - paddingX: space[3], - - '&:focus': { - outlineWidth: '1px', - outlineStyle: 'dashed', - outlineColor: 'blue8', - }, - }) -); +const BoldText = styled.span` + font-weight: bold; + left: 50%; + opacity: 0; + position: absolute; + top: 0; + transform: translateX(-50%); + white-space: nowrap; +`; + +const StyledButton = styled.button` + all: unset; + padding-inline: ${space[3]}; + position: relative; + + &:focus { + outline-width: 1px; + outline-style: dashed; + outline-color: ${colors.blue8}; + } +`; diff --git a/packages/app/src/pages/gemeente/[code]/positief-geteste-mensen.tsx b/packages/app/src/pages/gemeente/[code]/positief-geteste-mensen.tsx index 015bfbe782..32dccf2a7e 100644 --- a/packages/app/src/pages/gemeente/[code]/positief-geteste-mensen.tsx +++ b/packages/app/src/pages/gemeente/[code]/positief-geteste-mensen.tsx @@ -12,7 +12,7 @@ import { InView } from '~/components/in-view'; import { KpiTile } from '~/components/kpi-tile'; import { KpiValue } from '~/components/kpi-value'; import { Markdown } from '~/components/markdown'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/gemeente/[code]/rioolwater.tsx b/packages/app/src/pages/gemeente/[code]/rioolwater.tsx index 6a69e1e653..63a0c826a5 100644 --- a/packages/app/src/pages/gemeente/[code]/rioolwater.tsx +++ b/packages/app/src/pages/gemeente/[code]/rioolwater.tsx @@ -6,7 +6,7 @@ import { InView } from '~/components/in-view'; import { KpiTile } from '~/components/kpi-tile'; import { KpiValue } from '~/components/kpi-value'; import { Markdown } from '~/components/markdown'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/gemeente/[code]/sterfte.tsx b/packages/app/src/pages/gemeente/[code]/sterfte.tsx index aea28b6ba3..9e635beade 100644 --- a/packages/app/src/pages/gemeente/[code]/sterfte.tsx +++ b/packages/app/src/pages/gemeente/[code]/sterfte.tsx @@ -7,7 +7,7 @@ import { InView } from '~/components/in-view'; import { KpiTile } from '~/components/kpi-tile'; import { KpiValue } from '~/components/kpi-value'; import { Markdown } from '~/components/markdown'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/gemeente/[code]/vaccinaties.tsx b/packages/app/src/pages/gemeente/[code]/vaccinaties.tsx index bcdb40608d..7e3da871b4 100644 --- a/packages/app/src/pages/gemeente/[code]/vaccinaties.tsx +++ b/packages/app/src/pages/gemeente/[code]/vaccinaties.tsx @@ -6,7 +6,7 @@ import { isDefined, isPresent } from 'ts-is-present'; import { Divider } from '~/components/divider'; import { InView } from '~/components/in-view'; import { BorderedKpiSection } from '~/components/kpi/bordered-kpi-section'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/gemeente/[code]/ziekenhuis-opnames.tsx b/packages/app/src/pages/gemeente/[code]/ziekenhuis-opnames.tsx index a5881a1a89..6472c66a8e 100644 --- a/packages/app/src/pages/gemeente/[code]/ziekenhuis-opnames.tsx +++ b/packages/app/src/pages/gemeente/[code]/ziekenhuis-opnames.tsx @@ -10,7 +10,7 @@ import { thresholds } from '~/components/choropleth/logic/thresholds'; import { InView } from '~/components/in-view'; import { KpiTile } from '~/components/kpi-tile'; import { KpiValue } from '~/components/kpi-value'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/besmettelijke-mensen.tsx b/packages/app/src/pages/landelijk/besmettelijke-mensen.tsx index 6b29250f2e..1337c7b47a 100644 --- a/packages/app/src/pages/landelijk/besmettelijke-mensen.tsx +++ b/packages/app/src/pages/landelijk/besmettelijke-mensen.tsx @@ -3,7 +3,7 @@ import { Ziektegolf } from '@corona-dashboard/icons'; import { GetStaticPropsContext } from 'next'; import { ChartTile } from '~/components/chart-tile'; import { InView } from '~/components/in-view'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/gedrag.tsx b/packages/app/src/pages/landelijk/gedrag.tsx index b1862c2845..64f18eb648 100644 --- a/packages/app/src/pages/landelijk/gedrag.tsx +++ b/packages/app/src/pages/landelijk/gedrag.tsx @@ -24,7 +24,7 @@ import { ArticleParts, PagePartQueryResult } from '~/types/cms'; import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; import { getLastInsertionDateOfPage } from '~/utils/get-last-insertion-date-of-page'; import { useDynamicLokalizeTexts } from '~/utils/cms/use-dynamic-lokalize-texts'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { getPageInformationHeaderContent } from '~/utils/get-page-information-header-content'; import { WarningTile } from '~/components/warning-tile'; diff --git a/packages/app/src/pages/landelijk/gehandicaptenzorg.tsx b/packages/app/src/pages/landelijk/gehandicaptenzorg.tsx index a6bdd94f12..d7a4a7d3d0 100644 --- a/packages/app/src/pages/landelijk/gehandicaptenzorg.tsx +++ b/packages/app/src/pages/landelijk/gehandicaptenzorg.tsx @@ -8,7 +8,7 @@ import { ChoroplethTile } from '~/components/choropleth-tile'; import { thresholds } from '~/components/choropleth/logic/thresholds'; import { Divider } from '~/components/divider'; import { InView } from '~/components/in-view'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/kwetsbare-groepen-70-plussers.tsx b/packages/app/src/pages/landelijk/kwetsbare-groepen-70-plussers.tsx index f6d90be204..e823cf05a8 100644 --- a/packages/app/src/pages/landelijk/kwetsbare-groepen-70-plussers.tsx +++ b/packages/app/src/pages/landelijk/kwetsbare-groepen-70-plussers.tsx @@ -13,7 +13,7 @@ import { KpiTile } from '~/components/kpi-tile'; import { KpiValue } from '~/components/kpi-value'; import { BorderedKpiSection } from '~/components/kpi/bordered-kpi-section'; import { Markdown } from '~/components/markdown'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/patienten-in-beeld.tsx b/packages/app/src/pages/landelijk/patienten-in-beeld.tsx index d5fbe9004a..0c413a82f7 100644 --- a/packages/app/src/pages/landelijk/patienten-in-beeld.tsx +++ b/packages/app/src/pages/landelijk/patienten-in-beeld.tsx @@ -8,7 +8,7 @@ import { DynamicChoropleth } from '~/components/choropleth'; import { ChoroplethTile } from '~/components/choropleth-tile'; import { thresholds } from '~/components/choropleth/logic/thresholds'; import { InView } from '~/components/in-view'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { SEOHead } from '~/components/seo-head'; diff --git a/packages/app/src/pages/landelijk/positief-geteste-mensen.tsx b/packages/app/src/pages/landelijk/positief-geteste-mensen.tsx index 4db982974d..c6a6098f33 100644 --- a/packages/app/src/pages/landelijk/positief-geteste-mensen.tsx +++ b/packages/app/src/pages/landelijk/positief-geteste-mensen.tsx @@ -10,7 +10,7 @@ import { ChoroplethTile } from '~/components/choropleth-tile'; import { thresholds } from '~/components/choropleth/logic/thresholds'; import { InView } from '~/components/in-view'; import { Markdown } from '~/components/markdown'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/reproductiegetal.tsx b/packages/app/src/pages/landelijk/reproductiegetal.tsx index e07feac2a8..1d89c6f1e0 100644 --- a/packages/app/src/pages/landelijk/reproductiegetal.tsx +++ b/packages/app/src/pages/landelijk/reproductiegetal.tsx @@ -4,7 +4,7 @@ import { GetStaticPropsContext } from 'next'; import { InView } from '~/components/in-view'; import { KpiWithIllustrationTile } from '~/components/kpi-with-illustration-tile'; import { Markdown } from '~/components/markdown'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { PageKpi } from '~/components/page-kpi'; diff --git a/packages/app/src/pages/landelijk/rioolwater.tsx b/packages/app/src/pages/landelijk/rioolwater.tsx index a569e3819b..3f5bf403ca 100644 --- a/packages/app/src/pages/landelijk/rioolwater.tsx +++ b/packages/app/src/pages/landelijk/rioolwater.tsx @@ -7,7 +7,7 @@ import { thresholds } from '~/components/choropleth/logic/thresholds'; import { InView } from '~/components/in-view'; import { KpiTile } from '~/components/kpi-tile'; import { KpiValue } from '~/components/kpi-value'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/sterfte.tsx b/packages/app/src/pages/landelijk/sterfte.tsx index 116feec458..3d0d35158c 100644 --- a/packages/app/src/pages/landelijk/sterfte.tsx +++ b/packages/app/src/pages/landelijk/sterfte.tsx @@ -10,7 +10,7 @@ import { InView } from '~/components/in-view'; import { KpiTile } from '~/components/kpi-tile'; import { KpiValue } from '~/components/kpi-value'; import { Markdown } from '~/components/markdown'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/testen.tsx b/packages/app/src/pages/landelijk/testen.tsx index 51d5e12509..cc8f82628a 100644 --- a/packages/app/src/pages/landelijk/testen.tsx +++ b/packages/app/src/pages/landelijk/testen.tsx @@ -4,7 +4,7 @@ import { GetStaticPropsContext } from 'next'; import { useState } from 'react'; import { ChartTile } from '~/components/chart-tile'; import { InView } from '~/components/in-view'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/thuiswonende-ouderen.tsx b/packages/app/src/pages/landelijk/thuiswonende-ouderen.tsx index ba1c111e2c..5372a43b2a 100644 --- a/packages/app/src/pages/landelijk/thuiswonende-ouderen.tsx +++ b/packages/app/src/pages/landelijk/thuiswonende-ouderen.tsx @@ -8,7 +8,7 @@ import { ChoroplethTile } from '~/components/choropleth-tile'; import { thresholds } from '~/components/choropleth/logic/thresholds'; import { Divider } from '~/components/divider'; import { InView } from '~/components/in-view'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/vaccinaties.tsx b/packages/app/src/pages/landelijk/vaccinaties.tsx index c745a54a56..c529fafe46 100644 --- a/packages/app/src/pages/landelijk/vaccinaties.tsx +++ b/packages/app/src/pages/landelijk/vaccinaties.tsx @@ -7,7 +7,7 @@ import { ChartTile } from '~/components/chart-tile'; import { Divider } from '~/components/divider'; import { InView } from '~/components/in-view'; import { BorderedKpiSection } from '~/components/kpi/bordered-kpi-section'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/varianten.tsx b/packages/app/src/pages/landelijk/varianten.tsx index 6f0be79767..7e35ebd86a 100644 --- a/packages/app/src/pages/landelijk/varianten.tsx +++ b/packages/app/src/pages/landelijk/varianten.tsx @@ -1,7 +1,7 @@ import { Varianten } from '@corona-dashboard/icons'; import { GetStaticPropsContext } from 'next'; import { InView } from '~/components/in-view'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { TileList } from '~/components/tile-list'; diff --git a/packages/app/src/pages/landelijk/ziekenhuizen-en-zorg.tsx b/packages/app/src/pages/landelijk/ziekenhuizen-en-zorg.tsx index c26d5e4f5a..9a1013e1cc 100644 --- a/packages/app/src/pages/landelijk/ziekenhuizen-en-zorg.tsx +++ b/packages/app/src/pages/landelijk/ziekenhuizen-en-zorg.tsx @@ -6,7 +6,7 @@ import { ChartTile } from '~/components/chart-tile'; import { ChartTileToggleItem } from '~/components/chart-tile-toggle'; import { InView } from '~/components/in-view'; import { BorderedKpiSection } from '~/components/kpi/bordered-kpi-section'; -import { PageArticlesTile } from '~/components/page-articles-tile'; +import { PageArticlesTile } from '~/components/articles/page-articles-tile'; import { PageFaqTile } from '~/components/page-faq-tile'; import { PageInformationBlock } from '~/components/page-information-block'; import { SEOHead } from '~/components/seo-head'; diff --git a/packages/app/src/queries/get-page-parts-query.ts b/packages/app/src/queries/get-page-parts-query.ts index 43ab3b3b9e..8a0b57eeb3 100644 --- a/packages/app/src/queries/get-page-parts-query.ts +++ b/packages/app/src/queries/get-page-parts-query.ts @@ -10,8 +10,7 @@ export const getPagePartsQuery = (pageIdentifier: PageIdentifier) => { _type, pageDataKind, (_type == 'pageArticles') => { - // TODO: add updateDate field as introduced by COR-1601 - articles[]->{_id, title, slug, summary, intro, "cover": {"asset": cover.asset->}, mainCategory[0], publicationDate}, + articles[]->{_id, title, slug, summary, intro, "cover": {"asset": cover.asset->}, mainCategory, publicationDate, updatedDate}, sectionTitle }, (_type == 'pageFAQs') => { diff --git a/packages/app/src/types/cms.d.ts b/packages/app/src/types/cms.d.ts index 128062cbaa..a48b2f0aa3 100644 --- a/packages/app/src/types/cms.d.ts +++ b/packages/app/src/types/cms.d.ts @@ -1,5 +1,5 @@ import { PortableTextEntry } from '@sanity/block-content-to-react'; -import { ArticleSummary } from '~/components/article-teaser'; +import { ArticleSummary } from '~/components/articles/article-teaser'; import { CategoriesTypes } from '~/domain/topical/common/categories'; export type PageIdentifier = @@ -119,25 +119,31 @@ export interface InlineAttachment { } export type Editorial = Record & Article; + +export type ArticleMainCategory = 'knowledge' | 'news'; +export type ArticleUpdatedDate = string | null; +export type ArticlePublishedDate = string; + export interface Article { - title: string; + categories: CategoriesTypes[]; + category: string; + content: RichContentBlock[]; + cover: ImageBlock; + intro: RichContentBlock[]; + isHighlighted: boolean; + mainCategory: ArticleMainCategory; + metaDescription: string; + publicationDate: ArticlePublishedDate; slug: { _key: string; _type: 'slug'; current: string; }; - mainCategory: 'knowledge' | 'news'; - categories?: CategoriesTypes[]; - cover: ImageBlock; + summary: Block; + title: string; + updatedDate: ArticleUpdatedDate; imageMobile?: ImageBlock; imageDesktop?: ImageBlock; - summary: Block; - intro: RichContentBlock[]; - content: RichContentBlock[]; - metaDescription: string; - publicationDate: string; - isHighlighted: boolean; - category: string; } export interface ImageBlock { diff --git a/packages/cms/src/lokalize/key-mutations.csv b/packages/cms/src/lokalize/key-mutations.csv index 380d956503..72b30d2428 100644 --- a/packages/cms/src/lokalize/key-mutations.csv +++ b/packages/cms/src/lokalize/key-mutations.csv @@ -1,4 +1,16 @@ timestamp,action,key,document_id,move_to +2023-06-12T09:53:10.644Z,add,common.aaa_migration_tests.key_apply_json_edits_1,ieiHQoBlBY8xw7iMk1kxhZ,__ +2023-06-12T10:00:41.857Z,delete,common.aaa_migration_tests.key_apply_json_edits_1,ieiHQoBlBY8xw7iMk1kxhZ,__ +2023-06-19T15:08:37.387Z,delete,__root.test,HXomTaat4t1GNGkeYSmI4m,__ +2023-06-19T15:08:37.388Z,delete,__root.test_19062023,7zJj0XdR5638DDqCBIiegA,__ +2023-06-19T15:08:37.390Z,delete,__root.test_19062023_2,FW1NJKvivUBn8c48tQ653o,__ +2023-06-23T14:55:23.911Z,add,pages.topical_page.shared.secties.artikelen.categorie_filters.knowledge,Ku8wHpYNOt4eyma9n0xDYK,__ +2023-06-23T14:55:24.898Z,add,pages.topical_page.shared.secties.artikelen.categorie_filters.news,7Z5IwKV6fNGjCgSOcTM4Kl,__ +2023-06-29T10:43:45.602Z,add,common.article_list.articles_per_year,HZtFOUnNN2MvnI1rq0PJy5,__ +2023-07-03T12:20:03.253Z,add,common.article_teaser.articles_updated_per_year,sebpseFGc19zAe3rm1BjkE,__ +2023-07-03T13:05:52.010Z,add,common.article_detail.articles_updated_date,Wh1ub3UCj9nPP64dfE1pEB,__ +2023-07-03T13:05:52.987Z,add,common.article_teaser.articles_updated_date,sebpseFGc19zAe3rm1G59P,__ +2023-07-03T13:05:52.988Z,delete,common.article_teaser.articles_updated_per_year,sebpseFGc19zAe3rm1BjkE,__ 2023-06-28T11:28:23.814Z,add,common.article_list.articles_page_link,i4tC336oRzoosjJ7ciMAty,__ 2023-06-28T11:28:25.329Z,add,common.article_teaser.categories.knowledge,1CbY4BczrwxgbzbvsJsVot,__ 2023-06-28T11:28:26.304Z,add,common.article_teaser.categories.news,i4tC336oRzoosjJ7ciMBOt,__ diff --git a/packages/cms/src/schemas/fields/article-fields.ts b/packages/cms/src/schemas/fields/article-fields.ts index 78d46aa6c4..3c6db12fc8 100644 --- a/packages/cms/src/schemas/fields/article-fields.ts +++ b/packages/cms/src/schemas/fields/article-fields.ts @@ -41,16 +41,28 @@ export const ARTICLE_FIELDS = [ defineField({ title: 'Hoofdcategorie', name: 'mainCategory', - type: 'array', - of: [defineArrayMember({ type: 'string' })], + type: 'string', options: { - layout: 'grid', + layout: 'radio', list: [ { title: 'Kennisartikelen', value: 'knowledge' }, { title: 'Nieuwsartikelen', value: 'news' }, ], }, - validation: (rule) => rule.required().min(1).max(1), + validation: (rule) => rule.required(), + }), + defineField({ + title: 'Update datum', + name: 'updatedDate', + type: 'datetime', + description: + 'Dit veld moet worden ingevuld wanneer een "kennis" artikel wordt bijgewerkt, zodat de datum op het dashboard de bijgewerkte datum weergeeft in plaats van de oorspronkelijke publicatiedatum. Als dit veld niet wordt bijgewerkt, blijft de publicatiedatum zichtbaar.', + options: { + dateFormat: DATE_FORMAT, + timeFormat: TIME_FORMAT, + timeStep: 15, + }, + hidden: ({ parent }) => !parent?.mainCategory?.includes('knowledge'), }), defineField({ title: 'Categorieën instellen', @@ -60,13 +72,13 @@ export const ARTICLE_FIELDS = [ options: { layout: 'grid', list: [ - { title: 'Vaccinaties', value: 'vaccinaties' }, { title: 'Besmettingen', value: 'besmettingen' }, - { title: 'Sterfte', value: 'sterfte' }, - { title: 'Ziekenhuizen', value: 'ziekenhuizen' }, + { title: 'Gedrag', value: 'gedrag' }, { title: 'Kwetsbare groepen', value: 'kwetsbare_groepen' }, + { title: 'Sterfte', value: 'sterfte' }, + { title: 'Vaccinaties', value: 'vaccinaties' }, { title: 'Vroege indicatoren', value: 'vroege_indicatoren' }, - { title: 'Gedrag', value: 'gedrag' }, + { title: 'Ziekenhuizen', value: 'ziekenhuizen' }, ], }, validation: (rule) => rule.required().min(1),