Embed the Message Center

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

This guide covers creating custom Message Center implementations for React Native applications.

Override Default Display Behavior

To use a custom Message Center implementation instead of the default UI, disable auto-launch and add a listener to handle display events:

// Disable the default UI
Airship.messageCenter.setAutoLaunchDefaultMessageCenter(false);

// Add a listener to handle display events
Airship.addListener(EventType.DisplayMessageCenter, (event) => {
  if (event.messageId) {
    // Navigate to specific message
  } else {
    // Navigate to message center
  }
});

Custom Message Center Implementation

For complete control over Message Center placement and navigation, create a custom implementation using the Message Center components.

Using the MessageView

The MessageView component can be used to display individual messages:

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

Example: Custom Message Center Inbox

Here’s an example of a complete Message Center inbox implementation:

import * as React from 'react';
import {
  Text,
  View,
  FlatList,
  TouchableHighlight,
  RefreshControl,
} from 'react-native';
import Moment from 'moment';
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>
    );
  }
}

Example: Message Detail Screen

Here’s an example of a message detail screen:

import * as React from 'react';
import { View, ActivityIndicator, Alert } from 'react-native';
import { MessageView } from '@ua/react-native-airship';

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);
  }

  startLoading() {
    this.setState({ animating: true });
  }

  finishLoading() {
    this.setState({ animating: false });
  }

  failedLoading() {
    this.setState({ animating: false });
    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}
          style={{ flex: 1 }}
        />
        {this.state.animating && (
          <View style={styles.loadingIndicator}>
            <ActivityIndicator size="large" animating={this.state.animating} />
          </View>
        )}
      </View>
    );
  }
}

For more examples, see our sample app.