# 1ヶ月カレンダーの作成1

次に、ログイン後に1ヶ月カレンダーを表示するようにします。

`feature/calendar-page`にて作業します。

```bash
git switch -c feature/calendar-page
```

1ヶ月カレンダーを作るために、`date-fns`というライブラリをインストールしましょう。

`date-fns`はDateオブジェクトを扱う上で便利なメソッドが一通り揃っているため、こちらを利用します。

```bash
npm i date-fns
```

まず、今月の月を表示するようにしましょう。`date-fns`の`getMonth`という関数を利用することで、引数に渡したDateオブジェクトの月を取得することができます。注意点として、-1された値が返却される(1月の場合は0、12月の場合は11）ので、`+1`をして表示しましょう。

<pre class="language-tsx" data-title="pages/CalendarPage.tsx◎"><code class="lang-tsx"><strong>import { getMonth } from "date-fns";
</strong>
export const CalendarPage = () => {
<strong>  const today = new Date()
</strong>
  return (
    &#x3C;>
<strong>      &#x3C;h1 className=" font-bold text-3xl mb-5">
</strong><strong>        {`${(getMonth(today)) + 1}月`}
</strong><strong>      &#x3C;/h1>
</strong>    &#x3C;/>
  );
}

</code></pre>

次に1ヶ月カレンダー上部の曜日の部分を表示します。そのため曜日の配列を定義します。

`src`配下に`constants`ディレクトリを作成し、その中に`calendar.ts`を作成します。

その中に以下のような定数を定義します。

<pre class="language-typescript" data-title="src/constants/calendar.ts◎"><code class="lang-typescript"><strong>export const DAYS_LIST = ["日", "月", "火", "水", "木", "金", "土"]
</strong></code></pre>

こちらをmapにて表示しましょう。1ヶ月カレンダーはtableタグを使用して表示するようにしましょう。

<pre class="language-tsx" data-title="pages/CalendarPage.tsx◎"><code class="lang-tsx">import { getMonth } from "date-fns";
import { DAYS_LIST } from "../../constants/calendar";

export const CalendarPage = () => {
  const today = new Date()

  return (
    &#x3C;>
      &#x3C;h1 className=" font-bold text-3xl mb-5">{`${getMonth(today) + 1}月`}&#x3C;/h1>
<strong>      &#x3C;table className="w-[80%] border-collapse border-2 border-solid border-lime-800 table-fixed">
</strong><strong>        &#x3C;thead>
</strong><strong>          &#x3C;tr className="bg-lime-800 text-white rounded-tl-lg rounded-tr-lg py-10">
</strong><strong>            {DAYS_LIST.map((day) => (
</strong><strong>              &#x3C;th key={day} className="text-center text-xl py-3">
</strong><strong>                {day}
</strong><strong>              &#x3C;/th>
</strong><strong>            ))}
</strong><strong>          &#x3C;/tr>
</strong><strong>        &#x3C;/thead>
</strong><strong>      &#x3C;/table>
</strong>    &#x3C;/>
  );
}

</code></pre>

次に日付部分を表示します。日付部分の表示に関しては、

```
[
 [1, 2, 3, 4],
 [5, 6, 7, 8, 9, 10, 11],
 [12, 13, 14, 15, 16, 17, 18],
 [19, 20, 21, 22, 23, 24, 25],
 [26, 27, 28, 29, 30, 31],
]
```

のような二次元配列を作り、この配列をmapで回すようにします。

（実際は、数字のところにDateオブジェクトを入れます。）

ですので、以下のようなstateを定義します。

<pre class="language-tsx" data-title="pages/CalendarPage.tsx◎"><code class="lang-tsx">import { getMonth } from "date-fns";
import { DAYS_LIST } from "../../constants/calendar";
<strong>import { useState } from "react";
</strong>
export const CalendarPage = () => {
  const today = new Date()
<strong>  const [dateList, setDateList] = useState&#x3C;Date[][]>([]);
</strong>...
</code></pre>

そして`dateList`に`useEffect`にて二次元配列を格納します。

まず、`eachWeekOfInterval`という関数に`start`と`end`を渡すと、その期間が含まれる週の始めの日(日曜日)を配列で返します。&#x20;

例えば`start`に`2024-04-01`のDateオブジェクトを渡し、`end`に`2024-04-30`のDateオブジェクトを渡した場合に、

```
[
2024-03-31,
2024-04-07,
2024-04-14,
2024-04-21,
2024-04-28,
]
```

のような配列を返却します。

<figure><img src="https://1869761657-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcUBbYqol4PMzZJggiMqV%2Fuploads%2F38a3FUZyR1KkyRGcutSc%2Fppp.png?alt=media&#x26;token=a161006b-6b9f-480a-b881-c3d6433cc2b1" alt=""><figcaption></figcaption></figure>

また、`startOfMonth`、`endOfMonth`という関数を利用することで、引数に与えられた日の月初の日と、月終わりの日を取得することができます。

(例えば`startOfMonth(2024-04-14)`と呼び出せば、`2024-04-01`のDateオブジェクトを取得可能。）

この`eachWeekOfInterval`,`startOfMonth`,`endOfMonth`を利用することで、表示したい1ヶ月カレンダーの各週初日の日付の配列を作成することができます。

<pre class="language-tsx" data-title="pages/CalendarPage.tsx◎"><code class="lang-tsx"><strong>import { eachWeekOfInterval, endOfMonth, getMonth, startOfMonth } from "date-fns";
</strong>import { DAYS_LIST } from "../../constants/calendar";
<strong>import { useEffect, useState } from "react";
</strong>
export const CalendarPage = () => {
  const today = new Date()
  const [dateList, setDateList] = useState&#x3C;Date[][]>([]);

<strong>  useEffect(() => {
</strong><strong>      const monthOfSundayList = eachWeekOfInterval({
</strong><strong>        start: startOfMonth(today),
</strong><strong>        end: endOfMonth(today),
</strong><strong>      });
</strong><strong>  }, [])
</strong></code></pre>

次に、`eachDayOfInterval`という関数にて`start`と`end`を渡すとその期間の1日ごとのDateオブジェクトの配列を取得することができるので、`map`にて先ほどの各週初日の日付の配列を回し、`start`に各週初日の日付を渡し、`end`には`endOfWeek`を使用することで、引数に与えられた日付の週の最終日を取得することができるので、そちらを渡すことで、1週間の配列を作り、最終的に1ヶ月の二次元配列を作成することができます。

こちらのnewDateListをsetDateListにて格納しましょう。

<pre class="language-tsx" data-title="pages/CalendarPage.tsx◎"><code class="lang-tsx"><strong>import { eachDayOfInterval, eachWeekOfInterval, endOfMonth, endOfWeek, getMonth, startOfMonth } from "date-fns";
</strong>import { DAYS_LIST } from "../../constants/calendar";
import { useEffect, useState } from "react";

export const CalendarPage = () => {
  const today = new Date()
  const [dateList, setDateList] = useState&#x3C;Date[][]>([]);

  useEffect(() => {
    const monthOfSundayList = eachWeekOfInterval({
      start: startOfMonth(today),
      end: endOfMonth(today),
    })
<strong>    const newDateList: Date[][] = monthOfSundayList.map((date) => {
</strong><strong>      return eachDayOfInterval({
</strong><strong>        start: date,
</strong><strong>        end: endOfWeek(date),
</strong><strong>      })
</strong><strong>    })
</strong><strong>    setDateList(newDateList)
</strong>  }, [])
  ...
</code></pre>

では、こちらの`dateList`をmapにて表示しましょう。二次元配列なので、map内にてさらにmapで回す必要があります。また日付は`getDate`という関数で取得することができます。

<pre class="language-tsx" data-title="pages/CalendarPage.tsx◎"><code class="lang-tsx">...
  return (
    &#x3C;>
      &#x3C;h1 className=" font-bold text-3xl mb-5">{`${getMonth(today) + 1}月`}&#x3C;/h1>
      &#x3C;table className="w-[80%] border-collapse border-2 border-solid border-lime-800 table-fixed">
        &#x3C;thead>
          &#x3C;tr className="bg-lime-800 text-white rounded-tl-lg rounded-tr-lg py-10">
            {DAYS_LIST.map((day) => (
              &#x3C;th key={day} className="text-center text-xl py-3">
                {day}
              &#x3C;/th>
            ))}
          &#x3C;/tr>
        &#x3C;/thead>
<strong>        &#x3C;tbody>
</strong><strong>          {dateList.map((oneWeek) => (
</strong><strong>            &#x3C;tr key={`week-${getDate(oneWeek[0])}`} className="mx-10">
</strong><strong>              {oneWeek.map((item) => (
</strong><strong>                &#x3C;td
</strong><strong>                  key={`day-${getDate(item)}`}
</strong><strong>                  className="bg-white h-[10vh] border-2 border-solid border-lime-800"
</strong><strong>                >
</strong><strong>                  &#x3C;span className="inline-block w-[20px] leading-[20px] text-center">
</strong><strong>                    {getDate(item)}
</strong><strong>                  &#x3C;/span>
</strong><strong>                &#x3C;/td>
</strong><strong>              ))}
</strong><strong>            &#x3C;/tr>
</strong><strong>          ))}
</strong><strong>        &#x3C;/tbody>
</strong>      &#x3C;/table>
    &#x3C;/>
  );
...
</code></pre>

これで、以下のような1ヶ月カレンダーが表示されるかと思います。

<figure><img src="https://1869761657-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FcUBbYqol4PMzZJggiMqV%2Fuploads%2FByozwN5ynlFLFGesnhKZ%2Flll.png?alt=media&#x26;token=c7b97abc-0014-41c0-843c-8fcff807a14c" alt=""><figcaption></figcaption></figure>

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

```bash
git add .
```

```bash
git commit
```

commitメッセージは

```
feat: date-fnsを導入し、1ヶ月カレンダーを作成
```

としましょう。
