🗓️

カレンダーアプリを作る(フロントエンド編②)

に公開

こちらの記事は前回の続きになります。
機能要件3つ目の

  • 編集ボタンを押下すると編集用ダイアログを表示し、タイトル、日時を編集できる。閉じる、保存ボタンが存在する。

を実装していきます。

実装

実装1 カレンダーに登録されているスケジュールを取得する

カレンダーに登録されているスケジュールを習得するには、FullCalendarコンポーネントのeventClickを使います。カスタムフックでクリックイベントの関数を定義し、eventClickに設定します。

// /src/components/Calendar/CalendarPage.tsx
export const CalendarPage = () => {
  const {
    ...
    handleClick, // 追加
  } = useCalendarFunc();

  return (
    <div>
      ...
      <FullCalendar
        ...
        eventClick={handleClick} // 追加
      />
    </div>
  );
};
// /src/components/Calendar/hooks/useCalendarFunc.tsx
...
export const useCalendarFunc = () => {
  ...

  /**
   * カレンダーに登録済みのイベントをクリックし、そのイベント情報をステートで管理する。
   * @param addedInfo イベント情報
   */
  const handleClick = (addedInfo: any) => {
    const { id, title, start, end, allDay } = addedInfo.event;
    console.log(id, title, start, end, allDay);
  };

  return {
    ...
    handleClick // 追加
  };
};

登録済みのスケジュールのデータを取得することができました。

取得したデータはステートで管理します。

// /src/components/Calendar/hooks/useCalendarFunc.tsx
...
export const useCalendarFunc = () => {
  ...

  /**
   * カレンダーに登録済みのイベントをクリックし、そのイベント情報をステートで管理する。
   * @param addedInfo イベント情報
   */
  const handleClick = (addedInfo: any) => {
    const { id, title, start, end, allDay } = addedInfo.event;
    setEventsId(id);
    setEventsTitle(title);
    setIsAllDay(allDay);
    setEventsStartDate(start);
    setEventsStartTime(format(start, "HH:mm"));
    setEventsEndDate(end);
    setEventsEndTime(format(end, "HH:mm"));
  };

  return {
    ...
    handleClick // 追加
  };
};

setEventsStartTime(format(start, "HH:mm")); では、startという日付オブジェクトを"HH:mm"というフォーマットで文字列に変換し、その結果をsetEventsStartTime関数に渡しています。

実装2 スケジュール編集用のフォームを作成する

続いて、前回作成したフォームコンポーネントを使い、登録済みのデータをフォームに反映していきます。
まず、EditScheduleFormコンポーネントを作成し、各ステートをインポートします。
そして、前回作成したShceduleFormにプロップスを渡してあげます。

// /src/components/Calendar/parts/Form/EditScheduleForm.tsx
import { ScheduleForm } from "./ScheduleForm";

export const EditScheduleForm = (props: any) => {
  const {
    events,
    eventsId,
    title,
    allDay,
    startDate,
    startTime,
    endDate,
    endTime,
    format,
  } = props;

  const { myEvents, setMyEvents } = events;
  const { eventsTitle, setEventsTitle } = title;
  const { isAllDay, setIsAllDay } = allDay;
  const { eventsStartDate, setEventsStartDate } = startDate;
  const { eventsStartTime, setEventsStartTime } = startTime;
  const { eventsEndDate, setEventsEndDate } = endDate;
  const { eventsEndTime, setEventsEndTime } = endTime;

  const onEditEvent = () => {
    console.log("Edit");
  };
  return (
    <div>
      <ScheduleForm
        allDay={{ isAllDay, setIsAllDay }}
        title={{ eventsTitle, setEventsTitle }}
        startDate={{ eventsStartDate, setEventsStartDate }}
        startTime={{ eventsStartTime, setEventsStartTime }}
        endDate={{ eventsEndDate, setEventsEndDate }}
        endTime={{ eventsEndTime, setEventsEndTime }}
        format={format}
        clickEvent={onEditEvent}
      />
    </div>
  );
};

次に、CalendarPageコンポーネントにてEditScheduleFormコンポーネントを設定します。

...
      <div className="flex">
        <div>
          <div>スケジュール登録用</div>
          <ScheduleForm
            title={{ eventsTitle, setEventsTitle }}
            allDay={{ isAllDay, setIsAllDay }}
            startDate={{ eventsStartDate, setEventsStartDate }}
            startTime={{ eventsStartTime, setEventsStartTime }}
            endDate={{ eventsEndDate, setEventsEndDate }}
            endTime={{ eventsEndTime, setEventsEndTime }}
            format={formatCaption}
            // addEvent={onAddEvent}
            clickEvent={onAddEvent} // 名前の変更
          />
        </div>
        <div>
          <div>スケジュール編集用</div>
          <EditScheduleForm
            events={{ myEvents, setMyEvents }}
            eventsId={eventsId}
            title={{ eventsTitle, setEventsTitle }}
            allDay={{ isAllDay, setIsAllDay }}
            startDate={{ eventsStartDate, setEventsStartDate }}
            startTime={{ eventsStartTime, setEventsStartTime }}
            endDate={{ eventsEndDate, setEventsEndDate }}
            endTime={{ eventsEndTime, setEventsEndTime }}
            format={formatCaption}
          />
        </div>

※補足
ScheduleFormコンポーネントのaddEventは編集用にも使えるように名前をclickEventに変更しました。
また、ScheduleFormにて定義していた、formatCaption関数もカスタムフックに移動し、汎用的に使えるように変更しています。

// /src/components/Calendar/hooks/useCalendarFunc.tsx

export const useCalendarFunc = () => {
  const [eventsId, setEventsId] = useState<string>("");
  ...

  /**
   * Date型のオブジェクトを”〇〇月〇〇日(曜日)”の形にフォーマットする
   * @param date
   * @returns {string} 日本語にフォーマットした日付を返す
   */
  const formatCaption = (date: Date | undefined) => {
    if (!date) {
      return;
    }
    const dayArr = ["日", "月", "火", "水", "木", "金", "土"];
    const day = format(date, "MM月dd日");
    return `${day}(${dayArr[date.getDay()]})`;
  };

  ...
  return {
    ...

    formatCaption,
    setMyEvents,
    eventsId,
  };
};

画面としては、以下のようになります。
スケジュール登録用のフォームとスケジュール編集用のフォームは一緒のものを使っており、ステートも共通のものになっているため、同じ値が入ります。
ただ、このアプリケーションでは、二つの動作を同時に行う想定ではないため、特に問題ありません。
※現在は同時にフォームを表示していますが、最終的にはダイアログ等を使って調整します。

実装3 カレンダーに登録済みのスケジュールを変更する

編集用のフォームでスケジュールを編集後、保存ボタンを押すとカレンダー上のスケジュールが変更されるようにします。

// /src/components/Calendar/parts/Form/EditScheduleForm.tsx

export const EditScheduleForm = (props: any) => {
  ...

  /**
   * カレンダーに登録済みのスケジュールを変更する
   */
  const onEditEvent = () => {
    const [sh, sm] = eventsStartTime.split(":").map(Number);
    const [eh, em] = eventsEndTime.split(":").map(Number);
    eventsStartDate!.setHours(sh);
    eventsStartDate!.setMinutes(sm);
    eventsEndDate!.setHours(eh);
    eventsEndDate!.setMinutes(em);
    const data = {
      id: eventsId,
      title: eventsTitle,
      allDay: isAllDay,
      start_date: eventsStartDate,
      end_date: eventsEndDate,
    };
    setMyEvents((prevEvents: any) =>
      prevEvents.map((event: any) => {
        if (event.id === data.id) {
          return {
            ...event,
            id: data.id,
            title: data.title,
            allDay: data.allDay,
            start: data.start_date,
            end: data.end_date,
          };
        }
        return event;
      })
    );
  };
  return (
    <div>
      <ScheduleForm
        ...
        clickEvent={onEditEvent}
      />
    </div>
  );
};

myEventsをmapし、編集中のデータのIDと一致するデータをチェックし、一緒だった場合に、編集した値で更新をします。

以下のようにスケジュールを編集できるようになりました。

まとめ

スケジュールの編集機能は比較的簡単に実装できました。
今の所型定義を全てanyにしていますが、最後に全て定義するのでご安心ください。
また、UIについては、ここでは細かく書かないので、完成版は私のGitリポジトリをご覧下さい。
次の記事では、スケジュールの削除機能を実装します。

Create Quest.Inc Tech Blog

Discussion