Vue.jsでTodoistを模してTodoアプリを作ってみた①

# はじめに
少し前に、TodoistからTrelloへ乗り換えたのですが、Todoistが何となく恋しかったので、
Vue.js学習のアウトプットとしてTodoistのクローンアプリを作ろうと思いました！
作ってみると学ぶことだらけで、何かにまとめたいと思ったので記事を書くことにしました。


URL https://todoist-clone-c2bd0.web.app/


## 使用したツール
- VueRouter
- Vuex
- Firebase





## VueRouter
routerはこのような感じです。
今回作成したページは インボックス・今日・近日中・プロジェクト です。
#### router/index.js

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

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    name: "inbox",
    component: () => import("../views/Inbox.vue"),
  },
  {
    path: "/today",
    name: "today",
    component: () => import("../views/Today.vue"),
  },
  {
    path: "/fewday",
    name: "fewday",
    component: () => import("../views/Fewday.vue"),
  },
];

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

export default router;

```



## Vuex
firebaseに格納されているtaskのデータはこんな感じです。
titleがタスクの名前
dueDateが期日になっています。

```js
{
id:"hogehoge",
data:{
  title:"string",
  dueDate:{
     seconds:101010101  //(timestamp)
    }
  }
}
```

storeはこんな感じです。 tasksしかないのですが学習のためと思ってモジュール化しました
#### store/index.js

```js
import Vue from "vue";
import Vuex from "vuex";
import tasksModule from "./tasks";

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    tasksModule,
  },
});
```


#### tasks.js

```js
import firebase from "firebase";

const state = {
  tasks: [],
};

const getters = {
// Viewで使うときには並び順は期日順にしたいので、ここで並び替えの処理を書きます
  tasks(state) {
    let tasks = state.tasks;

    tasks.sort((a, b) => {
      if (a.data.dueDate.seconds < b.data.dueDate.seconds) return -1;
      if (a.data.dueDate.seconds > b.data.dueDate.seconds) return 1;
    });
    return tasks;
  },
};

const mutations = {
  fetchTasks(state, data) {
    state.tasks.push(data);
  },
  doneTask(state, id) {
    state.tasks = state.tasks.filter((el) => {
      return el.id != id;
    });
  },
  addTask(state, newTask) {
    state.tasks.push(newTask);
  },
};

const actions = {
// firebaseから全てのタスクを取得する処理
  fetchTasks({ commit }) {
    firebase
      .firestore()
      .collection("tasks")
      .get()
      .then((response) => {
        response.forEach((doc) =>
          commit("fetchTasks", { id: doc.id, data: doc.data() })
        );
      });
  },
// タスクを完了とする処理です。 データから削除しています。 フラグなんかをもたせる方いいかもです。
  doneTask({ commit }, { id }) {
    firebase
      .firestore()
      .collection("tasks")
      .doc(id)
      .delete()
      .then(() => {
        commit("doneTask", id);
      });
  },
// タスクを追加する処理です。 firebaseにpostします
  addTask({ commit }, newTask) {
    firebase
      .firestore()
      .collection("tasks")
      .add(newTask)
      .then((doc) => {
        commit("addTask", { id: doc.id, data: newTask });
      });
  },
};

const tasksModule = {
  namespaced: true,
  state,
  getters,
  mutations,
  actions,
};

export default tasksModule;
```

## View
雛形となるApp.vueはこんな感じです。
#### App.vue
サイドバーのナビで 表示するViewを制御しています。
一番初めにタスクを取得したいのでcreatedでfetchTasksを実行します。

```vuejs

<template>
  <div>
    <nav class="uk-navbar-container uk-margin" uk-navbar id="nav">
      <div class="uk-navbar-left">
        <div>
          <a
            class="uk-navbar-toggle"
            uk-navbar-toggle-icon
            href=""
            @click.prevent="toggleNav"
          ></a>
        </div>

        <ul class="uk-navbar-nav">
          <li>
            <a href="/">
              <span
                class="uk-icon uk-margin-small-right"
                uk-icon="icon: home"
              ></span>
            </a>
          </li>
        </ul>

        <div class="uk-navbar-item">
          <input
            class="uk-input uk-form-width-medium"
            type="text"
            placeholder="Search"
          />
        </div>
      </div>
    </nav>
    <div>
      <transition tag="div" name="slideX">
        <div class="uk-width-1-4@s side-nav" v-show="isNavShow">
          <ul class="uk-nav-default uk-nav-parent-icon" uk-nav>
            <li class="uk-active">
              <router-link to="/">インボックス</router-link>
            </li>
            <li class="uk-active">
              <router-link to="/today">今日</router-link>
            </li>
            <li class="uk-active">
              <router-link to="/fewday">近日中</router-link>
            </li>

            <li class="uk-nav-divider"></li>
          </ul>
        </div>
      </transition>

      <router-view id="container" />
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isNavShow: true,
    };
  },
  methods: {
    toggleNav() {
      this.isNavShow = !this.isNavShow;
    },
  },
  created() {
    this.$store.dispatch("tasksModule/fetchTasks");
  },
};
</script>
```