diff --git a/apps/pdc-frontend/src/app/[locale]/[...not-found]/page.tsx b/apps/pdc-frontend/src/app/[locale]/[...not-found]/page.tsx index a4d1fe01f..1a75ae101 100644 --- a/apps/pdc-frontend/src/app/[locale]/[...not-found]/page.tsx +++ b/apps/pdc-frontend/src/app/[locale]/[...not-found]/page.tsx @@ -26,7 +26,7 @@ const NotFoundPage = async ({ params: { locale } }: { params: { locale: string } ]} /> {data?.notFoundPage?.data?.attributes?.title} - {data?.notFoundPage?.data?.attributes?.body} + {data?.notFoundPage?.data?.attributes?.body} ); }; diff --git a/apps/pdc-frontend/src/app/[locale]/not-found.tsx b/apps/pdc-frontend/src/app/[locale]/not-found.tsx index bc45c3805..5d623c4fe 100644 --- a/apps/pdc-frontend/src/app/[locale]/not-found.tsx +++ b/apps/pdc-frontend/src/app/[locale]/not-found.tsx @@ -29,7 +29,7 @@ const NotFoundPage = async () => { ]} /> {data?.notFoundPage?.data?.attributes?.title} - {data?.notFoundPage?.data?.attributes?.body} + {data?.notFoundPage?.data?.attributes?.body} ); }; diff --git a/apps/pdc-frontend/src/app/[locale]/products/[slug]/page.tsx b/apps/pdc-frontend/src/app/[locale]/products/[slug]/page.tsx index e52a825fa..72e13b91e 100644 --- a/apps/pdc-frontend/src/app/[locale]/products/[slug]/page.tsx +++ b/apps/pdc-frontend/src/app/[locale]/products/[slug]/page.tsx @@ -1,6 +1,5 @@ import { Metadata } from 'next'; import { cookies, draftMode } from 'next/headers'; -import Image from 'next/image'; import { notFound } from 'next/navigation'; import React from 'react'; import { useTranslation } from '@/app/i18n'; @@ -22,11 +21,13 @@ import { import { BottomBar, BottomBarItem } from '@/components/BottomBar'; import { Breadcrumbs } from '@/components/Breadcrumb'; import { FAQSection } from '@/components/FAQSection'; +import { Img } from '@/components/Img'; import { Markdown } from '@/components/Markdown'; import { PreviewAlert } from '@/components/PreviewAlert'; import { ReactionLink } from '@/components/ReactionLink'; import { ScrollToTopButton } from '@/components/ScrollToTopButton'; import { GET_PRODUCT_BY_SLUG_FETCH } from '@/query'; +import { buildImgURL } from '@/util/buildImgURL'; import { createStrapiURL } from '@/util/createStrapiURL'; import { fetchData } from '@/util/fetchData'; @@ -135,7 +136,7 @@ const Product = async ({ params: { locale, slug }, searchParams }: ProductProps) const { product } = await getAllProducts(locale, slug); const priceData = product?.attributes.price && product?.attributes.price?.data?.attributes.price; - const strapiImageURL = process.env.STRAPI_PUBLIC_URL; + const { t } = await useTranslation(locale, 'common'); const Sections = () => product?.attributes && product?.attributes.sections.length > 0 @@ -143,7 +144,7 @@ const Product = async ({ params: { locale, slug }, searchParams }: ProductProps) switch (component.__typename) { case 'ComponentComponentsBlockContent': return component.content ? ( - + {component.content} ) : null; @@ -170,7 +171,6 @@ const Product = async ({ params: { locale, slug }, searchParams }: ProductProps) accordion={component.faq.data.attributes.faq.accordion} sectionTitle={component.faq.data.attributes.title} priceData={priceData} - strapiBackendURL={strapiImageURL} /> ); } @@ -183,7 +183,7 @@ const Product = async ({ params: { locale, slug }, searchParams }: ProductProps) label: title, headingLevel: 3, // TODO add this property from CMS body: ( - + {body} ), @@ -191,35 +191,20 @@ const Product = async ({ params: { locale, slug }, searchParams }: ProductProps) /> ); case 'ComponentComponentsImage': - if ( - component.imageData && - component.imageData.data.attributes && - component.imageData.data.attributes.url - ) { - return ( - {component.imageData.data.attributes.alternativeText - ); - } else { - return null; - } + return ( + {component?.imageData?.data?.attributes?.alternativeText} + ); + case 'ComponentComponentsSpotlight': return component.content ? ( - - {component.content} - + {component.content} ) : null; case 'ComponentComponentsButtonLink': diff --git a/apps/pdc-frontend/src/app/[locale]/search/tips/[query]/page.tsx b/apps/pdc-frontend/src/app/[locale]/search/tips/[query]/page.tsx index 787a70d75..1375e5cc8 100644 --- a/apps/pdc-frontend/src/app/[locale]/search/tips/[query]/page.tsx +++ b/apps/pdc-frontend/src/app/[locale]/search/tips/[query]/page.tsx @@ -60,7 +60,7 @@ const SearchTips = async ({ params: { locale, query } }: any) => { ]} /> {`${title} "${query}"`} - {body} + {body} ); }; diff --git a/apps/pdc-frontend/src/components/FAQSection/index.tsx b/apps/pdc-frontend/src/components/FAQSection/index.tsx index cb20f528a..1d0d7cc52 100644 --- a/apps/pdc-frontend/src/components/FAQSection/index.tsx +++ b/apps/pdc-frontend/src/components/FAQSection/index.tsx @@ -13,16 +13,9 @@ export interface FAQSectionProps { accordion?: AccordionType[]; locale?: string; priceData?: any; - strapiBackendURL?: any; } -export const FAQSection: React.FC = ({ - sectionTitle, - accordion, - locale, - priceData, - strapiBackendURL, -}) => ( +export const FAQSection: React.FC = ({ sectionTitle, accordion, locale, priceData }) => (
{sectionTitle} {accordion && accordion.length > 0 && ( @@ -32,7 +25,7 @@ export const FAQSection: React.FC = ({ label: title, headingLevel: 3, // TODO add this property from CMS body: ( - + {body} ), diff --git a/apps/pdc-frontend/src/components/Img/index.module.scss b/apps/pdc-frontend/src/components/Img/index.module.scss new file mode 100644 index 000000000..0ce265bd0 --- /dev/null +++ b/apps/pdc-frontend/src/components/Img/index.module.scss @@ -0,0 +1,22 @@ +.utrecht-img { + block-size: auto; + max-inline-size: 100%; +} + +.utrecht-figure { + --utrecht-figure-margin-inline-start: 0; + --utrecht-figure-margin-inline-end: 0; + --utrecht-figure-margin-block-start: var(--utrecht-space-block-md); + --utrecht-figure-margin-block-end: var(--utrecht-space-block-md); + + margin-block-end: var(--utrecht-figure-margin-block-end); + margin-block-start: var(--utrecht-figure-margin-block-start); + margin-inline-end: var(--utrecht-figure-margin-inline-end); + margin-inline-start: var(--utrecht-figure-margin-inline-start); +} + +.utrecht-figure__figcaption { + --utrecht-figure--figcaption-color: var(--utrecht-color-grey-40); + + color: var(--utrecht-figure--figcaption-color); +} diff --git a/apps/pdc-frontend/src/components/Img/index.tsx b/apps/pdc-frontend/src/components/Img/index.tsx new file mode 100644 index 000000000..ed1cf132c --- /dev/null +++ b/apps/pdc-frontend/src/components/Img/index.tsx @@ -0,0 +1,39 @@ +import classNames from 'classnames/bind'; +import Image from 'next/image'; +import React from 'react'; +import styles from './index.module.scss'; + +const css = classNames.bind(styles); + +export interface ImgProps + extends Omit, HTMLImageElement>, 'ref'> {} +export const Img = (props: ImgProps & { 'data-figcaption'?: null }) => { + const { height, width, src, alt, title } = props; + + if (width && height && src) { + const imgElement = ( + {alt + ); + + if (props['data-figcaption']) { + return ( +
+ {imgElement} +
{props['data-figcaption']}
+
+ ); + } + + return imgElement; + } + + return null; +}; diff --git a/apps/pdc-frontend/src/components/Markdown/index.tsx b/apps/pdc-frontend/src/components/Markdown/index.tsx index 84b1c07e9..af1b5b629 100644 --- a/apps/pdc-frontend/src/components/Markdown/index.tsx +++ b/apps/pdc-frontend/src/components/Markdown/index.tsx @@ -1,7 +1,4 @@ -'use client'; - import isAbsoluteUrl from 'is-absolute-url'; -import Image from 'next/image'; import NextLink from 'next/link'; import React from 'react'; import ReactMarkdown, { Components } from 'react-markdown'; @@ -26,8 +23,10 @@ import { UnorderedList, UnorderedListItem, } from '@/components'; -import { useTranslation } from '../../app/i18n/client'; +import { buildImgURL } from '@/util/buildImgURL'; +import { useTranslation } from '../../app/i18n'; import { fallbackLng } from '../../app/i18n/settings'; +import { Img } from '../Img'; type PriceTypes = { value: string; @@ -36,17 +35,7 @@ type PriceTypes = { id: string; }; -const components = ({ - strapiBackendURL, - priceData, - locale, - freeProductLabel, -}: { - strapiBackendURL: string; - priceData: PriceTypes[]; - locale: string; - freeProductLabel: string; -}) => +const components = ({ priceData, locale }: { priceData: PriceTypes[]; locale: string }) => ({ h1: ({ children, node }) => { delete node.properties?.style; @@ -137,33 +126,15 @@ const components = ({ delete node.properties?.style; return {children}; }, - img: ({ width, height, src, alt }) => { - if (width && height && src && alt) { - return ( - {alt - ); - } else { - return null; - } - }, - 'react-widget': ({ node }: any) => { + img: (props) => props.src && , + 'react-widget': async ({ node }: any) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { t } = await useTranslation(locale ?? fallbackLng, 'common'); if (node.properties?.id && priceData && priceData.length > 0) { const product = priceData.find(({ id }) => id === node.properties?.id); const price = Number(product?.value) === 0 - ? freeProductLabel + ? t('text.free-product') : new Intl.NumberFormat(locale, { style: 'currency', currency: product?.currency, @@ -180,23 +151,16 @@ interface MarkdownProps { children: any; priceData?: any; locale?: string; - strapiBackendURL?: string; } -export const Markdown: React.FC = ({ children, priceData, locale, strapiBackendURL }) => { - const url = strapiBackendURL ? new URL(strapiBackendURL) : null; - const { t } = useTranslation(locale ?? fallbackLng, 'common'); - return ( - - {children} - - ); -}; +export const Markdown: React.FC = ({ children, priceData, locale }) => ( + + {children} + +); diff --git a/apps/pdc-frontend/src/util/buildImgURL.ts b/apps/pdc-frontend/src/util/buildImgURL.ts new file mode 100644 index 000000000..a6258bbe6 --- /dev/null +++ b/apps/pdc-frontend/src/util/buildImgURL.ts @@ -0,0 +1,12 @@ +export const buildImgURL = (src: string) => { + if (!process.env.STRAPI_PUBLIC_URL) { + throw new Error('`STRAPI_PUBLIC_URL` is required to construct the image URL in the Markdown component.'); + } + const url = new URL(process.env.STRAPI_PUBLIC_URL); + // if we need to support a different image-provider-upload, we can use the following approach + // just rename env variable + // if (process.env.DEPLOY_TO_VERCEL && Boolean(process.env.DEPLOY_TO_VERCEL)) { + // return src; + // } + return `${url?.origin}${src}`; +};