QR忘れ物アプリ (5) アイテム登録ページ [Vue,Vuetify,Firebase]

# はじめに
構成
1. 環境構築: https://qiita.com/rayan/items/5d04ee2ca7860c220dec
2. ログインページ: https://qiita.com/rayan/items/1f0576395b9727635461
3. メニュー: https://qiita.com/rayan/items/3645506cdb10512fd87c
4. ユーザー設定確認・変更ページ: https://qiita.com/rayan/items/824f8b4c29384ae96258
5. アイテム登録ページ: __今回__

GitHubリポジトリ
> 準備中

# 省略名称
RTDB: Realtime Database

# 操作するファイル
- public
    - __index.html__
- src
    - router
        - __index.js__
    - mixins
        - __DatabaseOps.js__
    - views
        - __ItemRegisteration.vue__

## 新しく用いるライブラリ
- [qrcodejs](https://davidshimjs.github.io/qrcodejs/): QRコードをCanvas上に描画する。
- [html2canvas](https://html2canvas.hertzen.com/): div要素で表示されている内容をCanvas上に描画する。

## public/index.html
新しく用いる二つのライブラリを追加する。

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <!-- update the version number as needed -->
    <script src="/__/firebase/8.3.1/firebase-app.js"></script>
    <!-- include only the Firebase features as you need -->
    <script src="/__/firebase/8.3.1/firebase-auth.js"></script>
    <script src="/__/firebase/8.3.1/firebase-database.js"></script>
    <script src="/__/firebase/8.3.1/firebase-functions.js"></script>
    <!-- 
      initialize the SDK after all desired features are loaded, set useEmulator to false
      to avoid connecting the SDK to running emulators.
    -->
    <script src="/__/firebase/init.js?useEmulator=true"></script>
    <script src="https://www.gstatic.com/firebasejs/ui/4.8.0/firebase-ui-auth.js"></script>
    <link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/4.8.0/firebase-ui-auth.css" />
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">
    <script defer src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.js"></script>
    <script defer src="https://cdn.jsdelivr.net/npm/html2canvas@1.0.0-rc.5/dist/html2canvas.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
```

## src/views/ItemRegisteration.vue
アイテム登録ページの要素。

- まず、アイテム名を設定する。
- `var itemId = this.pushItems(item)`でRTDBにアイテムをpushし、その時のkeyを`itemId`に格納
- qrcodeDiv
    - アイテムIDからリンクを作成
        - `var url = 'http://127.0.0.1:5000/?foundItemId='+itemId`
    - qrcodejsでリンクをQRコードに変換
    - QRコードの上に説明する文字を配置する。
- qrcodeImage
    - qrcodeDivを表示する
    - html2canvasでqrcodeDivの内容のスクリーンショットを取り、描画する。
    - これにより、qrcodeImageで右クリックすることで文字を含んだQRコードをブラウザ上で保存することができる。
    - qrcodeDivが表示されたままだと、QRコードが二つ表示されてしまうのでqrcodeDivを非表示にする、

```vuejs
<template>
  <div>
    <Header :title="title"/>
    <v-card class="overflow-hidden">
      <v-sheet>
        <v-list-item-group
          v-model="selectedItem"
          color="primary"
        >
          <v-list-item
            v-for="(preference, i) in preferences"
            :key="i"
          >
            <v-text-field
              v-if="preference.type == 'textField'"
              v-model="preference.value"
              :label="preference.text"
            ></v-text-field>
            <v-checkbox
              v-if="preference.type == 'checkbox'"
              v-model="preference.value"
              :label="preference.text"
            ></v-checkbox>
            <v-select
              v-if="preference.type == 'select'"
              v-model="preference.value"
              :items="preference.values"
              :label="preference.text"
            ></v-select>
          </v-list-item>
        </v-list-item-group> 
        <v-spacer/>
        <v-list-item>
          <v-btn
            class="mr-4"
            @click="createQR"
          >
            Submit
          </v-btn>         
        </v-list-item>
        <v-spacer/>
        <v-list-item>     
          <div id="qrcodeImage"></div>
        </v-list-item>
      </v-sheet>
    </v-card>
    <div id="qrcodeDiv" class="container" style="margin: 0px; display: none;">
      <span class="qrcodeText" style="font-weight: bold">"QR Lost and Found" [QRコード忘れ物タグ]</span>
      <span class="qrcodeText">Please contact owner using QR code below</span>
      <span class="qrcodeText">拾った方はQRコードで所有者へ連絡をお願い致します</span>
      <span class="qrcodeText" id="qrcodeItemName"></span>
      <div id="qrcode" style="margin-top: 4px;"></div>
    </div>
  </div>
</template>

<style lang="scss">
.qrcodeText {
  line-height: 13px;
  font-size: 10px;
  display: block;
}
.container {
  background-color: #ffffff;
  border-radius: 2px;
  border-style: solid;
  border-color: #000000;
  width: 270px;
  text-align: center;
}
</style>

<script>
import Header from '@/components/Header'
import DatabaseOps from '@/mixins/DatabaseOps'

export default {
  name: "ItemRegisteration",
  data: () => ({
    preferences: [
      { text: 'Name of Item', value: '', type: 'textField'}
    ],
    title: 'Item Registeration'
  }),
  components: {
    Header
  },
  methods: {
    createQR() {
      var itemName = this.preferences[0].value;
      var item = {
        'currentLocation': '',
        'foundLocation': '',
        'found': false,
        'lost': false,
        'name': itemName
      }
      var itemId = this.pushItems(item);
      this.setItemIds(itemId);
      var url = 'http://127.0.0.1:5000/?foundItemId='+itemId;
      var qrcodeImageElementId = 'qrcodeImage';
      document.getElementById(qrcodeImageElementId).innerHTML = ''; // delete the previous QR code images
      this.generateQrcode(url, itemName);
      this.divToImage(qrcodeImageElementId);
    },
    generateQrcode(url, qrcodeItemName) {
      var qrcodeItemNameElementId = 'qrcodeItemName';
      var qrcodeElementId = 'qrcode';
      document.getElementById(qrcodeItemNameElementId).innerHTML = 'Item identifier: '+qrcodeItemName;
      document.getElementById(qrcodeElementId).innerHTML = ''; // reset qr code
      new QRCode(document.getElementById(qrcodeElementId), {
        text: url,
        width: 256,
        height: 256,
        colorDark : "#000000",
        colorLight : "#ffffff",
        correctLevel : QRCode.CorrectLevel.H
      });
    },
    divToImage(qrcodeImageElementId) {
      var qrcodeDivElementId = 'qrcodeDiv';
      document.getElementById(qrcodeDivElementId).style.display = 'block'; // show the div for converting to image
      html2canvas(document.getElementById(qrcodeDivElementId)).then((canvas) => { // convert div(QR code + text) into image
        document.getElementById(qrcodeImageElementId).appendChild(canvas);
        document.getElementById(qrcodeDivElementId).style.display = 'none'; // hide the original div
      });
    }
  },
  mixins: [DatabaseOps]
};
</script>
```

## router/index.js
新しくつくったItemRegisterationページの情報を追加する。

```javascript
import Vue from "vue";
import VueRouter from "vue-router";

Vue.use(VueRouter);

const routes = [
  {
    path: "*",
    redirect: "/"
  },
  {
    path: "/mainMenu",
    name: "MainMenu",
    meta: { requiresAuth: true },
    component: () =>
      import("@/views/MainMenu.vue"),
  },
  {
    path: "/userPreferences",
    name: "UserPreferences",
    meta: { requiresAuth: true },
    component: () =>
      import("@/views/UserPreferences.vue"),
  },
  {
    path: "/itemRegisteration",
    name: "ItemRegisteration",
    meta: { requiresAuth: true },
    component: () =>
      import("@/views/ItemRegisteration.vue"),
  },
  {
    path: "/",
    name: "Authentication",
    component: () =>
      import("@/views/Authentication.vue"),
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

router.beforeEach((to, from, next) => {
  let requiresAuth = to.matched.some(record => record.meta.requiresAuth)
  let currentUser = firebase.auth().currentUser
  if (requiresAuth) { // if this page requires auth, redirect to auth page
    if (!currentUser) {
      next({
        path: '/',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next() // this is required
  }
})

export default router;
```

# Build
- ビルドし、動作をテストする。動作のテストにはFirebase Emulatorが必要であるため、起動する。

```bash
npm run build
firebase emulators:start
```

- `dist/index.html`をブラウザで閲覧する。ログイン後、ItemRegisterationページに移動する。
- アイテム名を設定し、submitを押す。説明付きのQRコードが生成されることを確認する。

# 次回
アイテム一覧ページ