Slackのチームメンバーをビンゴ形式で回す

# はじめに
みなさんはチームでLTなどをする際に順番決めに迷った経験などはありますか。僕は大いに迷った経験があります。じゃんけんで決めるのも良いですが、時間がかかって大変ですよね。本記事はSlackのチームメンバーを対象とし、ビンゴ形式で順番を決めるアプリについて記述します。
記事をすべて読むのがめんどくさい方は[こちら](https://github.com/JinOketani/SlackBingo)からコードを確認して見てください。

# 今回のゴール
slackのチームに参加しているメンバーをビンゴ形式で回すものになります。
チェックボックス形式でメンバーを選択し、追加ボタンを押すとメンバーが追加されビンゴ形式で回る感じです。

<img src="https://qiita-image-store.s3.amazonaws.com/0/81341/75161d5c-3f0f-a1b3-3a33-222453a96f47.png" height="200">

<img src="https://qiita-image-store.s3.amazonaws.com/0/81341/791daf28-26bc-3ad1-05c6-9e2b431ddee7.gif" height="220">
# 実装
## 1.Slack Tokenの取得
[こちら](https://api.slack.com/custom-integrations/legacy-tokens)にアクセスしSlackのトークンを取得しましょう。<br>このトークンはSlackのチーム情報などを取得する際に使用します。<br>**※赤く塗りつぶされている箇所がトークンになります。**
![スクリーンショット 2017-12-11 18.52.54.png](https://qiita-image-store.s3.amazonaws.com/0/81341/e8064aff-d0e5-8f41-bf4b-0112773254a6.png)

## 2.JavaScriptファイルの作成
`script.js`ではSlackのチームメンバー情報の取得、チームメンバーを配列に入れランダムで取得する処理などを行います。

```javascript:script.js
$ = function (x) {
  return document.getElementById(x);
}

var n = 1;
var members = new Array();
var membersUse = new Array();

function paseJson() {
  var xmlHttp;
  var token = "先ほど取得したslackToken";
  var isStop = true;

  xmlHttp = new XMLHttpRequest();
  xmlHttp.open("GET", "https://slack.com/api/users.list?token=" + token, false);
  xmlHttp.send(null);
  data = xmlHttp.responseText;
  json = JSON.parse(data);
  users = json['members'];

  for (let user of users) {
    if (user['deleted'] == false) {
      members.push((user['name']));
    }
  }
  return members
}


function initCheckbox() {
  members = paseJson();
  for (member of members) {
    var box = $('box');
    box.insertAdjacentHTML('afterbegin', `<input type="checkbox" name="user" value="${member}" class="select-user"><label>${member}</label><br>`)
  }
}

function getCheckbox() {
  var checkbox = document.getElementsByName('user')
  for (i = 0; i < checkbox.length; i++) {
    if (checkbox[i].checked == true) {
      membersUse.push(checkbox[i].value);
    }
  }
  alert('追加されました');
  return membersUse;
}


function startBingo() {
  if (membersUse.length == 0) {
    alert('メンバーを選択してください');
  } else {
    $("start").style.display = "none";
    $("stop").style.display = "inline";
    isStop = false;
    roulette();
  }
}

function stopBingo() {
  $("start").style.display = "inline";
  $("stop").style.display = "none";
  isStop = true;
}

function resetBingo() {
  location.reload();
}


function roulette() {
  var id = "";
  var rnd = Math.floor(Math.random() * membersUse.length);

  if (isStop) {
    clearTimeout(id);
    $("view").innerText = membersUse[rnd];
    if (!$("out").innerText) {
      var newli = document.createElement("li");
      var list = $("out");
      var member = n + "：" + membersUse[rnd];
      list.append(newli);
      newli.append(member);
    } else {
      n++;
      var newli = document.createElement("li");
      var list = $("out");
      var member = n + "：" + membersUse[rnd];
      list.append(newli);
      newli.append(member);
    }
    membersUse.splice(rnd, 1);

    if (membersUse.length == 0) {
      alert("Finish");
      $("start").disabled = true;
      $("start").style.display = "none";
      $("reset").style.display = "inline";
    }
    return false;
  }

  $("view").innerText = membersUse[rnd];
  id = setTimeout("roulette()", 10);
}
```
## 3.HTMLファイルの作成
`index.html`ではボタンの配置や`script.js`から送られてきたデータの出力などを行います。

```html:index.html
<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <link href="style.css" rel="stylesheet" type="text/css"/>
    <meta name="viewport"
          content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=10.0, user-scalable=yes">
    <title>SlackBingo</title>
    <script type="text/javascript" src="./js/script.js"></script>
</head>
<body onload="initCheckbox()">
<header>
    <div id="nav-drawer">
        <input id="nav-input" type="checkbox" class="nav-unshown">
        <label id="nav-open" for="nav-input"><span></span></label>
        <label class="nav-unshown" id="nav-close" for="nav-input"></label>
        <div id="nav-content">
            <form id="box">
                <input type="button" id="post-member" class="btn-add" value="Add" onclick="getCheckbox()">
            </form>
        </div>
    </div>
</header>
<div id="main">
    <h1>Next...</h1>
    <div class="button">
        <form>
            <input type="button" id="start" name="start" value="Start" onclick="startBingo()">
            <input type="button" id="stop" name="stop" value="Stop" onclick="stopBingo()" style="display:none;">
            <input type="button" id="reset" name="reset" value="Reset" onclick="resetBingo()" style="display:none;">
        </form>
    </div>
    <div id="view"></div>
    <ul id="out"></ul>
</div>
</body>
</html>
```

## 4.CSSファイルの作成
`style.css`では最低限のスタイルを記述しています。

```css:style.css
html {
    color: #ffffff;
}

header {
    padding: 0;
    margin: 0;
}

body {
    min-height: 100%;
    margin: 0;
    height: 100vh;
    width: 100vw;
    background-image: url("./images/back_img2.jpg");
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
}

main {
    color: #ffffff;
    height: 100vh;
    width: 100vw;
    margin: auto;
}

h1 {
    margin: 0;
    text-align: center;
    padding-top: 5%;
}

#box {
    font-size: 1.3em;
    list-style: none;
}

.select-user {
    margin: 10px;
}


/*==============center button====================*/
.button {
    text-align: center;
    margin-top: 5%;
}

#start {
    width: 256px;
    padding: 4px 8px;
    margin: 0 8px;
    font-size: 1.2em;
    background-color: transparent;
    border: 2px solid #fff;
    color: #fff;
    line-height: 50px;
    text-align: center;
}

#start:hover {
    width: 256px;
    padding: 4px 8px;
    margin: 0 8px;
    font-size: 1.2em;
    background-color: #006e54;
    opacity: 0.8;
    color: #fff;
    line-height: 50px;
}

#stop {
    width: 256px;
    padding: 4px 8px;
    margin: 0 8px;
    font-size: 1.2em;
    background-color: transparent;
    opacity: 0.8;
    border: 2px solid #fff;
    color: #fff;
    line-height: 50px;
}

#stop:hover {
    width: 256px;
    padding: 4px 8px;
    margin: 0 8px;
    font-size: 1.2em;
    background-color: #bb5535;
    opacity: 0.8;
    border: 2px solid #fff;
    color: #fff;
    line-height: 50px;
}

#reset {
    width: 256px;
    padding: 4px 8px;
    margin: 0 8px;
    font-size: 1.2em;
    background-color: transparent;
    opacity: 0.8;
    border: 2px solid #fff;
    color: #fff;
    line-height: 50px;
}

#reset:hover {
    width: 256px;
    padding: 4px 8px;
    margin: 0 8px;
    font-size: 1.2em;
    background-color: #1ab7ea;
    opacity: 0.8;
    border: 2px solid #fff;
    color: #fff;
    line-height: 50px;
}

#view {
    text-align: center;
    margin-top: 5%;
    font-size: 40px;
}

/*PC display*/
@media only screen and (min-width: 768px) {
    #out {
        margin: 8%;
        text-align: center;
    }

    ul {
        list-style: none;
    }

    li {
        float: left;
        width: 200px;
        word-break: keep-all;
    }
}

/*SmartPhone display*/
@media only screen and (max-width: 768px) {
    .button {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        margin: auto;
        margin-bottom: 50px;
    }

    #out {
        list-style: none;
        margin-left: 25%;
    }

    li {
    }
}

/*header*/
header {
    padding:10px;
    background: #ffffff;
    opacity: 0.7;
}

#nav-drawer {
    color: #000000;
    position: relative;
}

/**/
.nav-unshown {
    display:none;
}

/*icon space*/
#nav-open {
    display: inline-block;
    width: 30px;
    height: 22px;
    vertical-align: middle;
}

/*menu*/
#nav-open span, #nav-open span:before, #nav-open span:after {
    position: absolute;
    height: 3px;/*線の太さ*/
    width: 25px;/*長さ*/
    border-radius: 3px;
    background: #555;
    display: block;
    content: '';
    cursor: pointer;
}
#nav-open span:before {
    bottom: -8px;
}
#nav-open span:after {
    bottom: -16px;
}

/*close action*/
#nav-close {
    display: none;/*はじめは隠しておく*/
    position: fixed;
    z-index: 99;
    top: 0;/*全体に広がるように*/
    left: 0;
    width: 100%;
    height: 100%;
    background: black;
    opacity: 0;
    transition: .3s ease-in-out;
}

/*menu contents*/
#nav-content {
    overflow: auto;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 9999;/*最前面に*/
    width: 90%;/*右側に隙間を作る*/
    max-width: 330px;/*最大幅*/
    height: 100%;
    background: #fff;/*背景色*/
    transition: .3s ease-in-out;/*滑らかに表示*/
    -webkit-transform: translateX(-105%);
    transform: translateX(-105%);/*左に隠しておく*/
}

/*チェックが入ったらもろもろ表示*/
#nav-input:checked ~ #nav-close {
    display: block;/*カバーを表示*/
    opacity: .5;
}

#nav-input:checked ~ #nav-content {
    -webkit-transform: translateX(0%);
    transform: translateX(0%);/*中身を表示*/
    box-shadow: 6px 0 25px rgba(0,0,0,.15);
}

.btn-add {
    float: right;
    width: 100px;
    padding: 2px 4px;
    margin: 10px;
    font-size: 0.8em;
    background-color: #1ab7ea;
    opacity: 0.8;
    border: 2px solid #fff;
    color: #fff;
    line-height: 50px;
}
```

# まとめ
完成系はこのようになると思います。
![1512989915.gif](https://qiita-image-store.s3.amazonaws.com/0/81341/791daf28-26bc-3ad1-05c6-9e2b431ddee7.gif)
チャンネルなどを選択できるようになればもっと便利になるかもしれませんねw
みなさんもSlackを用いてアプリ開発をしてみてはいかがでしょうか。