Refactor calendar navigation to use event bus

Decouples calendar navigation from direct DOM events
Adds new event constants for calendar navigation commands
Updates CalendarApp to handle navigation via event bus
Simplifies navigation logic and improves event-driven architecture
This commit is contained in:
Janus C. H. Knudsen 2025-12-16 22:51:01 +01:00
parent 8161b3c42a
commit 3710bb50c0
3 changed files with 34 additions and 19 deletions

View file

@ -67,5 +67,9 @@ export const CoreEvents = {
AUDIT_LOGGED: 'audit:logged', AUDIT_LOGGED: 'audit:logged',
// Rendering events // Rendering events
EVENTS_RENDERED: 'events:rendered' EVENTS_RENDERED: 'events:rendered',
// Calendar command events
CALENDAR_CMD_NAVIGATE_PREV: 'calendar:cmd:navigate:prev',
CALENDAR_CMD_NAVIGATE_NEXT: 'calendar:cmd:navigate:next'
} as const; } as const;

View file

@ -14,6 +14,8 @@ import { SettingsService } from '../storage/settings/SettingsService';
import { ResourceService } from '../storage/resources/ResourceService'; import { ResourceService } from '../storage/resources/ResourceService';
import { ViewConfigService } from '../storage/viewconfigs/ViewConfigService'; import { ViewConfigService } from '../storage/viewconfigs/ViewConfigService';
import { IWorkweekPreset } from '../types/SettingsTypes'; import { IWorkweekPreset } from '../types/SettingsTypes';
import { IEventBus } from '../types/CalendarTypes';
import { CoreEvents } from '../constants/CoreEvents';
export class CalendarApp { export class CalendarApp {
private animator!: NavigationAnimator; private animator!: NavigationAnimator;
@ -35,7 +37,8 @@ export class CalendarApp {
private eventPersistenceManager: EventPersistenceManager, private eventPersistenceManager: EventPersistenceManager,
private settingsService: SettingsService, private settingsService: SettingsService,
private resourceService: ResourceService, private resourceService: ResourceService,
private viewConfigService: ViewConfigService private viewConfigService: ViewConfigService,
private eventBus: IEventBus
) {} ) {}
async init(container: HTMLElement): Promise<void> { async init(container: HTMLElement): Promise<void> {
@ -74,16 +77,21 @@ export class CalendarApp {
} }
private setupEventListeners(): void { private setupEventListeners(): void {
// Navigation commands via EventBus
this.eventBus.on(CoreEvents.CALENDAR_CMD_NAVIGATE_PREV, () => {
this.handleNavigatePrev();
});
this.eventBus.on(CoreEvents.CALENDAR_CMD_NAVIGATE_NEXT, () => {
this.handleNavigateNext();
});
// Other commands via container DOM events (migrates later)
this.container.addEventListener('calendar:cmd:render', ((e: CustomEvent) => { this.container.addEventListener('calendar:cmd:render', ((e: CustomEvent) => {
const { viewId, direction } = e.detail; const { viewId, direction } = e.detail;
this.handleRenderCommand(viewId, direction); this.handleRenderCommand(viewId, direction);
}) as EventListener); }) as EventListener);
this.container.addEventListener('calendar:cmd:navigate', ((e: CustomEvent) => {
const { offset, direction } = e.detail;
this.handleNavigateCommand(offset, direction);
}) as EventListener);
this.container.addEventListener('calendar:cmd:drawer:toggle', (() => { this.container.addEventListener('calendar:cmd:drawer:toggle', (() => {
this.headerDrawerManager.toggle(); this.headerDrawerManager.toggle();
}) as EventListener); }) as EventListener);
@ -101,9 +109,15 @@ export class CalendarApp {
this.emitStatus('rendered', { viewId }); this.emitStatus('rendered', { viewId });
} }
private async handleNavigateCommand(offset: number, direction: 'left' | 'right'): Promise<void> { private async handleNavigatePrev(): Promise<void> {
this.weekOffset += offset; this.weekOffset--;
await this.animator.slide(direction, () => this.render()); await this.animator.slide('right', () => this.render());
this.emitStatus('rendered', { viewId: this.currentViewId });
}
private async handleNavigateNext(): Promise<void> {
this.weekOffset++;
await this.animator.slide('left', () => this.render());
this.emitStatus('rendered', { viewId: this.currentViewId }); this.emitStatus('rendered', { viewId: this.currentViewId });
} }

View file

@ -3,6 +3,8 @@ import { DataSeeder } from '../workers/DataSeeder';
import { AuditService } from '../storage/audit/AuditService'; import { AuditService } from '../storage/audit/AuditService';
import { CalendarApp } from '../core/CalendarApp'; import { CalendarApp } from '../core/CalendarApp';
import { DateService } from '../core/DateService'; import { DateService } from '../core/DateService';
import { IEventBus } from '../types/CalendarTypes';
import { CoreEvents } from '../constants/CoreEvents';
export class DemoApp { export class DemoApp {
private container!: HTMLElement; private container!: HTMLElement;
@ -13,7 +15,8 @@ export class DemoApp {
private dataSeeder: DataSeeder, private dataSeeder: DataSeeder,
private auditService: AuditService, private auditService: AuditService,
private calendarApp: CalendarApp, private calendarApp: CalendarApp,
private dateService: DateService private dateService: DateService,
private eventBus: IEventBus
) {} ) {}
async init(): Promise<void> { async init(): Promise<void> {
@ -48,11 +51,11 @@ export class DemoApp {
private setupNavigation(): void { private setupNavigation(): void {
document.getElementById('btn-prev')!.onclick = () => { document.getElementById('btn-prev')!.onclick = () => {
this.emitNavigateCommand(-1, 'right'); this.eventBus.emit(CoreEvents.CALENDAR_CMD_NAVIGATE_PREV);
}; };
document.getElementById('btn-next')!.onclick = () => { document.getElementById('btn-next')!.onclick = () => {
this.emitNavigateCommand(1, 'left'); this.eventBus.emit(CoreEvents.CALENDAR_CMD_NAVIGATE_NEXT);
}; };
} }
@ -97,10 +100,4 @@ export class DemoApp {
detail: { viewId, direction } detail: { viewId, direction }
})); }));
} }
private emitNavigateCommand(offset: number, direction: 'left' | 'right'): void {
this.container.dispatchEvent(new CustomEvent('calendar:cmd:navigate', {
detail: { offset, direction }
}));
}
} }