Featured Post
Sitecore NextJS Component Refactoring and Reusability
- Get link
- X
- Other Apps
The Sitecore Headless Services provide a different ways to consume the Sitecore Content into your Head application (website) depending on your need:
Sitecore Experience Platform (SXP) |
Sitecore Experience Manager |
Sitecore XM Cloud |
Sitecore Content Hub |
Sitecore Content Hub One |
The Sitecore Experience Platform is a true Headless Content Management System, and it provides the flexibility to implement a Head application with latest tech stack also, e.g., NextJS using sitecore-jss-nextjs SDK.
We can design Sitecore Renderings / Components with the help of sitecore-jss-nextjs SDK which provides the flexibility to view your web page in WYSIWYG (What You See Is What You Get) editor that allows you to easily make changes to items directly on the page. You can edit all the items that are visible on the page — text, graphics, logos, links, and so on.
Generally, the components developed using sitecore-jss-nextjs SDK are tightly coupled with the Sitecore implementation and developed as a SINGLE entity / object. It means it will not provide the reusability so that one component can be reused on multiple functionalities: Let’s consider, you have different types of pages or content types in your Sitecore PLAY! Summit Demo Web application:
- Session
- Speaker
- Vendor
- Sponsor
All the above content types have some fields which are common, e.g.
- Background Image
- Heading
- Name
By this way we can reuse these new components in many places/times, and find below the high level of refactoring details are: The reusability provides many benefits, and some are:
- Easy to maintain
- Design from reusable components is likely to cost less
- Modularization
- Consistency across the ecosystem
- Loose Coupling
- Ensure Flexibility
- Low maintenance
Create new rendering item Content Hero Banner (/sitecore/layout/Renderings/Project/edgewebsite/Common/ContentHeroBannerComponent) at Sitecore CMS, so that each content type (Sessions/Speakers/Vendors/Sponsors) will use the same rendering item and remove the existing rendering which render the Hero Banner Information e.g., SessionInformationPageHero, SpeakerInformationPageHero, etc..
Now create the NextJS rendering for the ContentHeroBannerComponent at /Website/src/rendering/src/components/Common/ContentHeroBannerComponent.tsx in the rendering code base:NextJS Types to store the Sitecore Layout Service Data:
- BaseContent
Create the Sitecore NextJS type baseContent to store the common fields at /Website/src/rendering/src/types/Common/ContentBanner/baseContent.ts in the rendering code base:
import { Field, ImageField } from '@sitecore-jss/sitecore-jss-nextjs'; export interface BaseContent { Name: Field<string>; Image: ImageField; }; export interface SocialMediaProfiles { FacebookProfileLink?: Field<string>; TwitterProfileLink?: Field<string>; InstagramProfileLink?: Field<string>; LinkedinProfileLink?: Field<string>; }
- contentBannerProps
Create the Sitecore NextJS type contentBannerProps to store the different content types at Website\src\rendering\src\types\Common\ContentBanner\contentBannerProps.ts in the rendering code base:
import { Room } from 'src/types/room'; import { Day } from 'src/types/day'; import { Timeslot } from 'src/interfaces/Timeslot'; import { BaseContent, SocialMediaProfiles } from './baseContent'; import { Field, ImageField } from '@sitecore-jss/sitecore-jss-nextjs'; export type ContentBannerProps = | SessionInformationPageHeroProps | InformationPageHeroProps | BannerProps export interface SessionInformationPageHeroProps extends BaseContent { Rooms: Room[]; Day: Day[]; Timeslots: Timeslot[]; Premium: Field<boolean>; TemplateName:string; } export interface InformationPageHeroProps extends BaseContent,SocialMediaProfiles { Rooms: Room[]; Day: Day[]; Timeslots: Timeslot[]; Premium: Field<boolean>; Featured: Field<boolean>; Picture: ImageField; JobTitle: Field<string>; Company: Field<string>; Location: Field<string>; TemplateName:string; Logo: ImageField; Level: Field<string>; } export type BannerProps = BaseContent
- types
Create the Sitecore NextJS type types , used to define the fields for common PageContent at Website\src\rendering\src\features\PageContent\types.ts in the rendering code base:
import { Field } from "@sitecore-jss/sitecore-jss-nextjs" export type DisplayNameProps = { Name: Field<string>; }; export type DisplayTitleProps = { Title: string; };
We have created following Sitecore NextJS components which helps to refactor the Hero Banner components:
- InformationPageHero
The SitecoreNextJS component InformationPageHero called from the ContentHeroBanner component to render the Hero Banner for the all the Content Type pages:
import { LayoutServicePageState, Text, useSitecoreContext } from '@sitecore-jss/sitecore-jss-nextjs'; import { faFacebookF, faTwitter, faLinkedinIn, faInstagram, } from '@fortawesome/free-brands-svg-icons'; import SocialIcon from 'components/NonSitecore/SocialIcon'; import { InformationPageHeroProps } from 'src/types/Common/ContentBanner/contentBannerProps'; import SessionHeroBanner from './SessionHeroBanner'; import DisplayName from 'src/features/PageContent/components/DisplayName'; import DisplayTitle from 'src/features/PageContent/components/DisplayTitle'; const InformationPageHero = (props: InformationPageHeroProps): JSX.Element => { const { sitecoreContext } = useSitecoreContext(); const isPageEditing = sitecoreContext.pageState === LayoutServicePageState.Edit; let lowerCaseQualificative =""; let imageSrc=""; if(props.TemplateName=="Speaker") { lowerCaseQualificative = props?.Featured?.value ? 'featured' : ''; imageSrc =props.Picture.value?.src } else if(props.TemplateName=="Vendor" || props.TemplateName=="Sponsor") { lowerCaseQualificative = props?.Level?.value ? props?.Level?.value.toLocaleLowerCase() : ''; imageSrc =props.Logo.value?.src } const informations = props.JobTitle?.value || props.Company?.value || props.Location?.value || isPageEditing ? ( <> {props.JobTitle?.value || isPageEditing ? ( <div> <span className="label">Job Title:</span>{' '} <Text field={props.JobTitle} tag="span" /> </div> ) : undefined} {props.Company?.value || isPageEditing ? ( <div> <span className="label">Company:</span> <Text field={props.Company} tag="span" /> </div> ) : undefined} {props.Location?.value || isPageEditing ? ( <div> <span className="label">Location:</span>{' '} <Text field={props.Location} tag="span" /> </div> ) : undefined} </> ) : undefined; const informationsHTML = informations ? ( <div className="informations">{informations}</div> ) : undefined; return props.TemplateName == "Session" ? ( <SessionHeroBanner Premium={undefined} Rooms={[]} Day={[]} Timeslots={[]} TemplateName={props.TemplateName} {...props} /> ) : ( <section className={`information-page-hero ${props.TemplateName.toLocaleLowerCase()}-information-page-hero ${lowerCaseQualificative}`} > <div className="content"> <div className="image-container"> {/* Purposefully not using a JSS Image component here to avoid width/height HTML attributes on the img tag */} <img src={imageSrc} alt="Image" loading="lazy" /> </div> <div className="gradient-container"></div> <div className="content-container"> <div className={`container-content-text`}> <div> <DisplayTitle Title={"Meet the <span className='information-type'>" + lowerCaseQualificative + "</span> " + props.TemplateName.toLocaleLowerCase() + ":"} /> <DisplayName Name={props.Name} /> </div> {informationsHTML} <div className="external-website-icons"> <SocialIcon Icon={faFacebookF} Link={props.FacebookProfileLink} /> <SocialIcon Icon={faTwitter} Link={props.TwitterProfileLink} /> <SocialIcon Icon={faLinkedinIn} Link={props.LinkedinProfileLink} /> <SocialIcon Icon={faInstagram} Link={props.InstagramProfileLink} /> </div> </div> </div> </div> </section> ) /* ( )*/ }; export default InformationPageHero;
- SessionHeroBanner
The SitecoreNextJS component SessionHeroBanner called from the InformationPageHero component if page item template name is Session, and this component will take care of rendering of Session Page Hero Banner:
import { faCalendar, faClock, faDoorOpen } from '@fortawesome/free-solid-svg-icons'; import InfoText from 'components/NonSitecore/InfoText'; import { getSessionDays, getSessionTime } from 'src/helpers/DateHelper'; import { InformationPageHeroProps } from 'src/types/Common/ContentBanner/contentBannerProps'; import { Text } from '@sitecore-jss/sitecore-jss-nextjs'; import DisplayName from 'src/features/PageContent/components/DisplayName'; import DisplayTitle from 'src/features/PageContent/components/DisplayTitle'; const SessionHeroBanner = (props: InformationPageHeroProps): JSX.Element => { const premiumSessionQualificative = props.Premium.value ? 'premium' : ''; return ( <section className={`session-information-page-hero ${premiumSessionQualificative}`}> <div className="background-container" style={{ backgroundImage: 'url(' + props.Image.value?.src + ')', }} > <div className="content"> <div className="image-container bg-cover bg-center flex-1 min-h-full" style={{ background: 'linear-gradient(to right, rgba(60, 60, 60, 0) 70%, rgba(0, 0, 0, 1) 100%)', }} > </div> <div className="content-container"> <div className="container-content-text"> <div> <DisplayTitle Title={"Explore the <span className='information-type'>" + premiumSessionQualificative + "</span> session: "} /> <DisplayName Name={props.Name} /> </div> <div> {/* Dispaly Multiple Rooms*/} {props?.Rooms && ( <InfoText Icon={faDoorOpen}> {props?.Rooms.map((roomDetails, index) => ( <Text style={{marginRight: 1 + 'em'}} key={index} tag="span" field={roomDetails?.fields?.Name} /> ))} </InfoText> )} <InfoText Icon={faCalendar}> <span>{getSessionDays(props.Day)}</span> </InfoText> <InfoText Icon={faClock}> <span>{getSessionTime(props.Timeslots)}</span> </InfoText> </div> </div> </div> </div> </div> </section> ); }; export default SessionHeroBanner;
We have created following Sitecore NextJS components which helps to display the common information with common UI, and reused in InformationPageHero and SessionHeroBanner components:
- DisplayTitle
The SitecoreNextJS component DisplayTitle called from the InformationPageHero and SessionHeroBanner component to render the Rich Text:
import { RichText } from '@sitecore-jss/sitecore-jss-nextjs'; import { DisplayTitleProps } from '../types'; const DisplayTitle = (props: DisplayTitleProps): JSX.Element => ( <section> <p className="title"> <RichText field={{ value: props?.Title }} /> </p> </section> ); export default DisplayTitle;
- DisplayName
The SitecoreNextJS component DisplayName called from the InformationPageHero and SessionHeroBanner component to render the Text field:
import { Text } from '@sitecore-jss/sitecore-jss-nextjs'; import { DisplayNameProps } from '../types'; const DisplayName = (props: DisplayNameProps): JSX.Element => ( <section> <h1 className="name"> <Text key="{props?.fields?.Name.value}" field={props?.Name} /> </h1> </section> ); export default DisplayName;
You also need to remove the existing components SessionInformationPageHero/SponsorInformationPageHero/VendorInformationPageHero/SponsorInformationPageHero from page templates of content types (standard values) and need to use ContentHeroBannerComponent component, which will take care of rendering the Hero Banner for different content types.
Above refactoring details are just the one of the way to refactor the existing components in your Sitecore NextJS application code base, and generally refactoring involves lots of time and efforts, so need to be considered as important tasks in your sprint planning.
This repository is used for the primary demo code base for Sitecore Edge for Content Hub and Experience Management.
- Get link
- X
- Other Apps
Comments