my-account-esm
v0.137.0
Published
Newskit Render
Downloads
4
Readme
@newskit-render/my-account
Getting Started
There are 2 ways to start with @newskit-render/my-account:
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).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
ornpm 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
data - Do not touch this will be overriden in My Account.
userData - Do not touch this will be overriden in My Account.
head - currently lets you override title tag of page
- pageTitle: string
- siteTitle: string | false
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)
- nav?:
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
sideNavSelected : string - The Id of the selected sideNav
sideNavOverrides
- menuItemOverrides
- stylePreset: MQ
- typographyPreset: MQ
- spaceInset: MQ
- backgroundColor: string
- menuItemOverrides
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
- firstNotice: - Banner when your subscription past due is below first treshold
The pastDueBanner uses some custom stylePreset
PastDueFirstNotice PastDueLastNotice UpdatePaymentButton
see here
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
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
- introductionProps: IntroductionProps
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
- 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
- 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
- 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
- cancellationList?: Array
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
- title?: Omit<TextBlockProps, 'children'> &
- footer: - Global property
- menuItemArray - Array of menu items
- text: string
- href: string
- id: string | number
- legalText: string
- 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
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 changepages/account
file structure in Core.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
- iconOverrides?:
zuoraCustomErrorMessages?: see Payment section
noSubscription?: NoSubscriptionProps (see below)
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,
})
}
- 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 - 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