カレンダーアプリを作る(フロントエンド編②)
こちらの記事は前回の続きになります。
機能要件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リポジトリをご覧下さい。
次の記事では、スケジュールの削除機能を実装します。
Discussion