2025-08-20 19:52:18 +02:00
|
|
|
/**
|
|
|
|
|
* GridManager - Simplified grid manager using Strategy Pattern
|
|
|
|
|
* Now delegates view-specific logic to strategy implementations
|
|
|
|
|
*/
|
2025-07-24 22:17:38 +02:00
|
|
|
|
|
|
|
|
import { eventBus } from '../core/EventBus';
|
|
|
|
|
import { calendarConfig } from '../core/CalendarConfig';
|
2025-08-20 19:52:18 +02:00
|
|
|
import { CoreEvents } from '../constants/CoreEvents';
|
|
|
|
|
import { ResourceCalendarData, CalendarView } from '../types/CalendarTypes';
|
2025-08-20 19:42:13 +02:00
|
|
|
import { AllDayEvent } from '../types/EventTypes';
|
2025-08-20 19:52:18 +02:00
|
|
|
import { ViewStrategy, ViewContext } from '../strategies/ViewStrategy';
|
|
|
|
|
import { WeekViewStrategy } from '../strategies/WeekViewStrategy';
|
|
|
|
|
import { MonthViewStrategy } from '../strategies/MonthViewStrategy';
|
2025-07-24 22:17:38 +02:00
|
|
|
|
|
|
|
|
/**
|
2025-08-20 19:52:18 +02:00
|
|
|
* Simplified GridManager focused on coordination, not implementation
|
2025-07-24 22:17:38 +02:00
|
|
|
*/
|
|
|
|
|
export class GridManager {
|
|
|
|
|
private container: HTMLElement | null = null;
|
2025-08-20 19:52:18 +02:00
|
|
|
private currentDate: Date = new Date();
|
|
|
|
|
private allDayEvents: AllDayEvent[] = [];
|
|
|
|
|
private resourceData: ResourceCalendarData | null = null;
|
|
|
|
|
private currentStrategy: ViewStrategy;
|
|
|
|
|
private eventCleanup: (() => void)[] = [];
|
2025-07-24 22:17:38 +02:00
|
|
|
|
|
|
|
|
constructor() {
|
2025-08-20 19:52:18 +02:00
|
|
|
console.log('🏗️ GridManager: Constructor called with Strategy Pattern');
|
|
|
|
|
|
|
|
|
|
// Default to week view strategy
|
|
|
|
|
this.currentStrategy = new WeekViewStrategy();
|
|
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
this.init();
|
|
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
private init(): void {
|
|
|
|
|
this.findElements();
|
|
|
|
|
this.subscribeToEvents();
|
2025-07-25 23:31:25 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
console.log('GridManager: Initialized with strategy pattern');
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
private findElements(): void {
|
2025-08-20 19:52:18 +02:00
|
|
|
this.container = document.querySelector('swp-calendar-container');
|
|
|
|
|
console.log('GridManager: Found container:', !!this.container);
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
private subscribeToEvents(): void {
|
2025-08-20 19:52:18 +02:00
|
|
|
// Listen for view changes to switch strategies
|
|
|
|
|
this.eventCleanup.push(
|
2025-08-20 20:22:51 +02:00
|
|
|
eventBus.on(CoreEvents.VIEW_CHANGED, (e: Event) => {
|
2025-08-20 19:52:18 +02:00
|
|
|
const detail = (e as CustomEvent).detail;
|
|
|
|
|
this.switchViewStrategy(detail.currentView);
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Listen for data changes
|
2025-08-20 21:38:54 +02:00
|
|
|
// REMOVED: GridManager should not re-render on DATE_CHANGED
|
|
|
|
|
// Date navigation is handled by NavigationManager
|
|
|
|
|
// this.eventCleanup.push(
|
|
|
|
|
// eventBus.on(CoreEvents.DATE_CHANGED, (e: Event) => {
|
|
|
|
|
// const detail = (e as CustomEvent).detail;
|
|
|
|
|
// this.currentDate = detail.currentDate;
|
|
|
|
|
// this.render();
|
|
|
|
|
// })
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// REMOVED: GridManager should not re-render on WEEK_CHANGED
|
|
|
|
|
// Navigation is handled by NavigationManager + NavigationRenderer
|
|
|
|
|
// this.eventCleanup.push(
|
|
|
|
|
// eventBus.on(CoreEvents.WEEK_CHANGED, (e: Event) => {
|
|
|
|
|
// const detail = (e as CustomEvent).detail;
|
|
|
|
|
// this.currentDate = detail.weekStart;
|
|
|
|
|
// this.render();
|
|
|
|
|
// })
|
|
|
|
|
// );
|
2025-08-20 19:52:18 +02:00
|
|
|
|
|
|
|
|
this.eventCleanup.push(
|
2025-08-20 20:22:51 +02:00
|
|
|
eventBus.on(CoreEvents.DATA_LOADED, (e: Event) => {
|
2025-08-20 19:52:18 +02:00
|
|
|
const detail = (e as CustomEvent).detail;
|
|
|
|
|
this.updateAllDayEvents(detail.events);
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Listen for config changes that affect rendering
|
|
|
|
|
this.eventCleanup.push(
|
2025-08-20 20:22:51 +02:00
|
|
|
eventBus.on(CoreEvents.REFRESH_REQUESTED, (e: Event) => {
|
2025-08-20 19:52:18 +02:00
|
|
|
this.render();
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this.eventCleanup.push(
|
2025-08-20 20:22:51 +02:00
|
|
|
eventBus.on(CoreEvents.WORKWEEK_CHANGED, () => {
|
2025-08-20 19:52:18 +02:00
|
|
|
this.render();
|
|
|
|
|
})
|
|
|
|
|
);
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Switch to a different view strategy
|
|
|
|
|
*/
|
|
|
|
|
public switchViewStrategy(view: CalendarView): void {
|
|
|
|
|
console.log(`GridManager: Switching to ${view} strategy`);
|
|
|
|
|
|
|
|
|
|
// Clean up current strategy
|
|
|
|
|
this.currentStrategy.destroy();
|
|
|
|
|
|
|
|
|
|
// Create new strategy based on view
|
|
|
|
|
switch (view) {
|
|
|
|
|
case 'week':
|
|
|
|
|
case 'day':
|
|
|
|
|
this.currentStrategy = new WeekViewStrategy();
|
|
|
|
|
break;
|
|
|
|
|
case 'month':
|
|
|
|
|
this.currentStrategy = new MonthViewStrategy();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
console.warn(`GridManager: Unknown view type ${view}, defaulting to week`);
|
|
|
|
|
this.currentStrategy = new WeekViewStrategy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Re-render with new strategy
|
|
|
|
|
this.render();
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-10 23:06:03 +02:00
|
|
|
/**
|
|
|
|
|
* Set resource data for resource calendar mode
|
|
|
|
|
*/
|
|
|
|
|
public setResourceData(resourceData: ResourceCalendarData | null): void {
|
|
|
|
|
this.resourceData = resourceData;
|
2025-08-20 19:52:18 +02:00
|
|
|
console.log('GridManager: Updated resource data');
|
|
|
|
|
this.render();
|
2025-08-10 23:06:03 +02:00
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
/**
|
2025-08-20 19:52:18 +02:00
|
|
|
* Main render method - delegates to current strategy
|
2025-07-24 22:17:38 +02:00
|
|
|
*/
|
2025-08-20 19:52:18 +02:00
|
|
|
public async render(): Promise<void> {
|
|
|
|
|
if (!this.container) {
|
|
|
|
|
console.warn('GridManager: No container found, cannot render');
|
|
|
|
|
return;
|
2025-08-09 01:16:04 +02:00
|
|
|
}
|
2025-08-20 00:39:31 +02:00
|
|
|
|
2025-08-20 21:38:54 +02:00
|
|
|
console.log(`🎨 GridManager: Rendering ${this.currentDate.toDateString()} using ${this.currentStrategy.constructor.name}`);
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
// Create context for strategy
|
|
|
|
|
const context: ViewContext = {
|
|
|
|
|
currentDate: this.currentDate,
|
|
|
|
|
container: this.container,
|
|
|
|
|
allDayEvents: this.allDayEvents,
|
|
|
|
|
resourceData: this.resourceData
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Delegate to current strategy
|
|
|
|
|
this.currentStrategy.renderGrid(context);
|
|
|
|
|
|
|
|
|
|
// Get layout info from strategy
|
|
|
|
|
const layoutConfig = this.currentStrategy.getLayoutConfig();
|
2025-08-16 00:51:12 +02:00
|
|
|
|
2025-08-20 21:38:54 +02:00
|
|
|
console.log(`GridManager: Emitting GRID_RENDERED for main container`);
|
|
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
// Emit grid rendered event
|
|
|
|
|
eventBus.emit(CoreEvents.GRID_RENDERED, {
|
|
|
|
|
container: this.container,
|
|
|
|
|
currentDate: this.currentDate,
|
|
|
|
|
layoutConfig: layoutConfig,
|
|
|
|
|
columnCount: layoutConfig.columnCount
|
2025-08-16 00:51:12 +02:00
|
|
|
});
|
2025-08-20 00:39:31 +02:00
|
|
|
|
2025-08-20 21:38:54 +02:00
|
|
|
console.log(`✅ Grid rendered with ${layoutConfig.columnCount} columns`);
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
2025-08-04 23:55:04 +02:00
|
|
|
/**
|
2025-08-20 19:52:18 +02:00
|
|
|
* Update all-day events and re-render
|
2025-08-04 23:55:04 +02:00
|
|
|
*/
|
2025-08-20 19:42:13 +02:00
|
|
|
private updateAllDayEvents(events: AllDayEvent[]): void {
|
2025-08-20 19:52:18 +02:00
|
|
|
console.log(`GridManager: Updating ${events.length} all-day events`);
|
|
|
|
|
this.allDayEvents = events.filter(event => event.allDay);
|
|
|
|
|
this.render();
|
2025-08-04 23:55:04 +02:00
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
/**
|
2025-08-20 19:52:18 +02:00
|
|
|
* Get current period label from strategy
|
2025-07-24 22:17:38 +02:00
|
|
|
*/
|
2025-08-20 19:52:18 +02:00
|
|
|
public getCurrentPeriodLabel(): string {
|
|
|
|
|
return this.currentStrategy.getPeriodLabel(this.currentDate);
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
/**
|
2025-08-20 19:52:18 +02:00
|
|
|
* Navigate to next period using strategy
|
2025-07-24 22:17:38 +02:00
|
|
|
*/
|
2025-08-20 19:52:18 +02:00
|
|
|
public navigateNext(): void {
|
|
|
|
|
const nextDate = this.currentStrategy.getNextPeriod(this.currentDate);
|
|
|
|
|
this.currentDate = nextDate;
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
eventBus.emit(CoreEvents.PERIOD_CHANGED, {
|
|
|
|
|
direction: 'next',
|
|
|
|
|
newDate: nextDate,
|
|
|
|
|
periodLabel: this.getCurrentPeriodLabel()
|
|
|
|
|
});
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
this.render();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Navigate to previous period using strategy
|
|
|
|
|
*/
|
|
|
|
|
public navigatePrevious(): void {
|
|
|
|
|
const prevDate = this.currentStrategy.getPreviousPeriod(this.currentDate);
|
|
|
|
|
this.currentDate = prevDate;
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
eventBus.emit(CoreEvents.PERIOD_CHANGED, {
|
|
|
|
|
direction: 'previous',
|
|
|
|
|
newDate: prevDate,
|
|
|
|
|
periodLabel: this.getCurrentPeriodLabel()
|
|
|
|
|
});
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
this.render();
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
2025-07-25 23:31:25 +02:00
|
|
|
/**
|
2025-08-20 19:52:18 +02:00
|
|
|
* Navigate to today
|
2025-07-25 23:31:25 +02:00
|
|
|
*/
|
2025-08-20 19:52:18 +02:00
|
|
|
public navigateToToday(): void {
|
|
|
|
|
this.currentDate = new Date();
|
2025-07-25 23:31:25 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
eventBus.emit(CoreEvents.DATE_CHANGED, {
|
|
|
|
|
newDate: this.currentDate,
|
|
|
|
|
periodLabel: this.getCurrentPeriodLabel()
|
|
|
|
|
});
|
2025-07-25 23:31:25 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
this.render();
|
2025-07-25 23:31:25 +02:00
|
|
|
}
|
2025-08-20 19:52:18 +02:00
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
/**
|
2025-08-20 19:52:18 +02:00
|
|
|
* Get current view's display dates
|
2025-07-24 22:17:38 +02:00
|
|
|
*/
|
2025-08-20 19:52:18 +02:00
|
|
|
public getDisplayDates(): Date[] {
|
|
|
|
|
return this.currentStrategy.getDisplayDates(this.currentDate);
|
|
|
|
|
}
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
/**
|
|
|
|
|
* Clean up all resources
|
|
|
|
|
*/
|
|
|
|
|
public destroy(): void {
|
|
|
|
|
console.log('GridManager: Cleaning up');
|
|
|
|
|
|
|
|
|
|
// Clean up event listeners
|
|
|
|
|
this.eventCleanup.forEach(cleanup => cleanup());
|
|
|
|
|
this.eventCleanup = [];
|
|
|
|
|
|
|
|
|
|
// Clean up current strategy
|
|
|
|
|
this.currentStrategy.destroy();
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-08-20 19:52:18 +02:00
|
|
|
// Clear references
|
|
|
|
|
this.container = null;
|
|
|
|
|
this.allDayEvents = [];
|
|
|
|
|
this.resourceData = null;
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
|
|
|
|
}
|