import { EventBus } from '../core/EventBus'; import { IEventBus, CalendarEvent, RenderContext } from '../types/CalendarTypes'; import { EventTypes } from '../constants/EventTypes'; import { StateEvents } from '../types/CalendarState'; import { calendarConfig } from '../core/CalendarConfig'; import { CalendarTypeFactory } from '../factories/CalendarTypeFactory'; import { EventManager } from './EventManager'; import { EventRendererStrategy } from '../renderers/EventRenderer'; /** * EventRenderer - Render events i DOM med positionering using Strategy Pattern * Håndterer event positioning og overlap detection */ export class EventRenderer { private eventBus: IEventBus; private eventManager: EventManager; private strategy: EventRendererStrategy; constructor(eventBus: IEventBus, eventManager: EventManager) { this.eventBus = eventBus; this.eventManager = eventManager; // Cache strategy at initialization const calendarType = calendarConfig.getCalendarMode(); this.strategy = CalendarTypeFactory.getEventRenderer(calendarType); this.setupEventListeners(); } /** * Render events in a specific container for a given period */ public renderEvents(context: RenderContext): void { console.log('EventRenderer: Rendering events for period', { startDate: context.startDate, endDate: context.endDate, container: context.container }); // Get events from EventManager for the period const events = this.eventManager.getEventsForPeriod( context.startDate, context.endDate ); console.log(`EventRenderer: Found ${events.length} events for period`); if (events.length === 0) { console.log('EventRenderer: No events to render for this period'); return; } // Use cached strategy to render events in the specific container this.strategy.renderEvents(events, context.container, calendarConfig); console.log(`EventRenderer: Successfully rendered ${events.length} events`); } private setupEventListeners(): void { // Event-driven rendering: React to grid and container events this.eventBus.on(EventTypes.GRID_RENDERED, (event: Event) => { console.log('EventRenderer: Received GRID_RENDERED event'); this.handleGridRendered(event as CustomEvent); }); this.eventBus.on(EventTypes.CONTAINER_READY_FOR_EVENTS, (event: Event) => { console.log('EventRenderer: Received CONTAINER_READY_FOR_EVENTS event'); this.handleContainerReady(event as CustomEvent); }); this.eventBus.on(EventTypes.VIEW_CHANGED, (event: Event) => { console.log('EventRenderer: Received VIEW_CHANGED event'); this.handleViewChanged(event as CustomEvent); }); // Handle calendar type changes - update cached strategy this.eventBus.on(EventTypes.CALENDAR_TYPE_CHANGED, () => { const calendarType = calendarConfig.getCalendarMode(); this.strategy = CalendarTypeFactory.getEventRenderer(calendarType); console.log(`EventRenderer: Updated strategy to ${calendarType}`); }); } /** * Handle GRID_RENDERED event - render events in the current grid */ private handleGridRendered(event: CustomEvent): void { const { container, startDate, endDate } = event.detail; if (!container) { console.error('EventRenderer: No container in GRID_RENDERED event', event.detail); return; } // Use period from event or fallback to calculated period const periodStart = startDate; const periodEnd = endDate; this.renderEvents({ container: container, startDate: periodStart, endDate: periodEnd }); } /** * Handle CONTAINER_READY_FOR_EVENTS event - render events in pre-rendered container */ private handleContainerReady(event: CustomEvent): void { const { container, startDate, endDate } = event.detail; if (!container || !startDate || !endDate) { console.error('EventRenderer: Invalid CONTAINER_READY_FOR_EVENTS event data', event.detail); return; } this.renderEvents({ container: container, startDate: new Date(startDate), endDate: new Date(endDate) }); } /** * Handle VIEW_CHANGED event - clear and re-render for new view */ private handleViewChanged(event: CustomEvent): void { // Clear all existing events since view structure may have changed this.clearEvents(); // New rendering will be triggered by subsequent GRID_RENDERED event console.log('EventRenderer: Cleared events for view change, waiting for GRID_RENDERED'); } private clearEvents(container?: HTMLElement): void { console.log(`EventRenderer: Clearing events`, container ? 'in container' : 'globally'); this.strategy.clearEvents(container); } public refresh(container?: HTMLElement): void { // Clear events in specific container or globally this.clearEvents(container); } public destroy(): void { this.clearEvents(); } }