Calendar/src/managers/CalendarManager.ts
Janus C. H. Knudsen d3f4667b61 Adds dynamic CSS grid column management
Updates ConfigManager to dynamically set CSS grid columns based on work week settings

Ensures the grid layout accurately reflects the number of visible days in the calendar view
Automatically updates grid columns when work week configuration changes

Improves responsive design and layout flexibility
2025-11-03 22:52:48 +01:00

233 lines
7.3 KiB
TypeScript

import { CoreEvents } from '../constants/CoreEvents';
import { Configuration } from '../configurations/CalendarConfig';
import { CalendarView, IEventBus } from '../types/CalendarTypes';
import { EventManager } from './EventManager';
import { GridManager } from './GridManager';
import { EventRenderingService } from '../renderers/EventRendererManager';
import { ScrollManager } from './ScrollManager';
/**
* CalendarManager - Main coordinator for all calendar managers
*/
export class CalendarManager {
private eventBus: IEventBus;
private eventManager: EventManager;
private gridManager: GridManager;
private eventRenderer: EventRenderingService;
private scrollManager: ScrollManager;
private config: Configuration;
private currentView: CalendarView = 'week';
private currentDate: Date = new Date();
private isInitialized: boolean = false;
constructor(
eventBus: IEventBus,
eventManager: EventManager,
gridManager: GridManager,
eventRenderingService: EventRenderingService,
scrollManager: ScrollManager,
config: Configuration
) {
this.eventBus = eventBus;
this.eventManager = eventManager;
this.gridManager = gridManager;
this.eventRenderer = eventRenderingService;
this.scrollManager = scrollManager;
this.config = config;
this.setupEventListeners();
}
/**
* Initialize calendar system using simple direct calls
*/
public async initialize(): Promise<void> {
if (this.isInitialized) {
return;
}
try {
// Step 1: Load data
await this.eventManager.loadData();
// Step 2: Render grid structure
await this.gridManager.render();
this.scrollManager.initialize();
this.setView(this.currentView);
this.setCurrentDate(this.currentDate);
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
});
}
/**
* Sæt aktuel dato
*/
public setCurrentDate(date: Date): void {
const previousDate = this.currentDate;
this.currentDate = new Date(date);
// Emit date change event
this.eventBus.emit(CoreEvents.DATE_CHANGED, {
previousDate,
currentDate: this.currentDate,
view: this.currentView
});
}
/**
* 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();
});
}
/**
* 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();
// Notify HeaderManager with correct current date after grid rebuild
this.eventBus.emit('workweek:header-update', {
currentDate: this.currentDate,
currentView: this.currentView,
workweek: this.config.currentWorkWeek
});
}
/**
* 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)
});
}
}