Enables all-day event to timed event conversion
Introduces the ability to convert all-day events to timed events by dragging them out of the header. Leverages a factory method to create timed events from all-day elements, ensuring proper data conversion and styling. Improves user experience by allowing more flexible event scheduling.
This commit is contained in:
parent
e9298934c6
commit
163314353b
3 changed files with 72 additions and 39 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -123,26 +123,13 @@ 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', {
|
||||
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,
|
||||
targetColumn: currentColumn,
|
||||
targetY: Math.max(0, targetY)
|
||||
originalElement: this.originalElement
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue