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

@ -6,6 +6,7 @@ import { AllDayEventRenderer } from '../renderers/AllDayEventRenderer';
import { AllDayLayoutEngine, IEventLayout } from '../utils/AllDayLayoutEngine';
import { IColumnBounds, ColumnDetectionUtils } from '../utils/ColumnDetectionUtils';
import { ICalendarEvent } from '../types/CalendarTypes';
import { CalendarEventType } from '../types/BookingTypes';
import { SwpAllDayEventElement } from '../elements/SwpEventElement';
import {
IDragMouseEnterHeaderEventPayload,
@ -164,8 +165,8 @@ export class AllDayManager {
eventBus.on('header:ready', async (event: Event) => {
let headerReadyEventPayload = (event as CustomEvent<IHeaderReadyEventPayload>).detail;
let startDate = new Date(headerReadyEventPayload.headerElements.at(0)!.date);
let endDate = new Date(headerReadyEventPayload.headerElements.at(-1)!.date);
let startDate = new Date(headerReadyEventPayload.headerElements.at(0)!.data as Date);
let endDate = new Date(headerReadyEventPayload.headerElements.at(-1)!.data as Date);
let events: ICalendarEvent[] = await this.eventManager.getEventsForPeriod(startDate, endDate);
// Filter for all-day events
@ -397,7 +398,7 @@ export class AllDayManager {
this.currentWeekDates = dayHeaders;
// Initialize layout engine with provided week dates
let layoutEngine = new AllDayLayoutEngine(dayHeaders.map(column => column.date));
let layoutEngine = new AllDayLayoutEngine(dayHeaders.map(column => column.data as Date));
// Calculate layout for all events together - AllDayLayoutEngine handles CalendarEvents directly
return layoutEngine.calculateLayout(events);
@ -485,10 +486,10 @@ export class AllDayManager {
*/
private async handleTimedToAllDayDrop(dragEndEvent: IDragEndEventPayload): Promise<void> {
if (!dragEndEvent.draggedClone || !dragEndEvent.finalPosition.column) return;
const clone = dragEndEvent.draggedClone as SwpAllDayEventElement;
const eventId = clone.eventId.replace('clone-', '');
const targetDate = dragEndEvent.finalPosition.column.date;
const targetDate = dragEndEvent.finalPosition.column.data as Date;
console.log('🔄 AllDayManager: Converting timed event to all-day', { eventId, targetDate });
@ -515,7 +516,7 @@ export class AllDayManager {
title: clone.title,
start: newStart,
end: newEnd,
type: clone.type,
type: clone.type as CalendarEventType,
allDay: true,
syncStatus: 'synced'
};
@ -533,10 +534,10 @@ export class AllDayManager {
*/
private async handleDragEnd(dragEndEvent: IDragEndEventPayload): Promise<void> {
if (!dragEndEvent.draggedClone || !dragEndEvent.finalPosition.column) return;
const clone = dragEndEvent.draggedClone as SwpAllDayEventElement;
const eventId = clone.eventId.replace('clone-', '');
const targetDate = dragEndEvent.finalPosition.column.date;
const targetDate = dragEndEvent.finalPosition.column.data as Date;
// Calculate duration in days
const durationDays = this.dateService.differenceInCalendarDays(clone.end, clone.start);