Nuxtでショッピングカートに商品情報を追加する

# 目的
個人開発してるサービスでカート機能を実装したい
今回は`カートに入れる`ボタンを押下したらカートに商品情報が入るようにしたい

# 参考サイト
[Nuxt.jsのStoreによるデータ保存 [vuex-persistedstate][js-cookie]](https://noumenon-th.net/programming/2019/08/24/nuxt-js-store/)

[Vuex でショッピングカートを実装できる無料コース「Vuex for Everyone」を受講した](https://kakakakakku.hatenablog.com/entry/2018/09/15/100141)

# 仕様

カートに入れる情報は下記を想定

- イベントID
- 商品ID
- 個数
- 区分(すぐ買う/後から配送)

同じ商品情報が存在した場合は、個数をインクリメントする
1週間ほどはカート情報は保持しておきたい

# 実装

## カート情報を入れるVuexの実装
仕様でも書いたとおりカートには下記の情報を保持するようにする

- イベントID
- 商品ID
- 個数
- 区分(すぐ買う/後から配送)

イベントIDと商品IDと区分の同一なデータが有れば`INCREMENT_QUANTITY`が無ければ`PUSH_PRODUCT_TO_CART`が実行されるようにする


```store/cart.js 
export const getters = {
  getCartProducts(state) {
    return state.products
  }
}

export const state = () => ({
  products: []
})

export const mutations = {
  PUSH_PRODUCT_TO_CART(state, payload) {
    state.products.push({
      eventId: payload.rootState.event_info.eventSelected.id,
      id: payload.product.id,
      quantity: 1,
      // カート追加時にイベントが開催中であれば、配送の区分を0(今すぐ受取る)にする
      // 終了後であれば配送区分を1(自宅へ配送)に設定する
      delivery:
        new Date(
          payload.rootState.event_info.eventSelected.end_date
        ).getTime() > new Date().getTime()
          ? 0
          : 1
    })
  },
  INCREMENT_QUANTITY(state, payload) {
    payload.cartItem.quantity++
  }
}

export const actions = {
  addProductToCart({ commit, rootState, state }, product) {
    const cartItem = state.products.find(
      item =>
        item.id === product.id &&
        item.eventId === rootState.event_info.eventSelected.id &&
        (item.delivery ===
        new Date(rootState.event_info.eventSelected.end_date).getTime() >
          new Date().getTime()
          ? 0
          : 1)
    )

    if (!cartItem) {
      commit('PUSH_PRODUCT_TO_CART', { rootState, product })
    } else {
      commit('INCREMENT_QUANTITY', { rootState, cartItem })
    }
  }
}

```

## カート追加処理を実装
呼び出し部分

```html
<div class="field-button">
      <input
        type="submit"
        class="button is-blue is-large is-fullwidth"
        value="カートに入れる"
        @click="addProductToCart(product)"
      />
</div>
```

カート追加するVuexのAction呼び出し

```javascript
addProductToCart(product) {
    this.$store.dispatch('cart/addProductToCart', product)
}
```

## カート商品情報の永続化設定
Vuexは、ブラウザを更新したらデータが消えてしまうため
永続化を行うために下記を行う

### モジュールをインストール

vuex-persistedstate
vuexを永続化させるためのモジュール
https://github.com/robinvdvleuten/vuex-persistedstate

js-cookie
cookieをnuxtで使用するためのモジュール
https://github.com/js-cookie/js-cookie

```
npm install vuex-persistedstate
npm install js-cookie
```

### 永続化の設定

```plugins/cookie-storage.js
import createPersistedState from 'vuex-persistedstate'
import * as Cookies from 'js-cookie'

const cookieStorage = {
  getItem: function(key) {
    return Cookies.getJSON(key)
  },
  setItem: function(key, value) {
    return Cookies.set(key, value, { expires: 7, secure: true })
  },
  removeItem: function(key) {
    return Cookies.remove(key)
  }
}

export default context => {
  createPersistedState({
    key: 'products-cart',
    paths: ['cart.products'],
    storage: cookieStorage,
    getState: cookieStorage.getItem,
    setState: cookieStorage.setItem
  })(context.store)
}

```