React Native Message Center

Airship’s SDK provides a simple interface for managing the Message Center within your application.

Airship Message Center is a place in your app where you can display persistent rich messages, including HTML, video, etc. The messages are hosted by Airship, and are typically displayed in standard inbox-style within your app.

Airship.messageCenter.setAutoLaunchDefaultMessageCenter(false);

Using the MessageView
<MessageView messageId="message-id"
             onLoadStarted={this.startLoading}
             onLoadFinished={this.finishLoading}
             onLoadError={this.failedLoading}
             style={{ flex: 1 }}
 />

An example of a Message Center inbox as a React component
/**
 * Sample React Native App
 *
 * MessageCenterScreen: Contains the list of messages.
 */
'use strict';

/* Copyright Airship and Contributors */
/**
 * Sample React Native App
 *
 * MessageCenterScreen: Contains the list of messages.
 */
'use strict';

import * as React from 'react';

import {
  Text,
  View,
  FlatList,
  TouchableHighlight,
  RefreshControl,
} from 'react-native';

import Moment from 'moment';

import styles from '../Styles';
import Airship, { Subscription, EventType, InboxMessage } from '@ua/react-native-airship';

interface MessageCenterScreenProps {
  navigation: any;
}

function Item({ message, navigation }: { message: any; navigation: any }) {
  return (
    <TouchableHighlight
      activeOpacity={0.6}
      underlayColor="#DDDDDD"
      onPress={() =>
        navigation.navigate('MessageDetails', {
          messageId: message.id,
          title: message.title,
        })
      }
    >
      <View style={styles.item}>
        <Text style={styles.itemTitle}>{message.title}</Text>
        <Text style={styles.itemSubtitle}>
          {Moment(message.sentDate).format('MM/DD/YYYY')}
        </Text>
        <View style={styles.itemSeparator} />
      </View>
    </TouchableHighlight>
  );
}

export default class MessageCenterScreen extends React.Component<
  MessageCenterScreenProps,
  {
    messages: InboxMessage[];
    refreshing: boolean;
  }
> {
  private updateSubscription?: Subscription;

  constructor(props: MessageCenterScreenProps) {
    super(props);
    this.state = {
      messages: [],
      refreshing: true,
    };

    this.refreshMessageCenter = this.refreshMessageCenter.bind(this);
    this.handleUpdateMessageList = this.handleUpdateMessageList.bind(this);
  }

  componentDidMount(): void {
    this.updateSubscription = Airship.addListener(
      EventType.MessageCenterUpdated,
      this.handleUpdateMessageList
    );
    this.handleUpdateMessageList();
  }

  componentWillUnmount(): void {
    this.updateSubscription?.remove();
  }

  handleUpdateMessageList() {
    Airship.messageCenter.getMessages().then((data) => {
      this.setState({
        messages: data,
        refreshing: false,
      });
    });
  }

  refreshMessageCenter() {
    Airship.messageCenter
      .refreshMessages()
      .then(() => {
        this.setState({
          refreshing: false,
        });
      })
      .catch((error) => {
        console.log('failed to refresh', error);
      });
  }

  render() {
    return (
      <View style={styles.backgroundContainer}>
        <FlatList
          data={this.state.messages}
          renderItem={({ item }) => (
            <Item message={item} navigation={this.props.navigation} />
          )}
          keyExtractor={(item) => item.id}
          refreshControl={
            <RefreshControl
              refreshing={this.state.refreshing}
              onRefresh={this.refreshMessageCenter}
            />
          }
        />
      </View>
    );
  }
}

interface MessageScreenProps {
  navigation: any;
  route: any;
}
export default class MessageScreen extends React.Component<
  MessageScreenProps,
  {
    animating: boolean;
  }
> {
  constructor(props: MessageScreenProps) {
    super(props);
    this.state = {
      animating: true,
    };

    this.startLoading = this.startLoading.bind(this);
    this.finishLoading = this.finishLoading.bind(this);
    this.failedLoading = this.failedLoading.bind(this);
  }

  startActivityIndicator() {
    setTimeout(() => {
      this.setState({
        animating: false,
      });
    }, 500);
  }

  stopActivityIndicator() {
    setTimeout(() => {
      this.setState({
        animating: false,
      });
    }, 500);
  }

  startLoading() {
    this.startActivityIndicator();
  }

  finishLoading() {
    this.stopActivityIndicator();
  }

  failedLoading() {
    this.stopActivityIndicator();
    Alert.alert('Error', 'Unable to load message. Please try again later', [
      { text: 'OK', onPress: () => this.props.navigation.goBack() },
    ]);
  }

  render() {
    const { params } = this.props.route;
    const messageId = params ? params.messageId : '';

    return (
      <View style={styles.backgroundContainer}>
        <MessageView
          messageId={messageId}
          onLoadStarted={this.startLoading}
          onLoadFinished={this.finishLoading}
          onLoadError={this.failedLoading}
          // @ts-ignore
          style={{ flex: 1 }}
        />
        {this.state.animating && (
          <View style={styles.loadingIndicator}>
            <ActivityIndicator size="large" animating={this.state.animating} />
          </View>
        )}
      </View>
    );
  }
}

Look at our sample app for more details.