diff --git a/src/managers/CalendarManager.ts b/src/managers/CalendarManager.ts
index 3fda062..2cf9e20 100644
--- a/src/managers/CalendarManager.ts
+++ b/src/managers/CalendarManager.ts
@@ -6,6 +6,7 @@ import { EventManager } from './EventManager.js';
import { GridManager } from './GridManager.js';
import { EventRenderingService } from '../renderers/EventRendererManager.js';
import { ScrollManager } from './ScrollManager.js';
+import { DateCalculator } from '../utils/DateCalculator.js';
/**
* CalendarManager - Main coordinator for all calendar managers
@@ -18,6 +19,7 @@ export class CalendarManager {
private gridManager: GridManager;
private eventRenderer: EventRenderingService;
private scrollManager: ScrollManager;
+ private dateCalculator: DateCalculator;
private currentView: CalendarView = 'week';
private currentDate: Date = new Date();
private isInitialized: boolean = false;
@@ -36,6 +38,7 @@ export class CalendarManager {
this.gridManager = gridManager;
this.eventRenderer = eventRenderer;
this.scrollManager = scrollManager;
+ this.dateCalculator = new DateCalculator(config);
this.setupEventListeners();
console.log('📋 CalendarManager: Created with proper dependency injection');
}
@@ -428,8 +431,8 @@ export class CalendarManager {
// Trigger event rendering for the current date range using correct method
this.eventRenderer.renderEvents({
container: container as HTMLElement,
- startDate: new Date(periodData.startDate),
- endDate: new Date(periodData.endDate)
+ startDate: new Date(periodData.start),
+ endDate: new Date(periodData.end)
});
}
@@ -471,10 +474,10 @@ export class CalendarManager {
const lastDate = new Date(lastDateStr);
// Calculate week number from first date
- const weekNumber = this.getWeekNumber(firstDate);
+ const weekNumber = this.dateCalculator.getWeekNumber(firstDate);
// Format date range
- const dateRange = this.formatDateRange(firstDate, lastDate);
+ const dateRange = this.dateCalculator.formatDateRange(firstDate, lastDate);
console.log('CalendarManager: Week info from columns:', {
firstDate: firstDateStr,
@@ -492,41 +495,5 @@ export class CalendarManager {
});
}
- /**
- * Helper method to get week number
- */
- private getWeekNumber(date: Date): number {
- const start = new Date(date.getFullYear(), 0, 1);
- const days = Math.floor((date.getTime() - start.getTime()) / (24 * 60 * 60 * 1000));
- return Math.ceil((days + start.getDay() + 1) / 7);
- }
-
- /**
- * Helper method to get week start (Sunday)
- */
- private getWeekStart(date: Date): Date {
- const weekStart = new Date(date);
- weekStart.setDate(date.getDate() - date.getDay());
- return weekStart;
- }
-
- /**
- * Helper method to format date range
- */
- private formatDateRange(start: Date, end: Date): string {
- const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
-
- const startMonth = months[start.getMonth()];
- const endMonth = months[end.getMonth()];
- const startDay = start.getDate();
- const endDay = end.getDate();
- const year = start.getFullYear();
-
- if (startMonth === endMonth) {
- return `${startMonth} ${startDay} - ${endDay}, ${year}`;
- } else {
- return `${startMonth} ${startDay} - ${endMonth} ${endDay}, ${year}`;
- }
- }
}
\ No newline at end of file
diff --git a/src/renderers/ColumnRenderer.ts b/src/renderers/ColumnRenderer.ts
index a6e55f9..19a896e 100644
--- a/src/renderers/ColumnRenderer.ts
+++ b/src/renderers/ColumnRenderer.ts
@@ -2,6 +2,7 @@
import { CalendarConfig } from '../core/CalendarConfig';
import { ResourceCalendarData } from '../types/CalendarTypes';
+import { DateCalculator } from '../utils/DateCalculator';
/**
* Interface for column rendering strategies
@@ -23,10 +24,15 @@ export interface ColumnRenderContext {
* Date-based column renderer (original functionality)
*/
export class DateColumnRenderer implements ColumnRenderer {
+ private dateCalculator: DateCalculator;
+
render(columnContainer: HTMLElement, context: ColumnRenderContext): void {
const { currentWeek, config } = context;
- const dates = this.getWeekDates(currentWeek, config);
+ // Initialize date calculator
+ this.dateCalculator = new DateCalculator(config);
+
+ const dates = this.dateCalculator.getWorkWeekDates(currentWeek);
const dateSettings = config.getDateViewSettings();
const daysToShow = dates.slice(0, dateSettings.weekDays);
@@ -34,7 +40,7 @@ export class DateColumnRenderer implements ColumnRenderer {
daysToShow.forEach((date) => {
const column = document.createElement('swp-day-column');
- (column as any).dataset.date = this.formatDate(date);
+ (column as any).dataset.date = this.dateCalculator.formatISODate(date);
const eventsLayer = document.createElement('swp-events-layer');
column.appendChild(eventsLayer);
@@ -43,26 +49,6 @@ export class DateColumnRenderer implements ColumnRenderer {
});
}
- private getWeekDates(weekStart: Date, config: CalendarConfig): Date[] {
- const dates: Date[] = [];
- const workWeekSettings = config.getWorkWeekSettings();
-
- // Calculate dates based on actual work days (e.g., [1,2,3,4] for Mon-Thu)
- workWeekSettings.workDays.forEach(dayOfWeek => {
- const date = new Date(weekStart);
- // Set to the start of the week (Sunday = 0)
- date.setDate(weekStart.getDate() - weekStart.getDay());
- // Add the specific day of week
- date.setDate(date.getDate() + dayOfWeek);
- dates.push(date);
- });
-
- return dates;
- }
-
- private formatDate(date: Date): string {
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
- }
}
/**
diff --git a/src/renderers/HeaderRenderer.ts b/src/renderers/HeaderRenderer.ts
index cf2d734..95488a0 100644
--- a/src/renderers/HeaderRenderer.ts
+++ b/src/renderers/HeaderRenderer.ts
@@ -2,6 +2,7 @@
import { CalendarConfig } from '../core/CalendarConfig';
import { ResourceCalendarData } from '../types/CalendarTypes';
+import { DateCalculator } from '../utils/DateCalculator';
/**
* Interface for header rendering strategies
@@ -24,17 +25,22 @@ export interface HeaderRenderContext {
* Date-based header renderer (original functionality)
*/
export class DateHeaderRenderer implements HeaderRenderer {
+ private dateCalculator: DateCalculator;
+
render(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
const { currentWeek, config, allDayEvents = [] } = context;
- const dates = this.getWeekDates(currentWeek, config);
+ // Initialize date calculator with config
+ this.dateCalculator = new DateCalculator(config);
+
+ const dates = this.dateCalculator.getWorkWeekDates(currentWeek);
const weekDays = config.get('weekDays');
const daysToShow = dates.slice(0, weekDays);
const workWeekSettings = config.getWorkWeekSettings();
daysToShow.forEach((date, index) => {
const header = document.createElement('swp-day-header');
- if (this.isToday(date)) {
+ if (this.dateCalculator.isToday(date)) {
(header as any).dataset.today = 'true';
}
@@ -42,7 +48,7 @@ export class DateHeaderRenderer implements HeaderRenderer {
${workWeekSettings.dayNames[index]}
${date.getDate()}
`;
- (header as any).dataset.date = this.formatDate(date);
+ (header as any).dataset.date = this.dateCalculator.formatISODate(date);
calendarHeader.appendChild(header);
});
@@ -54,7 +60,7 @@ export class DateHeaderRenderer implements HeaderRenderer {
private renderAllDayEvents(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
const { currentWeek, config, allDayEvents = [] } = context;
- const dates = this.getWeekDates(currentWeek, config);
+ const dates = this.dateCalculator.getWorkWeekDates(currentWeek);
const weekDays = config.get('weekDays');
const daysToShow = dates.slice(0, weekDays);
@@ -68,8 +74,8 @@ export class DateHeaderRenderer implements HeaderRenderer {
let endColumnIndex = -1;
daysToShow.forEach((date, index) => {
- const dateStr = this.formatDate(date);
- const startDateStr = this.formatDate(startDate);
+ const dateStr = this.dateCalculator.formatISODate(date);
+ const startDateStr = this.dateCalculator.formatISODate(startDate);
if (dateStr === startDateStr) {
startColumnIndex = index;
@@ -102,31 +108,6 @@ export class DateHeaderRenderer implements HeaderRenderer {
});
}
- private getWeekDates(weekStart: Date, config: CalendarConfig): Date[] {
- const dates: Date[] = [];
- const workWeekSettings = config.getWorkWeekSettings();
-
- // Calculate dates based on actual work days (e.g., [1,2,3,4] for Mon-Thu)
- workWeekSettings.workDays.forEach(dayOfWeek => {
- const date = new Date(weekStart);
- // Set to the start of the week (Sunday = 0)
- date.setDate(weekStart.getDate() - weekStart.getDay());
- // Add the specific day of week
- date.setDate(date.getDate() + dayOfWeek);
- dates.push(date);
- });
-
- return dates;
- }
-
- private isToday(date: Date): boolean {
- const today = new Date();
- return date.toDateString() === today.toDateString();
- }
-
- private formatDate(date: Date): string {
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
- }
}
diff --git a/src/renderers/NavigationRenderer.ts b/src/renderers/NavigationRenderer.ts
index bc22ce3..0d3f614 100644
--- a/src/renderers/NavigationRenderer.ts
+++ b/src/renderers/NavigationRenderer.ts
@@ -2,6 +2,7 @@ import { IEventBus } from '../types/CalendarTypes';
import { EventTypes } from '../constants/EventTypes';
import { DateUtils } from '../utils/DateUtils';
import { CalendarConfig } from '../core/CalendarConfig';
+import { DateCalculator } from '../utils/DateCalculator';
/**
* NavigationRenderer - Handles DOM rendering for navigation containers
@@ -10,10 +11,12 @@ import { CalendarConfig } from '../core/CalendarConfig';
export class NavigationRenderer {
private eventBus: IEventBus;
private config: CalendarConfig;
+ private dateCalculator: DateCalculator;
constructor(eventBus: IEventBus, config: CalendarConfig) {
this.eventBus = eventBus;
this.config = config;
+ this.dateCalculator = new DateCalculator(config);
this.setupEventListeners();
}
@@ -99,17 +102,14 @@ export class NavigationRenderer {
header.innerHTML = '';
dayColumns.innerHTML = '';
- // Render headers for target week
+ // Get dates using DateCalculator
+ const dates = this.dateCalculator.getWorkWeekDates(weekStart);
const workWeekSettings = this.config.getWorkWeekSettings();
- workWeekSettings.workDays.forEach((dayOfWeek, i) => {
- const date = new Date(weekStart);
- // Set to the start of the week (Sunday = 0)
- date.setDate(weekStart.getDate() - weekStart.getDay());
- // Add the specific day of week
- date.setDate(date.getDate() + dayOfWeek);
-
+
+ // Render headers for target week
+ dates.forEach((date, i) => {
const headerElement = document.createElement('swp-day-header');
- if (this.isToday(date)) {
+ if (this.dateCalculator.isToday(date)) {
headerElement.dataset.today = 'true';
}
@@ -117,20 +117,15 @@ export class NavigationRenderer {
${workWeekSettings.dayNames[i]}
${date.getDate()}
`;
- headerElement.dataset.date = this.formatDate(date);
+ headerElement.dataset.date = this.dateCalculator.formatISODate(date);
header.appendChild(headerElement);
});
// Render day columns for target week
- workWeekSettings.workDays.forEach(dayOfWeek => {
+ dates.forEach(date => {
const column = document.createElement('swp-day-column');
- const date = new Date(weekStart);
- // Set to the start of the week (Sunday = 0)
- date.setDate(weekStart.getDate() - weekStart.getDay());
- // Add the specific day of week
- date.setDate(date.getDate() + dayOfWeek);
- column.dataset.date = this.formatDate(date);
+ column.dataset.date = this.dateCalculator.formatISODate(date);
const eventsLayer = document.createElement('swp-events-layer');
column.appendChild(eventsLayer);
@@ -139,18 +134,4 @@ export class NavigationRenderer {
});
}
- /**
- * Utility method to format date
- */
- private formatDate(date: Date): string {
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
- }
-
- /**
- * Check if date is today
- */
- private isToday(date: Date): boolean {
- const today = new Date();
- return date.toDateString() === today.toDateString();
- }
}
\ No newline at end of file
diff --git a/src/utils/DateCalculator.ts b/src/utils/DateCalculator.ts
new file mode 100644
index 0000000..3ca32f5
--- /dev/null
+++ b/src/utils/DateCalculator.ts
@@ -0,0 +1,194 @@
+/**
+ * DateCalculator - Centralized date calculation logic for calendar
+ * Handles all date computations with proper week start handling
+ */
+
+import { CalendarConfig } from '../core/CalendarConfig';
+
+export class DateCalculator {
+ private config: CalendarConfig;
+
+ constructor(config: CalendarConfig) {
+ this.config = config;
+ }
+
+ /**
+ * Get dates for work week based on week start and work days configuration
+ * @param weekStart - The start date of the week (could be Sunday or Monday)
+ * @returns Array of dates for the configured work days
+ */
+ getWorkWeekDates(weekStart: Date): Date[] {
+ const dates: Date[] = [];
+ const workWeekSettings = this.config.getWorkWeekSettings();
+ const dateSettings = this.config.getDateViewSettings();
+ const firstDayOfWeek = dateSettings.firstDayOfWeek; // 0=Sunday, 1=Monday
+
+ // Get the actual start of the week based on configuration
+ const actualWeekStart = this.getWeekStart(weekStart, firstDayOfWeek);
+
+ // Calculate dates for each work day
+ workWeekSettings.workDays.forEach(dayOfWeek => {
+ const date = new Date(actualWeekStart);
+
+ if (firstDayOfWeek === 1 && dayOfWeek === 0) {
+ // For Monday-based weeks, Sunday is at the end (day 7)
+ date.setDate(actualWeekStart.getDate() + 7);
+ } else {
+ // Normal calculation
+ date.setDate(actualWeekStart.getDate() + dayOfWeek);
+ }
+
+ dates.push(date);
+ });
+
+ return dates;
+ }
+
+ /**
+ * Get the start of the week for a given date
+ * @param date - Any date in the week
+ * @param firstDayOfWeek - 0 for Sunday, 1 for Monday
+ * @returns The start date of the week
+ */
+ getWeekStart(date: Date, firstDayOfWeek: number = 1): Date {
+ const weekStart = new Date(date);
+ const currentDay = weekStart.getDay();
+
+ if (firstDayOfWeek === 1) {
+ // Monday as first day
+ const daysToSubtract = currentDay === 0 ? 6 : currentDay - 1;
+ weekStart.setDate(weekStart.getDate() - daysToSubtract);
+ } else {
+ // Sunday as first day
+ weekStart.setDate(weekStart.getDate() - currentDay);
+ }
+
+ weekStart.setHours(0, 0, 0, 0);
+ return weekStart;
+ }
+
+ /**
+ * Get the end of the week for a given date
+ * @param date - Any date in the week
+ * @param firstDayOfWeek - 0 for Sunday, 1 for Monday
+ * @returns The end date of the week
+ */
+ getWeekEnd(date: Date, firstDayOfWeek: number = 1): Date {
+ const weekStart = this.getWeekStart(date, firstDayOfWeek);
+ const weekEnd = new Date(weekStart);
+ weekEnd.setDate(weekStart.getDate() + 6);
+ weekEnd.setHours(23, 59, 59, 999);
+ return weekEnd;
+ }
+
+ /**
+ * Get week number for a date (ISO 8601)
+ * @param date - The date to get week number for
+ * @returns Week number (1-53)
+ */
+ getWeekNumber(date: Date): number {
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
+ const dayNum = d.getUTCDay() || 7;
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
+ return Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1)/7);
+ }
+
+ /**
+ * Format a date range for display
+ * @param start - Start date
+ * @param end - End date
+ * @returns Formatted date range string
+ */
+ formatDateRange(start: Date, end: Date): string {
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+
+ const startMonth = months[start.getMonth()];
+ const endMonth = months[end.getMonth()];
+ const startDay = start.getDate();
+ const endDay = end.getDate();
+ const startYear = start.getFullYear();
+ const endYear = end.getFullYear();
+
+ if (startYear !== endYear) {
+ return `${startMonth} ${startDay}, ${startYear} - ${endMonth} ${endDay}, ${endYear}`;
+ } else if (startMonth === endMonth) {
+ return `${startMonth} ${startDay} - ${endDay}, ${startYear}`;
+ } else {
+ return `${startMonth} ${startDay} - ${endMonth} ${endDay}, ${startYear}`;
+ }
+ }
+
+ /**
+ * Format a date to ISO date string (YYYY-MM-DD)
+ * @param date - Date to format
+ * @returns ISO date string
+ */
+ formatISODate(date: Date): string {
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
+ }
+
+ /**
+ * Check if a date is today
+ * @param date - Date to check
+ * @returns True if the date is today
+ */
+ isToday(date: Date): boolean {
+ const today = new Date();
+ return date.toDateString() === today.toDateString();
+ }
+
+ /**
+ * Add days to a date
+ * @param date - Base date
+ * @param days - Number of days to add (can be negative)
+ * @returns New date
+ */
+ addDays(date: Date, days: number): Date {
+ const result = new Date(date);
+ result.setDate(result.getDate() + days);
+ return result;
+ }
+
+ /**
+ * Add weeks to a date
+ * @param date - Base date
+ * @param weeks - Number of weeks to add (can be negative)
+ * @returns New date
+ */
+ addWeeks(date: Date, weeks: number): Date {
+ return this.addDays(date, weeks * 7);
+ }
+
+ /**
+ * Get all dates in a week
+ * @param weekStart - Start of the week
+ * @returns Array of 7 dates for the full week
+ */
+ getFullWeekDates(weekStart: Date): Date[] {
+ const dates: Date[] = [];
+ for (let i = 0; i < 7; i++) {
+ dates.push(this.addDays(weekStart, i));
+ }
+ return dates;
+ }
+
+ /**
+ * Get the day name for a date
+ * @param date - Date to get day name for
+ * @param format - 'short' or 'long'
+ * @returns Day name
+ */
+ getDayName(date: Date, format: 'short' | 'long' = 'short'): string {
+ const days = {
+ short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
+ long: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
+ };
+ return days[format][date.getDay()];
+ }
+}
+
+// Create singleton instance with config
+export function createDateCalculator(config: CalendarConfig): DateCalculator {
+ return new DateCalculator(config);
+}
\ No newline at end of file