import { EventBus } from '../core/EventBus'; import { IEventBus, CalendarEvent, ResourceCalendarData } from '../types/CalendarTypes'; import { EventTypes } from '../constants/EventTypes'; import { StateEvents } from '../types/CalendarState'; import { calendarConfig } from '../core/CalendarConfig'; /** * EventManager - Administrerer event lifecycle og CRUD operationer * Håndterer mock data og event synchronization */ export class EventManager { private eventBus: IEventBus; private events: CalendarEvent[] = []; constructor(eventBus: IEventBus) { console.log('EventManager: Constructor called'); this.eventBus = eventBus; this.setupEventListeners(); console.log('EventManager: Waiting for CALENDAR_INITIALIZED before loading data'); } private setupEventListeners(): void { // NOTE: Removed POC event listener to prevent interference with production code // POC sliding animation should not trigger separate event rendering // this.eventBus.on(EventTypes.WEEK_CONTENT_RENDERED, ...); } /** * Public method to load data - called directly by CalendarManager */ public async loadData(): Promise { console.log('EventManager: Loading data via direct call'); await this.loadMockData(); console.log(`EventManager: Data loaded successfully - ${this.events.length} events`); // Debug: Log first few events if (this.events.length > 0) { console.log('EventManager: First event:', { title: this.events[0].title, start: this.events[0].start, end: this.events[0].end }); } } private async loadMockData(): Promise { try { const calendarType = calendarConfig.getCalendarMode(); let jsonFile: string; console.log(`EventManager: Calendar type detected: '${calendarType}'`); if (calendarType === 'resource') { jsonFile = '/src/data/mock-resource-events.json'; } else { jsonFile = '/src/data/mock-events.json'; } console.log(`EventManager: Loading ${calendarType} calendar data from ${jsonFile}`); const response = await fetch(jsonFile); if (!response.ok) { throw new Error(`Failed to load mock events: ${response.status}`); } const data = await response.json(); console.log(`EventManager: Loaded data for ${calendarType} calendar`); // Store raw data for GridManager this.rawData = data; // Process data for internal use this.processCalendarData(calendarType, data); } catch (error) { console.error('EventManager: Failed to load mock events:', error); this.events = []; // Fallback to empty array } } private processCalendarData(calendarType: string, data: any): void { if (calendarType === 'resource') { const resourceData = data as ResourceCalendarData; this.events = resourceData.resources.flatMap(resource => resource.events.map(event => ({ ...event, resourceName: resource.name, resourceDisplayName: resource.displayName, resourceEmployeeId: resource.employeeId })) ); console.log(`EventManager: Processed ${this.events.length} events from ${resourceData.resources.length} resources`); } else { this.events = data as CalendarEvent[]; console.log(`EventManager: Processed ${this.events.length} date events`); } } private syncEvents(): void { // Events are now synced via StateEvents.DATA_LOADED during initialization // This method maintained for internal state management only console.log(`EventManager: Internal sync - ${this.events.length} events in memory`); } public getEvents(): CalendarEvent[] { return [...this.events]; } /** * Get raw resource data for resource calendar mode */ public getResourceData(): any { return this.rawData; } private rawData: any = null; public getEventById(id: string): CalendarEvent | undefined { return this.events.find(event => event.id === id); } public addEvent(event: Omit): CalendarEvent { const newEvent: CalendarEvent = { ...event, id: Date.now().toString() }; this.events.push(newEvent); this.syncEvents(); this.eventBus.emit(EventTypes.EVENT_CREATED, { event: newEvent }); return newEvent; } public updateEvent(id: string, updates: Partial): CalendarEvent | null { const eventIndex = this.events.findIndex(event => event.id === id); if (eventIndex === -1) return null; const updatedEvent = { ...this.events[eventIndex], ...updates }; this.events[eventIndex] = updatedEvent; this.syncEvents(); this.eventBus.emit(EventTypes.EVENT_UPDATED, { event: updatedEvent }); return updatedEvent; } public deleteEvent(id: string): boolean { const eventIndex = this.events.findIndex(event => event.id === id); if (eventIndex === -1) return false; const deletedEvent = this.events[eventIndex]; this.events.splice(eventIndex, 1); this.syncEvents(); this.eventBus.emit(EventTypes.EVENT_DELETED, { event: deletedEvent }); return true; } public refresh(): void { this.syncEvents(); } /** * Load events for a specific week into a container (POC-style) */ private loadEventsForWeek(weekStart: Date, weekEnd: Date, container: HTMLElement): void { console.log(`EventManager: Loading events for week ${weekStart.toDateString()} - ${weekEnd.toDateString()}`); // Filter events for this week const weekEvents = this.events.filter(event => { const eventDate = new Date(event.start); return eventDate >= weekStart && eventDate <= weekEnd; }); console.log(`EventManager: Found ${weekEvents.length} events for this week`); // Render events in the container (POC approach) this.renderEventsInContainer(weekEvents, container); } /** * Render events in a specific container (POC-style) */ private renderEventsInContainer(events: CalendarEvent[], container: HTMLElement): void { const dayColumns = container.querySelectorAll('swp-day-column'); events.forEach(event => { const eventDate = new Date(event.start); const dayOfWeek = eventDate.getDay(); // 0 = Sunday const column = dayColumns[dayOfWeek]; if (column) { const eventsLayer = column.querySelector('swp-events-layer'); if (eventsLayer) { this.renderEventInColumn(event, eventsLayer as HTMLElement); } } }); } /** * Render a single event in a column (POC-style) */ private renderEventInColumn(event: CalendarEvent, eventsLayer: HTMLElement): void { const eventElement = document.createElement('swp-event'); eventElement.dataset.type = event.type || 'meeting'; // Calculate position (simplified - assumes 7 AM start like POC) const startTime = new Date(event.start); const hours = startTime.getHours(); const minutes = startTime.getMinutes(); const startMinutes = (hours - 7) * 60 + minutes; // 7 is start hour like POC // Calculate duration const endTime = new Date(event.end); const durationMs = endTime.getTime() - startTime.getTime(); const durationMinutes = Math.floor(durationMs / (1000 * 60)); eventElement.style.top = `${startMinutes}px`; eventElement.style.height = `${durationMinutes}px`; eventElement.innerHTML = ` ${this.formatTime(hours, minutes)} ${event.title} `; eventsLayer.appendChild(eventElement); } /** * Format time for display (POC-style) */ private formatTime(hours: number, minutes: number): string { const period = hours >= 12 ? 'PM' : 'AM'; const displayHours = hours % 12 || 12; return `${displayHours}:${String(minutes).padStart(2, '0')} ${period}`; } public destroy(): void { this.events = []; } }