Skip to content

Commit

Permalink
[DEV-1546]: render blocks content (#773)
Browse files Browse the repository at this point in the history
* feat(DEV-1546): render blocks content on the FE

* chore: add changeset

* feat(DEV-1546): add missing code

* feat(DEV-1546): add subheadColor

* feat(DEV-1546): add subheadColor

* feat(DEV-1546): add missing subheadColor

* Update apps/nextjs-website/src/components/molecules/BlocksRendererClient/BlocksRendererClient.tsx

---------

Co-authored-by: Marco Ponchia <[email protected]>
  • Loading branch information
MikeAtUqido and MarcoPonchia authored Mar 27, 2024
1 parent c0c2a65 commit b842990
Show file tree
Hide file tree
Showing 10 changed files with 462 additions and 43 deletions.
5 changes: 5 additions & 0 deletions .changeset/brown-bugs-teach.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nextjs-website": patch
---

Add BlocksRendererClient component to render the blocks content coming from Strapi
1 change: 1 addition & 0 deletions apps/nextjs-website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@mui/utils": "^5.14.5",
"@pagopa/mui-italia": "1.0.1",
"@stoplight/elements": "^7.9.0",
"@strapi/blocks-react-renderer": "^1.0.1",
"aws-amplify": "^5.3.11",
"fp-ts": "^2.13.1",
"gitbook-docs": "*",
Expand Down
15 changes: 8 additions & 7 deletions apps/nextjs-website/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { translations } from '@/_contents/translations';
import SiteLabel from '@/components/atoms/SiteLabel/SiteLabel';
import HeroSwiper from '@/components/molecules/HeroSwiper/HeroSwiper';
import RelatedLinks from '@/components/atoms/RelatedLinks/RelatedLinks';
import NewsShowcase from '@/components/organisms/NewsShowcase/NewsShowcase';
Expand All @@ -10,6 +8,7 @@ import { getVisibleInHomeWebinars } from '@/lib/api';
import dynamic from 'next/dynamic';
import { baseUrl } from '@/config';
import { getHomepageProps } from '@/lib/cmsApi';
import BlocksRendererClient from '@/components/molecules/BlocksRendererClient/BlocksRendererClient';

export async function generateMetadata(): Promise<Metadata> {
return makeMetadata({
Expand All @@ -32,7 +31,6 @@ const NotSsrWebinarsSection = dynamic(

const Home = async () => {
const webinars = await getVisibleInHomeWebinars();
const { header } = translations;

const homepage = await getHomepageProps();

Expand All @@ -43,10 +41,13 @@ const Home = async () => {
<HeroSwiper
cards={homepage.hero.map((itemProp, index) => ({
...itemProp,
child:
index === 0 ? (
<SiteLabel title={header.title} boldTitle={header.boldTitle} />
) : undefined,
child: itemProp.subhead && (
<BlocksRendererClient
key={index}
content={itemProp.subhead}
color={itemProp.subheadColor}
/>
),
}))}
/>
<NewsShowcase
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
'use client';
import { Box, Stack, Typography, useTheme } from '@mui/material';
import { ButtonNaked } from '@pagopa/mui-italia';
import { BlocksContent } from '@strapi/blocks-react-renderer';
import Image from 'next/image';
import Link from 'next/link';
import React, { ReactNode } from 'react';

export type CtaSlideProps = {
readonly title: string;
readonly subhead?: BlocksContent;
readonly subheadColor?: 'contrastText' | 'main' | 'light' | 'dark';
readonly titleColor?: 'contrastText' | 'main' | 'light' | 'dark';
readonly callToAction?: {
readonly variant?: 'text' | 'contained' | 'outlined';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use client';

import { Typography, useTheme } from '@mui/material';
import { BlocksContent, BlocksRenderer } from '@strapi/blocks-react-renderer';
import Image from 'next/image';

const BlocksRendererClient = ({
content,
color,
}: {
readonly content?: BlocksContent;
color?: 'contrastText' | 'main' | 'light' | 'dark';
}) => {
const { palette } = useTheme();

if (!content) return null;

const textColor = color ? palette.primary[color] : palette.text.primary;

return (
<BlocksRenderer
content={content}
blocks={{
image: ({ image }) => (
<Image
src={image.url}
width={image.width}
height={image.height}
alt={image.alternativeText || ''}
/>
),
paragraph: ({ children }) => (
<Typography variant='body1' color={textColor}>
{children}
</Typography>
),
heading: ({ children, level }) => (
<Typography variant={`h${level}`} color={textColor}>
{children}
</Typography>
),
}}
/>
);
};

export default BlocksRendererClient;
229 changes: 225 additions & 4 deletions apps/nextjs-website/src/lib/strapi/__tests__/homepage.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NullToUndefined, StrapiHomepageCodec } from '@/lib/strapi/homepage';
import { StrapiHomepageCodec } from '@/lib/strapi/homepage';
import * as E from 'fp-ts/lib/Either';
import { NullToUndefinedCodec } from '../codecs/NullToUndefinedCodec';

const makeStrapiResponseJson = () => ({
data: {
Expand Down Expand Up @@ -48,6 +49,222 @@ const makeStrapiResponseJson = () => ({
{
id: 1,
title: 'aText',
subheadColor: 'contrastText',
subhead: [
{
type: 'paragraph',
children: [
{
type: 'text',
text: 'aText',
},
{
text: 'aText',
type: 'text',
bold: true,
},
{
text: 'aText',
type: 'text',
italic: true,
},
{
text: 'aText',
type: 'text',
underline: true,
},
{
text: 'aText',
type: 'text',
strikethrough: true,
},
{
text: 'aText',
type: 'text',
code: true,
},
{
text: 'aText',
type: 'text',
},
],
},
{
type: 'paragraph',
children: [
{
type: 'text',
text: '',
},
{
type: 'link',
url: 'https://aLink.com',
children: [
{
type: 'text',
text: 'aText',
},
],
},
{
text: '',
type: 'text',
},
],
},
{
type: 'heading',
children: [
{
type: 'text',
text: 'aHeading',
},
],
level: 1,
},
{
type: 'heading',
children: [
{
type: 'text',
text: 'aHeading',
},
],
level: 2,
},
{
type: 'heading',
children: [
{
type: 'text',
text: 'aHeading',
},
],
level: 3,
},
{
type: 'heading',
children: [
{
type: 'text',
text: 'aHeading',
},
],
level: 4,
},
{
type: 'heading',
children: [
{
type: 'text',
text: 'aHeading',
},
],
level: 5,
},
{
type: 'heading',
children: [
{
type: 'text',
text: 'aHeading',
},
],
level: 6,
},
{
type: 'list',
format: 'ordered',
children: [
{
type: 'list-item',
children: [
{
type: 'text',
text: 'aText',
},
],
},
{
type: 'list-item',
children: [
{
type: 'text',
text: 'aText',
},
],
},
],
},
{
type: 'image',
image: {
name: 'a-image.jpg',
alternativeText: 'a-image.jpg',
url: 'http://localhost:1337/uploads/a-image.jpg',
caption: null,
width: 728,
height: 416,
formats: {
thumbnail: {
name: 'thumbnail_a-image.jpg',
hash: 'thumbnail_a_image_db00b47553',
ext: '.jpg',
mime: 'image/jpeg',
path: null,
width: 245,
height: 140,
size: 5.18,
url: '/uploads/thumbnail_a_image_db00b47553.jpg',
},
small: {
name: 'small_a-image.jpg',
hash: 'small_a_image_db00b47553',
ext: '.jpg',
mime: 'image/jpeg',
path: null,
width: 500,
height: 286,
size: 14.85,
url: '/uploads/small_a_image_db00b47553.jpg',
},
},
hash: 'a_image_db00b47553',
ext: '.jpg',
mime: 'image/jpeg',
size: 26.69,
previewUrl: null,
provider: 'local',
provider_metadata: null,
createdAt: '2024-03-21T17:11:46.709Z',
updatedAt: '2024-03-21T17:11:46.709Z',
},
children: [
{
type: 'text',
text: '',
},
],
},
{
type: 'quote',
children: [
{
type: 'text',
text: 'aText',
},
],
},
{
type: 'code',
children: [
{
type: 'text',
text: 'aText',
},
],
},
],
titleColor: 'contrastText',
callToAction: {
id: 1,
Expand Down Expand Up @@ -174,6 +391,8 @@ const makeStrapiResponseWithNullsJson = () => ({
id: 1,
title: 'aText',
titleColor: 'contrastText',
subhead: null,
subheadColor: null,
callToAction: {
id: 1,
variant: 'text',
Expand All @@ -191,6 +410,8 @@ const makeStrapiResponseWithNullsJson = () => ({
title: 'aText',
titleColor: null,
callToAction: null,
subhead: null,
subheadColor: null,
backgroundImage: {
data: {
id: 2,
Expand Down Expand Up @@ -273,14 +494,14 @@ describe('StrapiHomepageCodec', () => {
});
});

describe('NullToUndefined', () => {
describe('NullToUndefinedCodec', () => {
it('should decode null to undefined', () => {
const actual = NullToUndefined.decode(null);
const actual = NullToUndefinedCodec.decode(null);
expect(E.isRight(actual)).toBeTruthy();
});

it('should encode undefined to null', () => {
const actual = NullToUndefined.encode(undefined);
const actual = NullToUndefinedCodec.encode(undefined);
expect(actual).toBeNull();
});
});
Loading

0 comments on commit b842990

Please sign in to comment.