# Onegevity UI-Kit front-end library

# Overview

The Onegevity UI-Kit is a JavaScript library that offers a suite of capabilities that greatly simplifies the process of integrating the Onegevity Health Intelligence Service into your web application. These capabilities include:

  • Built-in client SDKs for all of the Onegevity APIs
  • Non-intrusive, secure authentication flow for obtaining API access tokens
  • Rich UI components for performing all common actions needed to manage patient data throughout the process lifecycyle
  • An embeddable Single Page Application (SPA) that brings all of the above together into a complete user experience that can be hosted on a single page

Keep reading to learn how integrate the UI-Kit into your web application and begin leveraging Onegevity's Health Intelligence Service in your application.

# Installation

Onegevity provides two methods for adding the UI-Kit to your web project. Choose the one that best fits our application build / deployment pattern.

# NPM module

If you are using npm and a JavaScript bundler (like webpack, rollup, etc.) you may find it most convenient to add our package as a dependency of your project.

npm install @onegevity/ui-kit

The ui-kit npm package exports two classes for you to use:

  • OG - Provides access to the authentication flow
  • UIKit - Provides access to all of the UI components and the SPA component
import {OG, UIKit} from '@onegevity/ui-kit'

As we'll discuss shortly, depending on your integration pattern you may not use both of these classes.

For browser use only

The UI-Kit library is a frontend library and expects to be running in a browser context. It will not function when run in a server environment.

# <script> tag

You can also integrate the UI-Kit library into your web application by including it on your page using a <script> tag. You may reference the script from our content distribution network or you may download the library and include it in your application.

<script>
  function initOnegevity({ OG, UIKit }) {
      // Add code here to work with the UI-Kit .. examples to follow
  }
</script>
<script src="https://cdn.onegevity.com/artifacts/onegevity-ui-kit/onegevity-ui-kit.1.0.0.js"></script>

# Authentication and Authorization

In order to access the full range of Onegevity UI Kit features you will need to access data from the Onegevity API and that means that first you must authenticate your application with the Onegevity API. The UI-Kit provides an out-of-the box facility for coordinating the OAuth2 Authorization Code authentication flow. If you are unfamiliar with OAuth2 it may be worth your while to read a bit about OAuth (opens new window) and Authorization Code (opens new window) to understand what's happening behind the scenes.

# Prerequisites

Before you get started, you'll need to have the following things in hand:

  • Register your account with Onegevity and have obtained your OAuth Client ID and Client Secret
  • Registered and validated your website domain with Onegevity

# Implementing the Authorization Code authentication flow

In short, the OAuth2 Authorization Code flow is used to establish trust between three parties: your end user, your website, and the Onegevity API, with the goal being to safely and securely allow your users private data (hosted by the Onegevity API) to be surfaced in their browser when using your website. The flow is performed in three steps:

  1. The end user's browser requests an authorization code from the Onegevity API authorization server, passing in a state parameter and a redirect URI (hosted on your website)
  2. The browser request is redirected to your website with the state parameter and an authorization code. Your server then must call the Onegevity API to exchange the authorization code for an access token
  3. The response from your server provides the access token to the user's browser, which uses it to make authenticated requests to the Onegevity API

# Front-end implementation

The UI-Kit provides a facility for performing steps 1 and 3, while you must implement step 2 in your website code. To initiate the authorization flow call the OG.authUIKit() function, as demonstrated in the example below:

// Authenticate with the Onegevity service to initialize the UIKit.
const authOptions = {
  // this will point to the onegevity api base url .. be sure to use the staging url for testing purposes
  ogBasePath: 'https://api.onegevity.com',
  // your unique OAuth Client ID for your application, provided to you by Onegevity
  clientId: 'example-id',
  // an endpoint implemented on your server that finalizes the authentication (must be https://)
  redirectUri: 'https://www.example.com/onegevity/complete-authorization',
  // a CSRF-prevention state value that must be unique to the end user's web session.
  // your website backend is responsible for providing this value 
  state: '{{{state}}}',
  // the user's unique Onegevity Patient identifier
  // your website backend is responsible for providing this value
  patientId: '{{{patientIdentifier}}}',
}

// returns a Promise that, when successful, yields an authenticated UIKit object 
const authUIKit = OG.authUIKit(authOptions)

# Back-end implementation

In this scheme your website backend is responsible for 3 things:

  1. Providing a globally unique patientIdentifier that will be used to identify your logged in user in the Onegevity API.

patientIdentifier

A customerId or hashed email address are good options to use as your patientIdentifier.

  1. Computing a CSRF-prevention state parameter that can be used to verify the authenticity of the incoming request to exchange the authorization code for the access token

state

To fulfill it's job as a CSRF-prevention mechanism, regardless of how you generate your state parameter, you'll need to be able to retrieve or regenerate it on the subsequent web request to verify that the request is valid.

A good approach is to generate a lengthy random String and store it in the user's server-side session.

  1. Implementing an endpoint that will be called to exchange the authorization code for the access token

Register your endpoint with Onegevity

In order to complete the implementation process and begin testing your integration you must register your redirect endpoint with Onegevity.

Validate state

If the incoming state parameter on the request does not match, you must deny the request. Otherwise, POST a request to the /oauth/token endpoint on the Onegevity API to retrieve the access token and return the access token as the body of your response.

Example Code The following code examples demonstrate how a backend server might set up to complete the UI-Kit authorization flow

# Using the UIKit components

Once, an authenticated UIKit is initialized, full access to the functionality of the component library is enabled. You can choose what is best for your use case: you can use the SPA to provide access to all of the functionality from just one page or you can choose to only load a certain component on your page. Either way, the usage pattern is essentially the same. Examples of each are provided in the following sections.

# Using the UIKit Single Page Application

The SPA approach gives you a single component that you load into your page and it provides a complete UI for all of the functionality needed to interact with the Onegevity service:

  • A page for listing and requesting tests for a patient
  • A page for filling out surveys for tests
  • A page for activating sample collection kits
  • A page for reviewing the final results of a test
/*
    target is the only required option of the `spa` function.
    It must point to the target element where the SPA with be rendered.
*/
const target = document.querySelector('#demo')

/*
    The second argument is completely optional, but would include a map
    with a single key `patientInfo` containing additional information
    about the patient that is not available through the Onegevity API.
    All information is optional, but all available keys are enumerated
    below.
*/
authUIKit.then((uiKit) => uiKit.patientSpa(target, {
  patientInfo: {
    email: /*[[${patientEmail}]]*/ '',
    addressLine1: /*[[${patientAddressLine1}]]*/ '',
    city: /*[[${patientCity}]]*/ '',
    countryCode: /*[[${patientCountryCode}]]*/ '',
    regionCode: /*[[${patientRegionCode}]]*/ '',
    postalCode: /*[[${patientPostalCode}]]*/ '',
    phone: /*[[${patientPhone}]]*/ '',
  }
}))

# Using the Reports component

The Reports component is used to present the final report of a patient's test results. If the patient has multiple results for the same package (say they have retested every year) then it also provides a facility to view those historical results as well as display trendlines over time.

// Use the initialized UIKit to initialize the reports component
const reportOptions = {
  // required. The Package Identifier for the test results being displayed.
  packageId: 'BIOAGE',

  // required. The order identifier for the initial results.
  orderId: '300554-BA3',
}

/*
    The `reports` components will display a historical view of all
    results for the authenticated onegevity patient that match the
    provide package identifier. The results for the provided order
    identifier will be displayed first.
*/
const target = document.querySelector('#demo')
authUIKit.then(uiKit => uiKit.patientReports(target, reportOptions))

# Using the Survey component

The Survey component displays a step-by-step user interface for completing questionnaires or surveys needed to gather health information for a patient.

// Use the initialized UIKit to initialize the survey component
const surveyOptions = {
  // required. The survey key of the requested survey.
  surveyKey: 'thorne-health-profile',
  // required. The order identifier associated with the requested survey.
  orderId: '300554-1626808484301',
}

// The `survey` component will render a survey with all validation and submission logic provided.
const target = document.querySelector('#demo')
authUIKit.then(uiKit => uiKit.patientSurvey(target, surveyOptions))

# Using the Order component

The Order component is useful to display a form that collects all of the patient information necessary to submit an order for services to the Onegevity API.

// Use the initialized UIKit to initialize the order component
const orderOptions = {
/*
    optional. Patient information that is otherwise not known
    by the onegevity api. This information will auto populate
    the relevant form fields to provide a smoother user experience.
*/
  patientInfo: {
    email: 'dapper@dan.com',
    addressLine1: '1234 Somewhere Dr.',
    city: 'Appleton',
    countryCode: 'US',
    regionCode: 'WI',
    postalCode: '53590',
    phone: '609-432-2345',
  }
}
const target = document.querySelector('#demo')
authUIKit.then(uiKit => uiKit.patientOrder(target, orderOptions))

# Using the Activation Component

The Activation component provides a simple form needed to allow a patient to activate their sample collection kit.

// Use the initialized UIKit to initialize the activation component
const activationOptions = {
  // required. The Kit element identifier for the kit being activated.
  kitElementId: 'THYROID_KIT',
  // required. The order identifier associated with the kit being activated.
  orderId: '300554-1626808484301',
}

// The `activation` component provides a simple ui for activated a patients kit.
// and includes all frontend validation.
const target = document.querySelector('#demo')
authUIKit.then(uiKit => uiKit.patientActivation(target, activationOptions))

# Advanced Usage

# Backend data-fetching

In some situations you may decide that you need to integrate with the Onegevity API through your backend and will be obtaining access tokens on the server side, instead of doing it on the front-end using the UI-Kit authorization flow.

In this case you can still use the UIKit components to do the heavy lifting of rendering the data even if you load it from the API in your website back end. Simply retrieve the data from the Onegevity API on your server and make the resulting JSON objects available in the HTML document by some mechanism (either an endpoint on your server that you secure, or by rendering the JSON out into a <script> tag) and then pass the data directly into the component methods.

# Dynamic content slots

The UI-Kit components provide an eventing pattern that allows you to insert dynamic content of your own design into the visual elements it creates at specific, named slots by simply registering an event handler. This gives you the flexibility to add context to the information provided by the Onegevity platform that is relevant to your audience and your type of business.

TIP

At present the Reports component is the only component that offers dynamic content slots

Description: This slot appears at the very beginning of the report, just under the table of contents navigation links. It is suitable for a header, logo, or message appropriate to share with the viewer of the report.

Event name:
og-banner-slot

Payload:

{
  elem:  HTMLElement, // The DOM element for the slot that can be appended to
  type:  String       // String identifying the type of report being displayed
}

# Product Title

Description: This slot appears immediately alongside the name of a product recommendation in the report. It is suitable for providing a link to learn more, an add to cart button, etc.

Event name:
og-product-title-slot

Payload:

{
  product: Object,   // The product recommendation API object, as documented in API reference
  elem:  HTMLElement // The DOM element for the slot that can be appended to  
}

# Product Content

Description: This slot appears immediately underneath the name of a product recommendation in the report. It is suitable for providing any additional content or metadata about the recommended product before the body of the product recommendation.

Event name:
og-product-content-slot

Payload:

{
  product: Object,   // The product recommendation API object, as documented in API reference
  elem:  HTMLElement // The DOM element for the slot that can be appended to  
}

# Examples using dynamic slots

let reportContainerElement = window.querySelector('.report-container');

/* Append a link next to the product title to a detail page to learn more about it */ 
reportContainerElement.addEventListener("og-product-title-slot", (e) => {
  let slotElem = e.detail.elem
  let product = e.detail.product.products[0]
  let linkElem = slotElem.appendChild(document.createElement('a'))
  linkElem.append(`Read more about ${product.productName}`)
  linkElem.setAttribute('href', `https://yourdomain.com/products/detail/${product.productIdentifier}`)
});

/* Load the report content .. for each product recommendation the event listener for the product title slot will be called */
UIKit.reports(reportContainerElement, {
   reports: [ /*...*/ ],
   currentReportId: /*...*/
})