import { eventBus } from '../core/EventBus'; import { calendarConfig } from '../core/CalendarConfig'; import { CalendarTypeFactory } from '../factories/CalendarTypeFactory'; import { CoreEvents } from '../constants/CoreEvents'; import { HeaderRenderContext } from '../renderers/HeaderRenderer'; import { ResourceCalendarData } from '../types/CalendarTypes'; import { DragMouseEnterHeaderEventPayload, DragMouseLeaveHeaderEventPayload, HeaderReadyEventPayload } from '../types/EventTypes'; import { DateCalculator } from '../utils/DateCalculator'; /** * HeaderManager - Handles all header-related event logic * Separates event handling from rendering concerns */ export class HeaderManager { // Event listeners for drag events private dragMouseEnterHeaderListener: ((event: Event) => void) | null = null; private dragMouseLeaveHeaderListener: ((event: Event) => void) | null = null; constructor() { // Bind methods for event listeners this.setupHeaderDragListeners = this.setupHeaderDragListeners.bind(this); this.destroy = this.destroy.bind(this); // Listen for navigation events to update header this.setupNavigationListener(); } /** * Initialize header with initial date */ public initializeHeader(currentDate: Date, resourceData: ResourceCalendarData | null = null): void { this.updateHeader(currentDate, resourceData); } /** * Get cached calendar header element */ private getCalendarHeader(): HTMLElement | null { return document.querySelector('swp-calendar-header'); } /** * Setup header drag event listeners - REFACTORED to listen to DragDropManager events */ public setupHeaderDragListeners(): void { console.log('🎯 HeaderManager: Setting up drag event listeners'); // Create and store event listeners this.dragMouseEnterHeaderListener = (event: Event) => { const { targetColumn: targetDate, mousePosition, originalElement, draggedClone: cloneElement } = (event as CustomEvent).detail; console.log('🎯 HeaderManager: Received drag:mouseenter-header', { targetDate, originalElement: !!originalElement, cloneElement: !!cloneElement }); if (targetDate) { const calendarType = calendarConfig.getCalendarMode(); const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType); } }; this.dragMouseLeaveHeaderListener = (event: Event) => { const { targetDate, mousePosition, originalElement, draggedClone: cloneElement } = (event as CustomEvent).detail; console.log('🚪 HeaderManager: Received drag:mouseleave-header', { targetDate, originalElement: !!originalElement, cloneElement: !!cloneElement }); eventBus.emit('header:mouseleave', { element: this.getCalendarHeader(), targetDate, originalElement, cloneElement }); }; // Listen for drag events from DragDropManager eventBus.on('drag:mouseenter-header', this.dragMouseEnterHeaderListener); eventBus.on('drag:mouseleave-header', this.dragMouseLeaveHeaderListener); console.log('✅ HeaderManager: Drag event listeners attached'); } /** * Setup navigation event listener */ private setupNavigationListener(): void { eventBus.on(CoreEvents.NAVIGATION_COMPLETED, (event) => { const { currentDate, resourceData } = (event as CustomEvent).detail; this.updateHeader(currentDate, resourceData); }); // Also listen for date changes (including initial setup) eventBus.on(CoreEvents.DATE_CHANGED, (event) => { const { currentDate } = (event as CustomEvent).detail; this.updateHeader(currentDate, null); }); // Listen for workweek header updates after grid rebuild eventBus.on('workweek:header-update', (event) => { const { currentDate } = (event as CustomEvent).detail; this.updateHeader(currentDate, null); }); } /** * Update header content for navigation */ private updateHeader(currentDate: Date, resourceData: ResourceCalendarData | null = null): void { const calendarHeader = this.getOrCreateCalendarHeader(); if (!calendarHeader) return; // Clear existing content calendarHeader.innerHTML = ''; // Render new header content const calendarType = calendarConfig.getCalendarMode(); const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType); const context: HeaderRenderContext = { currentWeek: currentDate, config: calendarConfig, resourceData: resourceData }; headerRenderer.render(calendarHeader, context); // Setup event listeners on the new content this.setupHeaderDragListeners(); // Calculate period from current date const weekStart = DateCalculator.getISOWeekStart(currentDate); const weekEnd = DateCalculator.addDays(weekStart, 6); // Notify other managers that header is ready with period data const payload: HeaderReadyEventPayload = { headerElement: calendarHeader, startDate: weekStart, endDate: weekEnd, isNavigation: false }; eventBus.emit('header:ready', payload); } /** * Get calendar header element - header always exists now */ private getOrCreateCalendarHeader(): HTMLElement | null { const calendarHeader = this.getCalendarHeader(); if (!calendarHeader) { console.warn('HeaderManager: Calendar header not found - should always exist now!'); return null; } return calendarHeader; } /** * Clean up resources and event listeners */ public destroy(): void { // Remove eventBus listeners if (this.dragMouseEnterHeaderListener) { eventBus.off('drag:mouseenter-header', this.dragMouseEnterHeaderListener); } if (this.dragMouseLeaveHeaderListener) { eventBus.off('drag:mouseleave-header', this.dragMouseLeaveHeaderListener); } // Clear references this.dragMouseEnterHeaderListener = null; this.dragMouseLeaveHeaderListener = null; } }