Refactor entity services with hybrid sync pattern

Introduces BaseEntityService and SyncPlugin to eliminate code duplication across entity services

Improves:
- Code reusability through inheritance and composition
- Sync infrastructure for all entity types
- Polymorphic sync status management
- Reduced boilerplate code by ~75%

Supports generic sync for Event, Booking, Customer, and Resource entities
This commit is contained in:
Janus C. H. Knudsen 2025-11-18 16:37:33 +01:00
parent 2aa9d06fab
commit 8e52d670d6
30 changed files with 1960 additions and 526 deletions

View file

@ -102,7 +102,7 @@ export class DateEventRenderer implements IEventRenderer {
public handleDragMove(payload: IDragMoveEventPayload): void {
const swpEvent = payload.draggedClone as SwpEventElement;
const columnDate = this.dateService.parseISO(payload.columnBounds!!.date);
const columnDate = this.dateService.parseISO(payload.columnBounds!!.data as Date);
swpEvent.updatePosition(columnDate, payload.snappedY);
}
@ -118,7 +118,7 @@ export class DateEventRenderer implements IEventRenderer {
// Recalculate timestamps with new column date
const currentTop = parseFloat(payload.draggedClone.style.top) || 0;
const swpEvent = payload.draggedClone as SwpEventElement;
const columnDate = this.dateService.parseISO(payload.newColumn.date);
const columnDate = this.dateService.parseISO(payload.newColumn.data as Date);
swpEvent.updatePosition(columnDate, currentTop);
}
}
@ -130,7 +130,7 @@ export class DateEventRenderer implements IEventRenderer {
console.log('🎯 DateEventRenderer: Converting all-day to timed event', {
eventId: payload.calendarEvent.id,
targetColumn: payload.targetColumn.date,
targetColumn: payload.targetColumn.data as Date,
snappedY: payload.snappedY
});

View file

@ -210,7 +210,7 @@ export class EventRenderingService {
private setupDragMouseLeaveHeaderListener(): void {
this.dragMouseLeaveHeaderListener = (event: Event) => {
const { targetDate, mousePosition, originalElement, draggedClone: cloneElement } = (event as CustomEvent<IDragMouseLeaveHeaderEventPayload>).detail;
const { targetColumn, mousePosition, originalElement, draggedClone: cloneElement } = (event as CustomEvent<IDragMouseLeaveHeaderEventPayload>).detail;
if (cloneElement)
cloneElement.style.display = '';
@ -268,7 +268,8 @@ export class EventRenderingService {
newEnd
});
let columnBounds = ColumnDetectionUtils.getColumnBoundsByDate(newStart);
const dateIdentifier = newStart.toISOString().split('T')[0];
let columnBounds = ColumnDetectionUtils.getColumnBoundsByIdentifier(dateIdentifier);
if (columnBounds)
await this.renderSingleColumn(columnBounds);
@ -295,7 +296,7 @@ export class EventRenderingService {
}
// Re-render target column if exists and different from source
if (targetColumn && targetColumn.date !== originalSourceColumn?.date) {
if (targetColumn && (targetColumn.data as Date) !== (originalSourceColumn?.data as Date)) {
await this.renderSingleColumn(targetColumn);
}
}
@ -316,8 +317,9 @@ export class EventRenderingService {
*/
private async renderSingleColumn(column: IColumnBounds): Promise<void> {
// Get events for just this column's date
const columnStart = this.dateService.parseISO(`${column.date}T00:00:00`);
const columnEnd = this.dateService.parseISO(`${column.date}T23:59:59.999`);
const dateString = (column.data as Date).toISOString().split('T')[0];
const columnStart = this.dateService.parseISO(`${dateString}T00:00:00`);
const columnEnd = this.dateService.parseISO(`${dateString}T23:59:59.999`);
// Get events from EventManager for this single date
const events = await this.eventManager.getEventsForPeriod(columnStart, columnEnd);
@ -341,7 +343,7 @@ export class EventRenderingService {
}
console.log('🔄 EventRendererManager: Re-rendered single column', {
columnDate: column.date,
columnDate: column.data as Date,
eventsCount: timedEvents.length
});
}