React-Headless

This section describes how to integrate user preferences functionality in React Applications using separate headless preference component

This document will cover the methods to integrate User Preferences into your websites. Your users will be able to specify their notification preferences using this page. With SuprSend, the user can set preferences at 3 levels - communication channel, notification category, and selected channels inside a category. We'll cover methods to read and update data at all 3 levels.

We'll also give an example code to add to our pre-defined UI. This is how a typical preference page will look like

Pre-requisites


Installation

npm install @suprsend/react-preferences-headless
yarn add @suprsend/react-preferences-headless

Integration

NOTE: You can use fully functional preference example while integrating preference in your react applications. Just have to add accessToken logic, handleError, and customize Styling according to your requirements. UI provided by default in the example folder looks a bit similar to the image provided above.

Following are the components, and hooks that are exposed by this SDK.

SuprSendPreferenceProvider

Wrap your Preference component in this provider and pass mandatory props. All the hooks to integrate preferences will be available to children of this Provider.

import { SuprSendPreferenceProvider } from '@suprsend/react-preferences-headless';

function Example() {
  return (
    <SuprSendPreferenceProvider
      workspaceKey="<workspace_key>"
      distinctID="<distinct_id>"
      accessToken="<access_token>"
    >
      <Preference />
    </SuprSendPreferenceProvider>
  );
}

workspaceKey: You will get this key in SuprSend Dashboard inside Settings > API Keys.

distinctID: Pass the distinct_id of the user for which you want to modify preferences.

accessToken: This will be the JWT token of the distinct_id which you need to be generated in your backend and provided to the frontend through API. More details about this are available here.

tenantID: This is an optional prop. If you don't provide tenantID, preferences will be changed to default tenant. If you provide tenantID then preferences will be provided tenant specific only.


usePreferences

This is a react hook that is available inside SuprSendPreferenceProvider. This is used to get preference data.

import { usePreferences } from '@suprsend/react-preferences-headless';

export default function Preference() {
  const preferenceData = usePreferences();

  if (!preferenceData || preferenceData.loading) {
    return <p>Loading...</p>;
  } else if (preferenceData.error) {
    return <p>Something went wrong. Please refresh page and try again</p>;
  }
  return (
    <div style={{ margin: 24 }}>
      <h3 style={{ marginBottom: 24 }}>Notification Preferences</h3>
      <NotificationCategoryPreferences preferenceData={preferenceData.data} />
      <ChannelLevelPreferences preferenceData={preferenceData.data} />
    </div>
  );
}

// https://github.com/suprsend/suprsend-react-preference-headless/blob/example-format/src/types.ts

interface IPreferencesResponse {
  loading: boolean;
  error: boolean;
  error_data?: IPreferenceErrorData;
  data: IPreferenceState | null;
}

useUpdatePreferences

This hook is used to get update methods that are needed to update preferences data.

import { usePreferences, useUpdatePreferences } from '@suprsend/react-preferences-headless';

export default function Preference() {
  const preferenceData = usePreferences();
  const {
    update_category_preference,
    update_channel_preference_in_category,
    update_overall_channel_preference,
  } = useUpdatePreferences();

  return <div>Preference Component</div>
}

// https://github.com/suprsend/suprsend-react-preference-headless/blob/example-format/src/types.ts

interface IUseUpdatePreferences {
  update_category_preference?: (
    category: string,
    preference: PreferenceOptions
  ) => IPreferenceAPIReponse;

  update_channel_preference_in_category?: (
    channel: string,
    preference: PreferenceOptions,
    category: string
  ) => IPreferenceAPIReponse;
  
  update_overall_channel_preference?: (
    channel: string,
    preference: ChannelLevelPreferenceOptions
  ) => IPreferenceAPIReponse;
}

All three update functions work similarly to the ones in javascript sdk except you don't need to pass args argument in these methods.


usePreferenceEvent

This hook returns an emitter which can be used to listen to events emitted by sdk. Currently, sdk emits only one event preferences_error. This will be emitted when there is an error in the API call. We are using events to notify API errors because sdk internally debounces the update requests to avoid race conditions.

import { usePreferenceEvent } from '@suprsend/react-preferences-headless';

function Preference() {
  const preferenceData = usePreferences();
  const emitter = usePreferenceEvent();

  React.useEffect(() => {
    emitter?.on("preferences_error", (error: IPreferenceErrorData) => {
     // asynchronous api call errors needs to be handled here.
    });

    return () => {
      emitter?.off("preferences_error");
    };
  }, [emitter]);

  <div>Preferences Component</div>;
}


Generating accessToken

To authenticate preference APIs to SuprSend, accessToken needs to be provided to the SuprSendPreferenceProvider. Generate JWT token with following requirements

Algorithm: HS256

Secret: Use workspace secret to sign the JWT token. You can get the workspace secret from SuprSend Dashboard in Settings > API Keys.

Payload: Payload should be in below mentioned format

{
  "sub": "distinct_id", // your distinct_id
  "iat": 1516239022, // unix timestamp in sec at which token is issued
  "exp":1695212525 // unix timestamp in sec at which token will expire
}

🚧

Access Token should be generated in your Backend application and should be passed to client. It shouldnot be generated on client.

Token Invalid response type for all get, update methods and also for preferences_error emitter:

{
    "error": true,
    "response": {
        "message": "reason for error",
        "type": "TOKEN_INVALID"
    }
}

Token Expired response type for all get, and update methods and also for preferences_error emitter.

{
    "error": true,
    "response": {
        "message": "Token is expired",
        "type": "TOKEN_EXPIRED"
    }
}

If the token is expired you have to make api call to your service and provide a new JWT token to SuprSendPreferenceProvider as accessToken prop.