WebGLとチャットボットの組み合わせ React/Firebase編

Webの世界にちゃんと触れ初めて半年経ちました。
今回が初めて世の中にアプリケーションを出してみます、、
まずはリリースするとこまでを目標に頑張ります。

React/Firebase編です。
Reactプロジェクトでボットを動かした後、Firebaseにデプロイするところまでやります。
その他の記事はこちらから
<a href='https://qiita.com/chocoshop/items/9757776211c830b1751a' target='_blank'>・ボット編</a>


#作るもの
キャラクターと会話してる風のチャットボットを作ってみます。

#ざっくり登場人物
####フロントエンド
・React-redux **今回**
・Scss
・Three.js

####バックエンド
・Firebase **今回**
・Azure
・Microsoft BotFramework **今回**

綺麗なアーキテクチャとかさっぱりわからないので、なるべく知見のあるものを選んでいます。
バックエンドで詰まって時間浪費しないように、頑張ろう！


#React-Redux

Reactでフロントエンドを実装していくにあたり、<a href='https://github.com/microsoft/BotFramework-WebChat'>Bot Framework Web Chat</a> を使用します。いくつかサンプルが用意されており、今回はサンプルの中で11.12.14を参考にしています。


・Reactプロジェクトの作成

```
$ 作業ディレクトリ/ 
$ npx create-react-app webgl_bot
$ npm install botframework-webchat memoize-one
$ npm audit //足りないものとかあるかなー
$ npm install react react-dom //reactないって言われたw
$ git init && git add . //git入れるよ
$ git commit -m "First commit."
$ git remote add origin git@github.com:Yourname/aaaa.git && git push -u origin master
```

Gitのコマンドいつまでも覚えられない、、、
参考：https://qiita.com/KentaKodashima/items/16a787779ffecc29e717

・初期ディレクトリ構成
<img width="267" alt="スクリーンショット 2019-05-31 16.08.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323969/d86d4be3-9219-40dc-73a6-c52557404fd2.png">

##コンポーネント
今回使用するファイルを追加します。

```
$ cd src
$ touch AnimateWebChat.js // 親コンポーネント
$ touch Webchat.js // 子コンポーネント
$ touch animations.js // animation個別の動きを記述する
```
最初に`App.js`を書き換えます。

```App.js
+ import AnimateWebChat from './AnimateWebChat'

function App() {
  return (
    <AnimateWebChat /> // returnの中をコンポーネントを返すように書き換え
  );
}
```

`WebChat.js`にWebチャットをレンダリングする処理を記述していきます。

```WebChat.js
import { DirectLine } from 'botframework-directlinejs';
import React from 'react';
import ReactWebChat, { createStyleSet } from 'botframework-webchat';


export default class extends React.Component {
  constructor(props) {
    super(props);
    this.directLine = new DirectLine({ token: 'Your Token' });
  }

  render() {
    const {
        props: { className, store }, //AnimateWebchat.jsから渡されるprops、のはず
    } = this;

    return (
      <ReactWebChat 
      className = {`${className || ''}webchat`}
      directLine = { this.directLine }
      store = { store }
       />
    );
  }
}
```
次にユーザからの応答を聞いて、イベントを発火させる`AnimateWebchat.js`を書いていきます。
このクラスにstoreを立ててアプリケーション全体のstateを管理します。

`action`にユーザが入力した文字列やアクションのタイプが入っています。
アクションのタイプはデフォルトで用意されています。
各アクションの違いはまだ細かく確認できていないので追記したいです。
こちらでデフォルトのアクションを確認できます。
https://github.com/Microsoft/BotFramework-WebChat/tree/master/packages/core/src/actions

```AnimateWebchat.js
import React from 'react'
import { createStore, createStyleSet } from 'botframework-webchat'

import Webchat from './Webchat'
import animations from './animations'

export default class extends React.Component {
    constructor(props) {
        super(props)
　　　　　// storeを立ててactionを元にイベント発火、stateの書き換えをする
        const store = createStore({}, ({ dispatch }) => next => action => {
            if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
                setTimeout(() => {
                    dispatch({
                        type: 'WEB_CHAT/SEND_EVENT',
                        payload: {
                            name: 'webchat/join',
                            value: {
                                language: window.navigator.language
                            }
                        }
                    });
                }, 1000);
            } else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
　　　　　　　　　　//animations呼び出し時にactionを参照するようにする
                const DoAnimation = animations.bind(action) 
                DoAnimation();
            }
            return next(action);
    });

      this.state = { store };
  }

render() {
    const {
        state: {
            store,
        }
    } = this;
    return (
        <Webchat
            className="Animate" //WebChatコンポーネントにpropsを渡していく
            store={store}
        />
    )
}
}
```
##スタイリング調整

スタイルを調整します。デフォルトの値は全て削除して書き換えます。

```App.css
code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
}
html,
body {
  height: 100%;
  margin: 0;
  position: relative;
  font-family: 
-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#root,
#root > * {
  height: 100%;
  width: 100%;
}

```

ここで一度 `yarn start`します。ボットが応答していることを確認します。
![demo0603002.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323969/eb168431-e0a7-33cc-e885-d599bffe8a35.gif)



##ユーザアクションを元にイベント着火
ユーザのアクションを元に、アニメーションを実装していきます。
今回は、テストとしてユーザが入力した文字列を元に画面にアラートを出すようにします。

```animations.js
export default function () {
    const activity = this.payload.activity //呼び出し元であるactionをthisとする、はず
    if (activity.from.role === 'user') {
        switch (activity.text) {
            case 'hello':
                alert('Get Hello saying')
                break;
        
            default:
                break;
        }
    }
}
```

ぼやけて見づらいですが、helloと入力した時にアラートが出ています。
![demo0603003.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323969/f961a268-1705-d66f-9dd5-5bf4f9ba5925.gif)


ここまでで一度firebaseにデプロイします。


#Firebase
Firebaseは初めて触りました。
(Azureのwebappでもよかったけど、周りにFirebase+vueでアプリ作っている人が多いので、困った時に聞けそう。また、サーバ側のことはなるべく楽してフロントエンドに時間割きたいので:boy:)

今回は、firebaseのHostingを利用します。
以下を参考にしてnpmだけyarnに読み替えてデプロイしました。
<a href='https://qiita.com/nakamura_hikaru/items/fa285f1105240711af54'>・FirebaseとReactjs - Hosting</a>


デプロイに成功したので今回はここまでにします。:star: