@newskit-render/standalone-components
TypeScript icon, indicating that this package has built-in type declarations

3.20.13 • Public • Published

@newskit-render/standalone-components

Overview

The Standalone-components package contains components, that can live within or outside the Render application.

Getting started

Install the package to start using it. Depending on your package manager, run:

For yarn: yarn add @newskit-render/standalone-components

For npm: npm install @newskit-render/standalone-components.

Components

1. Article recommendations

Article recommendations implementation is split into two main components:

  • ArticleRecommendationsProvider
  • RecommendedArticleList

Article Recommendations Provider

This component as the name suggests is a React context provider. It will hold the digital personalisation templates (DPATemplates), fetch the recommended articles and map them to the appropriate template.

The component takes the following props.

export type ArticleRecommendationsProviderProps = {
  articleId?: string
  context: ArticleRecommendationsProviderBaseContextType
  children: ReactNode
  config: Config
}

articleId is required to get the recommended articles for the given article

config is required to access NewsKit API to be able to fetch the recommended articles

export type Config = {
  newskitApiEnvUrl: string
  newskitApiXApiKey: string
}

The context holds the dpaTemplates dpaTemplate is a template, that holds information about the articles, ads and how they should be rendered on the screen.

const context: ArticleRecommendationsProviderContextType = {
  dpaTemplates: [
    {
      templateId: 'list-1',
      columnCount: '1',
      size: 'small',
     {
      templateId: 'list-1',
      columnCount: '1',
      size: 'small',
      recommendedArticlesCount: 4,
      ads: {
        count: 3,
        articlesMargin: 2,
        options: {
          id: 'dynamic-mpu',
          className: 'nuk-ad-placeholder',
          dataAdLabel: 'dynamicMpus',
        },
      },
    },
    {
      templateId: 'list-2',
      columnCount: { xs: '1', sm: '2', lg: '4' },
      size: 'large',
      recommendedArticlesCount: 8,
    },
  ],
}

dpa template props:

templateId template identifier used to uniquely identify the template

columnCount together with the totalArticlesCount will determine the layout. Example: list-1 will result in a 1x4 article grid, while list-2 will result in a 4x2 grid on a large screen.

size the size of the articles

recommendedArticlesCount is the number of the recommended articles ads is an optional object containing data for ads Ads props: count the number of ads that we want to have in the current template articlesMargin is the number of articles that you want to have in between the ads options.id will contain the prefix of the ad id(E.G dynamic-mpu-1, dynamic-mpu-2 etc.) options.className is the class name used for all ads options.dataAdLabel is the data attribute used for all ad

RecommendedArticleList

This component should be a children of Article Recommendations provider. It's purpose is to render all articles and ads from a specific dpa template based on a template id

Usage

In order to use Article recommendations provider and recommended articles list you must wrap your page or the section where you want to display recommendations.

You need to pass to Article recommendations provider the context object, that holds dpa templates and the config for Newskit API.

Then you can use RecommenedArticleList as a children of ArticleRecommendationsProvider and pass it a template id, that is used as an id in one of the dpa templates.

See example below:

const context: ArticleRecommendationsProviderContextType = {
  dpaTemplates: [
    {
      templateId: 'list-1',
      columnCount: '1',
      size: 'small',
     {
      templateId: 'list-1',
      columnCount: '1',
      size: 'small',
      recommendedArticlesCount: 4,
      ads: {
        count: 3,
        articlesMargin: 2,
        options: {
          id: 'dynamic-mpu',
          className: 'nuk-ad-placeholder',
          dataAdLabel: 'dynamicMpus',
        },
      },
    },
    {
      templateId: 'list-2',
      columnCount: { xs: '1', sm: '2', lg: '4' },
      size: 'large',
      recommendedArticlesCount: 8,
    },
  ],
}
const Article: React.FC<ArticleSlug> = ({
  universalArticle,
  articleURL,
  twitterUsername,
  siteHost,
  gscId,
  user,
  articleId,
  config,
}) => (
  <ArticleRecommendationsProvider articleId={articleId} config={config} context={context}>
      <RecommendedArticleList templateId="list-1" />
        ...
      <RecommendedArticleList templateId="list-2" />
  </ArticleRecommendationsProvider>
)

export async function getServerSideProps(context) {
  return {
    props: {
      config: {
        newskitApiEnvUrl,
        newskitApiXApiKey,
      },
      articleId,
    },
  }
}

4. Help-hub:

Help-Hub is a section of a website on which your customers can search for a specific problem and find some help to resolve it. It consists of three parts:

  1. Landing page: Where the user is able to search their queries and see the most common questions.
  2. Search results page: Displaying the relevant results based on the user query. To facilitate the search we are using Algolia.
  3. Help article page: Page displaying a specific search result.

The Help-hub pages will work independent of other components and are customized using the context.

Prerequisite

Help-hub is designed to work only with Next.js, so make sure that your app is running with Next.js Before integrating Help-hub, you must ensure that you have an Algolia (Search API) account. If you don't have an account, please create one. After you have obtained an Algolia account, you need to insert the data in it (see docs: https://www.algolia.com/doc/guides/sending-and-managing-data/send-and-update-your-data/#pushing-your-data-to-an-algolia-index). The data must follow the following format:

{
  title: string
  objectID: string
  content: string
}

For obtaining the Algolia credentials, ask your manager If your team does not have account, you will have to request or create such

Ask CSP for futher information about populating the data in Algolia. They can assist for getting the data from Salesforce. Slack channel: #cps-support

How to use

1. Credentials

You need to have Algolia credentials as enviromnent variables:

  • ALGOLIA_API_KEY
  • ALGOLIA_APP_ID
  • ALGOLIA_INDEX

2. Implementation

2.1. Context

This is the default context for all the pages use out of the box

export const baseContext: BaseContextOptions = {
  baseUrl: '/help-hub',
  seo: {
    title: 'Help Hub',
    description: '',
    url: '',
    siteHost: '',
    hrefLang: '',
  },
  navigationPrimary: {
    nav: [
      {
        text: 'Section One',
        link: '/section-one',
        icon: null,
        ariaLabel: 'Section One Link',
      },
      {
        text: 'Section Two',
        link: '/section-two',
        icon: null,
        ariaLabel: 'Section Two Link',
      },
      {
        text: 'Section Three',
        link: '/section-three',
        icon: null,
        ariaLabel: 'Section Three Link',
      },
    ],
  },
  header: {
    overlineOverrides: {
      typographyPreset: {
        xs: 'utitityLabel020',
        sm: 'utitityLabel030',
      },
      stylePreset: 'inkBrand010',
      marginBlockEnd: 'space040',
    },
    title: '',
    titleOverrides: {
      typographyPreset: { xs: 'utilityHeading040', sm: 'utilityHeading050' },
      stylePreset: 'inkContrast',
      marginBlockEnd: 'space000',
      as: 'h1',
    },
    description: '',
    descriptionOverrides: {
      typographyPreset: { xs: 'utilityBody020', sm: 'utilityBody030' },
      stylePreset: 'inkBase',
      marginBlockEnd: 'space000',
    },
    backButtonOverrides: {
      marginBlockEnd: { xs: 'space050', sm: 'space060', md: 'space070' },
      stylePreset: 'buttonOutlinedSecondary',
      typographyPreset: 'utilityButton010',
      iconSize: 'iconSize010',
    },
    marginBlockEnd: { xs: 'space050', sm: 'space060', md: 'space040' },
    showDivider: false,
  },
  searchBar: {
    marginBlockEnd: { xs: 'space060', sm: 'space080' },
    color: 'inkBase',
    placeholder: {
      color: 'inkSubtle',
      typographyPreset: 'utilityBody030',
    },
    icon: {
      color: 'inkBrand010',
      position: 'right' as const,
    },
    autocomplete: {
      color: 'interactivePrimary030',
    },
    border: {
      style: '1px solid',
      color: 'interactiveInput020',
    },
    outline: {
      style: 'outlineStyleDefault',
      color: 'outlineColorDefault',
      width: 'outlineWidthDefault',
    },
  },
  contentListView: {
    introduction: {
      marginBlockEnd: 'space060',
    },
  },
  articleNotFound: "Sorry, we can't find the article you are looking for",
  searchResultEmpty: "Sorry, we can't find the result you are looking for",
  marginBlockEnd: { xs: 'space070', md: 'space090' },
  inputPlaceholder: 'Describe your issue',
  footer: {
    menuItemArray: [
      { text: 'About us', href: '/about-us', id: 1 },
      {
        text: 'Privacy & cookie policy',
        href: 'http://www.newsprivacy.co.uk/',
        id: 3,
      },
      { text: 'Terms & conditions', href: '/terms-and-conditions', id: 4 },
    ],
    legalText: `© NewsKit Limited ${new Date().getFullYear()}.
      Registered in England No. 000000. Registered office: 1 London Bridge Street, SE1 9GF.`,
  },
  footerOverrides: {
    ariaLabel: 'Footer Menu',
    menuItemOverrides: {
      stylePreset: 'baseInteractivePrimary030',
      typographyPreset: 'utilityButton020',
    },
    menuOverrides: {
      marginBlockEnd: 'space050',
      backgroundColor: 'interface010',
      borderColor: 'interface050',
      padding: {
        md: 'sizing090',
        xs: 'sizing040',
      },
    },
    legalTextOverrides: {
      marginBlockEnd: 'space050',
      stylePreset: 'legalText',
      typographyPreset: 'utilityMeta010',
      padding: {
        md: 'sizing100',
        xs: 'sizing060',
      },
    },
  },
}

2.2 Properties of BaseContextOptions

  1. baseUrl - relative url when the help hub landing page lives

  2. seo: - Used in the Header component

    • title: string
    • description: string
    • url: string
    • siteHost: string
    • hrefLang: string
  3. navigationPrimary - Global property changes nav links in top banner area - Array of nav objects or false to have no nav

    • nav?:
      • text: string
      • link: string
      • icon: React.ReactElement
      • ariaLabel?: string
    • title?: string
    • logoSrc?: string (path to logo.svg)
    • logoWidth?: string (width of logo)
    • titlePosition?: string (uses css top property to ajust title position)
  4. header - Property used to change the title value and styles of each page

    • overlineOverrides

      • typographyPreset: MQ
      • stylePreset: MQ
      • marginBlockEnd: MQ
    • title: string

    • titleOverrides

      • typographyPreset: MQ
      • stylePreset: MQ
      • marginBlockEnd: string
      • as: h1 | h2 | h3 | h4 | h5 | h6
    • description: string

    • descriptionOverrides

      • typographyPreset: MQ
      • stylePreset: MQ
      • marginBlockEnd: string
    • backButtonOverrides

      • marginBlockEnd: MQ
      • stylePreset: MQ
      • typographyPreset: MQ
      • iconSize: MQ
    • marginBlockEnd: MQ

    • showDivider: boolean

  5. searchBar: Property used to style the search bar container

    • marginBlockEnd: MQ
    • color: string - Search bar input text color
    • placeholder
      • color: string - Placeholder text color
      • typographyPreset: string
    • icon
      • color: string - Search icon color
      • position: string - Position of the icon relative to the search input text.
    • autocomplete
      • color: string - Autocomplete results text color
    • border
      • style: string - Style of the search bar border.
      • color: string - Border color.
    • outline
      • style: string - Style of the search bar outline
      • color: string - outline color
      • width: string - outline width
  6. contentListView: Property used to style the results table

    • introduction: - Used to style the table title
      • marginBlockEnd: MQ
  7. articleNotFound: string - Warning message for when the article is not found

  8. searchResultEmpty: string - Warning message for when there is not search string

  9. marginBlockEnd: MQ

  10. inputPlaceholder: string - Search bar placeholder

  11. footer: Global property

    • menuItemArray: [ { text: string href: string id: integer, } ]
    • legalText: string
  12. footerOverrides: Global property

    • ariaLabel: string

    • menuItemOverrides:

      • stylePreset: MQ
      • typographyPreset: MQ
    • menuOverrides:

      • marginBlockEnd: MQ
      • backgroundColor: MQ
      • borderColor: MQ
      • padding: MQ
    • legalTextOverrides:

      • marginBlockEnd: MQ
      • stylePreset: MQ
      • typographyPreset: MQ
      • padding: MQ

As said above, help hub consists of three pages and we will take a look on how to add each one of them individually.

Each page extend the above BaseContextOptions with their own properties:

2.3 HelpHubLandingPageContextOptions

  1. articlesTabelInfo
    • title: string
    • titleOverrides
      • typographyPreset: MQ
      • stylePreset: MQ
      • marginBlockEnd: string
      • as: h1 | h2 | h3 | h4 | h5 | h6
  2. mostReadArticles: [ {
    • title: string
    • objectID: string } ]

2.4 ResultsPageContextOptions

  1. hits: [ {

    • title: string
    • objectID: string
    • content: string } ]
  2. introductionProps:

    • title: string
    • titleOverrides
      • typographyPreset: MQ
      • stylePreset: MQ
      • marginBlockEnd: string
      • as: h1 | h2 | h3 | h4 | h5 | h6
    • description: string
    • showDivider: boolean
  3. stylePreset: MQ

  4. showDividerByBreakpoint: boolean

2.5 ArticlePageContextOptions

  1. introductionProps:

    • titleOverrides
      • typographyPreset: MQ
      • stylePreset: MQ
      • marginBlockEnd: string
      • as: h1 | h2 | h3 | h4 | h5 | h6
  2. title: string

  3. content: string

  4. searchBreadcrumbContext?:

    • searchBreadcrumbProps?: Omit<BreadcrumbsProps, 'children'> see Newskit
    • notFoundBreadcrumbProps?: Omit<BreadcrumbsProps, 'children'>
    • searchBreadcrumbItemOne?: string
    • searchBreadcrumbItemTwo?: string

Standalone-components package exports page components, page context, page context types (PageContextOptions) and a provider function for each page.

2.6 Help-Hub Landing page.

As stated above, landing page will display the most read articles. For now these articles are hardcoded and need to be passed to the Landing page (see example below). These articles must be already imported in Algolia in order for them to work.

This example shows how to set up the page and override the page context with your own values:

import React, { useContext } from 'react'
import newrelic from 'newrelic'
import {
  AlgoliaCredentials,
  HelpHubLandingPage,
  helpHubLandingPageContext,
  HelpHubLandingPageContextOptions,
  helpHubLandingPageProvider,
} from '@newskit-render/standalone-components'
import { createThemeDropdownObject } from '../../helpers/createThemeDropdownObject'
import { AppContext } from '../../context'
import { addCacheHeaders } from '../../helpers/addCacheHeaders'

const landingPageContext: Partial<HelpHubLandingPageContextOptions> = {
  ...helpHubLandingPageContext,
  header: {
    title: 'Your custom title',
  },
  mostReadArticles: [
    {
      title: 'Sign-in with Google',
      objectID: 'sign-with-google',
    },
    {
      title:
        'I am trying to share an article via Google+ but an error message keeps appearing',
      objectID:
        'i-am-trying-to-share-an-article-via-google-but-an-error-message-keeps-appearing',
    },
    {
      title: 'How will I find out if I have won a competition?',
      objectID: 'how-will-i-find-out-if-i-have-won-a-competition',
    },
    {
      title: 'How do I login/reset my password?',
      objectID: 'how-do-i-login-reset-my-password',
    },
    {
      title: 'How do I cancel or change my pack?',
      objectID: 'how-do-i-cancel-or-change-my-pack',
    },
    {
      title: 'Can I share my Times & Sunday Times iPad subscription access?',
      objectID: 'can-i-share-my-times-sunday-times-ipad-subscription-access',
    },
  ],
}

const LandingPage: React.FC<{
  credentials: AlgoliaCredentials
}> = (props) => {
  const { theme, setTheme } = useContext(AppContext)
  const themeDropdownObject = createThemeDropdownObject(setTheme)

  return (
    <HelpHubLandingPage
      {...props}
      context={landingPageContext}
      customTheme={theme}
      themeDropdownObject={themeDropdownObject}
    />
  )
}

export default LandingPage

export const getServerSideProps = async (context) => {
  newrelic.setTransactionName('HelpHubLandingPage')
  console.warn('context:')
  console.warn(context.req && context.req.headers)
  addCacheHeaders(context.res)

  return helpHubLandingPageProvider()
}

2.7 Help-hub Search Results page.

example usage:

import React, { useContext } from 'react'
import newrelic from 'newrelic'
import {
  HelpHubResultsPage,
  AlgoliaCredentials,
  Hit,
  helpHubResultsProvider,
  helpHubResultsPageContext,
  HelpHubResultsPageContextOptions,
} from '@newskit-render/standalone-components'
import { createThemeDropdownObject } from '../../helpers/createThemeDropdownObject'
import { AppContext } from '../../context'
import { addCacheHeaders } from '../../helpers/addCacheHeaders'

const resultsPageContext: Partial<HelpHubResultsPageContextOptions> = {
  ...helpHubResultsPageContext,
  header: {
    title: 'Search results custom title',
    description: 'Your search for "##QUERY##" returned ##COUNT## results',
    titleOverrides: {
      marginBlockEnd: 'space050',
    },
    marginBlockEnd: 'space060',
  },
  searchBar: {
    marginBlockEnd: { xs: 'space060', md: 'space070' },
  },
  marginBlockEnd: { xs: 'space060', sm: 'space070', md: 'space090' },
}

const ResultsPage: React.FC<{
  credentials: AlgoliaCredentials
  hits: Hit[]
}> = (props) => {
  const { theme, setTheme } = useContext(AppContext)
  const themeDropdownObject = createThemeDropdownObject(setTheme)

  return (
    <HelpHubResultsPage
      {...props}
      customTheme={theme}
      context={resultsPageContext}
      themeDropdownObject={themeDropdownObject}
    />
  )
}

export default ResultsPage

export const getServerSideProps = async (context) => {
  newrelic.setTransactionName('HelpHubResultsPage')
  console.warn('context:')
  console.warn(context.req && context.req.headers)
  addCacheHeaders(context.res)

  return helpHubResultsProvider(context)
}

By default ResultsPage will return up to 20 results. This can be changed by adding a second parameter to helpHubResultsProvider

export const getServerSideProps = async (context) => {
  newrelic.setTransactionName('HelpHubResultsPage')
  console.warn('context:')
  console.warn(context.req && context.req.headers)
  addCacheHeaders(context.res)

  return helpHubResultsProvider(context, 10)
}

2.8 Help-hub Help Article page. Article page uses Next.js router to get the article parameter in order to fetch the article. The parameter is called title. That means that your path in Next routing system should look like this:

help-hub/article/[title]/index.tsx

Example use:

import React, { useContext } from 'react'
import newrelic from 'newrelic'
import {
  AlgoliaCredentials,
  HelpHubArticlePage,
  helpHubArticleProvider,
  helpHubArticlePageContext,
  HelpHubArticlePageContextOptions,
} from '@newskit-render/standalone-components'
import { createThemeDropdownObject } from '../../../../helpers/createThemeDropdownObject'
import { AppContext } from '../../../../context'
import { addCacheHeaders } from '../../../../helpers/addCacheHeaders'

const articlePageContext: Partial<HelpHubArticlePageContextOptions> = {
  ...helpHubArticlePageContext,
  introductionProps: {
    titleOverrides: {
      typographyPreset: { xs: 'utilityHeading040', sm: 'utilityHeading050' },
      stylePreset: 'inkContrast',
      marginBlockEnd: 'space040',
      as: 'h1',
    },
  },
}

const ArticlePage: React.FC<{
  credentials: AlgoliaCredentials
  title: string
  content: string
}> = (props) => {
  const { theme, setTheme } = useContext(AppContext)
  const themeDropdownObject = createThemeDropdownObject(setTheme)

  return (
    <HelpHubArticlePage
      {...props}
      customTheme={theme}
      context={articlePageContext}
      themeDropdownObject={themeDropdownObject}
    />
  )
}

export default ArticlePage

export const getServerSideProps = async (context) => {
  newrelic.setTransactionName('HelpHubArticlePage')
  console.warn('context:')
  console.warn(context.req && context.req.headers)
  addCacheHeaders(context.res)

  return helpHubArticleProvider(context)
}

Readme

Keywords

none

Package Sidebar

Install

npm i @newskit-render/standalone-components

Weekly Downloads

589

Version

3.20.13

License

UNLICENSED

Unpacked Size

746 kB

Total Files

500

Last publish

Collaborators

  • newskit