import { EventBus } from '../core/EventBus'; import { IEventBus, CalendarEvent, RenderContext } from '../types/CalendarTypes'; import { CoreEvents } from '../constants/CoreEvents'; import { calendarConfig } from '../core/CalendarConfig'; import { CalendarTypeFactory } from '../factories/CalendarTypeFactory'; import { EventManager } from '../managers/EventManager'; import { EventRendererStrategy } from './EventRenderer'; /** * EventRenderingService - Render events i DOM med positionering using Strategy Pattern * Håndterer event positioning og overlap detection */ export class EventRenderingService { 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(` 📅 Getting events for ${context.startDate.toDateString()} - ${context.endDate.toDateString()}`); // Clear existing events in the specific container first this.strategy.clearEvents(context.container); console.log(` 🧹 Cleared existing events in container`); // Get events from EventManager for the period const events = this.eventManager.getEventsForPeriod( context.startDate, context.endDate ); console.log(` 📊 Found ${events.length} events for period`); if (events.length === 0) { console.log(' ⚠️ 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(` ✅ Rendered ${events.length} events successfully`); // Emit EVENTS_RENDERED event for filtering system this.eventBus.emit(CoreEvents.EVENTS_RENDERED, { events: events, container: context.container }); } private setupEventListeners(): void { // Event-driven rendering: React to grid and container events this.eventBus.on(CoreEvents.GRID_RENDERED, (event: Event) => { console.log('EventRenderer: Received GRID_RENDERED event'); this.handleGridRendered(event as CustomEvent); }); // CONTAINER_READY_FOR_EVENTS removed - events are now pre-rendered synchronously // 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(CoreEvents.VIEW_CHANGED, (event: Event) => { console.log('EventRenderer: Received VIEW_CHANGED event'); this.handleViewChanged(event as CustomEvent); }); } /** * Handle GRID_RENDERED event - render events in the current grid */ private handleGridRendered(event: CustomEvent): void { const { container, startDate, endDate, currentDate } = event.detail; if (!container) { console.error('EventRenderer: No container in GRID_RENDERED event', event.detail); return; } let periodStart: Date; let periodEnd: Date; if (startDate && endDate) { // Direct date format - use as provided periodStart = startDate; periodEnd = endDate; } else if (currentDate) { console.error('EventRenderer: GRID_RENDERED events must include explicit startDate and endDate', event.detail); return; } else { console.error('EventRenderer: No date information in GRID_RENDERED event', event.detail); return; } 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(); } }