Adds resource filtering and view customization

Enhances calendar view with dynamic resource selection
Enables users to filter and customize calendar views by resources
Introduces new event for view updates and dynamic rendering

Supports flexible calendar view configuration
This commit is contained in:
Janus C. H. Knudsen 2025-12-17 18:37:32 +01:00
parent 8d938c721c
commit 66dfe9f2ef
3 changed files with 61 additions and 5 deletions

View file

@ -74,5 +74,6 @@ export const CoreEvents = {
CALENDAR_CMD_NAVIGATE_NEXT: 'calendar:cmd:navigate:next',
CALENDAR_CMD_DRAWER_TOGGLE: 'calendar:cmd:drawer:toggle',
CALENDAR_CMD_RENDER: 'calendar:cmd:render',
CALENDAR_CMD_WORKWEEK_CHANGE: 'calendar:cmd:workweek:change'
CALENDAR_CMD_WORKWEEK_CHANGE: 'calendar:cmd:workweek:change',
CALENDAR_CMD_VIEW_UPDATE: 'calendar:cmd:view:update'
} as const;

View file

@ -23,6 +23,7 @@ export class CalendarApp {
private weekOffset = 0;
private currentViewId = 'simple';
private workweekPreset: IWorkweekPreset | null = null;
private groupingOverrides: Map<string, string[]> = new Map();
constructor(
private orchestrator: CalendarOrchestrator,
@ -102,6 +103,12 @@ export class CalendarApp {
const { presetId } = e.detail;
this.handleWorkweekChange(presetId);
}) as EventListener);
// View update via EventBus
this.eventBus.on(CoreEvents.CALENDAR_CMD_VIEW_UPDATE, ((e: CustomEvent) => {
const { type, values } = e.detail;
this.handleViewUpdate(type, values);
}) as EventListener);
}
private async handleRenderCommand(viewId: string): Promise<void> {
@ -131,6 +138,12 @@ export class CalendarApp {
}
}
private async handleViewUpdate(type: string, values: string[]): Promise<void> {
this.groupingOverrides.set(type, values);
await this.render();
this.emitStatus('rendered', { viewId: this.currentViewId });
}
private async render(): Promise<void> {
const storedConfig = await this.viewConfigService.getById(this.currentViewId);
if (!storedConfig) {
@ -144,12 +157,21 @@ export class CalendarApp {
? this.dateService.getWeekDates(this.weekOffset, 1)
: this.dateService.getWorkWeekDates(this.weekOffset, workDays);
// Clone config and populate dates
// Clone config and apply overrides
const viewConfig: ViewConfig = {
...storedConfig,
groupings: storedConfig.groupings.map(g =>
g.type === 'date' ? { ...g, values: dates } : g
)
groupings: storedConfig.groupings.map(g => {
// Apply date values
if (g.type === 'date') {
return { ...g, values: dates };
}
// Apply grouping overrides
const override = this.groupingOverrides.get(g.type);
if (override) {
return { ...g, values: override };
}
return g;
})
};
await this.orchestrator.render(viewConfig, this.container);

View file

@ -3,6 +3,7 @@ import { DataSeeder } from '../workers/DataSeeder';
import { AuditService } from '../storage/audit/AuditService';
import { CalendarApp } from '../core/CalendarApp';
import { DateService } from '../core/DateService';
import { ResourceService } from '../storage/resources/ResourceService';
import { IEventBus } from '../types/CalendarTypes';
import { CoreEvents } from '../constants/CoreEvents';
@ -16,6 +17,7 @@ export class DemoApp {
private auditService: AuditService,
private calendarApp: CalendarApp,
private dateService: DateService,
private resourceService: ResourceService,
private eventBus: IEventBus
) {}
@ -42,6 +44,7 @@ export class DemoApp {
this.setupDrawerToggle();
this.setupViewSwitching();
this.setupWorkweekSelector();
await this.setupResourceSelector();
// Listen for calendar status events
this.setupStatusListeners();
@ -70,12 +73,19 @@ export class DemoApp {
const view = (chip as HTMLElement).dataset.view;
if (view) {
this.currentView = view;
this.updateSelectorVisibility();
this.eventBus.emit(CoreEvents.CALENDAR_CMD_RENDER, { viewId: view });
}
});
});
}
private updateSelectorVisibility(): void {
const selector = document.querySelector('swp-resource-selector');
const showSelector = this.currentView === 'picker' || this.currentView === 'day';
selector?.classList.toggle('hidden', !showSelector);
}
private setupDrawerToggle(): void {
document.getElementById('btn-drawer')!.onclick = () => {
this.eventBus.emit(CoreEvents.CALENDAR_CMD_DRAWER_TOGGLE);
@ -90,6 +100,29 @@ export class DemoApp {
});
}
private async setupResourceSelector(): Promise<void> {
const resources = await this.resourceService.getAll();
const container = document.querySelector('.resource-checkboxes') as HTMLElement;
if (!container) return;
container.innerHTML = '';
resources.forEach(r => {
const label = document.createElement('label');
label.innerHTML = `
<input type="checkbox" value="${r.id}" checked>
${r.displayName}
`;
container.appendChild(label);
});
container.addEventListener('change', () => {
const checked = container.querySelectorAll('input:checked') as NodeListOf<HTMLInputElement>;
const values = Array.from(checked).map(cb => cb.value);
this.eventBus.emit(CoreEvents.CALENDAR_CMD_VIEW_UPDATE, { type: 'resource', values });
});
}
private setupStatusListeners(): void {
this.container.addEventListener('calendar:status:ready', () => {
console.log('[DemoApp] Calendar ready');