nuxtからGoogleカレンダーの予定を作る

※ element ui使ってます

nuxtjs上でgoogle calendarに予定を作成する方法を勉強したのでqiitaにメモ
※もっと良いやり方があれば教えてください

以下インラインコメントで簡単に説明

```add-event.vue
<template>
  <section>
    <el-button v-if="auth2 && !isLogined" @click="login" type="primary">
      ログイン
    </el-button>
    <el-button v-if="auth2 && isLogined" @click="logout" type="primary">
      ログアウト
    </el-button>
    <label>予定作成</label>
    <div v-if="auth2 && isLogined">
      <!-- 予定のある日をカレンダーで選ぶ -->
      <el-date-picker
        v-model="calendarDate"
        :picker-options="pickerOptionsFuture"
        type="date"
        format="yyyy/MM/dd"
      />
      <!-- 開始時間を8時から21時まで15分刻みで選ぶ -->
      <el-time-select
        v-model="calendarStartTime"
        :picker-options="{
          start: '08:00',
          step: '00:15',
          end: '21:00'
        }"
        placeholder="開始時間"
      >
      </el-time-select>
      <!-- 予定の継続時間を選ぶ -->
      <el-select v-model="calendarTerm" placeholder="継続時間">
        <el-option :value="15" label="15" />
        <el-option :value="30" label="30" />
        <el-option :value="45" label="45" />
        <el-option :value="60" label="60" />
        <el-option :value="75" label="75" />
        <el-option :value="90" label="90" />
        <el-option :value="105" label="105" />
        <el-option :value="120" label="120" />
      </el-select>
      分
      <!-- 予定の要約を記入する -->
      <el-input v-model="calendarSummray" placeholder="予定内容" />
      <el-button @click="addCalendar" type="primary">登録</el-button>
    </div>
  </section>
</template>

<script>
import moment from 'moment'

const SCOPE = 'https://www.googleapis.com/auth/calendar.events'
const CLIENT_ID = '<!-- gcp OAuth 2.0 クライアント ID -->'
const API_KEY = '<!-- firebase api key -->'
export default {
  head() {
    return {
      script: [{ hid: 'gapi', src: 'https://apis.google.com/js/client.js' }]
    }
  },
  data() {
    const isLogined = false
    const auth2 = undefined
    const pickerOptionsFuture = {
      disabledDate(time) {
        return moment(time).format('YYYY-MM-DD') < moment().format('YYYY-MM-DD')
      }
    }

    return {
      calendarDate: '',
      calendarStartTime: '',
      calendarTerm: '',
      calendarSummray: '',
      isLogined,
      auth2,
      pickerOptionsFuture
    }
  },
  async mounted() {
    // google apiが読み込まれるのを待つ
    while (!window.gapi || !window.gapi.auth2) {
      await new Promise(resolve => setTimeout(resolve, 10))
    }
    // google api auth2の初期化
    window.gapi.auth2.init({
      apiKey: API_KEY,
      client_id: CLIENT_ID,
      scope: SCOPE,
      immediate: true
    })
    this.auth2 = window.gapi.auth2.getAuthInstance()

    // ログイン済みかチェック
    if (this.auth2.isSignedIn.get()) {
      this.isLogined = true
    }

    // カレンダーの初期化
    window.gapi.load('client')
    window.gapi.client.init({
      discoveryDocs: [
        'https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest'
      ],
      scope: SCOPE,
      apiKey: API_KEY,
      clientId: CLIENT_ID
    })
    window.gapi.client.load('calendar', 'v3')
  },
  methods: {
    async login() {
      if (this.auth2.isSignedIn.get()) {
        this.isLogined = true
        return
      }
      await this.auth2.signIn()
      this.isLogined = true
    },
    logout() {
      this.auth2.signOut()
      this.isLogined = false
    },
    addCalendar() {
      // ガードブロック
      if (!this.auth2.isSignedIn.get()) {
        this.$message({
          message: 'ログインしてください',
          type: 'error'
        })
        return
      }
      if (!this.calendarDate) {
        this.$message({
          message: '日付を選択してください',
          type: 'error'
        })
        return
      }
      if (!this.calendarStartTime) {
        this.$message({
          message: '開始時間を選択してください',
          type: 'error'
        })
        return
      }
      if (!this.calendarTerm) {
        this.$message({
          message: '期間を選択してください',
          type: 'error'
        })
        return
      }
      if (!this.calendarSummray) {
        this.$message({
          message: '予定内容を入力してください',
          type: 'error'
        })
        return
      }

      // 予定開始時刻・終了時刻を作る
      const eventDate = moment(this.calendarDate).format('YYYY-MM-DD')
      const eventFrom = this.calendarStartTime + ':00'
      const eventTo = moment(this.calendarStartTime, 'HH:mm')
        .add(this.calendarTerm, 'minutes')
        .format('HH:mm:00')
      const event = {
        summary: this.calendarSummray,
        start: {
          dateTime: `${eventDate}T${eventFrom}+09:00`,
          timeZone: 'Asia/Tokyo' // time zoneを日本にする
        },
        end: {
          dateTime: `${eventDate}T${eventTo}+09:00`,
          timeZone: 'Asia/Tokyo' // time zoneを日本にする
        },
        recurrence: [],
        attendees: [],
        reminders: {
          useDefault: false,
          overrides: [
            { method: 'email', minutes: 24 * 60 }, // 1日前にリマインドメール
            { method: 'popup', minutes: 10 } // 10分前にリマインドノーティフィケーション
          ]
        }
      }
      // 予定作成
      const request = window.gapi.client.calendar.events.insert({
        calendarId: 'primary',
        resource: event
      })
      request.execute(() => {
        this.$message({
          message: 'カレンダー登録しました。',
          type: 'success'
        })
      })
    }
  }
}
</script>
```