Visualizing Sahha Scores in React-Native (TypeScript)

In this tutorial, we will walk through the process of visualizing health-related data using Sahha in a React Native application. We will use react-native-gifted-charts for rendering bar charts and sahha-react-native for gathering the data. The steps below will guide you through setting up the project, configuring Sahha, authenticating the user, and displaying the data.

Prerequisites

Before we begin, ensure you have the following:

  • Basic knowledge of React Native and TypeScript.
  • Node.js installed on your machine.
  • React Native CLI installed.
  • A Sahha account and API keys.

Setting Up Your React Native Project

First, initialize your React Native project:

npx react-native init SahhaVisualization cd SahhaVisualization

Install the necessary dependencies:

npm install sahha-react-native react-native-config react-native-gifted-charts date-fns

Dependencies explained:

  • sahha-react-native: The Sahha SDK for integrating their behavioral health insights API into React Native apps, enabling analysis and visualization of health data.
  • react-native-config: Manages environment variables in React Native apps, allowing you to store and access configuration settings securely.
  • react-native-gifted-charts: A library for rendering beautiful and customizable charts in React Native applications.
  • date-fns: A modern JavaScript date utility library for date manipulation, providing a wide range of functions to work with dates.

Configuring the Sahha SDK

Create a .env file in the root of your project and add your Sahha API credentials:

SAHHA_APPLICATION_ID=your_application_id SAHHA_APPLICATION_SECRET=your_application_secret

Next inside the App.tsx file we want to add the following configuration object to the top of the file after our imports:

const SAHHA_CONFIGURATION_SETTINGS = { environment: SahhaEnvironment.sandbox, };

This is a minimal configuration object, you can see all of the available configuration settings in the Sahha documentation.

We then need to call the configure function from the Sahha SDK, to keep things tidy I am going to create a wrapper function to convert the Sahha.configure function into a promise so we can use async await syntax.

javascript

const configureSahha = () => new Promise((resolve, reject) => Sahha.configure( SAHHA_CONFIGURATION_SETTINGS, (error: string, success: boolean) => { if (success) resolve(success); reject(error); }, ), );

And then inside the render function of our App.tsx file I am going to create a useEffect with an empty dependency array so that it runs once on app start. We then need to add our configureSahha wrapper function, as it is an async function we also need to wrap it in an immediately-invoked async function expression and a try catch block.

Our useEffect should now look like this:

javascript

useEffect(() => { (async () => { try { await configureSahha(); } catch (e) { console.error(e); } })(); }, []);



Authenticating the Sahha SDK

Now we have successfully configured the Sahha SDK, we need to authenticate so we can retrieve data for a profile. For this you will need your applicationID and applicationSecret. You can find these values in the credentials section of the Sahha dashboard.

To authenticate we need to call the authenticate function from the Sahha SDK, just like the configure function I am again going to create a wrapper function to convert the Sahha.authenticate function into a promise so we can use async await syntax.

javascript

const authenticateSahha = (externalId: string) => new Promise((resolve, reject) => Sahha.authenticate( Config.SAHHA_APPLICATION_ID || '', Config.SAHHA_APPLICATION_SECRET || '', externalId, (error, success) => { if (success) resolve(success); reject(error); }, ), );

Once we have added this function, we can then add it to our useEffect inside the render function.

javascript

useEffect(() => { (async () => { try { await configureSahha(); await authenticateSahha('your-external-id'); } catch (e) { console.error(e); } })(); }, []);

Be sure to replace the ‘your-external-id’ string to the external ID of the profile you want to authenticate.

Retrieving Health Score data from the Sahha SDK

Now that we have configured and authenticated the Sahha SDK, we can start retrieving Health Score data.

Before we retrieve any data, I am going to add the type definition for the response from the Sahha analyzeDateRange function.

javascript

type SahhaScore = { id: string; type: string; state: string; score: number; factors: { name: string; value: number; }[]; inputData: string[]; createdAt: string; }; type SahhaAnalyzeResponse = { inferences?: SahhaScore[] }

This is a loose type definition, You can find more information about the shape of the response in the Scores & Insights section of the Sahha documentation.

Once we have the type definitions we are going to create another wrapper function for the sahha.analyzeDateRange function.

javascript

const analyzeSahhaDateRange = ( startDate: Date, endDate: Date, ): Promise<SahhaAnalyzeResponse> => new Promise((resolve, reject) => Sahha.analyzeDateRange( startDate.getTime(), endDate.getTime(), (error, value) => { try { if (error) throw new Error(error); resolve(JSON.parse(value)); } catch (e) { reject(e); } }, ), );

We will then get our startDate and endDate, for this I am going to use date-fns but you can use any date library you prefer, or plain JS Date obejcts.

We are going to get set our end date as the current date and our start date as 6 days ago giving us a one week date range. We will also get all the dates between those values for our chart will always have 7 days.

Place this code at the top of your render function in your App.tsx file:

javascript

const end = new Date(); const start = subDays(end, 6); const days = eachDayOfInterval({start, end});

We can then call our wrapper function inside the useEffect after the other two function calls:

javascript

useEffect(() => { (async () => { try { await configureSahha(); await authenticateSahha('healthy-profile-01'); const {inferences} = await analyzeSahhaDateRange(start, end); } catch (e) { console.error(e); } })(); }, []);

💡 The analysis engine requires a minimum amount of device sensor data to be uploaded and processed before an analysis can be determined.

If you call analyze for a new user profile or a user that has been inactive lately, it's possible for the response to be 204 No Content. This is not an error.

You will need to wait and try again every 24 hours until an analysis is available.



Visualizing Sahha Wellbeing Scores in a bar chart

Now we are getting our Health Score data back form the Sahha SDK for our date range we can add a chart to visualize it.

As the sahha.analyzeDateRange function returns all types of Health Scores, I am going to first filter the array into scores with the ‘wellbeing’ type.

To do this simply add the following line after retrieving the score data:

javascript

const wellbeingScores = inferences?.filter(s => s.type === 'wellbeing') || [];

We then need to convert our welling score array into an array that can be passed into our bar chart.

I am going to use react-native-gifted-charts, to keep it simple we only need to pass an array containing a value and a label.

For the value we are going to use the score value field, we will also multiply this by 100 to get a percentage value as the score values come back as a number between 0 and 1.

For the label, I am going to use date-fns format function to convert the date in a short hand day.

Because we want to ensure we show each day in our date range, we need to loop over our days array we created earlier, find the score in our score array from the same day and return and object with a value and label.

I’m going to create a helper function to do just this, place this function in the render function of your App.tsx file:

javascript

const createChartData = (scores: SahhaScore[]) => days.map(date => { const scoreForDate = scores.find(s => isSameDay(s.createdAt, date)); const value = (scoreForDate?.score || 0) * 100; return {value, label: format(date, 'E')}; });

We then need to create a useState variable to store our chartData array, add the following line to the top of your App.tsx file:

javascript

const [chartData, setChartData] = useState<BarChartPropsType['data']>([]);

For type safety we are using the BarChartPropsType from react-native-gifted-charts and extracting the data field from it.

We can now update our useEffect to transform the data and update our chartData state variable.

Your useEffect should now look like this:

javascript

useEffect(() => { (async () => { try { await configureSahha(); await authenticateSahha('healthy-profile-01'); const {inferences} = await analyzeSahhaDateRange(start, end); const wellbeingScores = inferences?.filter(s => s.type === 'wellbeing') || []; setChartData(createChartData(wellbeingScores)); } catch (e) { console.error(e); } })(); }, []);

Finally we simply need to add the <BarChart> component from react-native-gifted-charts and pass the chartData state variable to the data property.

javascript

<BarChart data={chartData} />



Full code example

Below is the full code example with a few additional styling tweaks.

javascript

import {eachDayOfInterval, format, isSameDay, subDays} from 'date-fns'; import React, {useEffect, useState} from 'react'; import { SafeAreaView, StatusBar, Text, View, useColorScheme, } from 'react-native'; import Config from 'react-native-config'; import {BarChart, BarChartPropsType} from 'react-native-gifted-charts'; import Sahha, {SahhaEnvironment} from 'sahha-react-native'; type SahhaScore = { id: string; type: string; state: string; score: number; factors: { name: string; value: number; }[]; inputData: string[]; createdAt: string; }; type SahhaAnalyzeResponse = { inferences?: SahhaScore[]; }; const SAHHA_CONFIGURATION_SETTINGS = { environment: SahhaEnvironment.sandbox, }; const configureSahha = () => new Promise((resolve, reject) => Sahha.configure( SAHHA_CONFIGURATION_SETTINGS, (error: string, success: boolean) => { if (success) resolve(success); reject(error); }, ), ); const authenticateSahha = (externalId: string) => new Promise((resolve, reject) => Sahha.authenticate( Config.SAHHA_APPLICATION_ID || '', Config.SAHHA_APPLICATION_SECRET || '', externalId, (error, success) => { if (success) resolve(success); reject(error); }, ), ); const analyzeSahhaDateRange = ( startDate: Date, endDate: Date, ): Promise<SahhaAnalyzeResponse> => new Promise((resolve, reject) => Sahha.analyzeDateRange( startDate.getTime(), endDate.getTime(), (error, value) => { try { if (error) throw new Error(error); resolve(JSON.parse(value)); } catch (e) { reject(e); } }, ), ); function App(): React.JSX.Element { const isDarkMode = useColorScheme() === 'dark'; const backgroundColor = isDarkMode ? '#1c1917' : '#fafaf9'; const color = isDarkMode ? '#fafaf9' : '#1c1917'; const end = new Date(); const start = subDays(end, 6); const days = eachDayOfInterval({start, end}); const [chartData, setChartData] = useState<BarChartPropsType['data']>([]); const createChartData = (scores: SahhaScore[]) => days.map(date => { const scoreForDate = scores.find(s => isSameDay(s.createdAt, date)); const value = (scoreForDate?.score || 0) * 100; return {value, label: format(date, 'E')}; }); useEffect(() => { (async () => { try { await configureSahha(); await authenticateSahha('healthy-profile-01'); const {inferences} = await analyzeSahhaDateRange(start, end); const wellbeingScores = inferences?.filter(s => s.type === 'wellbeing') || []; setChartData(createChartData(wellbeingScores)); } catch (e) { console.error(e); } })(); }, []); return ( <SafeAreaView style={{ flex: 1, padding: 16, backgroundColor, }}> <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} backgroundColor={backgroundColor} /> <View style={{flex: 1}}> <Text style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 16, color, }}> Your wellbeing scores </Text> <BarChart data={chartData} barWidth={16} barBorderRadius={4} stepValue={10} maxValue={100} noOfSections={11} frontColor="#0EA5E9" xAxisLabelTextStyle={{color}} yAxisTextStyle={{color}} hideRules xAxisThickness={0} yAxisThickness={0} /> </View> </SafeAreaView> ); } export default App;

And here is the output



Conclusion

In this tutorial, we have successfully created a React Native application that visualizes health-related data using the Sahha SDK. We covered the following key steps:

  1. Setting Up the Project: Initialized a new React Native project and installed the necessary dependencies.
  2. Configuring Sahha: Set up the Sahha SDK with your application credentials.
  3. Authenticating: Authenticated the user profile to retrieve health data.
  4. Retrieving Data: Fetched the wellbeing scores from Sahha's API.
  5. Visualizing Data: Displayed the data in a bar chart using react-native-gifted-charts.

By following these steps, you can now visualize behavioral health insights within your React Native application, providing valuable feedback and insights to your users.

Feel free to customize and expand upon this foundation to create more complex and interactive visualizations. The integration of Sahha's health data capabilities opens up numerous possibilities for health and wellness applications.