Rendering a person
Contents
In this chapter you will add a new component that renders persons
Person content type
The Headless Movie DB contains sample content, and content types. One of these is Person
. From Content Studio, you may find and list persons. By selecting the JSON preview, you can also study the properties of a person:
{
"_id": "a8b374a2-c532-45eb-9aa1-73d1c37cd681",
"_name": "lea-seydoux",
"_path": "/hmdb/persons/lea-seydoux",
"creator": "user:system:su",
"modifier": "user:system:su",
"createdTime": "2021-11-23T10:01:16.711Z",
"modifiedTime": "2021-11-23T13:06:38.493Z",
"owner": "user:system:su",
"type": "com.enonic.app.hmdb:person",
"displayName": "Léa Seydoux",
"hasChildren": true,
"language": "en",
"valid": true,
"childOrder": "modifiedtime DESC",
"data": {
"photos": "09b3af0e-6da3-4bcf-88d9-11cbe9c41283",
"bio": "French actress Léa Seydoux was born in 1985 in Paris, France, to Valérie Schlumberger, a philanthropist, and Henri Seydoux, a businessman.",
"dateofbirth": "1985-07-01"
},
"x": {},
"page": {},
"attachments": {},
"publish": {
"from": "2024-11-13T13:32:39.427Z",
"first": "2024-11-13T13:32:39.427Z"
},
"workflow": {
"state": "READY",
"checks": {}
}
}
To implement the rendering we need to add code that will perform a two-step operation:
Fetch the data
-
Create a data fetcher
/src/main/resources/react4xp/components/PersonProcessor.tsimport type { Content } from '@enonic-types/lib-content'; import type { ContentTypeProcessorFunction } from '@enonic-types/lib-react4xp/DataFetcher'; import { imageUrl } from '/lib/xp/portal'; import { get as getContentByKey } from '/lib/xp/content'; /* interface Photo { _id: string; displayName: string; } */ export const personProcessor: ContentTypeProcessorFunction<Content<Record<string, unknown>>> = (params) => { log.info('personProcessor params:%s', params); const photos = params.content.data.photos; const firstPhotoId = Array.isArray(photos) ? photos[0] : photos; // Fetch the first photo const {_id, displayName} = getContentByKey<Content>({ key: firstPhotoId }); return { props: /*<PersonProps>*/{ displayName: `${params.content.displayName}`, photo: { _id, title: displayName, imageUrl: imageUrl({id: _id, scale: 'width(500)'}) } } }; };
-
Then add it to the dataFetcher, with these lines:
dataFetcherimport { personProcessor } from './components/PersonProcessor'; dataFetcher.addContentType('com.enonic.app.hmdb:person', { processor: personProcessor });
We are now able to fetch the Person data, next up we need to render it.
Register component
The component consists of two files:
//import type { PersonProps } from '/types/PersonProps';
import React from 'react'
//import * as React from 'react';
import * as styles from './Person.module.css';
export const Person = (props) => {
const {displayName, photo} = props as any;
return (
< >
<div /*className={styles.person}*/>
<h2>{displayName}</h2>
{
photo ? (
<img src={photo.imageUrl}
title={photo.displayName}
alt={photo.displayName}
width="500"
/>
) : (
<p>No photo available</p>
)
}
</div>
</>
)
}
+ ./src/main/resources/react4xp/components/Person.module.css (CSS module)
.person {
display: flex;
flex-direction: column;
}
.person,
.person .bio {
font-family: sans-serif;
}
.bio {
line-height: 24px;
}
.bio figcaption {
font-size: 12px;
}
.bio figure > img {
width: 100%;
height: auto;
}
.photos {
padding: 0 20px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 50px;
gap: 50px;
}
.photos img {
width: 100%;
height: auto; /* Ensures images scale properly */
}
@media screen and (max-width: 720px) {
.bio figure {
width: auto !important;
}
}
+ Once they are created register the component in the componentRegistry, by adding the following lines:
+ .componentRegistry
import { Person } from './components/Person';
componentRegistry.addContentType('com.enonic.app.hmdb:person', { View: Person });
Result
Back in Content Studio, select a random person to see the glorious result.