diff --git a/src/public/app/widgets/buttons/calendar.ts b/src/public/app/widgets/buttons/calendar.ts index 41b73415b..87803f6cb 100644 --- a/src/public/app/widgets/buttons/calendar.ts +++ b/src/public/app/widgets/buttons/calendar.ts @@ -8,7 +8,7 @@ import toastService from "../../services/toast.js"; import options from "../../services/options.js"; import { Dropdown } from "bootstrap"; import type { EventData } from "../../components/app_context.js"; -import dayjs from "dayjs"; +import dayjs, { Dayjs } from "dayjs"; import utc from "dayjs/plugin/utc.js"; import "../../../stylesheets/calendar.css"; @@ -90,9 +90,9 @@ export default class CalendarWidget extends RightDropdownButtonWidget { private monthDropdown!: Dropdown; private firstDayOfWeek!: number; private weekCalculationOptions!: WeekCalculationOptions; - private activeDate: Date | null = null; - private todaysDate!: Date; - private date!: Date; + private activeDate: Dayjs | null = null; + private todaysDate!: Dayjs; + private date!: Dayjs; constructor(title: string = "", icon: string = "") { super(title, icon, DROPDOWN_TPL); @@ -118,18 +118,18 @@ export default class CalendarWidget extends RightDropdownButtonWidget { const target = e.target as HTMLElement; const value = target.dataset.value; if (value) { - this.date = dayjs(this.date).month(parseInt(value)).toDate(); + this.date = this.date.month(parseInt(value)); this.createMonth(); } }); this.$next = this.$dropdownContent.find('[data-calendar-toggle="next"]'); this.$next.on("click", () => { - this.date = dayjs(this.date).add(1, 'month').toDate(); + this.date = this.date.add(1, 'month'); this.createMonth(); }); this.$previous = this.$dropdownContent.find('[data-calendar-toggle="previous"]'); this.$previous.on("click", () => { - this.date = dayjs(this.date).subtract(1, 'month').toDate(); + this.date = this.date.subtract(1, 'month'); this.createMonth(); }); @@ -137,17 +137,17 @@ export default class CalendarWidget extends RightDropdownButtonWidget { this.$yearSelect = this.$dropdownContent.find('[data-calendar-input="year"]'); this.$yearSelect.on("input", (e) => { const target = e.target as HTMLInputElement; - this.date = dayjs(this.date).year(parseInt(target.value)).toDate(); + this.date = this.date.year(parseInt(target.value)); this.createMonth(); }); this.$nextYear = this.$dropdownContent.find('[data-calendar-toggle="nextYear"]'); this.$nextYear.on("click", () => { - this.date = dayjs(this.date).add(1, 'year').toDate(); + this.date = this.date.add(1, 'year'); this.createMonth(); }); this.$previousYear = this.$dropdownContent.find('[data-calendar-toggle="previousYear"]'); this.$previousYear.on("click", () => { - this.date = dayjs(this.date).subtract(1, 'year').toDate(); + this.date = this.date.subtract(1, 'year'); this.createMonth(); }); @@ -203,9 +203,9 @@ export default class CalendarWidget extends RightDropdownButtonWidget { }; } - getWeekNumber(date: Date): number { - const year = dayjs(date).year(); - const jan1 = dayjs().year(year).month(0).date(1); + getWeekNumber(date: Dayjs): number { + const year = date.year(); + const jan1 = date.clone().startOf('year'); const jan1Day = jan1.day(); let firstWeekStart = jan1.clone(); @@ -239,22 +239,23 @@ export default class CalendarWidget extends RightDropdownButtonWidget { } } - const diffDays = dayjs(date).diff(firstWeekStart, 'day') + 1; + const diffDays = date.diff(firstWeekStart, 'day') + 1; const weekNumber = Math.floor(diffDays / 7) + 1; // Check if the week number is less than 0, which means the date is in the previous year if (weekNumber <= 0) { - const prevYearLastWeek = this.getWeekNumber(dayjs(date).subtract(1, 'year').endOf('year').toDate()); + const prevYearLastWeek = this.getWeekNumber(date.subtract(1, 'year').endOf('year')); return prevYearLastWeek; } // Check if it's the last week of December - if (dayjs(date).month() === 11) { // December - const lastDayOfYear = dayjs().year(year).month(11).date(31); + if (date.month() === 11) { // December + const lastDayOfYear = date.clone().month(11).date(31); const lastWeekStart = lastDayOfYear.subtract((lastDayOfYear.day() - this.firstDayOfWeek + 7) % 7, 'day'); - if (this.isEqual(date, lastWeekStart.toDate())) { - const nextYearFirstWeek = this.getWeekNumber(lastDayOfYear.add(1, 'day').toDate()); + // Use local timezone to avoid date mismatch + if (date.isSame(lastWeekStart, 'day')) { + const nextYearFirstWeek = this.getWeekNumber(lastDayOfYear.add(1, 'day')); return nextYearFirstWeek; } } @@ -268,29 +269,29 @@ export default class CalendarWidget extends RightDropdownButtonWidget { init(activeDate: string | null) { // attaching time fixes local timezone handling - this.activeDate = activeDate ? dayjs(`${activeDate}T12:00:00`).toDate() : null; - this.todaysDate = dayjs().toDate(); - this.date = dayjs(this.activeDate || this.todaysDate).startOf('month').toDate(); + this.activeDate = activeDate ? dayjs(`${activeDate}T12:00:00`) : null; + this.todaysDate = dayjs(); + this.date = dayjs(this.activeDate || this.todaysDate).startOf('month'); this.createMonth(); } createDay(dateNotesForMonth: DateNotesForMonth, num: number) { - const $newDay = $("").addClass("calendar-date").attr("data-calendar-date", utils.formatDateISO(this.date)); + const $newDay = $("").addClass("calendar-date").attr("data-calendar-date", this.date.local().format('YYYY-MM-DD')); const $date = $("").html(String(num)); - const dateNoteId = dateNotesForMonth[utils.formatDateISO(this.date)]; + const dateNoteId = dateNotesForMonth[this.date.local().format('YYYY-MM-DD')]; if (dateNoteId) { $newDay.addClass("calendar-date-exists"); $newDay.attr("data-href", `#root/${dateNoteId}`); } - if (this.isEqual(this.date, this.activeDate)) { + if (this.date.isSame(this.activeDate, 'day')) { $newDay.addClass("calendar-date-active"); } - if (this.isEqual(this.date, this.todaysDate)) { + if (this.date.isSame(this.todaysDate, 'day')) { $newDay.addClass("calendar-date-today"); } @@ -307,61 +308,51 @@ export default class CalendarWidget extends RightDropdownButtonWidget { return $newWeekNumber; } - isEqual(a: Date, b: Date | null) { - if ((!a && b) || (a && !b)) { - return false; - } - - if (!b) return false; - - return dayjs(a).isSame(dayjs(b), 'day'); - } - - private getPrevMonthDays(firstDayOfWeek: number): { weekNumber: number, dates: Date[] } { - const prevMonthLastDay = dayjs(this.date).subtract(1, 'month').endOf('month'); + private getPrevMonthDays(firstDayOfWeek: number): { weekNumber: number, dates: Dayjs[] } { + const prevMonthLastDay = this.date.subtract(1, 'month').endOf('month'); const daysToAdd = (firstDayOfWeek - this.firstDayOfWeek + 7) % 7; - const dates = []; + const dates: Dayjs[] = []; - const firstDay = dayjs(this.date).startOf('month'); - const weekNumber = this.getWeekNumber(firstDay.toDate()); + const firstDay = this.date.startOf('month'); + const weekNumber = this.getWeekNumber(firstDay); // Get dates from previous month for (let i = daysToAdd - 1; i >= 0; i--) { - dates.push(prevMonthLastDay.subtract(i, 'day').toDate()); + dates.push(prevMonthLastDay.subtract(i, 'day')); } return { weekNumber, dates }; } - private getNextMonthDays(lastDayOfWeek: number): Date[] { - const nextMonthFirstDay = dayjs(this.date).add(1, 'month').startOf('month'); - const dates = []; + private getNextMonthDays(lastDayOfWeek: number): Dayjs[] { + const nextMonthFirstDay = this.date.add(1, 'month').startOf('month'); + const dates: Dayjs[] = []; const lastDayOfUserWeek = (this.firstDayOfWeek + 6) % 7; const daysToAdd = (lastDayOfUserWeek - lastDayOfWeek + 7) % 7; // Get dates from next month for (let i = 0; i < daysToAdd; i++) { - dates.push(nextMonthFirstDay.add(i, 'day').toDate()); + dates.push(nextMonthFirstDay.add(i, 'day')); } return dates; } async createMonth() { - const month = dayjs(this.date).format('YYYY-MM'); + const month = this.date.format('YYYY-MM'); const dateNotesForMonth: DateNotesForMonth = await server.get(`special-notes/notes-for-month/${month}`); this.$month.empty(); - const firstDay = dayjs(this.date).startOf('month'); + const firstDay = this.date.startOf('month'); const firstDayOfWeek = firstDay.day(); // Add dates from previous month if (firstDayOfWeek !== this.firstDayOfWeek) { const { weekNumber, dates } = this.getPrevMonthDays(firstDayOfWeek); - const prevMonth = dayjs(this.date).subtract(1, 'month').format('YYYY-MM'); + const prevMonth = this.date.subtract(1, 'month').format('YYYY-MM'); const dateNotesForPrevMonth: DateNotesForMonth = await server.get(`special-notes/notes-for-month/${prevMonth}`); const $weekNumber = this.createWeekNumber(weekNumber); @@ -370,55 +361,54 @@ export default class CalendarWidget extends RightDropdownButtonWidget { dates.forEach(date => { const tempDate = this.date; this.date = date; - const $day = this.createDay(dateNotesForPrevMonth, dayjs(date).date()); + const $day = this.createDay(dateNotesForPrevMonth, date.date()); $day.addClass('calendar-date-prev-month'); this.$month.append($day); this.date = tempDate; }); } - const currentMonth = this.date.getMonth(); + const currentMonth = this.date.month(); - while (this.date.getMonth() === currentMonth) { - // Using UTC to avoid issues with summer/winter time - const weekNumber = this.getWeekNumber(dayjs(this.date).utc().toDate()); + while (this.date.month() === currentMonth) { + const weekNumber = this.getWeekNumber(this.date); // Add week number if it's first day of week - if (this.date.getDay() === this.firstDayOfWeek) { + if (this.date.day() === this.firstDayOfWeek) { const $weekNumber = this.createWeekNumber(weekNumber); this.$month.append($weekNumber); } - const $day = this.createDay(dateNotesForMonth, this.date.getDate()); + const $day = this.createDay(dateNotesForMonth, this.date.date()); this.$month.append($day); - this.date = dayjs(this.date).add(1, 'day').toDate(); + this.date = this.date.add(1, 'day'); } // while loop trips over and day is at 30/31, bring it back - this.date = dayjs(this.date).startOf('month').subtract(1, 'month').toDate(); + this.date = this.date.startOf('month').subtract(1, 'month'); // Add dates from next month - const lastDayOfMonth = dayjs(this.date).endOf('month').toDate(); - const lastDayOfWeek = lastDayOfMonth.getDay(); + const lastDayOfMonth = this.date.endOf('month'); + const lastDayOfWeek = lastDayOfMonth.day(); const lastDayOfUserWeek = (this.firstDayOfWeek + 6) % 7; if (lastDayOfWeek !== lastDayOfUserWeek) { const dates = this.getNextMonthDays(lastDayOfWeek); - const nextMonth = dayjs(this.date).add(1, 'month').format('YYYY-MM'); + const nextMonth = this.date.add(1, 'month').format('YYYY-MM'); const dateNotesForNextMonth: DateNotesForMonth = await server.get(`special-notes/notes-for-month/${nextMonth}`); dates.forEach(date => { const tempDate = this.date; this.date = date; - const $day = this.createDay(dateNotesForNextMonth, dayjs(date).date()); + const $day = this.createDay(dateNotesForNextMonth, date.date()); $day.addClass('calendar-date-next-month'); this.$month.append($day); this.date = tempDate; }); } - this.$monthSelect.text(MONTHS[this.date.getMonth()]); - this.$yearSelect.val(this.date.getFullYear()); + this.$monthSelect.text(MONTHS[this.date.month()]); + this.$yearSelect.val(this.date.year()); } async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {