0.137.0 • Published 2 years ago

my-account-esm v0.137.0

Weekly downloads
-
License
UNLICENSED
Repository
-
Last release
2 years ago

@newskit-render/my-account

Getting Started

There are 2 ways to start with @newskit-render/my-account:

  1. If you want to build a project from scratch, that will have everything from newskit-render, you need to run create-render-app (See Newskit-Render Getting started).

  2. If you already have a next application and you want to include my-account package you just need to run yarn add @newskit-render/my-account or npm install @newskit-render/my-account based on which package manager you use. Next you need to create an account folder inside your pages folder, and you can add your account pages there:

import { PersonalDetails, getProviderProps } from '@newskit-render/my-account'

export default PersonalDetails

export const getServerSideProps = async (context) =>
  getProviderProps({ ...context, provider: 'PersonalDetails' })

Authentication

If you have already included my account into your application, you will be able to see account pages, but they won't be populated with any data. That's because my-account needs environment variables in order to connect with MAIN.

We assume that you already have created MAIN tenant for your title (If not, please check setup new MAIN tenant). Please ask a member of your team for the values of the environment variables.

MAIN_GRAPHQL_URL=""
MAIN_COOKIE_NAME=""

MAIN_GRAPHQL_URL: This is the main graphql endpoint for your tenant. You can ask someone from your team, or a member from main to provide it for you. MAIN_COOKIE_NAME: The prefix of the cookie that MAIN returns to you e.g acs_ngn. You can see examples of the other environment variables here(https://

If you are interested in my-account - main integration and you want some in-depth info about it, you can have a look at our space in confluence

Theming

The My Account package can take your custom theme. It uses NewsKit's theming system to enable customisation. See Newskit theming

To override the My Account base theme you need to pass a new theme as a prop of a page component:

import React from 'react'
import { PersonalDetails, getProviderProps, accountTheme } from '@newskit-render/my-account'
import { createTheme } from 'newskit'

const customTheme = createTheme({
  name: 'new-theme',
  baseTheme: accountTheme,
  overrides: {
    stylePresets: {
      ADD YOUR CUSTOM PRESETS
    }
  }
})

const AccountPersonalDetails = (props) => (
  <PersonalDetails {...props} customTheme={customTheme}  />
)

export default AccountPersonalDetails

export const getServerSideProps = async (context) =>
  getProviderProps({ ...context, provider: 'PersonalDetails' })

User the accountTheme as the base to any new theme you create. You can see this theme here

Page types

Currently provides a number of defualt pages, however they are based on 2 page types

  • Display
  • Edit

The current Display pages (pages/account/) are Personal Details page (PersonalDetails component), Subscription and Billing page (SubscriptionAndBilling component) and Newsletters & Alerts page (NewslettersAndAlerts component). They differ from Edit pages by using sections data type to display information (see Page overrides and Properties of ContextOptions for information on sections).

All Edit pages are currently accessed from pages/account/edit/[field].tsx (EditField component). They differ from Display pages by using forms data type to display forms you can edit user data with (see Page overrides and Properties of ContextOptions for information on forms).

Page overrides

The My Account package has data driven pages using React context. You can override defaults starting on a page bases.

The following examples will override aspects of the Personal Details page:

import React from 'react'
import { PersonalDetails, getProviderProps, ContextOptions, personalDetailsContext } from '@newskit-render/my-account'

const overrideContext: ContextOptions = {
  ...personalDetailsContext,
  header: {
    ...personalDetailsContext.header,
    description:
      'This will override the default header details',
  },
  sectionsOverrides: {
    list: {
      titleOverrides: {
        spaceStack: {
          xs: 'space040',
          md: 'space050',
        },
        typographyPreset: 'utilityHeading020',
        as: 'h3'
      },
    },
  },
}

const Page = (props) => <PersonalDetails context={overrideContext} {...props} />

export default Page

export const getServerSideProps = async (context) =>
  getProviderProps({ ...context, provider: 'PersonalDetails' })

The above overrides the pages header description and list items title styles.

const overrideContext: ContextOptions = {
  ...personalDetailsContext,
  sections: [
    {
      type: 'list',
      props: {
        introductionProps: {
          title: 'Section added'
        },
        items: [
          {
            label: 'Backup Email',
            type: 'email',
            default: '[You can add a backup email]',
            href: '/account/edit/backup-email',
            ariaLabel: 'Add bacup email',
          }
        ]
      }
    }
  ]
}

You can override the sections on the page

const overrideContext: ContextOptions = {
  ...personalDetailsContext,
  sections: [
    ...personalDetailsContext.sections,
    {
      type: 'list',
      props: {
        introductionProps: {
          title: 'Another section added'
        },
        items: [
          {
            label: 'Backup Email',
            type: 'email',
            default: '[You can add a backup email]',
            href: '/account/edit/backup-email',
            ariaLabel: 'Add bacup email',
          }
        ]
      }
    }
  ]
}

Add onto the existing sections.

The following examples will override aspects of Edit pages pages/account/edit/[field].tsx:

import React from 'react'
import { EditField, getProviderProps, ContextOptions, editFieldContext } from '@newskit-render/my-account'
import { IconFilledInfo, IconFilledSearch } from 'newskit'
import validation from '../../../validation'

const overrideContext: ContextOptions = {
  ...editFieldContext,
  forms: {
    ...editFieldContext.forms,
    password: {
      header: {
        title: 'Change your Password',
        image: {
          src: '/MyAccount/personal-details-header.svg',
          alt: '',
        },
        showDivider: true,
      },
      props: {
        text: [
          'For extra security we will send you a <b>change password link</b> to the email saved in your account.',
          'The link can only be used once and expires in 20 minutes.',
        ],
        textOverriders: {
          typographyPreset: {
            xs: 'utilityBody020',
            sm: 'utilityBody030',
          },
          stylePreset: 'inkBase',
          spaceStack: {
            xs: 'space060',
            sm: 'space070',
          },
        },
        buttonGroupProps: {
          primaryText: 'Get Link',
        },
      },
    },
    name: {
      props: {
        inputText: {
          cells: {
            xs: 12,
            md: 6,
          },
        },
        infoPanel: {
          icon: <IconFilledInfo overrides={{ size: 'iconSize030' }} />,
          children:
            'We will only use your name to comunicate with you directly. When making comments on our websites and apps, your ‘display name’ is used to protect your identity.',
          infoPanelCells: {
            xs: 12,
            md: 8
          },
          spaceStack: 'space060',
        },
      },
    },
    address: {
      header: {
        description: 'You can edit your address here.',
      },
      props: {
        inputText: {
          spaceStack: 'space040',
        },
        fullAddressInput: {
          label: 'Search for Address',
          assistiveText: 'Type any part of address or postcode to search',
          cells: {
            xs: 12,
          },
          spaceStack: {
            xs: 'space080',
            md: 'space090',
          },
          icon: (
            <IconFilledSearch
              overrides={{
                size: 'iconSize030',
              }}
            />
          ),
        },
        line1Input: {
          label: 'Address field 1',
          cells: {
            xs: 6,
          },
        },
        line2Input: {
          label: 'Address field 2',
          cells: {
            xs: 6,
          },
        },
        line3Input: {
          label: 'Town/City',
          cells: {
            xs: 6,
          },
        },
        line4Input: {
          label: 'County',
          cells: {
            xs: 6,
          },
        },
        line5Input: {
          label: 'Postcode',
          cells: {
            xs: 6,
          },
        },
        countryInput: {
          label: 'Country',
          cells: {
            xs: 6,
          },
        },
      },
    }
  }
}

const AccountEditField = (props) => (
  <EditField {...props} validation={validation} context={overrideContext} />
)

export default AccountEditField

export const getServerSideProps = async (context) =>
  getProviderProps({ ...context, provider: 'EditField' })

Here we have changed 3 forms - Password, Name and Address.

Section types

Currently only support list

Item types

  • 'name'
  • 'dob'
  • 'displayName'
  • 'email'
  • 'password'
  • 'mobile'
  • 'landline'
  • 'address'
  • 'subscription'
  • 'price'
  • 'customerNumber'
  • 'subDate'
  • 'benefits'
  • 'payment'
  • 'billDate'
  • 'amountDue'
  • 'newsletters'
  • 'commentingNotifications'
  • 'contactPreferences'

Properties of ContextOptions

  1. data - Do not touch this will be overriden in My Account.
  2. userData - Do not touch this will be overriden in My Account.
  3. head - currently lets you override title tag of page

    • pageTitle: string
    • siteTitle: string | false
  4. 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)
  5. sideNav - Global property changes sidebar navigation - Array of nav objects

    • text: string
    • href: string
    • id: string

The sideNav uses NewsKit's MenuItem component with a custom stylePreset: navigationSecondayHorizontal that can be found here if you need to override in your custom theme

  1. sideNavSelected : string - The Id of the selected sideNav

  2. sideNavOverrides

    • menuItemOverrides
      • stylePreset: MQ
      • typographyPreset: MQ
      • spaceInset: MQ
    • backgroundColor: string
  3. pastDueBanner - Banner displayed when your subscription is passed due

    • firstNotice: - Banner when your subscription past due is below first treshold
      • title: string - Banner title
      • text: string - Banner text
      • button: string - Banner button text
    • secondNotice: - Banner when your subscription past due is bigger than first treshold, but lower that second treshold
      • title: string - Banner title
      • text: string - Banner text
      • button: string - Banner button text
    • terminated: Banner when your subscription past due is bigger than second treshold
      • title: string - Banner title
      • text: string - Banner text
      • button: string - Banner button text
    • treshold: - Past due banner tresholds
      • firstNotice: number
      • secondNotice: number

The pastDueBanner uses some custom stylePreset PastDueFirstNotice PastDueLastNotice UpdatePaymentButton see here

  1. header - Changes Page header

    • title: string
    • titleOverrides: TitleOverrides (see below)
    • fullWidthTitle: boolean
    • description: string
    • descriptionOverrides: DescriptionOverrides (see below)
    • backButton:
      • href: string
      • 'aria-label': string
      • text: string
    • backButtonOverrides:
      • stylePreset: MQ
      • typographyPreset: MQ
      • spaceInset: MQ
      • spaceStack: MQ
      • iconSize: MQ
      • size: 'small' | 'medium' | 'large'
      • asLink: boolean (will render as LinkStandalone not Button)
    • image: ImageProps
    • spaceStack: MQ
    • showDivider: boolean
    • imageCell?: CellProps CellProps see NewsKit (can be used to change order of items)
    • introductionCell?: CellProps
    • backButtonCell?: CellProps
  2. sections - Array of section items

  • type: string - currently only list
  • props: ContentListViewProps

    • introductionProps: IntroductionProps
      • title: string
      • titleOverrides: TitleOverrides (see below)
      • description: string
      • descriptionOverrides: DescriptionOverrides (see below)
    • items?: Array (see below)
    • ariaLabel?: string
  • ContentListItem

    • label: string
    • default: string
    • href: string
    • type: - Currently only name see above
    • path?: string
    • ariaLabel?: string

The ContentListItem uses some custom stylePresets baseInteractivePrimary030 contentListView see here

  1. sectionsOverrides - currently only for lists
  • list

    • titleOverrides: TitleOverrides (see below)
    • descriptionOverrides: DescriptionOverrides (see below)
  • TitleOverrides

    • typographyPreset: MQ
    • stylePreset: MQ
    • spaceStack: MQ
    • as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div' | 'span'
  • DescriptionOverrides

    • typographyPreset: MQ
    • stylePreset: MQ
    • spaceStack: MQ
  1. forms
  • default?: FormContext (see below)
  • password?: PasswordContext (see below)
  • name?: FormContext
  • 'display-name'?: FormContext
  • email?: FormContext
  • landline?: FormContext
  • mobile?: FormContext
  • payment?: FormContext
  • address?: AddressFormContext (see below)
  • 'commenting-notifications'?: CommentingNotificationsContext (see below)

  • FormContext

    • header?: (see 4. header)
    • props?: FormProps (see below)
  • PasswordContext

    • header?: (see 4. header)
    • props?: FormProps (see below) &
      • resendButtonGroupProps?: ButtonGroupProps (see below)
  • FormProps

    • text?: string[]
    • textOverriders?:
      • stylePreset?: MQ
      • typographyPreset?: MQ
      • spaceStack?: MQ
    • buttonGroupProps?: ButtonGroupProps (see below)
    • inputText?: (extends Newskit TextInputProps but you will only want to use the override props)
      • cells?: MQ
      • spaceStack?: MQ
    • listItems?: Array (see above)
    • infoPanel?: InfoPanel (see below)
  • InfoPanel: InlineMessageProps see Newkit &

    • infoPanelCells?: MQ
    • spaceStack?: MQ
  • AddressFormContext

    • header?: HeaderProps
    • props?: FormProps &
      • fullAddressInput?: AddressInputCell (see below)
      • line1Input?: AddressInputCell
      • line2Input?: AddressInputCell
      • line3Input?: AddressInputCell
      • line4Input?: AddressInputCell
      • line5Input?: AddressInputCell
      • line6Input?: AddressInputCell
      • countryInput?: AddressInputCell
  • AddressInputCell (extends Newskit TextInputProps)

    • cells?: MQ
    • spaceStack?: MQ
    • stylePreset?: MQ
    • spaceInset?: MQ
  • CommentingNotificationsContext

    • header?: HeaderProps
    • props?: FormProps &
      • listItems?: Array (see above)
      • text?: string[]
      • ariaLabel?: string
  1. cancellation
  • reason?: CancellationContext (see below)
  • confirm?: TODO

  • CancellationContext

    • header?: HeaderProps
    • props?: CancellationReasonProps | ConfirmCancellationProps (see below)
  • CancellationReasonProps

    • cancellationList?: Array
      • id: string
      • text: string
      • hasTextInput: boolean
      • cancellationObjectOverrides?
        • typographyPreset?: MQ
        • spaceStack?: MQ
        • stylePreset?: string
      • buttonGroupProps?: ButtonGroupProps (see below) omits hasError
      • message?: string
      • messageOverrides?: Omit<InlineMessageProps, 'children'> &
        • spaceStack?: MQ
  • ConfirmCancellationProps

    • listProps?: UnorderedListProps (see Newskit)
    • children?: string[]
    • buttonGroupProps?: ButtonGroupProps (see below) omits hasError
    • listHeader?: string
    • validation?: Record<string, any>
    • confirmationModal?: CancelModalProps (see below)
  • CancelModalProps

    • title: string
    • href: string
    • text?: string[]
    • expirationDate?: string
    • message?: string
    • buttonText?: string
    • overrides?: {
      • title?: Omit<TextBlockProps, 'children'> &
        • spaceStack?: MQ
      • text?: Omit<TextBlockProps, 'children'> &
        • spaceStack?: MQ
      • message?: Omit<InlineMessageProps, 'children'> &
        • spaceStack?: MQ
      • button?: Omit<ButtonLinkProps, 'children' | 'href'> } onDismiss?: () => void
  1. footer: - Global property
  • menuItemArray - Array of menu items
    • text: string
    • href: string
    • id: string | number
  • legalText: string
  1. footerOverides: - Global property
  • ariaLabel: string
  • menuItemHorizontalOverrides: menuItemOverrides (see below)
  • menuItemVerticalOverrides: menuItemOverrides (see below)
  • menuOverrides:
    • spaceStack: MQ
    • backgroundColor: string
    • borderColor: string
    • padding:
      • xs: string
      • md: string
  • legalTextOverrides:

    • spaceStack?: MQ
    • stylePreset?: MQ
    • typographyPreset: MQ
    • padding:
      • xs: string
      • md: string
  • menuItemOverrides:

    • stylePreset: MQ
    • typographyPreset: MQ
    • spaceInset: MQ
  1. baseUrl: string - change if your not sticking to default routing set up in Core. Currently set as /account but will need to be changes if you change pages/account file structure in Core.

  2. ButtonGroupProps (override all here or individually by form)

  • primaryText?: string
  • secondaryText?: string
  • primaryButton?: ButtonProps (see below)
  • secondaryButton?: ButtonProps
  • primaryCell?: CellProps see NewsKit
  • secondaryCell?: CellProps
  • hasError: boolean
  • secureFlag?: SecureFlagProps (see below) &
    • spaceStack?: MQ
  • keepFixed?: boolean
  • stylePreset?: MQ
  • spaceStack?: MQ

The ButtonGroup uses custom stylePresets buttonGroupXs buttonGroupSm see here

  • ButtonProps extend Newskit ButtonProps &

    • ariaLabel?: string
    • href?: string
    • onClick?: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
  • SecureFlagProps extends Newskit FlagProps &

    • iconOverrides?:
      • spaceInset?: MQ
      • spaceInline?: MQ
      • size?: MQ
      • stylePreset?: MQ
    • icon?: ReactElement
  1. zuoraCustomErrorMessages?: see Payment section

  2. noSubscription?: NoSubscriptionProps (see below)

  3. previousSubscription?: NoSubscriptionProps
  • NoSubscriptionProps
    • header?: HeaderProps
    • buttonGroupProps?: ButtonGroupProps

Address Form - Loqate

The Address form uses Loqate to add address lookup functionality. For it to work you need to add LOQACCOUNT_KEY to your CircleCi context.

To get the LOQACCOUNT_KEY please speak to the Render team.

Update Preference centre link

You can update the link to the Preference centre using the context. Example:

const overrideContext: ContextOptions = NewslettersAndAlertsContext;
(overrideContext.sections[0].props as ContentListViewProps).items[2].href = 'https://mypreferences.the-tls.co.uk/login'

const Page = (props) => <NewslettersAndAlerts context={overrideContext} {...props} />

export default Page

Reset password expiration

In the Password reset page, you can customize the lifetime of the password reset link. The time will be shown in the inline message to the users and will also indicate how long until the inline message is no longer shown.

To set a time, add the following row to your .env.local. Value is in seconds.

PASSWORD_URL_LIFETIME=900

If this is not set, the default value will be 900 seconds (15 minutes).

Past Due Banner

The Past Due Banner is an exported Component, which can be rendered anywhere. Just import the Component and use it in a React application:

import { PastDueBannerExternal } from '@newskit-render/my-account'

      <PastDueBannerExternal
        pastDueBanner={pastDueBanner}
        data={data}
        wrapper={BannerContainer}
      />

Props:

  • className?: string
  • pastDueBanner?: PastDueBanner
  • vxInstances: VxInstance[]
  • wrapper?: React.ComponentType
  • theme?: UncompiledTheme

The pastDueBanner props must be in the following format (the default one). If you do not provide context, the following will be used

const pastDueBanner = {
  firstNotice: {
    title: "We haven't been able to take payment",
    text: 'You may need to update your payment details to keep your subscription.',
    button: 'Update payment details',
  },
  secondNotice: {
    title: 'Act now to keep your subscription',
    text: 'We’ve tried several times, but haven’t been able to take payment. Please update your payment details to keep your subscription.',
    button: 'Update payment details',
  },
  terminated: {
    title: 'Your subscription has been terminated',
    text: 'We didn’t receive payment for your subscription. To reactivate it, please call 0800 018 5177.',
  },
  treshold: {
    firstNotice: 26,
    secondNotice: 30,
  },
}

For the data prop we are expecting a VXInstances Array: Example:

[
  {
    interactions: [
      {
        pastDue: {
          isPastDue: true,
          since: '2021-06-17 07:39:41 +0000 UTC',
        },
      },
    ],
  },
]

Payment

There are two payment providers - Stripe and Zuora. When you load Provider component, you need to provide a paymentMethod props. The value passed should come from enum exported from my-accaunt package. E.g

import {
  Payment,
  getProviderProps,
  PaymentProvider,
} from '@newskit-render/my-account'

export default Payment

export const getServerSideProps = async (context) => {

  return getProviderProps({
    ...context,
    provider: 'Payment',
    paymentProvider: PaymentProvider.Zuora,
  })
}
  1. Stripe - requires a stripe key. The key can be passed by the env variable STRIPE_KEY, which should be loaded in env.local. If the variable is not passed, Stripe will be loaded with test account. Stripe key can be retrieved from here. More info on Stripe integration can be found here
  2. Zuora - Needs to have the following env variables

You need to follow these steps in order to get the oAuth env variables: (https://knowledgecenter.zuora.com/Billing/Tenant_Management/A_Administrator_Settings/Manage_Users/Create_an_API_User, https://www.zuora.com/developer/api-guides/) #Zuora OAuth ZUORA_OAUTH_ACCESS_URL ZUORA_OAUTH_CLIENT_ID ZUORA_OAUTH_CLIENT_SECRET

#Zuora RSA signature ZUORA_PAGE_ID - You need to configure a payment page (https://nidigitalsolutions.jira.com/wiki/spaces/TNLDigital/pages/1343357177/Zuora+Payment+Iframe+Integration) ZUORA_CURRENCY - The currency code - E.g USD ZUORA_RSA_SIGNATURE_URL - Please check (https://knowledgecenter.zuora.com/Billing/Billing_and_Payments/LA_Hosted_Payment_Pages/B_Payment_Pages_2.0/F_Generate_the_Digital_Signature_for_Payment_Pages_2.0) ZUORA_RSA_SIGNATURE_URI - Please check (https://knowledgecenter.zuora.com/Billing/Billing_and_Payments/LA_Hosted_Payment_Pages/B_Payment_Pages_2.0/F_Generate_the_Digital_Signature_for_Payment_Pages_2.0)

Zoura's validation error messages can be overriden in the context:

  • zuoraCustomErrorMessages?:
    • creditCardHolderName: string
    • creditCardNumber:
      • one: string
      • two: string
      • three: string
    • cardSecurityCode:
      • one: string
      • four: string
    • creditCardExpiration: string
    • creditCardPostalCode: string
    • creditCardCountry: string

These correspond to Zoura's retured error code: 001: Required field not completed - detault for single property or one 002: Invalid card number - two 003: Invalid card type - three 004: Invalid CVV number - four