Cleans up the codebase by removing unnecessary console log statements. These logs were primarily used for debugging and are no longer needed in the production code. This reduces noise in the console and improves overall performance.
452 lines
No EOL
14 KiB
TypeScript
452 lines
No EOL
14 KiB
TypeScript
import { EventBus } from '../core/EventBus.js';
|
|
import { CoreEvents } from '../constants/CoreEvents.js';
|
|
import { CalendarConfig } from '../core/CalendarConfig.js';
|
|
import { CalendarEvent, CalendarView, IEventBus } from '../types/CalendarTypes.js';
|
|
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';
|
|
import { EventFilterManager } from './EventFilterManager.js';
|
|
|
|
/**
|
|
* CalendarManager - Main coordinator for all calendar managers
|
|
* Uses simple direct method calls instead of complex state management
|
|
*/
|
|
export class CalendarManager {
|
|
private eventBus: IEventBus;
|
|
private config: CalendarConfig;
|
|
private eventManager: EventManager;
|
|
private gridManager: GridManager;
|
|
private eventRenderer: EventRenderingService;
|
|
private scrollManager: ScrollManager;
|
|
private eventFilterManager: EventFilterManager;
|
|
private dateCalculator: DateCalculator;
|
|
private currentView: CalendarView = 'week';
|
|
private currentDate: Date = new Date();
|
|
private isInitialized: boolean = false;
|
|
|
|
constructor(
|
|
eventBus: IEventBus,
|
|
config: CalendarConfig,
|
|
eventManager: EventManager,
|
|
gridManager: GridManager,
|
|
eventRenderer: EventRenderingService,
|
|
scrollManager: ScrollManager
|
|
) {
|
|
this.eventBus = eventBus;
|
|
this.config = config;
|
|
this.eventManager = eventManager;
|
|
this.gridManager = gridManager;
|
|
this.eventRenderer = eventRenderer;
|
|
this.scrollManager = scrollManager;
|
|
this.eventFilterManager = new EventFilterManager();
|
|
this.dateCalculator = new DateCalculator(config);
|
|
this.setupEventListeners();
|
|
}
|
|
|
|
/**
|
|
* Initialize calendar system using simple direct calls
|
|
*/
|
|
public async initialize(): Promise<void> {
|
|
if (this.isInitialized) {
|
|
return;
|
|
}
|
|
|
|
|
|
try {
|
|
// Debug: Check calendar type
|
|
const calendarType = this.config.getCalendarMode();
|
|
|
|
// Step 1: Load data
|
|
await this.eventManager.loadData();
|
|
|
|
// Step 2: Pass data to GridManager and render grid structure
|
|
if (calendarType === 'resource') {
|
|
const resourceData = this.eventManager.getResourceData();
|
|
this.gridManager.setResourceData(resourceData);
|
|
}
|
|
await this.gridManager.render();
|
|
|
|
// Step 2b: Trigger event rendering now that data is loaded
|
|
// Re-emit GRID_RENDERED to trigger EventRendererManager
|
|
const gridContainer = document.querySelector('swp-calendar-container');
|
|
if (gridContainer) {
|
|
const periodRange = this.gridManager.getDisplayDates();
|
|
this.eventBus.emit(CoreEvents.GRID_RENDERED, {
|
|
container: gridContainer,
|
|
currentDate: new Date(),
|
|
startDate: periodRange[0],
|
|
endDate: periodRange[periodRange.length - 1],
|
|
columnCount: periodRange.length
|
|
});
|
|
}
|
|
|
|
// Step 3: Initialize scroll synchronization
|
|
this.scrollManager.initialize();
|
|
|
|
// Step 4: Set initial view and date BEFORE event rendering
|
|
this.setView(this.currentView);
|
|
this.setCurrentDate(this.currentDate);
|
|
|
|
// Step 5: Event rendering will be triggered by GRID_RENDERED event
|
|
|
|
this.isInitialized = true;
|
|
|
|
// Emit initialization complete event
|
|
this.eventBus.emit(CoreEvents.INITIALIZED, {
|
|
currentDate: this.currentDate,
|
|
currentView: this.currentView
|
|
});
|
|
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Skift calendar view (dag/uge/måned)
|
|
*/
|
|
public setView(view: CalendarView): void {
|
|
if (this.currentView === view) {
|
|
return;
|
|
}
|
|
|
|
const previousView = this.currentView;
|
|
this.currentView = view;
|
|
|
|
|
|
// Emit view change event
|
|
this.eventBus.emit(CoreEvents.VIEW_CHANGED, {
|
|
previousView,
|
|
currentView: view,
|
|
date: this.currentDate
|
|
});
|
|
|
|
// Grid re-rendering will trigger event rendering automatically via GRID_RENDERED event
|
|
}
|
|
|
|
/**
|
|
* Sæt aktuel dato
|
|
*/
|
|
public setCurrentDate(date: Date): void {
|
|
// Validate input date
|
|
if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
|
|
return;
|
|
}
|
|
|
|
const previousDate = this.currentDate;
|
|
this.currentDate = new Date(date);
|
|
|
|
// Validate that both dates are valid before logging
|
|
const prevDateStr = previousDate && !isNaN(previousDate.getTime()) ? previousDate.toISOString() : 'Invalid Date';
|
|
const newDateStr = this.currentDate.toISOString();
|
|
|
|
|
|
// Emit date change event
|
|
this.eventBus.emit(CoreEvents.DATE_CHANGED, {
|
|
previousDate,
|
|
currentDate: this.currentDate,
|
|
view: this.currentView
|
|
});
|
|
|
|
// Grid update for new date will trigger event rendering automatically via GRID_RENDERED event
|
|
}
|
|
|
|
/**
|
|
* Naviger til i dag
|
|
*/
|
|
public goToToday(): void {
|
|
this.setCurrentDate(new Date());
|
|
}
|
|
|
|
/**
|
|
* Naviger til næste periode (dag/uge/måned afhængig af view)
|
|
*/
|
|
public goToNext(): void {
|
|
const nextDate = this.calculateNextDate();
|
|
this.setCurrentDate(nextDate);
|
|
}
|
|
|
|
/**
|
|
* Naviger til forrige periode (dag/uge/måned afhængig af view)
|
|
*/
|
|
public goToPrevious(): void {
|
|
const previousDate = this.calculatePreviousDate();
|
|
this.setCurrentDate(previousDate);
|
|
}
|
|
|
|
/**
|
|
* Hent aktuel view
|
|
*/
|
|
public getCurrentView(): CalendarView {
|
|
return this.currentView;
|
|
}
|
|
|
|
/**
|
|
* Hent aktuel dato
|
|
*/
|
|
public getCurrentDate(): Date {
|
|
return new Date(this.currentDate);
|
|
}
|
|
|
|
/**
|
|
* Hent calendar konfiguration
|
|
*/
|
|
public getConfig(): CalendarConfig {
|
|
return this.config;
|
|
}
|
|
|
|
/**
|
|
* Check om calendar er initialiseret
|
|
*/
|
|
public isCalendarInitialized(): boolean {
|
|
return this.isInitialized;
|
|
}
|
|
|
|
/**
|
|
* Get initialization report for debugging
|
|
*/
|
|
public getInitializationReport(): any {
|
|
return {
|
|
isInitialized: this.isInitialized,
|
|
currentView: this.currentView,
|
|
currentDate: this.currentDate,
|
|
initializationTime: 'N/A - simple initialization'
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Genindlæs calendar data
|
|
*/
|
|
public refresh(): void {
|
|
|
|
this.eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
|
view: this.currentView,
|
|
date: this.currentDate
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Ryd calendar og nulstil til standard tilstand
|
|
*/
|
|
public reset(): void {
|
|
|
|
this.currentView = 'week';
|
|
this.currentDate = new Date();
|
|
|
|
this.eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
|
view: this.currentView,
|
|
date: this.currentDate
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Setup event listeners for at håndtere events fra andre managers
|
|
*/
|
|
private setupEventListeners(): void {
|
|
// Listen for workweek changes only
|
|
this.eventBus.on(CoreEvents.WORKWEEK_CHANGED, (event: Event) => {
|
|
const customEvent = event as CustomEvent;
|
|
this.handleWorkweekChange();
|
|
|
|
// Also update week info display since workweek affects date range display
|
|
this.updateWeekInfoForWorkweekChange();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Beregn næste dato baseret på aktuel view
|
|
*/
|
|
private calculateNextDate(): Date {
|
|
const nextDate = new Date(this.currentDate);
|
|
|
|
switch (this.currentView) {
|
|
case 'day':
|
|
nextDate.setDate(nextDate.getDate() + 1);
|
|
break;
|
|
case 'week':
|
|
const workWeekSettings = this.config.getWorkWeekSettings();
|
|
nextDate.setDate(nextDate.getDate() + 7); // Move to next calendar week regardless of work days
|
|
break;
|
|
case 'month':
|
|
nextDate.setMonth(nextDate.getMonth() + 1);
|
|
break;
|
|
}
|
|
|
|
return nextDate;
|
|
}
|
|
|
|
/**
|
|
* Beregn forrige dato baseret på aktuel view
|
|
*/
|
|
private calculatePreviousDate(): Date {
|
|
const previousDate = new Date(this.currentDate);
|
|
|
|
switch (this.currentView) {
|
|
case 'day':
|
|
previousDate.setDate(previousDate.getDate() - 1);
|
|
break;
|
|
case 'week':
|
|
const workWeekSettings = this.config.getWorkWeekSettings();
|
|
previousDate.setDate(previousDate.getDate() - 7); // Move to previous calendar week regardless of work days
|
|
break;
|
|
case 'month':
|
|
previousDate.setMonth(previousDate.getMonth() - 1);
|
|
break;
|
|
}
|
|
|
|
return previousDate;
|
|
}
|
|
|
|
/**
|
|
* Calculate the current period based on view and date
|
|
*/
|
|
private calculateCurrentPeriod(): { start: string; end: string } {
|
|
const current = new Date(this.currentDate);
|
|
|
|
switch (this.currentView) {
|
|
case 'day':
|
|
const dayStart = new Date(current);
|
|
dayStart.setHours(0, 0, 0, 0);
|
|
const dayEnd = new Date(current);
|
|
dayEnd.setHours(23, 59, 59, 999);
|
|
return {
|
|
start: dayStart.toISOString(),
|
|
end: dayEnd.toISOString()
|
|
};
|
|
|
|
case 'week':
|
|
// Find start of week (Monday)
|
|
const weekStart = new Date(current);
|
|
const dayOfWeek = weekStart.getDay();
|
|
const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // Sunday = 0, so 6 days back to Monday
|
|
weekStart.setDate(weekStart.getDate() - daysToMonday);
|
|
weekStart.setHours(0, 0, 0, 0);
|
|
|
|
// Find end of week (Sunday)
|
|
const weekEnd = new Date(weekStart);
|
|
weekEnd.setDate(weekEnd.getDate() + 6);
|
|
weekEnd.setHours(23, 59, 59, 999);
|
|
|
|
return {
|
|
start: weekStart.toISOString(),
|
|
end: weekEnd.toISOString()
|
|
};
|
|
|
|
case 'month':
|
|
const monthStart = new Date(current.getFullYear(), current.getMonth(), 1);
|
|
const monthEnd = new Date(current.getFullYear(), current.getMonth() + 1, 0, 23, 59, 59, 999);
|
|
return {
|
|
start: monthStart.toISOString(),
|
|
end: monthEnd.toISOString()
|
|
};
|
|
|
|
default:
|
|
// Fallback to week view
|
|
const fallbackStart = new Date(current);
|
|
fallbackStart.setDate(fallbackStart.getDate() - 3);
|
|
fallbackStart.setHours(0, 0, 0, 0);
|
|
const fallbackEnd = new Date(current);
|
|
fallbackEnd.setDate(fallbackEnd.getDate() + 3);
|
|
fallbackEnd.setHours(23, 59, 59, 999);
|
|
return {
|
|
start: fallbackStart.toISOString(),
|
|
end: fallbackEnd.toISOString()
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle workweek configuration changes
|
|
*/
|
|
private handleWorkweekChange(): void {
|
|
|
|
// Force a complete grid rebuild by clearing existing structure
|
|
const container = document.querySelector('swp-calendar-container');
|
|
if (container) {
|
|
container.innerHTML = ''; // Clear everything to force full rebuild
|
|
}
|
|
|
|
// Re-render the grid with new workweek settings (will now rebuild everything)
|
|
this.gridManager.render();
|
|
|
|
// Re-initialize scroll manager after grid rebuild
|
|
this.scrollManager.initialize();
|
|
|
|
// Re-render events in the new grid structure
|
|
this.rerenderEvents();
|
|
}
|
|
|
|
/**
|
|
* Re-render events after grid structure changes
|
|
*/
|
|
private rerenderEvents(): void {
|
|
|
|
// Get current period data to determine date range
|
|
const periodData = this.calculateCurrentPeriod();
|
|
|
|
// Find the grid container to render events in
|
|
const container = document.querySelector('swp-calendar-container');
|
|
if (!container) {
|
|
return;
|
|
}
|
|
|
|
// Trigger event rendering for the current date range using correct method
|
|
this.eventRenderer.renderEvents({
|
|
container: container as HTMLElement,
|
|
startDate: new Date(periodData.start),
|
|
endDate: new Date(periodData.end)
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update week info display after workweek changes
|
|
*/
|
|
private updateWeekInfoForWorkweekChange(): void {
|
|
// Don't do anything here - let GRID_RENDERED event handle it
|
|
}
|
|
|
|
/**
|
|
* Update week info based on actual rendered columns
|
|
*/
|
|
private updateWeekInfoFromRenderedColumns(): void {
|
|
|
|
// Get actual dates from rendered columns
|
|
const columns = document.querySelectorAll('swp-day-column');
|
|
if (columns.length === 0) {
|
|
return;
|
|
}
|
|
|
|
// Get first and last column dates
|
|
const firstColumn = columns[0] as HTMLElement;
|
|
const lastColumn = columns[columns.length - 1] as HTMLElement;
|
|
|
|
const firstDateStr = firstColumn.dataset.date;
|
|
const lastDateStr = lastColumn.dataset.date;
|
|
|
|
if (!firstDateStr || !lastDateStr) {
|
|
return;
|
|
}
|
|
|
|
// Parse dates
|
|
const firstDate = new Date(firstDateStr);
|
|
const lastDate = new Date(lastDateStr);
|
|
|
|
// Calculate week number from first date
|
|
const weekNumber = this.dateCalculator.getWeekNumber(firstDate);
|
|
|
|
// Format date range
|
|
const dateRange = this.dateCalculator.formatDateRange(firstDate, lastDate);
|
|
|
|
// Emit week info update
|
|
this.eventBus.emit(CoreEvents.WEEK_CHANGED, {
|
|
weekNumber,
|
|
dateRange,
|
|
weekStart: firstDate,
|
|
weekEnd: lastDate
|
|
});
|
|
}
|
|
|
|
|
|
} |