diff --git a/src/managers/AllDayManager.ts b/src/managers/AllDayManager.ts index c88f775..0b0a525 100644 --- a/src/managers/AllDayManager.ts +++ b/src/managers/AllDayManager.ts @@ -120,6 +120,12 @@ export class AllDayManager { // Recalculate all-day height since clones may have been removed this.checkAndAnimateAllDayHeight(); }); + + // Listen for height check requests from EventRendererManager + eventBus.on('allday:checkHeight', () => { + console.log('📏 AllDayManager: Received allday:checkHeight request'); + this.checkAndAnimateAllDayHeight(); + }); } /** diff --git a/src/managers/HeaderManager.ts b/src/managers/HeaderManager.ts index 854cb23..5c9d123 100644 --- a/src/managers/HeaderManager.ts +++ b/src/managers/HeaderManager.ts @@ -172,27 +172,21 @@ export class HeaderManager { // Setup event listeners on the new content this.setupHeaderDragListeners(); - // Notify other managers that header was rebuilt - eventBus.emit('header:rebuilt', { + // Notify other managers that header is ready + eventBus.emit('header:ready', { headerElement: calendarHeader }); } /** - * Get or create calendar header element + * Get calendar header element - header always exists now */ private getOrCreateCalendarHeader(): HTMLElement | null { - let calendarHeader = this.getCalendarHeader(); + const calendarHeader = this.getCalendarHeader(); if (!calendarHeader) { - // Find grid container and create header - const gridContainer = document.querySelector('swp-grid-container'); - if (gridContainer) { - calendarHeader = document.createElement('swp-calendar-header'); - // Insert header as first child - gridContainer.insertBefore(calendarHeader, gridContainer.firstChild); - - } + console.warn('HeaderManager: Calendar header not found - should always exist now!'); + return null; } return calendarHeader; diff --git a/src/managers/ScrollManager.ts b/src/managers/ScrollManager.ts index 4b77289..b399c92 100644 --- a/src/managers/ScrollManager.ts +++ b/src/managers/ScrollManager.ts @@ -42,8 +42,8 @@ export class ScrollManager { this.updateScrollableHeight(); }); - // Handle header rebuild - refresh header reference and re-sync - eventBus.on('header:rebuilt', () => { + // Handle header ready - refresh header reference and re-sync + eventBus.on('header:ready', () => { this.calendarHeader = document.querySelector('swp-calendar-header'); if (this.scrollableContent && this.calendarHeader) { this.setupHorizontalScrollSynchronization(); diff --git a/src/renderers/EventRenderer.ts b/src/renderers/EventRenderer.ts index 41c657e..2f56bc0 100644 --- a/src/renderers/EventRenderer.ts +++ b/src/renderers/EventRenderer.ts @@ -542,11 +542,20 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { renderEvents(events: CalendarEvent[], container: HTMLElement): void { + // Filter out all-day events - they should be handled by AllDayEventRenderer + const timedEvents = events.filter(event => !event.allDay); + + console.log('🎯 EventRenderer: Filtering events', { + totalEvents: events.length, + timedEvents: timedEvents.length, + filteredOutAllDay: events.length - timedEvents.length + }); + // Find columns in the specific container for regular events const columns = this.getColumns(container); columns.forEach(column => { - const columnEvents = this.getEventsForColumn(column, events); + const columnEvents = this.getEventsForColumn(column, timedEvents); const eventsLayer = column.querySelector('swp-events-layer'); if (eventsLayer) { @@ -659,6 +668,14 @@ export class DateEventRenderer extends BaseEventRenderer { this.setupDragEventListeners(); } + /** + * Setup drag event listeners - placeholder method + */ + private setupDragEventListeners(): void { + // Drag event listeners are handled by EventRendererManager + // This method exists for compatibility + } + protected getColumns(container: HTMLElement): HTMLElement[] { const columns = container.querySelectorAll('swp-day-column'); return Array.from(columns) as HTMLElement[]; diff --git a/src/renderers/EventRendererManager.ts b/src/renderers/EventRendererManager.ts index f8f34e8..53140fa 100644 --- a/src/renderers/EventRendererManager.ts +++ b/src/renderers/EventRendererManager.ts @@ -6,6 +6,7 @@ import { CalendarTypeFactory } from '../factories/CalendarTypeFactory'; import { EventManager } from '../managers/EventManager'; import { EventRendererStrategy } from './EventRenderer'; import { SwpEventElement } from '../elements/SwpEventElement'; +import { AllDayEventRenderer } from './AllDayEventRenderer'; import { DragStartEventPayload, DragMoveEventPayload, DragEndEventPayload, DragMouseEnterHeaderEventPayload, DragMouseLeaveHeaderEventPayload } from '../types/EventTypes'; /** * EventRenderingService - Render events i DOM med positionering using Strategy Pattern @@ -15,6 +16,11 @@ export class EventRenderingService { private eventBus: IEventBus; private eventManager: EventManager; private strategy: EventRendererStrategy; + private allDayEventRenderer: AllDayEventRenderer; + + // Store all-day events until header is ready with dates + private pendingAllDayEvents: CalendarEvent[] = []; + private isHeaderReady: boolean = false; private dragMouseLeaveHeaderListener: ((event: Event) => void) | null = null; @@ -25,6 +31,9 @@ export class EventRenderingService { // Cache strategy at initialization const calendarType = calendarConfig.getCalendarMode(); this.strategy = CalendarTypeFactory.getEventRenderer(calendarType); + + // Initialize all-day event renderer + this.allDayEventRenderer = new AllDayEventRenderer(); this.setupEventListeners(); } @@ -43,13 +52,40 @@ export class EventRenderingService { context.endDate ); - if (events.length === 0) { return; } - // Use cached strategy to render events in the specific container - this.strategy.renderEvents(events, context.container); + // Filter events by type + const timedEvents = events.filter(event => !event.allDay); + const allDayEvents = events.filter(event => event.allDay); + + console.log('🎯 EventRenderingService: Event filtering', { + totalEvents: events.length, + timedEvents: timedEvents.length, + allDayEvents: allDayEvents.length, + allDayEventIds: allDayEvents.map(e => e.id) + }); + + // Render timed events using existing strategy + if (timedEvents.length > 0) { + this.strategy.renderEvents(timedEvents, context.container); + } + + // Render all-day events - wait for header if not ready + if (allDayEvents.length > 0) { + if (this.isHeaderReady) { + this.renderAllDayEvents(allDayEvents); + // Check and adjust all-day container height after rendering + this.eventBus.emit('allday:checkHeight'); + } else { + console.log('🕐 EventRendererManager: Header not ready, storing all-day events for later'); + // Only store if we don't already have pending events to avoid duplicates + if (this.pendingAllDayEvents.length === 0) { + this.pendingAllDayEvents = [...allDayEvents]; + } + } + } // Emit EVENTS_RENDERED event for filtering system this.eventBus.emit(CoreEvents.EVENTS_RENDERED, { @@ -68,6 +104,20 @@ export class EventRenderingService { this.handleViewChanged(event as CustomEvent); }); + // Listen for header ready - when dates are populated + this.eventBus.on('header:ready', () => { + console.log('🎯 EventRendererManager: Header ready, rendering pending all-day events'); + this.isHeaderReady = true; + + if (this.pendingAllDayEvents.length > 0) { + this.renderAllDayEvents(this.pendingAllDayEvents); + this.pendingAllDayEvents = []; // Clear after rendering + + // Check and adjust all-day container height after rendering + this.eventBus.emit('allday:checkHeight'); + } + }); + // Handle all drag events and delegate to appropriate renderer this.setupDragEventListeners(); @@ -299,8 +349,45 @@ export class EventRenderingService { }); } + /** + * Render all-day events using AllDayEventRenderer + */ + private renderAllDayEvents(allDayEvents: CalendarEvent[]): void { + console.log('🏗️ EventRenderingService: Rendering all-day events', { + count: allDayEvents.length, + events: allDayEvents.map(e => ({ id: e.id, title: e.title })) + }); + + // Header always exists now, so we can render directly + allDayEvents.forEach(event => { + const renderedElement = this.allDayEventRenderer.renderAllDayEvent(event); + if (renderedElement) { + console.log('✅ EventRenderingService: Rendered all-day event', { + id: event.id, + title: event.title, + element: renderedElement.tagName + }); + } else { + console.warn('❌ EventRenderingService: Failed to render all-day event', { + id: event.id, + title: event.title + }); + } + }); + } + private clearEvents(container?: HTMLElement): void { this.strategy.clearEvents(container); + + // Also clear all-day events + const allDayContainer = document.querySelector('swp-allday-container'); + if (allDayContainer) { + allDayContainer.querySelectorAll('swp-event').forEach(event => event.remove()); + } + + // Clear pending all-day events + this.pendingAllDayEvents = []; + this.isHeaderReady = false; } public refresh(container?: HTMLElement): void { diff --git a/src/renderers/GridRenderer.ts b/src/renderers/GridRenderer.ts index bb3a68d..4273f59 100644 --- a/src/renderers/GridRenderer.ts +++ b/src/renderers/GridRenderer.ts @@ -108,6 +108,10 @@ export class GridRenderer { ): HTMLElement { const gridContainer = document.createElement('swp-grid-container'); + // Create calendar header as first child - always exists now! + const calendarHeader = document.createElement('swp-calendar-header'); + gridContainer.appendChild(calendarHeader); + // Create scrollable content structure const scrollableContent = document.createElement('swp-scrollable-content'); const timeGrid = document.createElement('swp-time-grid'); @@ -124,6 +128,8 @@ export class GridRenderer { scrollableContent.appendChild(timeGrid); gridContainer.appendChild(scrollableContent); + console.log('✅ GridRenderer: Created grid container with header'); + return gridContainer; }