Angular

This section describes how to integrate user preferences functionality in Angular Applications.

This document will cover the methods to integrate User Preferences in your Angular Applications. 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.

There's an example code to add our pre-defined UI at the end of this documentation. This is how a typical preference page will look like


All the data points and functions are same as Javascript application

Pre-requisites


Integration

All preference methods and properties are available under suprsend.user.preferences instance. Here's a reference of all the properties and methods available in this instance. Please read to javascript documentation to understand all these methods and properties in detail


Read Preferences data

There will be 3 components: preference, channel-level-preferences, and category-level-preferences. preference will be the main component and inside it, there will be an instance property that contains user preference data. Whenever there's an update we will update the latest preference data in the same state for the component to rerender.

import suprsend from "@suprsend/web-sdk";

// this is main component
@Component({
  selector: 'app-preference',
  templateUrl: './preference.component.html',
  styleUrls: ['./preference.component.css'],
})
export class PreferenceComponent implements OnInit {
  preferencesData: any = null;
  
  ...
  
}

Step 1. Get Preference data

After adding the component, call suprsend.user.preferences.get_preferences() method to get the preferences data for the already identified user. This method is used to get full user preferences data from the SuprSend. This method should be called first before any update methods. Calling this method will make an API call and returns a preference response, which you can store in your instance property preferenceData if there is no error.


Step 2. Configure Event Listeners

After calling get_preferences, call these 2 event listeners

  1. preferences_updated - This event is fired when you get a successful response after calling get_preferences method. In the callback, you will get the latest preference data as a parameter. You can use this data to update the latest preference data in the existing instance property preferenceData for the component to render.
  2. preferences_error - When there are validation errors or API errors SDK will fire preferences_error event. In the callback, you will then get error-related information as a parameter.
@Component({...})
export class PreferenceComponent implements OnInit {
  preferencesData: any = null;

  ngOnInit(): void {
    suprsend.user.preferences.get_preferences().then((resp) => {
      if (resp.error) {
        console.log(resp.message);
      } else {
        this.preferencesData = resp;
      }
    });
		
		// listen for update in preferences data
    suprsend.emitter.on('preferences_updated', (preferenceData) => {
      this.preferencesData = { ...preferenceData };
    });

    // listen for errors
    suprsend.emitter.on('preferences_error', (error) => {
      console.log('ERROR:', error);
    });
  }
}

Show Preference data on the UI

Preferences data is of 2 types:

  1. Category Preference - User can set preferences at overall category level or select specific channels in a category from this section.
Category Preference

Category Preference


  1. Channel Preferences - User can set preferences at overall channel level from this section.
Channel Preference

Channel Preference


Code block to Render Header and Blank state

Our Main component preference has 2 child components one for each type of preference.

<p *ngIf="!this.preferencesData">Loading...</p>

<div *ngIf="this.preferencesData" class="main-div">
  <h3 class="main-header">Notification Preferences</h3> 

  <!-- notification category level preferences -->
  <app-category-level-preferences [preferencesData]="this.preferencesData"></app-category-level-preferences>

  <!-- channel level preferences -->
  <app-channel-level-preferences [preferencesData]="this.preferencesData"></app-channel-level-preferences>
</div>

Show Category level Preference section on the UI

In category-level preferences, you'll have to fetch the data from 3 parts:

  • Section - to show sections like "Product Updates" in below example
  • Category - to show categories and their overall status like "Refunds" in below example
  • CategoryChannel - to show communication channels inside the category and their status


Below are the steps to render category preference UI:

  1. Loop through the property preferenceData.sections for showing sections, show sub-categories inside each section, and show subcategory's channels inside each sub-category.

  2. Add a switch button next to each sub-category for opting in and out of the category. Add checkbox components in sub-category channels for opting in and out of category-channel. You can use any third-party npm package to import these components or design your own component.

  3. To update category preference on the click of the switch button, call update_category_preference method and if no error is received in response, update the latest data in the instance property. For preference state opt-in set the switch state as on and off for the opt-out state.


  1. To update category-channel preference on the click of checkbox next to each channel, call the update_channel_preference_in_category method. Update the latest data in the instance property if no error is received in response. For preference state opt-in set the checkbox state as checked and unchecked for the opt-out state.


Code block to Render Category section

import { Component, Input } from '@angular/core';
import suprsend, { PreferenceOptions } from '@suprsend/web-sdk';

@Component({
  selector: 'app-category-level-preferences',
  templateUrl: './category-level-preferences.component.html',
  styleUrls: ['./category-level-preferences.component.css'],
})
export class CategoryLevelPreferencesComponent {
  @Input() public preferencesData: any;

  handleCategoryPreferenceChange(e: boolean, subcategory: string) {
    const resp = suprsend.user.preferences.update_category_preference(
      subcategory,
      e ? PreferenceOptions.OPT_IN : PreferenceOptions.OPT_OUT
    );
    if (resp.error) {
      console.log(resp.message);
    } else {
      this.preferencesData = { ...resp };
    }
  }

  handleChannelPreferenceInCategoryChange(channel: any, category: string) {
    if (!channel.is_editable) return;

    const resp =
      suprsend.user.preferences.update_channel_preference_in_category(
        channel.channel,
        channel.preference === PreferenceOptions.OPT_IN
          ? PreferenceOptions.OPT_OUT
          : PreferenceOptions.OPT_IN,
        category
      );
    if (resp.error) {
      console.log(resp.message);
    } else {
      this.preferencesData = { ...resp };
    }
  }
}
<div
  *ngFor="let section of this.preferencesData.sections"
  class="cat-container"
>
  <div *ngIf="section.name">
    <div class="section-name-container">
      <p class="section-name-text">{{ section.name }}</p>
      <p class="section-description-text">{{ section.description }}</p>
    </div>
  </div>
  <div *ngFor="let subcategory of section.subcategories">
    <div class="subcategory-container">
      <div class="subcategory-top-div">
        <div>
          <p class="subcategory-name">{{ subcategory.name }}</p>
          <p class="subcategory-description">{{ subcategory.description }}</p>
        </div>
        <ui-switch
          size="small"
          color="#2463eb"
          [disabled]="!subcategory.is_editable"
          [checked]="subcategory.preference === 'opt_in'"
          (change)="
            handleCategoryPreferenceChange($event, subcategory.category)
          "
        ></ui-switch>
      </div>

      <div class="subcategory-channel-container">
        <div
          *ngFor="let channel of subcategory.channels"
          class="category-channel-checkbox"
        >
          <input
            type="checkbox"
            [id]="subcategory.category + '-' + channel.channel"
            [disabled]="!channel.is_editable"
            [checked]="channel.preference === 'opt_in'"
            (change)="
              handleChannelPreferenceInCategoryChange(
                channel,
                subcategory.category
              )
            "
          />
          <label
            class="category-channel-label"
            [for]="subcategory.category + '-' + channel.channel"
            >{{ channel.channel }}</label
          >
        </div>
      </div>
    </div>
  </div>
</div>

Show Channel level Preference section on the UI

Below are the steps to render channel preference UI:

  1. Loop through the property preferenceData.channel_preferences for showing channels and for every channel item we will show an option to select preference using radio buttons.

  2. Add a radio button next, against channel level options for switching from all to required preference in channel.

  3. To update channel preference on the click of the radio button, call update_overall_channel_preference method, and if no error is received in response, update the latest data in the state.

Code block to Render Channel section

import { Component, Input } from '@angular/core';
import suprsend, { ChannelLevelPreferenceOptions } from '@suprsend/web-sdk';

@Component({
  selector: 'app-channel-level-preferences',
  templateUrl: './channel-level-preferences.component.html',
  styleUrls: ['./channel-level-preferences.component.css'],
})
export class ChannelLevelPreferencesComponent {
  @Input() public preferencesData: any;

  handleChange(channel: string, preference: string) {
    const preferenceStatus =
      preference === 'ALL'
        ? ChannelLevelPreferenceOptions.ALL
        : ChannelLevelPreferenceOptions.REQUIRED;
    const resp = suprsend.user.preferences.update_overall_channel_preference(
      channel,
      preferenceStatus
    );
    if (resp.error) {
      console.log(resp.message);
    } else {
      this.preferencesData = { ...resp };
    }
  }
}
<div>
  <div class="channel-header-div">
    <p class="channel-header-p">What notifications to allow for channel?</p>
  </div>
  <div>
    <div *ngFor="let channel of this.preferencesData.channel_preferences">
      <div class="channel-container">
        <p class="channel-channel-text">{{ channel.channel }}</p>
        <p
          class="channel-help-text"
          *ngIf="channel.is_restricted; else allText"
        >
          Allow required notifications only
        </p>
        <ng-template #allText
          ><p class="channel-help-text">Allow all notifications</p>
        </ng-template>

        <div class="channel-radio-container">
          <p class="channel-radio-pref-text">
            {{ channel.channel }} Preferences
          </p>
          <div class="radio-grp">
            <div class="radio-grp-2">
              <div class="radio-grp-container">
                <div>
                  <input
                    type="radio"
                    [checked]="!channel.is_restricted"
                    name="all-{{ channel.channel }}"
                    id="all-{{ channel.channel }}"
                    (change)="handleChange(channel.channel, 'ALL')"
                  />
                </div>
                <label class="all-label" for="all-{{ channel.channel }}">
                  All
                </label>
              </div>
              <p class="channel-radiohelp-text">
                Allow All Notifications, except the ones that I have turned off
              </p>
            </div>
            <div>
              <div class="radio-grp-container">
                <div>
                  <input
                    type="radio"
                    name="required-{{ channel.channel }}"
                    id="required-{{ channel.channel }}"
                    [checked]="channel.is_restricted"
                    (change)="handleChange(channel.channel, 'REQUIRED')"
                  />
                </div>
                <label
                  class="required-label"
                  for="required-{{ channel.channel }}"
                >
                  Required
                </label>
              </div>
              <p class="channel-radiohelp-text">
                Allow only important notifications related to account and
                security settings
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Example Code to Render Full Preference Page

You can refer to our angular-example GitHub repository to get check the full code.