/** * AllDayCoordinator - Orchestrates all-day event functionality * * NO STATE - Only coordinates between services * - Listens to EventBus events * - Delegates to specialized services * - Manages service lifecycle */ import { eventBus } from '../../core/EventBus'; import { ALL_DAY_CONSTANTS } from '../../configurations/CalendarConfig'; import { AllDayLayoutEngine } from '../../utils/AllDayLayoutEngine'; import { CoreEvents } from '../../constants/CoreEvents'; import { AllDayDomReader } from './AllDayDomReader'; import { ColumnDetectionUtils } from '../../utils/ColumnDetectionUtils'; /** * AllDayCoordinator - Orchestrates all-day event functionality * Replaces the monolithic AllDayManager with a coordinated service architecture */ export class AllDayCoordinator { constructor(eventManager, allDayEventRenderer, dateService, heightService, collapseService, dragService) { this.eventManager = eventManager; this.allDayEventRenderer = allDayEventRenderer; this.dateService = dateService; this.heightService = heightService; this.collapseService = collapseService; this.dragService = dragService; // Sync CSS variable with TypeScript constant document.documentElement.style.setProperty('--single-row-height', `${ALL_DAY_CONSTANTS.EVENT_HEIGHT}px`); this.setupEventListeners(); } /** * Setup event listeners and delegate to services */ setupEventListeners() { // Timed → All-day conversion eventBus.on('drag:mouseenter-header', (event) => { const payload = event.detail; if (payload.draggedClone.hasAttribute('data-allday')) return; console.log('🔄 AllDayCoordinator: Received drag:mouseenter-header', { targetDate: payload.targetColumn, originalElementId: payload.originalElement?.dataset?.eventId, originalElementTag: payload.originalElement?.tagName }); this.dragService.handleConvertToAllDay(payload); // Recalculate layouts and height after timed → all-day conversion this.recalculateLayoutsAndHeight(); }); eventBus.on('drag:mouseleave-header', (event) => { const { originalElement } = event.detail; console.log('🚪 AllDayCoordinator: Received drag:mouseleave-header', { originalElementId: originalElement?.dataset?.eventId }); }); // All-day drag start eventBus.on('drag:start', (event) => { const payload = event.detail; if (!payload.draggedClone?.hasAttribute('data-allday')) return; this.allDayEventRenderer.handleDragStart(payload); }); // All-day column change eventBus.on('drag:column-change', (event) => { const payload = event.detail; if (!payload.draggedClone?.hasAttribute('data-allday')) return; this.dragService.handleColumnChange(payload); }); // Drag end eventBus.on('drag:end', (event) => { const dragEndPayload = event.detail; console.log('🎯 AllDayCoordinator: drag:end received', { target: dragEndPayload.target, originalElementTag: dragEndPayload.originalElement?.tagName, hasAllDayAttribute: dragEndPayload.originalElement?.hasAttribute('data-allday'), eventId: dragEndPayload.originalElement?.dataset.eventId }); // Handle all-day → all-day drops (within header) if (dragEndPayload.target === 'swp-day-header') { console.log('✅ AllDayCoordinator: Handling all-day → all-day drop'); this.dragService.handleDragEnd(dragEndPayload); // Recalculate layouts and height after all-day → all-day repositioning this.recalculateLayoutsAndHeight(); return; } // Handle all-day → timed conversion (dropped in column) if (dragEndPayload.target === 'swp-day-column' && dragEndPayload.originalElement?.hasAttribute('data-allday')) { const eventId = dragEndPayload.originalElement.dataset.eventId; console.log('🔄 AllDayCoordinator: All-day → timed conversion', { eventId }); // Remove event element from DOM const container = AllDayDomReader.getAllDayContainer(); const eventElement = container?.querySelector(`[data-event-id="${eventId}"]`); if (eventElement) { eventElement.remove(); } // Recalculate layouts and height after event removal this.recalculateLayoutsAndHeight(); } }); // Drag cancelled eventBus.on('drag:cancelled', (event) => { const { draggedElement, reason } = event.detail; console.log('🚫 AllDayCoordinator: Drag cancelled', { eventId: draggedElement?.dataset?.eventId, reason }); }); // Header ready - render all-day events eventBus.on('header:ready', async (event) => { const headerReadyEventPayload = event.detail; const startDate = new Date(headerReadyEventPayload.headerElements.at(0).date); const endDate = new Date(headerReadyEventPayload.headerElements.at(-1).date); const events = await this.eventManager.getEventsForPeriod(startDate, endDate); // Filter for all-day events const allDayEvents = events.filter(event => event.allDay); // Calculate layouts const layouts = this.calculateAllDayEventsLayout(allDayEvents, headerReadyEventPayload.headerElements); // Render events this.allDayEventRenderer.renderAllDayEventsForPeriod(layouts); // Initialize collapse/expand UI and calculate height this.collapseService.initializeUI(); }); // View changed eventBus.on(CoreEvents.VIEW_CHANGED, (event) => { this.allDayEventRenderer.handleViewChanged(event); }); } /** * Calculate layout for ALL all-day events using AllDayLayoutEngine */ calculateAllDayEventsLayout(events, dayHeaders) { // Initialize layout engine with provided week dates const layoutEngine = new AllDayLayoutEngine(dayHeaders.map(column => column.date)); // Calculate layout for all events together return layoutEngine.calculateLayout(events); } /** * Recalculate layouts and update height * Called after events are added/removed/moved in all-day area * Uses AllDayLayoutEngine to optimally reorganize all events */ recalculateLayoutsAndHeight() { // 1. Read current events from DOM const events = AllDayDomReader.getEventsAsData(); const weekDates = ColumnDetectionUtils.getColumns(); // 2. Calculate optimal layouts using greedy algorithm const layouts = this.calculateAllDayEventsLayout(events, weekDates); // 3. Apply layouts to DOM this.dragService.applyLayoutUpdates(layouts); // 4. Calculate max row from NEW layouts const maxRow = layouts.length > 0 ? Math.max(...layouts.map(l => l.row)) : 0; // 5. Check if collapsed state should be maintained const isExpanded = AllDayDomReader.isExpanded(); const targetRows = isExpanded ? maxRow : Math.min(maxRow, ALL_DAY_CONSTANTS.MAX_COLLAPSED_ROWS); // 6. Animate height to target this.heightService.animateToRows(targetRows); } /** * Public API for collapsing all-day row */ collapseAllDayRow() { this.heightService.collapseAllDayRow(); } } //# sourceMappingURL=AllDayCoordinator.js.map