Calendar/src/managers/EventManager.ts
2025-11-03 21:30:50 +01:00

157 lines
4.7 KiB
TypeScript

import { IEventBus, ICalendarEvent } from '../types/CalendarTypes';
import { CoreEvents } from '../constants/CoreEvents';
import { Configuration } from '../configuration/CalendarConfig';
import { DateService } from '../utils/DateService';
import { IEventRepository } from '../repositories/IEventRepository';
/**
* EventManager - Event lifecycle and CRUD operations
* Handles event management and CRUD operations
*/
export class EventManager {
private events: ICalendarEvent[] = [];
private dateService: DateService;
private config: Configuration;
private repository: IEventRepository;
constructor(
private eventBus: IEventBus,
dateService: DateService,
config: Configuration,
repository: IEventRepository
) {
this.dateService = dateService;
this.config = config;
this.repository = repository;
}
/**
* Load event data from repository
*/
public async loadData(): Promise<void> {
try {
this.events = await this.repository.loadEvents();
} catch (error) {
console.error('Failed to load event data:', error);
this.events = [];
throw error;
}
}
/**
* Get events with optional copying for performance
*/
public getEvents(copy: boolean = false): ICalendarEvent[] {
return copy ? [...this.events] : this.events;
}
/**
* Optimized event lookup with early return
*/
public getEventById(id: string): ICalendarEvent | undefined {
// Use find for better performance than filter + first
return this.events.find(event => event.id === id);
}
/**
* Get event by ID and return event info for navigation
* @param id Event ID to find
* @returns Event with navigation info or null if not found
*/
public getEventForNavigation(id: string): { event: ICalendarEvent; eventDate: Date } | null {
const event = this.getEventById(id);
if (!event) {
return null;
}
// Validate event dates
const validation = this.dateService.validateDate(event.start);
if (!validation.valid) {
console.warn(`EventManager: Invalid event start date for event ${id}:`, validation.error);
return null;
}
// Validate date range
if (!this.dateService.isValidRange(event.start, event.end)) {
console.warn(`EventManager: Invalid date range for event ${id}: start must be before end`);
return null;
}
return {
event,
eventDate: event.start
};
}
/**
* Navigate to specific event by ID
* Emits navigation events for other managers to handle
* @param eventId Event ID to navigate to
* @returns true if event found and navigation initiated, false otherwise
*/
public navigateToEvent(eventId: string): boolean {
const eventInfo = this.getEventForNavigation(eventId);
if (!eventInfo) {
console.warn(`EventManager: Event with ID ${eventId} not found`);
return false;
}
const { event, eventDate } = eventInfo;
// Emit navigation request event
this.eventBus.emit(CoreEvents.NAVIGATE_TO_EVENT, {
eventId,
event,
eventDate,
eventStartTime: event.start
});
return true;
}
/**
* Get events that overlap with a given time period
*/
public getEventsForPeriod(startDate: Date, endDate: Date): ICalendarEvent[] {
// Event overlaps period if it starts before period ends AND ends after period starts
return this.events.filter(event => {
return event.start <= endDate && event.end >= startDate;
});
}
/**
* Create a new event and add it to the calendar
*/
public addEvent(event: Omit<ICalendarEvent, 'id'>): ICalendarEvent {
const newEvent: ICalendarEvent = {
...event,
id: `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
};
this.events.push(newEvent);
this.eventBus.emit(CoreEvents.EVENT_CREATED, {
event: newEvent
});
return newEvent;
}
/**
* Update an existing event
*/
public updateEvent(id: string, updates: Partial<ICalendarEvent>): ICalendarEvent | 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.eventBus.emit(CoreEvents.EVENT_UPDATED, {
event: updatedEvent
});
return updatedEvent;
}
}