[Advent Calendar 2021][Day15]カレンダー参加機能を作る

undefined
はじめに
Advent Calendar 2021のDay15。 今回は、カレンダー参加機能を作っていきます。
graphqlクエリ・ミューテーションを定義する
下記を追記します。カレンダーのGetterと参加者のInsertを新規追加です。
- gql/queries/calendar.graphlq
query GetCalendarByPkQuery($id: Int!) { calendars_by_pk(id: $id) { created_at id name participants { article_title article_url day updated_at created_at calendar_id } updated_at }}mutation InsertParticipantsMutation($object: participants_insert_input!) { insert_participants_one(object: $object) { updated_at uid day created_at calendar_id article_url article_title }}
コードを生成します。
yarn graphql-codegen
新規ページを作成する
カレンダーの詳細ページを新規につくります。カレンダーIDでカレンダーを指定する。 UIは、次回作り込んでいくのでだいぶ適当です・・。
- /calendars/id.vue
<template> <div> <div v-for="(value, key) in calendarMap"> <template v-if="value"> <a :href="value.article_url">{{ value.article_title }}</a> </template> <template v-else> <button @click="openModal(key)">{{ `Day:${key}` }}</button> </template> </div> <div class="modal" :class="modalClass"> <div class="modal-box"> <p>参加</p> <div class="form-control"> <label class="label"> <span class="label-text">記事名</span> </label> <input v-model="articleTitle" type="text" class="input input-primary input-bordered" /> <label class="label"> <span class="label-text">記事URL</span> </label> <input v-model="articleURL" type="text" class="input input-primary input-bordered" /> </div> <div class="modal-action"> <a @click="insert" class="btn btn-primary">参加する</a> <a @click="closeModal" class="btn">閉じる</a> </div> </div> </div> </div></template><script setup lang="ts">import { GetCalendarByPkQueryDocument, GetCalendarByPkQueryQueryVariables, InsertParticipantsMutationDocument, InsertParticipantsMutationMutationVariables } from "~/gql/queries/calendar";import { useClientHandle } from "@urql/vue";import { useNuxtApp, useAsyncData } from '#app'import { useRoute, useRouter } from 'vue-router'import { reactive, ref } from 'vue'const nuxtApp = useNuxtApp()const urql = useClientHandle();const route = useRoute()const variables: GetCalendarByPkQueryQueryVariables = { id: Number(route.params.id[0])}const queryResult = await urql.useQuery({ query: GetCalendarByPkQueryDocument, variables })let { data, fetching } = await queryResultlet calendarMap = {}for (let i = 1; i < 25; i++) { calendarMap[i] = null}for (const p of data.value.calendars_by_pk.participants) { calendarMap[p.day] = p}const insertCalendarResult = urql.useMutation(InsertParticipantsMutationDocument);const insert = () => { const variables: InsertParticipantsMutationMutationVariables = { object: { article_title: articleTitle.value, article_url: articleURL.value, calendar_id: Number(route.params.id[0]), day: selectedDay.value } }; insertCalendarResult.executeMutation(variables).then(async (result) => { await queryResult.executeQuery({ requestPolicy: 'network-only', }) closeModal() });}const articleTitle = ref('')const articleURL = ref('')const selectedDay = ref(0)const modalClass = reactive<any>({ 'modal': true, 'modal-open': false })const openModal = (day) => { modalClass['modal-open'] = true selectedDay.value = day}const closeModal = () => { modalClass['modal-open'] = false}</script>
トップページから新規のページに遷移できるようにします。
<table v-if="data.calendars.length"> <tbody> <tr v-for="c in data.calendars" :key="c.id">+ <td>+ <NuxtLink :to="`/calendars/${c.id}`">{{ c.name }}</NuxtLink>+ </td> </tr> </tbody> </table>
その他
topページの実装でuseStateを使っている所をreactive,refに修正。
まとめ
今回は、カレンダー参加機能を作りました。 次回は、カレンダー表示機能をつくります。
