[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に修正。

まとめ

今回は、カレンダー参加機能を作りました。 次回は、カレンダー表示機能をつくります。