import { EventBus } from '../core/EventBus'; import { IEventBus, CalendarEvent } from '../types/CalendarTypes'; import { EventTypes } from '../constants/EventTypes'; import { StateEvents } from '../types/CalendarState'; import { calendarConfig } from '../core/CalendarConfig'; import { CalendarTypeFactory } from '../factories/CalendarTypeFactory'; /** * EventRenderer - Render events i DOM med positionering using Strategy Pattern * Håndterer event positioning og overlap detection */ export class EventRenderer { private eventBus: IEventBus; private pendingEvents: CalendarEvent[] = []; private dataReady: boolean = false; private gridReady: boolean = false; constructor(eventBus: IEventBus) { this.eventBus = eventBus; this.setupEventListeners(); } private setupEventListeners(): void { // Listen for state-driven data loaded event this.eventBus.on(StateEvents.DATA_LOADED, (event: Event) => { const customEvent = event as CustomEvent; // Events are in customEvent.detail (direct from StateEvent payload) const eventCount = customEvent.detail.data?.eventCount || 0; const events = customEvent.detail.data?.events || []; console.log('EventRenderer: Received DATA_LOADED with', eventCount, 'events'); this.pendingEvents = events; // Store the actual events this.dataReady = true; this.tryRenderEvents(); }); // Listen for state-driven grid rendered event this.eventBus.on(StateEvents.GRID_RENDERED, (event: Event) => { const customEvent = event as CustomEvent; console.log('EventRenderer: Received GRID_RENDERED'); this.gridReady = true; this.tryRenderEvents(); }); this.eventBus.on(EventTypes.VIEW_RENDERED, () => { // Clear existing events when view changes this.clearEvents(); }); // Handle calendar type changes this.eventBus.on(EventTypes.CALENDAR_TYPE_CHANGED, () => { // Re-render events with new strategy this.tryRenderEvents(); }); } private tryRenderEvents(): void { // Only render if we have both data and grid ready console.log('EventRenderer: tryRenderEvents called', { dataReady: this.dataReady, gridReady: this.gridReady, pendingEvents: this.pendingEvents.length }); if (!this.dataReady || !this.gridReady) { console.log('EventRenderer: Waiting - data ready:', this.dataReady, 'grid ready:', this.gridReady); return; } if (this.pendingEvents.length > 0) { const calendarType = calendarConfig.getCalendarMode(); let columnsSelector = calendarType === 'resource' ? 'swp-resource-column' : 'swp-day-column'; const columns = document.querySelectorAll(columnsSelector); console.log(`EventRenderer: Found ${columns.length} ${columnsSelector} elements for ${calendarType} calendar`); if (columns.length > 0) { console.log('🎨 EventRenderer: Both data and grid ready, rendering events!'); const eventCount = this.pendingEvents.length; this.renderEvents(this.pendingEvents); this.pendingEvents = []; // Clear pending events after rendering // Emit events rendered event this.eventBus.emit(StateEvents.EVENTS_RENDERED, { type: StateEvents.EVENTS_RENDERED, component: 'EventRenderer', timestamp: Date.now(), data: { eventCount, calendarMode: calendarType, renderMethod: 'state-driven' }, metadata: { phase: 'event-rendering' } }); } else { console.log('EventRenderer: Grid not ready yet, columns not found'); } } else { console.log('EventRenderer: No pending events to render'); } } private renderEvents(events: CalendarEvent[]): void { console.log('EventRenderer: renderEvents called with', events.length, 'events'); // Get the appropriate event renderer strategy const calendarType = calendarConfig.getCalendarMode(); const eventRenderer = CalendarTypeFactory.getEventRenderer(calendarType); console.log(`EventRenderer: Using ${calendarType} event renderer strategy`); // Use strategy to render events eventRenderer.renderEvents(events, calendarConfig); // Emit event rendered this.eventBus.emit(EventTypes.EVENT_RENDERED, { count: events.filter(e => !e.allDay).length }); } private clearEvents(): void { const calendarType = calendarConfig.getCalendarMode(); const eventRenderer = CalendarTypeFactory.getEventRenderer(calendarType); eventRenderer.clearEvents(); } public refresh(): void { this.tryRenderEvents(); } public destroy(): void { this.pendingEvents = []; this.clearEvents(); } }