Finishing up your integration

May 22, 2024

Pricing section integration

Let’s look at the overview of the modeling required for the pricing elements:

The mapping from the definition to the visual elements is similar to what we have seen in the feature section. We again have a type that is composed of sub-type elements. This is done using the

+ * (solidTemplate:pricingTier)            

line. This is a child node definition that is restricted to a single content node type solidTemplate:pricingTier. The type definition is just below and is rather straightforward except for the feature property: it is multi-valued, and allowed to have a dynamic number of values, which will be useful when content editors want to list more or fewer features for a single pricing tier. Finally, the pricing button is modeled exactly like the hero section buttons.

Now let’s add the content definition in definitions.cnd

[solidTemplate:pricingTier]
 - price (string) = '49/month'
 - featuresTitle (string) = 'What you will get' i18n
 - feature (string) = 'Lorem ipsum dolor sit nisi' i18n multiple
 - pricingButtonText (string) = 'Pre order now' i18n
 - pricingButtonLink (weakreference) < jnt:page    

And then

[solidTemplate:pricingSection] > jnt:content, solidTemplatemix:solidTemplateComponents
 - title (string) = 'Unlimited for all' i18n
 - text (string) = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut ad quis nostrud.' i18n
+ * (solidTemplate:pricingTier)    

As we have two content type definitions, we will need two view files to render these. Let’s start with the pricingTier one, which is embedded in the pricingSection one. We will therefore create a file called $NPM_TEMPLATE/src/server/views/pricingTier/PricingTierDefault.jsx with the following content:

import React from 'react';
import { useServerContext, getNodeProps, buildUrl } from '@jahia/js-server-core';

export const PricingTierDefault = () => {
    const {currentNode, renderContext, currentResource} = useServerContext();
    const props = getNodeProps(currentNode, ['featuresTitle', 'feature', 'price', 'pricingButtonText', 'pricingButtonLink']);
    
    return (
        <div className="pricing-table">
            <div className="pricing-table-inner is-revealing">
                <div className="pricing-table-main">
                    <div className="pricing-table-header pb-24">
                        <div className="pricing-table-price"><span className="pricing-table-price-currency h2">$</span><span className="pricing-table-price-amount h1">{props.price}</span></div>
                    </div>
                    <div className="pricing-table-features-title text-xs pt-24 pb-24">{props.featuresTitle}</div>
                    <ul className="pricing-table-features list-reset text-xs">
                        {props.feature.map(value => 
                            <li key={value}>
                                <span>{value}</span>
                            </li>
                        )}
                    </ul>
                </div>
                <div className="pricing-table-cta mb-8">
                    <a className="button button-primary button-shadow button-block" href={props.pricingButtonLink ? buildUrl({path:props.pricingButtonLink.getPath()}, renderContext, currentResource) : '#'}>{props.pricingButtonText}</a>
                </div>
            </div>
        </div>
    )
}

PricingTierDefault.jahiaComponent = {
    nodeType: 'solidTemplate:pricingTier',
    displayName: 'Pricing tier',
    componentType: 'view'
}

In this view, we have to render a multi-valued property (feature). We do so by simply iterating over the values as they are directly accessible as an array.

We can now work on the parent view, which will display the title, introduction text, and the list of pricing entries.

Basically let’s create a new file: $NPM_TEMPLATE/src/server/views/pricingSection/PricingSectionDefault.jsx with the following content:

import React from 'react';
import {Render, AddContentButtons, useServerContext, getChildNodes, getNodeProps} from '@jahia/js-server-core';

export const PricingSectionDefault = () => {
    const {currentNode} = useServerContext();
    const allChildren = getChildNodes(currentNode, -1);
    const props = getNodeProps(currentNode, ['title', 'paragraph']);

    return (
        <section className="pricing section">
            <div className="container-sm">
                <div className="pricing-inner section-inner">
                    <div className="pricing-header text-center">
                        <h2 className="section-title mt-0">{props.title}</h2>
                        <p className="section-paragraph mb-0">{props.paragraph}</p>
                    </div>
                    <div className="pricing-tables-wrap">
                        {allChildren && allChildren.map((child) =>
                            <Render path={child.getPath()} key={child.getIdentifier()} />
                        )}
                    </div>
                    <AddContentButtons />
                </div>
            </div>
        </section>
    )
}

PricingSectionDefault.jahiaComponent = {
    nodeType: 'solidTemplate:pricingSection',
    displayName: 'Pricing section',
    componentType: 'view'
}    

As done in the features section, we use the get to iterate through the node children nodes to render them using the Render helper.

Finally, the <AddContentButtons /> helper call is used to render, only in edit mode, a button to add new content nodes.

Now we can remove the hardcoded HTML section from the $NPM_TEMPLATE/src/server/templates/page/PageHome.jsx template. Simply remove the following HTML section:

            <section class="pricing section">
			... content removed for brevity...
            </section>    

Then we need to export our two views, we first need to create a src/server/views/pricingTier/index.js file with the following content:

export * from './PricingTierDefault';    

And then create a src/server/views/pricingSection/index.js file with the following content:

export * from './PricingSectionDefault';    

And finally we must add the new types to the main src/server/views/index.js file with the following content:

export * from './pricingTier';
export * from './pricingSection';    

We can now refresh our browser and creating the content by using a process exactly like the one for the features section:

  1. Click on the New content button in the page
  2. Open the base category
  3. Select the pricingSection type and click CREATE
  4. Click SAVE to create the section with the default values and then click the back button. You should now see the section with a pricingTier button.
  5. Click the New pricingTier button to open the Content Editor to create a new pricingTier content object.
  6. Notice the feature property that has an ADD button below it. Click that button a few times to add features. You may copy-paste the default text if you like or enter your own.
  7. Click the SAVE button and then the back button to return to the home page.
  8. Click the PREVIEW button to see what the resulting page looks like, it should look like this:

Call to action section

The call to action section is possibly the simplest of all the content type definitions in this template. Here is the overview:

First let’s add definition to definitions.cnd

[solidTemplate:ctaSection] > jnt:content, solidTemplatemix:solidTemplateComponents
 - text (string) = 'Still not convinced on buying?' i18n
 - ctaButtonText (string) = 'Get in touch' i18n
 - ctaButtonLink (weakreference) < jnt:page    

Creating its view is equally straightforward, in $NPM_TEMPLATE/src/server/views/ctaSection/CtaSectionDefault.jsx :

import React from 'react';
import {useServerContext, getNodeProps, buildUrl } from '@jahia/js-server-core';

export const CtaSectionDefault = () => {
    const {currentNode, renderContext, currentResource} = useServerContext();
    const props = getNodeProps(currentNode, ['text', 'ctaButtonLink', 'ctaButtonText']);
    return (
        <section className="cta section">
        <div className="container">
            <div className="cta-inner section-inner">
                <h3 className="section-title mt-0">{props.text}</h3>
                <div className="cta-cta">
                    <a className="button button-primary button-wide-mobile" href={props.ctaButtonLink ? buildUrl({path: props.ctaButtonLink.getPath()}, renderContext, currentResource) : '#'}>{props.ctaButtonText}</a>
                </div>
            </div>
        </div>
    </section>
    );
}

CtaSectionDefault.jahiaComponent = {
    nodeType: 'solidTemplate:ctaSection',
    displayName: 'Call to action section',
    componentType: 'view'
}    

Finally don’t forget to remove the hardcoded HTML section from the $NPM_TEMPLATE/src/server/templates/page/PageHome.jsx template:

			<section class="cta section">
				<div class="container">
					<div class="cta-inner section-inner">
						<h3 class="section-title mt-0">Still not convinced on buying?</h3>
						<div class="cta-cta">
							<a class="button button-primary button-wide-mobile" href="#">Get in touch</a>
						</div>
					</div>
				</div>
			</section>    

Then we need to export our view, we first need to create a src/server/views/ctaSection/index.js file with the following content:

export * from './CtaSectionDefault';    

And finally, we must add the new type to the main src/server/views/index.js file with the following content:

export * from './ctaSection';    

We can then re-create the content object using the following steps:

  1. Refresh your browser’s page
  2. Click on New content in the page
  3. Select the ctaSection content type and click CREATE
  4. Click SAVE to create the section content object and then click the back button
  5. Click the PREVIEW button to see what the resulting page looks like, it should look like this:

Next step

Continue to conclusion