7 min read
.
on Jul 18, 2019
Notification badges are a core feature of any mobile app, displaying important data to the user in realtime and reengaging out-of-app users.

Icon badges, or notification badges, are useful UI elements in any Android or iOS app. They allow icons to become alive and display important data to the user in realtime. They might show how many users are online, a notification count, or the number of unread messages. You can see them being used by app icons on Android and iOS, as well as in apps like Facebook, Snapchat, Instagram, and YouTube.

Luckily, with PubNub, building realtime notification badges is simple. We’ll be using some useful React Native libraries to clone Facebook Messenger and add badges to the icons.

The final result will be a skeleton app that looks like:

facebook clone active users realtime badge

 

We will also be using PubNub for realtime updates to the badge. Get your free PubNub API keys here to enable Pub/Sub Messaging and Presence. Important: You must enable Presence in the PubNub Admin Dashboard for this app to work.

Creating a Facebook Messenger Clone in React Native

Before diving into the code, you will need to install Node.js, if you haven’t already. Next, to use React Native, you will also need to install the React Native CLI, through which we can initialize and run our project.

sudo npm install -g react-native-cli
sudo npm install -g react-native

Now, let’s build a blank react-native app.

react-native init realtimebadge && cd realtimebadge

Add React Native Elements, React Native Vector Icons, React Navigation, React Native Gesture Handler, and React PubNub to your project.

npm install --save react-native-elements react-native-vector-icons react-pubnub react-native-gesture-handler react-navigation && react-native link

Note
: you may need to manually link react-native-gesture-handler if automatically linking does not work. Follow the steps here to manually link react-native-gesture-handler.

In App.js, include PubNub into your app and initialize a PubNub instance with the free API keys you received above. Under componentDidMount(), subscribe to an arbitrary channel, with the boolean flag withPresence set to true.

import React, { Component } from "react";
import { Text } from "react-native";
import PubNubReact from 'pubnub-react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.pubnub = new PubNubReact({
    publishKey: "INSERT-PUB-KEY-HERE",
    subscribeKey: "INSERT-SUB-KEY-HERE"
    });
    this.state = {
    };

    this.pubnub.init(this);
  }

  componentDidMount() {
    this.pubnub.subscribe({
      channels: ['channel1'],
      withPresence: true
    });
  }

  render() {
    return <Text>Hello world.</Text>;
  }
}

Create a new folder in the root directory called src. Within src, create three more folders called navigation, styles, and screens.

We’ll need to create a blank screen as a default screen for each navigation view. You may modify this screen for your use cases. For our demo purposes, it will simply display “Empty screen.” as text. Create a file called Empty.js and place it inside src/screens.

import React from "react";
import { StatusBar, StyleSheet, Text } from "react-native";
import { SafeAreaView } from "react-navigation";
import AppStyles from '../styles/Styles';

export class Empty extends React.Component {
  static navigationOptions = {
    headerTitle: "Empty"
  };
  render() {
    return (
      <SafeAreaView>
        <StatusBar
        backgroundColor={AppStyles.colors.accentColor}
        barStyle={AppStyles.barStyle}
        />
        <Text>Empty screen.</Text>
      </SafeAreaView>
    );
  }
}

The styling for the UI can be found in styles/Styles.js. Customize it at your will.

const AppStyles = {
    colors: {
        accentColor: '#0084ff',
        inactiveGreyColor: '#626262',
        lightGreyColor: '#7f8c8d',
        separator: '#bdc3c7',
        white: 'white',
        black: 'black',
        grey: 'grey',
        green: 'green',
        onlineGreen: '#2ecc71',
        lightWhite: '#f9f9f9'
    },
    fonts: {
        FONT_REGULAR: 'Roboto-Regular',
        FONT_MEDIUM: 'Roboto-Medium',
        FONT_LIGHT: 'Roboto-Light',
        FONT_THIN: 'Roboto-Thin'
    },
    barStyle: "light-content"
};

export default AppStyles;

To create Facebook Messenger styled navigation bars, we’ll be using react-navigation.

The top navigation bar will include “Messages,” “Active,” “Groups,” and “Calls” as a material-design themed tab bar from react-navigation’s createMaterialTopTabNavigator. Create a file called Messages.js and include the following code below.

import { Platform } from 'react-native';
import { createMaterialTopTabNavigator, createAppContainer } from 'react-navigation';

import Empty from "../screens/Empty";

import AppStyles from '../styles/Styles';

export const Messages = createMaterialTopTabNavigator({
  MessagesScreen: {
    screen: Empty,
    navigationOptions: { header: null, title: 'Messages' }
  },
  ActiveScreen: {
    screen: Empty,
    navigationOptions: { header: null, title: 'Active' }
  },
  GroupsScreen: {
    screen: Empty,
    navigationOptions: { header: null, title: 'Groups' }
  },
  CallsScreen: {
    screen: Empty,
    navigationOptions: { header: null, title: 'Calls' }
  }
},
{
  tabBarPosition: 'top',
  tabBarOptions: {
    activeTintColor: AppStyles.colors.accentColor,
    inactiveTintColor: AppStyles.colors.inactiveGreyColor,
    pressColor: AppStyles.colors.lightGreyColor,
    labelStyle: {
      fontWeight: 'bold',
      fontSize: Platform.OS === 'ios' ? 11 : 12,
      fontFamily: AppStyles.fonts.FONT_MEDIUM
    },
    indicatorStyle: {
      backgroundColor: AppStyles.colors.accentColor
    },
    style: {
      backgroundColor: 'white'
    }
  }
});

If you export this component into your App.js render, you will see something like this:

facebook navigation bar

Now, let’s build the base navigator of the app which includes a bottom tab navigation bar as well as the top bar that we just made.

Conveniently, we can use Icon from react-native-elements as the tabBarIcon. We’ll be later changing these icons into BadgedIcons. Create a file named Navigation.js inside src/Navigation and begin by adding the bottom icons.

import React from 'react';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
import { Badge, Icon, withBadge } from 'react-native-elements'

import { Messages } from './Messages';

import AppStyles from '../styles/Styles';
import Empty from "../screens/Empty";

const MessagesIcon = ({ tintColor }) => (
  <Icon
    type="ionicon"
    name="ios-chatbubbles"
    size={24}
    color={tintColor}
  />
);
const UsersIcon = ({ tintColor }) => (
  <Icon
    type="material"
    name="supervisor-account"
    size={24}
    color={tintColor}
  />
);

const DiscoverIcon = ({ tintColor }) => (
  <Icon
    type="ionicon"
    name="md-compass"
    size={24}
    color={tintColor}
  />
);

Just like we did for the top bar, we can easily build a bottom navigation bar with icons by using createBottomTabNavigator.

const BottomTabNavigation = createBottomTabNavigator({
  MessagesScreen: {
    screen: Messages,
    navigationOptions: {
      header: null,
      tabBarIcon: MessagesIcon
    }
  },
  UsersScreen: {
    screen: Empty,
    navigationOptions: {
      header: null,
      tabBarIcon: UsersIcon
    }
  },
  DiscoverScreen: {
    screen: Empty,
    navigationOptions: {
      header: null,
      tabBarIcon: DiscoverIcon
    }
  }
},
{
  tabBarOptions: {
    showLabel: false,
    activeTintColor: '#0084ff',
    inactiveTintColor: AppStyles.colors.inactiveGreyColor,
    pressColor: '#7f8c8d'
  }
});

To include this navigation component to the App, first create a default export.

const Navigation = createAppContainer(BottomTabNavigation);

export default Navigation;

And then add it to your App.js as follows.

import React, { Component } from "react";
import Navigation from "./src/navigation/Navigation";
import PubNubReact from 'pubnub-react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.pubnub = new PubNubReact({
    publishKey: "INSERT-PUB-KEY-HERE",
    subscribeKey: "INSERT-SUB-KEY-HERE"
    });
    this.state = {
    };

    this.pubnub.init(this);
  }

  componentDidMount() {
    this.pubnub.subscribe({
      channels: ['channel1'],
      withPresence: true
    });
  }

  render() {
    return <Navigation />;
  }
}

At this point, we’ve finished up the UI and we are ready to include badges into our app.

Adding Badges to Icons in React Native

To use react-native-elements’ badge, let’s import it from `react-native-elements`.

import { withBadge } from 'react-native-elements' 

Now instead of the MessagesIcon we created, we can replace it with a BadgedIcon.

const MessagesBadge = withBadge(5)(Icon)

Note: we can pass in any count inside the first withBadge argument.

And simply change the Icon render to MessagesBadge.

const MessagesIcon = ({ tintColor }) => (
  <MessagesBadge
    type="ionicon"
    name="ios-chatbubbles"
    size={24}
    color={tintColor}
  />
);

You have now added a badge to the messages icon that looks like this:

realtime badges in facebook app

Active Users Badge

As of now, we’ve hardcoded the badge count for the MessagesIcon. However, we can make our UsersIcon badge become alive by using PubNub Presence to find the number of users connected.

In App.js, after connecting to PubNub, we can have each user subscribe to a global channel. Then, with a Presence hereNow() call, we will be able to retrieve the number of users connected. We will update this value usersCount in the state and pass it into our navigation props, allowing us to access this value for our badge, in realtime.

Your App.js should now look like this:

import React, { Component } from "react";
import Navigation from "./src/navigation/Navigation";
import PubNubReact from 'pubnub-react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.pubnub = new PubNubReact({
      publishKey: "INSERT-PUB-KEY-HERE",
      subscribeKey: "INSERT-SUB-KEY-HERE"
    });
    this.state = {
      userCount: 0,
    };

    this.pubnub.init(this);
  }

  componentDidMount() {
    this.pubnub.subscribe({
      channels: ['channel1'],
      withPresence: true
    });

    let presenceUsers;
    setInterval(() => {
      this.pubnub.hereNow(
      {
        includeUUIDs: true,
        includeState: true
      },
      (status, response) => {
        // handle status, response
        console.log(status);
        console.log(response);
        if (response != undefined) presenceUsers = response.totalOccupancy;
      }
    );
      this.setState({userCount: presenceUsers})
    }, 10000);
  }

  render() {
    return <Navigation screenProps={{userCount: this.state.userCount}}/>;
  }
}

Here, we use setInterval() to continuously check the number of users joined every 10 seconds (you may change this for your needs). Then, we store the user count in the state and pass it through the Navigation component as a screenProp. When rendering our badged icon, we can access it from the screenProps as userCount.

As such, we need to change our UsersScreen to include an icon as well as the badge. This is an alternative way to use the badge compared to how we previously used it for the messages badge.

UsersScreen: {
  screen: Empty,
  navigationOptions: ({ screenProps, navigation }) => ({
    header: null,
    tabBarIcon: () => (
      <View>
        <Icon
          type="material"
          name="supervisor-account"
          size={24}
        />

        <Badge
          value={screenProps.userCount}
          containerStyle={{ position: 'absolute', top: -4, right: -4 }}
        />
    </View>
    )
  })
},

Congratulations! You have added a realtime badge feature into your app that displays the active users count on an icon using PubNub Presence. As more users open and join the app, the badge will update the user count accordingly. Here is the result:

realtime badge facebook gif

Conclusion

In this tutorial, you learned how to build a basic messaging app. Then, you were able to add badges to icons in React Native. Finally, you used PubNub Presence to create an active users icon which displays the user count in its badge in realtime.

More From PubNub