[Bolt]モーダルウィンドウを開いてSubmitするまでの実装

# 手順

モーダルウィンドウ経由であれこれやりたい！となったときに色々ハマったので備忘録。
主に

- Interactive Components設定忘れ
- block kitのID忘れ
- 各種イベントの取得方法

あたりでハマりました。

## 事前準備

`Interactive Components` の設定を忘れないようにしておきます。
この設定は `Event Subscriptions` のものと同様で構いません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165355/f9d3da15-84a6-eb9e-d5fd-33b278fdace1.png)


## 1.モーダルウィンドウを立ち上げるためのボタンを描画

まずは起点となる、モーダルウィンドウを呼び出すためのボタンを作ります。

```js:index.js
const {App} = require('@slack/bolt');

const app = new App({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  token: process.env.SLACK_BOT_TOKEN
});

// モーダル用のウィンドウを呼び出すボタンを送信
app.event('app_mention', ({event, say}) => {
  say(entryModal);
});

(async () => {
  await app.start(process.env.SLACK_PORT || 8080);
  console.log('⚡️ Bolt app is running!');
})();
```

```js:entryModal
{
  blocks: [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "modal window"
      },
      "accessory": {
        "type": "button",
        "text": {
          "type": "plain_text",
          "text": "open modal"
        },
        "action_id": "open_modal" // 2.モーダルウィンドウを描画で使うためのID
      }
    }
  ]
}
```

## 2.モーダルウィンドウを描画

続いて先ほどのaction_idを使用してモーダルウィンドウを描画していきます。

```js:index.js
app.action('open_modal', ({body, ack, context}) => {
  ack();
  try {
    app.client.views.open({
      token: context.botToken,
      trigger_id: body.trigger_id,
      view: require(modalView)
    });
  } catch (e) {
    console.log(e);
  }
});
```

```js:modalView
{
  "type": "modal",
  "callback_id": "modal_view", // 3.Submitで使うためのID
  "title": {
    "type": "plain_text",
    "text": "Modal window",
    "emoji": true
  },
  "submit": {
    "type": "plain_text",
    "text": "submit",
    "emoji": true
  },
  "close": {
    "type": "plain_text",
    "text": "cancel",
    "emoji": true
  },
  "blocks": [
    {
      "type": "input",
      "block_id": "modal_view_block", // 3.Submitで値を取得する際に使用
      "element": {
        "type": "radio_buttons",
        "action_id": "modal_view_block_radio", // 3.Submitで値を取得する際に使用
        "options": [
          {
            "text": {
              "type": "plain_text",
              "text": "うどん",
              "emoji": true
            },
            "value": "1"
          },
          {
            "text": {
              "type": "plain_text",
              "text": "ラーメン",
              "emoji": true
            },
            "value": "2"
          }
        ]
      },
      "label": {
        "type": "plain_text",
        "text": "麺類",
        "emoji": true
      },
    }
  ],
};
```

## 3.submit

最後にSubmitされた値を取得してみます。
Bolt組み込み関数の[viewメソッド](https://slack.dev/bolt/ja-jp/concepts#view_submissions)を使うと良さそうです。

```js:index.js
app.view('modal_view', ({body, ack, view}) => {
  ack();
  const type = view.state.values.modal_view_block.modal_view_block_radio;
  console.log(body, view, type);
  try {
    // あとはよしなに
    app.client.chat.postMessage({
      token: context.botToken,
      channel: body['user']['id'],
      text: 'submit!'
    });
  } catch (e) {
    console.log(e);
  }
});
```

# 参考
- https://slack.dev/bolt/ja-jp/concepts#view_submissions
- https://api.slack.com/reference/interaction-payloads/views#view_submission_example
- https://slack.dev/bolt/ja-jp/concepts#creating-modals
- https://slack.dev/bolt/ja-jp/tutorial/getting-started