Nary a Package Missing

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

    0.175.0 • Public • Published

    @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

    Rquired Environment Variables

    In order to run the application,we need the following required environment variables.

    PUBLISHER=""
    MAIN_COOKIE_NAME=""
    MAIN_GRAPHQL_URL=""
    

    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 } from '@newskit-render/my-account'
    import { sharedTheme } from '@newskit-render/shared-components'
    import { createTheme } from 'newskit'
    
    const customTheme = createTheme({
      name: 'new-theme',
      baseTheme: sharedTheme,
      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 sharedTheme as the base to any new theme you create. You can see this theme here

    Currently the app created with create-render-app has a dropdown theme selector that you can see by pressing '`' key. This is also implemented in Account. When you add a custom theme you should remove the AppContext and createThemeDropdownObject logic.

    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
        • dismissDays?: number - number of days you want banner dismissed after if not dones so by user
        • 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
        • dismissDays?: number - number of days you want banner dismissed after if not dones so by user
        • 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
        • dismissDays?: number - number of days you want banner dismissed after if not dones so by user
        • button: string - Banner button text
      • toBeCancelled: Banner shown when user has cancelled subscription but before end of billing cycle
        • title: string - Banner title
        • text: string - Banner text
        • dismissDays?: number - number of days you want banner dismissed after if not dones so by user
        • button: string - Banner button text
      • cancelled: Banner shown when user has cancelled subscription and is after end of billing cycle
        • title: string - Banner title
        • text: string - Banner text
        • dismissDays?: number - number of days you want banner dismissed after if not dones so by user
        • 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 has been move into @newskit-render/shared-components

    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/shared-components'
    
    <PastDueBannerExternal
      pastDueBanner={pastDueBanner}
      user={user}
      wrapper={BannerContainer}
    />
    

    Props:

    • className?: string
    • pastDueBanner?: PastDueBanner
    • user: UserData
    • 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',
        phoneNumber: 'XXXX-XXX-XXXX',
        text:
          'We didn’t receive payment for your subscription. To reactivate it, please call ##PHONE_NUMBER##.',
        dismissDays: 7,
      },
      cancelled: {
        title: 'Your subscription has been cancelled.',
        phoneNumber: 'XXXX-XXX-XXXX',
        text:
          'You’ll no longer have access to subscription benefits. To re-activate call ##PHONE_NUMBER##.',
        dismissDays: 7,
      },
      toBeCancelled: {
        title: 'Your subscription will end soon.',
        phoneNumber: 'XXXX-XXX-XXXX',
        text:
          'You have cancelled your subscription and will lose access to all benefits on ##DATE##. To re-activate your subscription call ##PHONE_NUMBER##.',
      },
      treshold: {
        firstNotice: 26,
        secondNotice: 30,
      },
    }
    

    For the user prop we are expecting information from MAIN API user: Example:

    {
      User {
        paymentFailure {
          active
          startDate
        }
        subscriptions {
          serviceCancellationDate
        }
      }
    }
    

    please see MAIN's voyager

    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 - Data for Zoura forms will come from MAIN and you should speak to the MAIN team about setting up a form. You will need to have the following env variables for this to work:

    TITLE - MAIN can give you this but it will need to be passed into your kubernettes using the Helm value-{env}.yml files:

    TITLE: 'thesunuk'
    

    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 .

    Keywords

    none

    Install

    npm i @newskit-render/my-account

    DownloadsWeekly Downloads

    538

    Version

    0.175.0

    License

    UNLICENSED

    Unpacked Size

    1.25 MB

    Total Files

    782

    Last publish

    Collaborators

    • newskit