kenjuの日記

About Programming, Mathematics and Security

Intercom JavaScript APIの知見メモ

CSツールとして仕事でIntercomを利用している。

Intercom JavaScript APIが存在していて、globalに読み込んでいるIntercom objectに対して、

  • 起動時・シャットダウン・未読数変更時などのイベント監視
  • 設定のオーバーライド
  • 動的なメッセージウィンドウの開閉

などのAPIが提供されている。

developers.intercom.com

最低限必要な洗練されたAPIが揃っていると言う印象。

具体例

例えば、自前のデザインを適用したIntercom Messengerを実装する必要性があって、作成したのが↓のReact Componennts。

ポイントは以下の二つ:

  • 遅延ロード対策のため、setIntervalsetTimeoutで「1秒ごとにwindow.intercomがロードされたかどうかを確認する。これを最大30秒間まで続ける」という処理を行なっている
  • window.intercom objectがロードされたら、The Intercom JavaScript APIのうちいくつかのイベント監視APIを利用
export default class IntercomLauncher extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      booted: false,
      opened: false,
      hasUnread: false,
    };
  }

  componentDidMount() {
    this.setIntervalToCustomLauncher();
  }

  setIntervalToCustomLauncher() {
    const intervalToCheckIntercomBooted = setInterval(() => setupIntercom(), 1 * 1000);
    const timeoutToClearInterval = setTimeout(() => clearInterval(intervalToCheckIntercomBooted), 3 * 1000);

    const setupIntercom = () => {
      // windowにIntercom objectが読み込まれない場合は何もしない
      if (window.Intercom && window.Intercom.booted) {
        this.setState({ booted: true });

        // 遅延ロード対策。少し複雑だが、それぞれのTimeoutで↓を管理している
        //   interval : 1秒ごとに intercom がローディングされたかどうかを確認する
        //   timeout : 30秒経過しても intercom のロードを確認できなかった場合、interval自体をクリアする
        clearInterval(intervalToCheckIntercomBooted);
        clearTimeout(timeoutToClearInterval);

        const overwrittenSettings = {
          // 独自の<a/>タグでメッセンジャーを開くために必要な設定。詳細は以下:
          //   https://docs.intercom.com/configure-intercom-for-your-product-or-site/customize-the-intercom-messenger/customize-the-intercom-messenger-technical
          custom_launcher_selector: '.intercom-launcher',
          hide_default_launcher: true,
        };

        // イベントを監視
        window.Intercom('boot', overwrittenSettings);
        window.Intercom('onShow', () => this.setState({ opened: true }));
        window.Intercom('onHide', () => this.setState({ opened: false }));
        window.Intercom('onUnreadCountChange', this.handleUnreadCountChange.bind(this));
      }
    };
  }

  // 未読数が変更された場合の処理は複雑なのでメソッドとして切り出している
  handleUnreadCountChange(unreadCount) {
    const hasUnread = unreadCount > 0;
    this.setState({ hasUnread });
    this.unreadCount.textContent = hasUnread ? unreadCount : '';
  }

  render() {
    const stateBooted = this.state.booted ? 'is-intercomMessenger-booted' : '';
    const stateOpen = this.state.opened ? 'is-intercomMessenger-open' : '';
    return (
      <a href={`mailto:${process.env.INTERCOM_APP_ID}@incoming.intercom.io`}
          className={classNames('intercom-launcher', stateBooted, stateOpen)}>
        <div className='intercom-icon-close'/>
        <div className='intercom-icon-open'/>
        <span ref={(unreadCount) => this.unreadCount = unreadCount}
            className={this.state.hasUnread ? 'is-intercomMessenger-open' : '')}/>
      </a>
    );
  }
}