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:

Person JSON
{
    "_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

  1. Create a data fetcher

    /src/main/resources/react4xp/components/PersonProcessor.ts
    import 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)'})
    			}
    		}
    	};
    };
  2. Then add it to the dataFetcher, with these lines:

    dataFetcher
    import { 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:

/src/main/resources/react4xp/components/Person.tsx (React component)
//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.

Next

You are on a roll, next - lets look into how we may pass editorial content to the component via props.


Contents

Contents

AI-powered search

Juke AI