# カレンダーの予定作成機能3

では実際にカレンダーに予定を追加しましょう。

そのため、`dateList`を更新する必要があるので、新しい予定を引数として受け取り、`dateList`を更新する関数を作成しましょう。

`useCalendar`に`addSchedule`という関数を定義します。

まず、`newDateList`という`dateList`のコピーを作成します。

次に`newDateList`から引数で受け取った`schedule`の日付のインデックスを取得し、そのインデックスの`schedules`に`schedule`を格納するようにします。そして、setDdateListにてnewDateListをセットするようにします。こちらの関数を`return`にて返却するようにしましょう。

<pre class="language-typescript" data-title="hooks/useCalendar.ts◎"><code class="lang-typescript">import { useEffect, useState } from "react"
import {
  eachDayOfInterval,
  eachWeekOfInterval,
  endOfMonth,
  endOfWeek,
  isSameDay,
  startOfMonth,
} from "date-fns"
import { DateList, Schedule } from "../types/calendar"
import { getScheduleList } from "../api/calendar"

type PropsType = {
  currentDate: Date
}

export const useCalendar = ({ currentDate }: PropsType) => {
    const [dateList, setDateList] = useState&#x3C;DateList>([])

<strong>    const addSchedule = (schedule: Schedule) => {
</strong><strong>      const newDateList = [...dateList]
</strong><strong>      const firstIndex = newDateList.findIndex((oneWeek) =>
</strong><strong>        oneWeek.some((item) => isSameDay(item.date, schedule.date))
</strong><strong>      )
</strong><strong>      if (firstIndex === -1) return
</strong><strong>      const secondIndex = newDateList[firstIndex].findIndex((item) =>
</strong><strong>        isSameDay(item.date, schedule.date)
</strong><strong>      )
</strong><strong>      newDateList[firstIndex][secondIndex].schedules = [
</strong><strong>        ...newDateList[firstIndex][secondIndex].schedules,
</strong><strong>        schedule,
</strong><strong>      ]
</strong><strong>      setDateList(newDateList)
</strong><strong>    }
</strong>...
    return {
      dateList,
<strong>      addSchedule,
</strong>    }
...
</code></pre>

ここで、firstIndexとsecondIndexを取得する処理がuseEffect内の処理と同じですので、その部分を関数として切り出しましょう。`getDateListIndex`という関数にて`currentDateList`と`schedule`を受け取り、`firstIndex`、`secondIndex`を配列の形で返却します。

<pre class="language-typescript"><code class="lang-typescript">...
<strong>  const getDateListIndex = (
</strong><strong>    currentDateList: DateList,
</strong><strong>    schedule: Schedule
</strong><strong>  ): number[] => {
</strong><strong>    const firstIndex = currentDateList.findIndex((oneWeek) => {
</strong><strong>      return oneWeek.some((item) => isSameDay(item.date, schedule.date));
</strong><strong>    });
</strong><strong>    if (firstIndex === -1) return [-1, -1];
</strong><strong>    const secondIndex = currentDateList[firstIndex].findIndex((item) => {
</strong><strong>      return isSameDay(item.date, schedule.date);
</strong><strong>    });
</strong><strong>    return [firstIndex, secondIndex];
</strong><strong>  };
</strong>
  const addSchedule = (schedule: Schedule) => {
    const newDateList = [...dateList];

<strong>    const [firstIndex, secondIndex] = getDateListIndex(newDateList, schedule);
</strong><strong>    if (firstIndex === -1) return;
</strong>
    newDateList[firstIndex][secondIndex].schedules = [
      ...newDateList[firstIndex][secondIndex].schedules,
      schedule,
    ];
    setDateList(newDateList);
  };

  useEffect(() => {
    const monthOfSundayList = eachWeekOfInterval({
      start: startOfMonth(currentDate),
      end: endOfMonth(currentDate),
    });
    const newDateList: DateList = monthOfSundayList.map((date) => {
      return eachDayOfInterval({
        start: date,
        end: endOfWeek(date),
      }).map((date) => ({ date, schedules: [] as Schedule[] }));
    });

    const scheduleList = getScheduleList();
    scheduleList.forEach((schedule) => {
<strong>      const [firstIndex, secondIndex] = getDateListIndex(newDateList, schedule);
</strong><strong>      if (firstIndex === -1) return;
</strong>
      newDateList[firstIndex][secondIndex].schedules = [
        ...newDateList[firstIndex][secondIndex].schedules,
        schedule,
      ];
    });

    setDateList(newDateList);
  }, [currentDate]);
</code></pre>

そして、`CalendarPage`の`useCalendar`にて、`addSchedule`を受け取ります。それを`CalendarNav`に渡します。

<pre class="language-tsx" data-title="pages/CalendarPage.tsx◎"><code class="lang-tsx">import { getMonth} from "date-fns";
import { CalendarHeader } from "../organisms/CalendarHeader";
import { CalendarBody } from "../organisms/CalendarBody";
import { useCalendar } from "../../hooks/useCalendar";
import { useState } from "react";
import { CalendarNav } from "../organisms/CalendarNav";

export const CalendarPage = () => {
  const [currentDate, setCurrentDate] = useState(new Date())
<strong>  const { dateList, addSchedule } = useCalendar({ currentDate: currentDate });
</strong>
  return (
    &#x3C;>
      &#x3C;h1 className=" font-bold text-3xl mb-5">{`${
        getMonth(currentDate) + 1
      }月`}&#x3C;/h1>
<strong>      &#x3C;CalendarNav setCurrentDate={setCurrentDate} addSchedule={addSchedule} />
</strong>      &#x3C;table className="w-[80%] border-collapse border-2 border-solid border-lime-800 table-fixed">
        &#x3C;CalendarHeader />
        &#x3C;CalendarBody currentDate={currentDate} dateList={dateList} />
      &#x3C;/table>
    &#x3C;/>
  );
}

</code></pre>

それを`CalendarNav`にて受け取れるようにし、`CreateScheduleModal`にて渡し、

`CreateScheduleModal`でも受け取れるようにします。

<pre class="language-tsx" data-title="oragnisms/CalendarNav.tsx◎"><code class="lang-tsx">import { Dispatch, SetStateAction, useState } from "react"
import { addMonths } from "date-fns"
import { FaArrowAltCircleLeft, FaArrowAltCircleRight } from "react-icons/fa"
import { PrimaryBtn } from "../atoms/PrimaryBtn"
import { CreateScheduleModal } from "./CreateScheduleModal"
<strong>import { Schedule } from "../../types/calendar"
</strong>
type PropsType = {
  setCurrentDate: Dispatch&#x3C;SetStateAction&#x3C;Date>>;
<strong>  addSchedule: (schedule: Schedule) => void;
</strong>};

<strong>export const CalendarNav = ({ setCurrentDate, addSchedule }: PropsType) => {
</strong>...
      &#x3C;CreateScheduleModal
        isOpen={isOpen}
        closeModal={closeModal}
<strong>        addSchedule={addSchedule}
</strong>      />
...
</code></pre>

<pre class="language-tsx" data-title="oragnisms/CreateScheduleModal.tsx◎"><code class="lang-tsx">import Modal from "react-modal";
import { ChangeEvent, FormEvent, useState } from "react";
import { format } from "date-fns";
import { Input } from "../atoms/Input";
import { PrimaryBtn } from "../atoms/PrimaryBtn";
<strong>import { NewSchedule, Schedule } from "../../types/calendar";
</strong>import { Textarea } from "../atoms/Textarea";

type PropsType = {
  isOpen: boolean;
  closeModal: () => void;
<strong>  addSchedule: (schedule: Schedule) => void;
</strong>};

const customStyles = {
  content: {
    top: "50%",
    left: "50%",
    width: "30%",
    height: "50vh",
    transform: "translate(-50%, -50%)",
  },
};

export const CreateScheduleModal = ({
  isOpen,
  closeModal,
<strong>  addSchedule,
</strong>}: PropsType) => {
...
</code></pre>

では、予定を作成する関数を作成します。formタグのonSubmitにセットしますので、デフォルトの挙動をキャンセルするため、`event.preventDefault()`を実行します。

次に`addSchedule`を実行するのですが、渡す引数の型が`Schedule型`で、`newSchedule`は`NewSchedule型`なので型が異なります。

そのため、`newSchedule`を`Schedule型`に変換する必要があるので、`newSchedule`から新しいオブジェクトを生成します。idは固定値として、`date`は`newSchedule.date`を文字列型からDate型に変換する必要があり、その場合は`parse`という関数にて変換することができます。parseは第一引数に文字列を渡し、第二引数にその文字列の形式を渡すことで変換することができます。そして作成したオブジェクトを`addSchedule`に渡して実行することで、新しい予定がカレンダーに追加されるかと思います。次に`setNewSchedule`にて`newSchedule`を初期化します。最後に`closeModal()`にてモーダルを閉じるようにしましょう。

formタグの`onSubmit`にこの関数を渡しましょう。

<pre class="language-tsx" data-title="oragnisms/CreateScheduleModal.tsx◎"><code class="lang-tsx">...
  const changeNewSchedule = (
    event: ChangeEvent&#x3C;HTMLInputElement | HTMLTextAreaElement>
  ) => {
    const { name, value } = event.target;
    setNewSchedule({ ...newSchedule, [name]: value });
  };

<strong>  const handleCreateSchedule = (event: FormEvent&#x3C;HTMLFormElement>) => {
</strong><strong>    event.preventDefault()
</strong><strong>    const { title, date, description } = newSchedule
</strong><strong>    const schedule: Schedule = {
</strong><strong>      id: 100001,
</strong><strong>      title,
</strong><strong>      date: parse(date, "yyyy-MM-dd", new Date()),
</strong><strong>      description: description,
</strong><strong>    }
</strong><strong>    addSchedule(schedule)
</strong><strong>    setNewSchedule({
</strong><strong>      title: "",
</strong><strong>      date: format(new Date(), "yyyy-MM-dd"),
</strong><strong>      description: "",
</strong><strong>    })
</strong><strong>    closeModal()
</strong><strong>  }
</strong>...
<strong>       &#x3C;form className="flex flex-col gap-8" onSubmit={handleCreateSchedule}>
</strong>...
</code></pre>

こちらを画面にて確認すると、新しい予定を追加することができるかと思います。

<figure><img src="https://1869761657-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcUBbYqol4PMzZJggiMqV%2Fuploads%2FPwmv2gVwMgH20UxChUWB%2F8a.png?alt=media&#x26;token=786c5142-e8f7-45de-925c-9b61b77a1db6" alt=""><figcaption></figcaption></figure>

ここまでの作業をcommitしましょう。

```bash
git add .
```

```bash
git commit
```

commitメッセージは

```
feat: 予定作成フォームに入力した内容をカレンダーの予定に追加する機能を作成
```

としましょう。
