diff --git a/src/elements/SwpEventElement.ts b/src/elements/SwpEventElement.ts index ce9dcc5..ae2adb6 100644 --- a/src/elements/SwpEventElement.ts +++ b/src/elements/SwpEventElement.ts @@ -115,6 +115,51 @@ export class SwpEventElement extends BaseEventElement { public static fromCalendarEvent(event: CalendarEvent): SwpEventElement { return new SwpEventElement(event); } + + /** + * Factory method to convert an all-day HTML element to a timed SwpEventElement + */ + public static fromAllDayElement(allDayElement: HTMLElement): SwpEventElement { + // Extract data from all-day element's dataset + const eventId = allDayElement.dataset.eventId || ''; + const title = allDayElement.dataset.title || allDayElement.textContent || 'Untitled'; + const type = allDayElement.dataset.type || 'work'; + const startStr = allDayElement.dataset.start; + const endStr = allDayElement.dataset.end; + const durationStr = allDayElement.dataset.duration; + + if (!startStr || !endStr) { + throw new Error('All-day element missing start/end dates'); + } + + // Parse dates and set reasonable 1-hour duration for timed event + const originalStart = new Date(startStr); + const duration = durationStr ? parseInt(durationStr) : 60; // Default 1 hour + + // For conversion, use current time or a reasonable default (9 AM) + const now = new Date(); + const startDate = new Date(originalStart); + startDate.setHours(now.getHours() || 9, now.getMinutes() || 0, 0, 0); + + const endDate = new Date(startDate); + endDate.setMinutes(endDate.getMinutes() + duration); + + // Create CalendarEvent object + const calendarEvent: CalendarEvent = { + id: eventId, + title: title, + start: startDate, + end: endDate, + type: type, + allDay: false, + syncStatus: 'synced', + metadata: { + duration: duration.toString() + } + }; + + return new SwpEventElement(calendarEvent); + } } /** diff --git a/src/managers/DragDropManager.ts b/src/managers/DragDropManager.ts index d48783d..0836b8c 100644 --- a/src/managers/DragDropManager.ts +++ b/src/managers/DragDropManager.ts @@ -123,25 +123,12 @@ export class DragDropManager { // Listen for header mouseleave events (for all-day to timed conversion when leaving header) this.eventBus.on('header:mouseleave', (event) => { // Check if we're dragging an all-day event - if ((event as any).buttons === 1 && this.draggedEventId && this.isAllDayEventBeingDragged()) { - // Get current mouse position to determine target column and Y - const currentColumn = this.detectColumn(this.lastMousePosition.x, this.lastMousePosition.y); - - if (currentColumn) { - // Calculate Y position relative to the column - const columnElement = this.getCachedColumnElement(currentColumn); - if (columnElement) { - const columnRect = columnElement.getBoundingClientRect(); - const targetY = this.lastMousePosition.y - columnRect.top - this.mouseOffset.y; - - // Emit event to convert to timed - this.eventBus.emit('drag:convert-to-timed', { - eventId: this.draggedEventId, - targetColumn: currentColumn, - targetY: Math.max(0, targetY) - }); - } - } + if (this.draggedEventId && this.isAllDayEventBeingDragged()) { + // Convert all-day event to timed event using SwpEventElement factory + this.eventBus.emit('drag:convert-allday-to-timed', { + eventId: this.draggedEventId, + originalElement: this.originalElement + }); } }); } diff --git a/src/renderers/EventRenderer.ts b/src/renderers/EventRenderer.ts index d7624b6..431d4e4 100644 --- a/src/renderers/EventRenderer.ts +++ b/src/renderers/EventRenderer.ts @@ -147,10 +147,10 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { this.handleConvertToTimed(eventId, targetColumn, targetY); }); - // Handle simple all-day duration adjustment (when leaving header) - eventBus.on('drag:adjust-allday-duration', (event) => { - const { eventId, durationMinutes } = (event as CustomEvent).detail; - this.handleAdjustAllDayDuration(eventId, durationMinutes); + // Handle all-day to timed conversion (when leaving header) + eventBus.on('drag:convert-allday-to-timed', (event) => { + const { eventId, originalElement } = (event as CustomEvent).detail; + this.handleConvertAllDayToTimed(eventId, originalElement); }); // Handle navigation period change (when slide animation completes) @@ -780,30 +780,31 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { } /** - * Handle simple all-day duration adjustment (when leaving header) + * Handle all-day to timed conversion using SwpEventElement factory */ - private handleAdjustAllDayDuration(eventId: string, durationMinutes: number): void { + private handleConvertAllDayToTimed(eventId: string, originalElement: HTMLElement): void { if (!this.draggedClone) return; - // Only adjust if it's an all-day event + // Only convert if it's an all-day event if (this.draggedClone.tagName !== 'SWP-ALLDAY-EVENT') return; - // Simply adjust the duration and height - keep all other data intact - this.draggedClone.dataset.duration = durationMinutes.toString(); + // Use SwpEventElement factory to create a proper timed event + const swpTimedEvent = SwpEventElement.fromAllDayElement(this.draggedClone); + const newTimedElement = swpTimedEvent.getElement(); - // Calculate new height based on duration - const gridSettings = calendarConfig.getGridSettings(); - const hourHeight = gridSettings.hourHeight; - const newHeight = (durationMinutes / 60) * hourHeight; - this.draggedClone.style.height = `${newHeight}px`; + // Apply drag styling to the new element + this.applyDragStyling(newTimedElement); - // Remove all-day specific styling to make it behave like a timed event - this.draggedClone.style.gridColumn = ''; - this.draggedClone.style.gridRow = ''; - this.draggedClone.dataset.allDay = "false"; + // Get parent container + const parent = this.draggedClone.parentElement; - // Apply basic timed event positioning - this.applyDragStyling(this.draggedClone); + // Replace the all-day clone with the new timed event element + if (parent) { + parent.replaceChild(newTimedElement, this.draggedClone); + } + + // Update our reference to the new element + this.draggedClone = newTimedElement; } /**