[Advent Calendar 2021][Day23]カレンダーの更新削除を実装する(3)

undefined

はじめに

Advent Calendar 2021のDay23。 カレンダー更新を実装していきます。

UI Componentを分割する

カレンダー詳細画面でカレンダーの更新と削除を行えるようにドロップダウンメニューを作成します。 トップページとカレンダー詳細で同じモーダルを使えそうなので、共通化しようと思います。

  • components/Dropdown.vue
<template>    <div class="flex-none">        <div class="dropdown dropdown-end">            <div tabindex="0" class="m-1">                <button class="btn btn-ghost btn-square" aria-label="button component">                    <svg                        xmlns="http://www.w3.org/2000/svg"                        fill="none"                        viewBox="0 0 24 24"                        class="inline-block w-6 h-6 stroke-current"                    >                        <path                            stroke-linecap="round"                            stroke-linejoin="round"                            stroke-width="2"                            d="M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z"                        />                    </svg>                </button>            </div>            <ul tabindex="0" class="p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52">                <slot />            </ul>        </div>    </div></template>
  • components/CalendarModal.vue
<template>    <Modal :title="title" :open="open">        <div class="form-control">            <label class="label">                <span class="label-text">カレンダー名</span>            </label>            <input                v-model="calendarName"                type="text"                class="input input-primary input-bordered"                @input="$emit('update:calendarName', $event.target.value)"            />        </div>        <div v-if="errorMessage" class="mt-4 alert alert-error">            <div class="flex-1">                <svg                    xmlns="http://www.w3.org/2000/svg"                    fill="none"                    viewBox="0 0 24 24"                    class="w-6 h-6 mx-2 stroke-current"                >                    <path                        stroke-linecap="round"                        stroke-linejoin="round"                        stroke-width="2"                        d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"                    />                </svg>                <label>{{ errorMessage }}</label>            </div>        </div>    </Modal></template><script>export default {    data() {        return {            calendarName: "",        }    },    props: {        title: {            type: String,            default: 'カレンダー作成'        },        open: {            type: Boolean,            default: false        },        calendarName: {            type: String,            default: ''        },        errorMessage: {            type: String,            default: ''        }    },}</script>

graphql

参加者とカレンダーのクエリが一緒になっていたので分割します。更新にはActionを使うよう修正します。

  • gql/queries/calendar.graphql
query ListCalendarsQuery($limit: Int = 10, $created_at: order_by = desc) {  calendars(limit: $limit, order_by: {created_at: $created_at}) {    id    name    updated_at    created_at  }}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 ActionCreateCalendarMutation($name: String = "") {  actionCreateCalendar(in: {name: $name}) {    created_at    id    name    uid    updated_at  }}mutation ActionUpdateCalendarMutation($id: Int!, $name: String!) {  actionUpdateCalendar(in: {id: $id, name: $name}) {    id    name    uid    created_at    updated_at  }}
  • gql/queries/participants.graphql
mutation InsertParticipantsMutation($object: participants_insert_input!) {  insert_participants_one(object: $object) {    updated_at    uid    day    created_at    calendar_id    article_url    article_title  }}

ページのテンプレート部分をドロップダウンメニューとカレンダーモーダルを使うよう修正。

  • pages/calendars/id.vue
<template>    <div>        <div class="flex">            <div class="flex-auto">                <h1 class="text-2xl font-bold">{{ calendarTitle }}</h1>            </div>            <div v-if="!!user" class="flex-none">                <Dropdown>                    <li class="menu-title">                        <span>カレンダー</span>                    </li>                    <li>                        <a @click="openCalendarModal = true">編集</a>                    </li>                    <li>                        <a>削除</a>                    </li>                </Dropdown>                <CalendarModal                    title="カレンダー編集"                    :open="openCalendarModal"                    @ok="onCalendarOkClick"                    @cancel="openCalendarModal = false"                    v-model:calendarName="calendarName"                    :errorMessage="errorMessage"                />            </div>        </div>        <div class="grid grid-cols-1 md:gap-4 md:grid-cols-6">            <div v-for="(value, key) in calendarMap" class="card shadow">                <div class="card-body">                    <a v-if="value" :href="value.article_url" target="_blank">                        <h2                            class="card-title link"                        >{{ `Day${key}: ${value.article_title || 'タイトルなし'}` }}</h2>                    </a>                    <a v-else-if="user" @click="selectedDay = key; openModal = true">                        <h2 class="card-title link">{{ `Day:${key}` }}</h2>                    </a>                    <span v-else>                        <h2 class="card-title">{{ `Day:${key}` }}</h2>                    </span>                </div>            </div>        </div>        <Modal :title="modalTitle" :open="openModal" @ok="onOkClick" @cancel="openModal = false">            <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>        </Modal>    </div></template>

その他

不具合の修正。

まとめ

今回はカレンダーの更新機能を実装しました。 次回は、カレンダーの削除機能を実装していきます。