Uncategorized

カレンダーの表示部分を変更する

最終的には以下のようにその週だけを表示したい

そのために編集を行う

ステップ1:PomodoroCalendar.vue<script> の修正(データの準備と計算ロジックの変更)

現在の月の表示に必要なデータと、1週間分の表示に必要なデータを計算するロジックに変更します。

変更前 (PomodoroCalendar.vue<script>datacomputed 部分):

JavaScript

  data() {
    const today = new Date();
    const currentYear = today.getFullYear();
    const currentMonth = today.getMonth() + 1;
    return {
      year: currentYear,
      month: currentMonth,
      daysOfWeek: ["日", "月", "火", "水", "木", "金", "土"],
      todayDate: today.getDate(),
      todayMonth: currentMonth,
      todayYear: currentYear,
      calendarWorkLogs: [...this.workLogs],
    };
  },
  computed: {
    daysInMonth() {
      return new Date(this.year, this.month, 0).getDate();
    },
    firstDayOfMonth() {
      return new Date(this.year, this.month - 1, 1).getDay(); // 0:日, 1:月,...
    },
    calendarGrid() {
      const grid = [];
      let week = [];
      let dayCounter = 1;

      // 月の初めまでの空白を追加
      for (let i = 0; i < this.firstDayOfMonth; i++) {
        week.push(null);
      }

      while (dayCounter <= this.daysInMonth) {
        week.push(new Date(this.year, this.month - 1, dayCounter));
        if (week.length === 7) {
          grid.push(week);
          week = [];
        }
        dayCounter++;
      }

      // 月の終わりまでの空白を追加
      while (week.length < 7 && week.length > 0) {
        week.push(null);
      }
      if (week.length > 0) {
        grid.push(week);
      }

      return grid;
    },
  },

変更後 (PomodoroCalendar.vue<script>datacomputed 部分):

JavaScript

  data() {
    const today = new Date();
    const currentYear = today.getFullYear();
    const currentMonth = today.getMonth() + 1;
    const currentDay = today.getDate();

    // 表示する週の開始日を計算 (例: 先週の月曜日)
    const daysToMonday = today.getDay() === 0 ? 6 : today.getDay() - 1; // 今週の月曜日までの日数
    const startOfWeek = new Date(today);
    startOfWeek.setDate(currentDay - daysToMonday - 7); // 先週の月曜日

    const weekDates = [];
    for (let i = 0; i < 7; i++) {
      const date = new Date(startOfWeek);
      date.setDate(startOfWeek.getDate() + i);
      weekDates.push(date);
    }

    return {
      year: currentYear,
      month: currentMonth,
      daysOfWeek: ["日", "月", "火", "水", "木", "金", "土"],
      todayDate: today.getDate(),
      todayMonth: currentMonth,
      todayYear: currentYear,
      calendarWorkLogs: [...this.workLogs],
      weekDates: weekDates, // 表示する1週間の日付配列
    };
  },
  computed: {
    calendarGrid() {
      return [this.weekDates]; // 1週間分のデータだけを持つ配列を返す
    },
  },

変更点の解説:

  • data() の変更:
    • currentDay: 今日の日付を取得します。
    • startOfWeek: 表示する週の開始日(ここでは先週の月曜日)を計算します。
      • today.getDay(): 今日の曜日(0:日, 1:月, ... 6:土)を取得します。
      • daysToMonday: 今週の月曜日までの日数を計算します。日曜日の場合は 6、月曜日の場合は 0、... 土曜日の場合は 5 になります。
      • startOfWeek.setDate(currentDay - daysToMonday - 7): 今日の日付から今週の月曜日までの日数とさらに7日(先週)を引くことで、先週の月曜日の Date オブジェクトを作成します。
    • weekDates: startOfWeek を基準に、7日分の Date オブジェクトを格納した配列を作成します。これが表示する1週間の日付データとなります。
    • yearmonth は今日のものを使用していますが、必要に応じて weekDates の最初の日付から取得するように変更できます。
    • calendarWorkLogs: 変更なし。
  • computed.calendarGrid() の変更:
    • 以前は月の全日を含む二次元配列を生成していましたが、変更後は this.weekDates を要素とする一次元配列をさらに配列で囲んだ [[...]] の形式で返します。これは、テンプレートの v-for が週ごとの行を処理することを前提としているため、1週間分のデータを1つの「週」として扱います。

ステップ2:PomodoroCalendar.vue<template> の修正(表示の変更)

テンプレートの v-forweekDates 配列に合わせて修正します。

変更前 (PomodoroCalendar.vue<template> 部分):

HTML

<template>
  <div>
    <h2>{{ year }}年 {{ month }}月</h2>
    <table>
      <thead>
        <tr>
          <th v-for="day in daysOfWeek" :key="day">{{ day }}</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(week, index) in calendarGrid" :key="index">
          <td
            v-for="(date, i) in week"
            :key="i"
            :class="{ today: isToday(date), empty: !date }"
          >
            {{ date ? date.getDate() : "" }}
            <div v-if="date">
              <div v-for="log in getWorkLogsForDate(date)" :key="log.startTime">
                - {{ log.task }} ({{ log.startTime }} - {{ log.endTime }})
              </div>
            </div>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

変更後 (PomodoroCalendar.vue<template> 部分):

HTML

<template>
  <div>
    <h2>
      {{ weekDates[0] ? weekDates[0].getFullYear() : "" }}年
      {{ weekDates[0] ? weekDates[0].getMonth() + 1 : "" }}月
      ({{ formatDateRange }})
    </h2>
    <table>
      <thead>
        <tr>
          <th v-for="day in daysOfWeek" :key="day">{{ day }}</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td
            v-for="date in weekDates"
            :key="date ? date.getTime() : i"
            :class="{ today: isToday(date) }"
          >
            {{ date ? date.getDate() : "" }}
            <div v-if="date">
              <div v-for="log in getWorkLogsForDate(date)" :key="log.startTime">
                - {{ log.task }} ({{ log.startTime }} - {{ log.endTime }})
              </div>
            </div>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
// ... (script 部分はステップ1で変更)
export default {
  // ... (name, props, data, watch)
  computed: {
    calendarGrid() {
      return [this.weekDates];
    },
    formatDateRange() {
      if (this.weekDates.length === 7 && this.weekDates[0] && this.weekDates[6]) {
        const startDay = this.weekDates[0].getDate();
        const endDay = this.weekDates[6].getDate();
        return `${startDay} - ${endDay}日`;
      }
      return "";
    },
  },
  methods: {
    // ... (isToday, getWorkLogsForDate)
  },
};
</script>

変更点の解説:

  • <h2> 部分の修正:
    • 表示する年と月を weekDates 配列の最初の要素から取得するように変更しました。
    • 表示する日付の範囲を示す formatDateRange computed プロパティを追加し、表示しています。
  • <tbody> 部分の修正:
    • 週ごとの <tr>v-for を削除し、直接 weekDates<td> でループするように変更しました。1週間分のデータが weekDates に格納されているため、1行で表示できます。
    • <td>keydate ? date.getTime() : i に変更しました。Date オブジェクトが存在する場合はそのタイムスタンプを、存在しない場合はインデックスを使用します(今回は weekDates に常に Date オブジェクトが入るので、主に TypeScript などでの型安全性を考慮した記述です)。
    • .empty クラスの条件を削除しました。weekDates には常に日付が入るため、空のセルはなくなります。

ステップ3:PomodoroCalendar.vue<script>methods の修正(日付の比較)

isToday メソッドが Date オブジェクトを受け取るように修正します。

変更前 (PomodoroCalendar.vue<script>methods 部分):

JavaScript

  methods: {
    isToday(date) {
      return (
        date &&
        date.getDate() === this.todayDate &&
        date.getMonth() + 1 === this.todayMonth &&
        date.getFullYear() === this.todayYear
      );
    },
    getWorkLogsForDate(date) {
      if (!date) {
        return [];
      }
      const formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1)
        .toString()
        .padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
      return this.calendarWorkLogs.filter((log) => log.date === formattedDate);
    },
    // ...
  },

変更後 (PomodoroCalendar.vue<script>methods 部分):

JavaScript

  methods: {
    isToday(date) {
      if (!date) return false;
      return (
        date.getDate() === this.todayDate &&
        date.getMonth() === this.todayMonth - 1 && // JavaScript の month は 0-indexed
        date.getFullYear() === this.todayYear
      );
    },
    getWorkLogsForDate(date) {
      if (!date) {
        return [];
      }
      const formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1)
        .toString()
        .padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
      return this.calendarWorkLogs.filter((log) => log.date === formattedDate);
    },
    // ...
  },

変更点の解説:

  • isToday(date) の修正:
    • 引数 dateDate オブジェクトであることを前提として比較を行います。
    • date.getMonth() は 0 から始まるため、this.todayMonth - 1 と比較するように修正しました。

このような形になった

この状態だとタイマー終了後タスクが反映されなくなってしまったため
再度紐付けを行う

再度紐付け

問題点:

現在の App.vuehandleWorkFinished 関数では、カレンダーが表示されている場合に calendarRef.value.addWorkLog(logData) を呼び出していますが、PomodoroCalendar コンポーネントがマウントされる前にタイマーが終了した場合、calendarRef.valuenull になっている可能性があります。

また、mounted フックでの watch は、画面遷移後に初期表示用の calendarWorkLogs を反映する意図がありますが、タイマー終了後に即座に反映するためには別の仕組みが必要です。

修正方針:

  1. App.vue でタイマー終了時に受け取ったログを calendarWorkLogs に保持し続ける。
  2. PomodoroCalendar がマウントされた際に、calendarWorkLogs に保持されているログを自身に追加する。
  3. タイマー終了時にカレンダーが表示されていれば、即座に PomodoroCalendaraddWorkLog を呼び出す。

ステップ1:App.vue<script> の修正

handleWorkFinished 関数と mounted フックを修正します。

JavaScript

  setup() {
    const route = useRoute();
    const calendarRef = ref(null); // PomodoroCalendar コンポーネントの参照
    const calendarWorkLogs = ref([]); // 作業ログを保持

    const handleWorkFinished = (logData) => {
      console.log("App.vue で作業終了イベントを受け取りました:", logData);
      calendarWorkLogs.value.push(logData); // 作業終了時にログを calendarWorkLogs に追加
      if (route.path === "/calendar" && calendarRef.value) {
        calendarRef.value.addWorkLog(logData); // カレンダーが表示されていれば直接追加
      }
    };

    return { route, calendarRef, calendarWorkLogs, handleWorkFinished };
  },
  mounted() {
    this.$watch(
      () => this.$route.path,
      (newPath) => {
        if (newPath === "/calendar" && this.calendarRef) {
          // カレンダー表示時に保持しているログをすべて追加
          this.calendarWorkLogs.value.forEach(log => {
            this.calendarRef.value.addWorkLog(log);
          });
          // 追加後にクリア (即時反映のため、保持は不要)
          this.calendarWorkLogs.value = [];
        }
      }
    );
  },
};

変更点の解説:

  • setup() 関数の変更:
    • calendarWorkLogs のコメントを修正し、作業ログを保持する役割を明確にしました。
  • mounted() フックの変更:
    • カレンダー画面 (/calendar) に遷移し、calendarRef が存在する場合に、calendarWorkLogs に保持されているすべてのログを calendarRef.value.addWorkLog(log) を使って PomodoroCalendar に追加します。
    • ログを追加後、calendarWorkLogs.value = []; で配列をクリアします。これは、ログを即時反映するため、App.vue で保持する必要がなくなるためです。

ステップ2:PomodoroCalendar.vue<script> の修正(マウント時のログ反映)

PomodoroCalendar がマウントされた際に、props で受け取った workLogs を自身の calendarWorkLogs に反映させる処理を追加します。

JavaScript

  data() {
    const today = new Date();
    const currentYear = today.getFullYear();
    const currentMonth = today.getMonth() + 1;
    const currentDay = today.getDate();

    const daysToMonday = today.getDay() === 0 ? 6 : today.getDay() - 1;
    const startOfWeek = new Date(today);
    startOfWeek.setDate(currentDay - daysToMonday - 7);

    const weekDates = [];
    for (let i = 0; i < 7; i++) {
      const date = new Date(startOfWeek);
      date.setDate(startOfWeek.getDate() + i);
      weekDates.push(date);
    }

    const hours = Array.from({ length: 24 }, (_, i) => i);

    return {
      year: currentYear,
      month: currentMonth,
      daysOfWeek: ["日", "月", "火", "水", "木", "金", "土"],
      todayDate: today.getDate(),
      todayMonth: currentMonth,
      todayYear: currentYear,
      calendarWorkLogs: [], // 初期化を空にする
      weekDates: weekDates,
      hours: hours,
    };
  },
  watch: {
    workLogs(newWorkLogs) {
      this.calendarWorkLogs = [...newWorkLogs];
    },
  },
  mounted() {
    // props で受け取った initialWorkLogs を初期表示時に追加
    this.workLogs.forEach(log => {
      this.addWorkLog(log);
    });
  },
  methods: {
    addWorkLog(logData) {
      this.calendarWorkLogs.push(logData);
    },
    // ... (他のメソッドは変更なし)
  },

変更点の解説:

  • data() の変更:
    • calendarWorkLogs の初期化を [] に変更しました。初期表示は mounted フックで行います。
  • mounted() フックの追加:
    • コンポーネントがマウントされた際に、props で受け取った workLogsforEach でループ処理し、自身の addWorkLog メソッドを使って calendarWorkLogs に追加します。これにより、初期表示時に App.vue から渡されたログが表示されます。

これらの変更を加えることで、タイマー終了後にカレンダー画面に遷移していれば即座にタスクが反映され、カレンダー画面が既に表示されている場合でも、タイマー終了後にタスクが追加されるようになります。

マウントされるってどういう意味

  • マウントされる: このコンポーネントの実体が、HTML の特定の場所(通常は index.html 内の id="app" の要素)に組み込まれ、ブラウザの画面に描画されることです。初めてユーザーの目に見えるようになり、データに基づいて表示が変化したり、ユーザーの操作に応じたりできるようになります。

これでもだめ

-Uncategorized