diff --git a/src/managers/GridManager.ts b/src/managers/GridManager.ts index 5cf925e..9efbdac 100644 --- a/src/managers/GridManager.ts +++ b/src/managers/GridManager.ts @@ -150,13 +150,13 @@ export class GridManager { */ public navigateNext(): void { let nextDate: Date; - + switch (this.currentView) { case 'week': nextDate = this.dateService.addWeeks(this.currentDate, 1); break; case 'month': - nextDate = this.addMonths(this.currentDate, 1); + nextDate = this.dateService.addMonths(this.currentDate, 1); break; case 'day': nextDate = this.dateService.addDays(this.currentDate, 1); @@ -164,30 +164,30 @@ export class GridManager { default: nextDate = this.dateService.addWeeks(this.currentDate, 1); } - + this.currentDate = nextDate; - + eventBus.emit(CoreEvents.NAVIGATION_COMPLETED, { direction: 'next', newDate: nextDate, periodLabel: this.getCurrentPeriodLabel() }); - + this.render(); } - + /** * Navigate to previous period */ public navigatePrevious(): void { let prevDate: Date; - + switch (this.currentView) { case 'week': prevDate = this.dateService.addWeeks(this.currentDate, -1); break; case 'month': - prevDate = this.addMonths(this.currentDate, -1); + prevDate = this.dateService.addMonths(this.currentDate, -1); break; case 'day': prevDate = this.dateService.addDays(this.currentDate, -1); @@ -195,15 +195,15 @@ export class GridManager { default: prevDate = this.dateService.addWeeks(this.currentDate, -1); } - + this.currentDate = prevDate; - + eventBus.emit(CoreEvents.NAVIGATION_COMPLETED, { direction: 'previous', newDate: prevDate, periodLabel: this.getCurrentPeriodLabel() }); - + this.render(); } @@ -299,35 +299,24 @@ export class GridManager { } } - /** - * Helper method to add months to a date - */ - private addMonths(date: Date, months: number): Date { - const result = new Date(date); - result.setMonth(result.getMonth() + months); - return result; - } - /** * Helper method to get month start */ private getMonthStart(date: Date): Date { - const result = new Date(date); - result.setDate(1); - result.setHours(0, 0, 0, 0); - return result; + const year = date.getFullYear(); + const month = date.getMonth(); + return this.dateService.startOfDay(new Date(year, month, 1)); } - + /** * Helper method to get month end */ private getMonthEnd(date: Date): Date { - const result = new Date(date); - result.setMonth(result.getMonth() + 1, 0); - result.setHours(23, 59, 59, 999); - return result; + const nextMonth = this.dateService.addMonths(date, 1); + const firstOfNextMonth = this.getMonthStart(nextMonth); + return this.dateService.endOfDay(this.dateService.addDays(firstOfNextMonth, -1)); } - + /** * Helper method to get all dates in a month */ @@ -335,11 +324,13 @@ export class GridManager { const dates: Date[] = []; const monthStart = this.getMonthStart(date); const monthEnd = this.getMonthEnd(date); - - for (let d = new Date(monthStart); d <= monthEnd; d.setDate(d.getDate() + 1)) { - dates.push(new Date(d)); + + const totalDays = Math.ceil((monthEnd.getTime() - monthStart.getTime()) / (1000 * 60 * 60 * 24)) + 1; + + for (let i = 0; i < totalDays; i++) { + dates.push(this.dateService.addDays(monthStart, i)); } - + return dates; } } \ No newline at end of file diff --git a/src/managers/NavigationManager.ts b/src/managers/NavigationManager.ts index e4f46c3..8a3c286 100644 --- a/src/managers/NavigationManager.ts +++ b/src/managers/NavigationManager.ts @@ -153,14 +153,14 @@ export class NavigationManager { } private navigateToPreviousWeek(): void { - this.targetWeek.setDate(this.targetWeek.getDate() - 7); + this.targetWeek = this.dateService.addWeeks(this.targetWeek, -1); const weekToShow = new Date(this.targetWeek); this.animationQueue++; this.animateTransition('prev', weekToShow); } private navigateToNextWeek(): void { - this.targetWeek.setDate(this.targetWeek.getDate() + 7); + this.targetWeek = this.dateService.addWeeks(this.targetWeek, 1); const weekToShow = new Date(this.targetWeek); this.animationQueue++; this.animateTransition('next', weekToShow); diff --git a/src/renderers/EventRenderer.ts b/src/renderers/EventRenderer.ts index efbe961..5c8ff32 100644 --- a/src/renderers/EventRenderer.ts +++ b/src/renderers/EventRenderer.ts @@ -11,7 +11,7 @@ import { DragOffset, StackLinkData } from '../types/DragDropTypes'; import { ColumnBounds } from '../utils/ColumnDetectionUtils'; import { DragColumnChangeEventPayload, DragMoveEventPayload, DragStartEventPayload } from '../types/EventTypes'; import { DateService } from '../utils/DateService'; -import { format, setHours, setMinutes, setSeconds, addDays } from 'date-fns'; +import { format } from 'date-fns'; /** * Interface for event rendering strategies @@ -164,40 +164,25 @@ export class DateEventRenderer implements EventRendererStrategy { * Update data-start and data-end attributes with ISO timestamps */ private updateDateTimeAttributes(element: HTMLElement, columnDate: Date, startMinutes: number, endMinutes: number): void { - const startDate = this.createDateWithMinutes(columnDate, startMinutes); - - let endDate = this.createDateWithMinutes(columnDate, endMinutes); - + const startDate = this.dateService.createDateAtTime(columnDate, startMinutes); + + let endDate = this.dateService.createDateAtTime(columnDate, endMinutes); + // Handle cross-midnight events if (endMinutes >= 1440) { const extraDays = Math.floor(endMinutes / 1440); - endDate = addDays(endDate, extraDays); + endDate = this.dateService.addDays(endDate, extraDays); } - + element.dataset.start = startDate.toISOString(); element.dataset.end = endDate.toISOString(); } - /** - * Create a date with specific minutes since midnight - */ - private createDateWithMinutes(baseDate: Date, totalMinutes: number): Date { - const hours = Math.floor(totalMinutes / 60); - const minutes = totalMinutes % 60; - - return setSeconds(setMinutes(setHours(baseDate, hours), minutes), 0); - } - /** * Format minutes since midnight to time string */ private formatTimeFromMinutes(totalMinutes: number): string { - const hours = Math.floor(totalMinutes / 60); - const minutes = totalMinutes % 60; - const date = new Date(); - date.setHours(hours, minutes, 0, 0); - - return format(date, 'HH:mm'); + return this.dateService.minutesToTime(totalMinutes); } /** diff --git a/src/strategies/MonthViewStrategy.ts b/src/strategies/MonthViewStrategy.ts index 1c3f18b..9ee61ea 100644 --- a/src/strategies/MonthViewStrategy.ts +++ b/src/strategies/MonthViewStrategy.ts @@ -98,19 +98,21 @@ export class MonthViewStrategy implements ViewStrategy { } private getMonthDates(monthDate: Date): Date[] { - // Get first day of month - const firstOfMonth = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1); - + // Get first day of month using DateService + const year = monthDate.getFullYear(); + const month = monthDate.getMonth(); + const firstOfMonth = this.dateService.startOfDay(new Date(year, month, 1)); + // Get Monday of the week containing first day const weekBounds = this.dateService.getWeekBounds(firstOfMonth); const startDate = this.dateService.startOfDay(weekBounds.start); - + // Generate 42 days (6 weeks) const dates: Date[] = []; for (let i = 0; i < 42; i++) { dates.push(this.dateService.addDays(startDate, i)); } - + return dates; } @@ -120,11 +122,17 @@ export class MonthViewStrategy implements ViewStrategy { } getNextPeriod(currentDate: Date): Date { - return new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1); + const nextMonth = this.dateService.addMonths(currentDate, 1); + const year = nextMonth.getFullYear(); + const month = nextMonth.getMonth(); + return this.dateService.startOfDay(new Date(year, month, 1)); } - + getPreviousPeriod(currentDate: Date): Date { - return new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1); + const prevMonth = this.dateService.addMonths(currentDate, -1); + const year = prevMonth.getFullYear(); + const month = prevMonth.getMonth(); + return this.dateService.startOfDay(new Date(year, month, 1)); } getPeriodLabel(date: Date): string { @@ -140,15 +148,17 @@ export class MonthViewStrategy implements ViewStrategy { getPeriodRange(baseDate: Date): { startDate: Date; endDate: Date } { // Month view shows events for the entire month grid (including partial weeks) - const firstOfMonth = new Date(baseDate.getFullYear(), baseDate.getMonth(), 1); - + const year = baseDate.getFullYear(); + const month = baseDate.getMonth(); + const firstOfMonth = this.dateService.startOfDay(new Date(year, month, 1)); + // Get Monday of the week containing first day const weekBounds = this.dateService.getWeekBounds(firstOfMonth); const startDate = this.dateService.startOfDay(weekBounds.start); - + // End date is 41 days after start (42 total days) const endDate = this.dateService.addDays(startDate, 41); - + return { startDate, endDate diff --git a/src/utils/DateService.ts b/src/utils/DateService.ts index 1ccfea8..626a442 100644 --- a/src/utils/DateService.ts +++ b/src/utils/DateService.ts @@ -20,6 +20,7 @@ import { startOfWeek, endOfWeek, addWeeks, + addMonths, isSameDay, getISOWeek } from 'date-fns'; @@ -257,6 +258,16 @@ export class DateService { public addWeeks(date: Date, weeks: number): Date { return addWeeks(date, weeks); } + + /** + * Add months to a date + * @param date - Base date + * @param months - Number of months to add (can be negative) + * @returns New date + */ + public addMonths(date: Date, months: number): Date { + return addMonths(date, months); + } /** * Get ISO week number (1-53) diff --git a/src/utils/PositionUtils.ts b/src/utils/PositionUtils.ts index 218987d..9043b77 100644 --- a/src/utils/PositionUtils.ts +++ b/src/utils/PositionUtils.ts @@ -226,12 +226,7 @@ export class PositionUtils { */ public static timeStringToIso(timeString: string, date: Date = new Date()): string { const totalMinutes = PositionUtils.dateService.timeToMinutes(timeString); - const hours = Math.floor(totalMinutes / 60); - const minutes = totalMinutes % 60; - - const newDate = new Date(date); - newDate.setHours(hours, minutes, 0, 0); - + const newDate = PositionUtils.dateService.createDateAtTime(date, totalMinutes); return newDate.toISOString(); }