Next.js

Here’s how to create a Next.js starter project and integrate OneSDK package modules. This will give you a solid foundation to build with OneSDK and Next.js.

Video walk-through

Watch the following video for a short walk-through of how to perform OneSDK integration with Next.js.


Steps

Here are the steps to integrate OneSDK using Next.js:

Initialize Project

Create the next boilerplate using this command:

npx create-next-app@latest my-next-app

Once the setup is complete, go to your project and run the following command:

npm i

Install the OneSDK package into your project

npm i @frankieone/one-sdk

Code Examples

To use oneSDK, we use hooks to initialize oneSDK instance with the correct credentials (Customer ID and API key). Retrieve the token with the correct credentials and then pass the initialized instance

useOneSDK
This is an example of using hooks to pass an initialized instance of OneSDK so that it can be used in separate components.

"use client"
import OneSDK from "@frankieone/one-sdk"
import { useEffect, useRef, useState } from "react"

const CUSTOMER_ID = process.env.NEXT_PUBLIC_CUSTOMER_ID
const API_KEY = process.env.NEXT_PUBLIC_API_KEY
const CHILD_ID = ''

const CUSTOMER_ID2 = process.env.NEXT_PUBLIC_CUSTOMER_ID2
const API_KEY2 = process.env.NEXT_PUBLIC_API_KEY2
const CHILD_ID2 = process.env.NEXT_PUBLIC_CHILD_ID2

const useOneSDK = ({config}) => {
  const [oneSDKInstance, setOneSDKInstance] = useState(null)
  const [error, setError] = useState(null)
  const [loading, setLoading] = useState(false)
  const initializedRef = useRef(false);

  const generateToken = async () => {
    const parseURL = () => {
      return btoa(`${CUSTOMER_ID}:${API_KEY}`)
    }
    try {

      const tokenRawAsync = await fetch("https://backend.latest.frankiefinancial.io/auth/v2/machine-session", {
          method: "POST",
          headers: {
              "authorization": "machine " + parseURL(),
              "Content-Type": "application/json"
          },
          body: JSON.stringify({
              permissions: {
                  "preset": "one-sdk",
                  "reference": `demo-${new Date().toISOString()}`//"<YOUR_UNIQUE_CUSTOMER_REF>"
              }
          })
      });
      return await tokenRawAsync.json()
    } catch (error) {
      setError(error.message)
      return null
    }
  }

  const generateOneSDKInstance = async () => {
    setLoading(true)
    const tokenSessionFromBackEnd = await generateToken()
    if(!tokenSessionFromBackEnd) return
    const SDKConfig = config || {
      mode: "development",
      recipe: {
        form: {
          provider: {
            name: 'react'
          },
        }
      }
    }
    try {

      const oneSDKInit = await OneSDK({
        session: tokenSessionFromBackEnd,
        ...SDKConfig
      })
      setOneSDKInstance(oneSDKInit)
    } catch(error) {
      setError(error.message)
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    if(!initializedRef.current) {

      generateOneSDKInstance()
      initializedRef.current = true
    }
  }, [config])

  return {
    oneSDKInstance,
    error,
    loading
  }
}

export default useOneSDK

Call useOneSDK in component using this sample-code as an example:

"use client"
import { useEffect } from "react";
import useOneSDK from "../useOneSDK";

const End2End = () => {
  const config = {
    mode: "development",
    recipe: {
      form: {
        provider: {
          name: "react",
        },
      },
    },
  };
  const { oneSDKInstance, error: errorOneSDK, loading } = useOneSDK({ config })
  
    const initOneSDK = () => {
      const welcome = oneSDKInstance.component('form', {
      name: 'WELCOME',
      type: 'manual',
      /*descriptions: [
              { label: ‘This is a sample dynamic page.’, style: {} },
              { label: ‘It can contain multiple paragraphs.’, style: {} },
            ], */
      //cta: {style: {‘ff-button’:{backgroundColor: “red”}}}
    });
    const form_consent = oneSDKInstance.component("form", {name: "CONSENT"});
    const form_loading1 = oneSDKInstance.component("form", {name: "LOADING", title: {label: "Loading..."}, descriptions: [{label: ""}]});
    const form_loading2 = oneSDKInstance.component("form", {name: "LOADING", title: {label: "Extracting data..."}, descriptions: [{label: "Hold tight, this can take up to 30 seconds. Please do not referesh this page or click the 'back' button on your browser."}]});
    const form_loading3 = oneSDKInstance.component("form", {name: "LOADING", title: {label: "Hold on..."}, descriptions: [{label: ""}]});
    const form_document = oneSDKInstance.component("form", {
      name: "DOCUMENT",
      showPreps: true,
    });
    const form_review = oneSDKInstance.component("form", {
      name: "REVIEW",
      type: "ocr",
    });
    
    const biometrics = oneSDKInstance.component('biometrics');

    welcome.mount("#form-container");
    welcome.on("form:welcome:ready", () => {
      form_consent.mount("#form-container");
    });

    form_consent.on("form:consent:ready", async () => {

      form_document.mount("#form-container");
    });

    welcome.on("form:welcome:failed", () => {
      // display error message
    });

    welcome.on("*", (message) => {
      console.log(message);
    });

    let docType;

    form_document.on("form:document:ready", async ({inputInfo}) => {

      form_loading1.mount("#form-container");
      docType = inputInfo.documentType;
      
      const ocr = oneSDKInstance.component("ocr", {
        documents: [{ type: docType, countries: ["AUS"] }],
      });

      ocr.mount("#form-container");
      ocr.on("ready", () => form_loading1.unmount())

      ocr.on("*", (message) => {
        console.log(message);
      });

      ocr.on("results", ({ document }) => {   
        doSomethingAfterOcr({ document })
      });

      ocr.on("loading", (display)=>{
        if(display){
          form_loading2.mount("#form-container");
        }else{
          form_loading2.unmount() 
        }
      });
    });

    function doSomethingAfterOcr({ document }) {
      // Present the details of the document that were detected from the uploaded image or images.
      // Decide whether to proceed to the next stage of the onboarding process
      // depending on whether document verification was successful.
      if (document) {
        console.log(document);
        console.log(document.ocrResult.dateOfBirth);
        console.log("trying to load review screen");
        
        form_review.mount("#form-container");
        
      } else {
        console.log("No document returned");
      }
    }

    form_review.on("form:review:ready", async () => {
      biometrics.mount("#form-container");
    });

    biometrics.on("*", (message) => {
      console.log(message);
    });

    biometrics.on('error', console.error);

    let error = false;
    biometrics.on('detection_failed', () => (error = true));
    biometrics.on('session_closed', () => {
      // If the session was closed due to an error, try running the biometrics component again.
      if (error) biometrics.mount("#form-container");
      error = false;
    });

    biometrics.on("loading", (display)=>{
      if(display){
        //alert("loading, show now")
        form_loading3.mount("#form-container");
      }else{
        form_loading3.unmount() 
      }
    });

    biometrics.on('processing', () => alert('We will get back to you with results soon'));
    biometrics.on('results', (result) => {
      // Decide whether to proceed to the next stage of the onboarding process
      // depending on whether biometrics verification was successful.
      console.log(result);
    });
    // oneSdkReact.on('*', console.log('oke'));
    }
    
  useEffect(() => {
    if(oneSDKInstance) {

      initOneSDK()
    }
  }, [oneSDKInstance])

  return loading ? <div>Loading...</div> : <div id='form-container' ></div>
}

export default End2End

Run the project using npm start.