Enhance calendar view with resource-aware rendering

Adds support for filtering events and rendering across multiple views with resource-specific context

Improves event and date rendering to handle resource-based filtering
Introduces day view and extends existing calendar infrastructure to support more flexible view configurations
This commit is contained in:
Janus C. H. Knudsen 2025-12-09 22:31:28 +01:00
parent 6fc9be9534
commit 7f6279a6f3
17 changed files with 570 additions and 38 deletions

View file

@ -21,8 +21,14 @@ export class EventRenderer {
/**
* Render events for visible dates into day columns
* @param container - Calendar container element
* @param filter - Filter with 'date' and optionally 'resource' arrays
*/
async render(container: HTMLElement, visibleDates: string[]): Promise<void> {
async render(container: HTMLElement, filter: Record<string, string[]>): Promise<void> {
const visibleDates = filter['date'] || [];
if (visibleDates.length === 0) return;
// Get date range for query
const startDate = new Date(visibleDates[0]);
const endDate = new Date(visibleDates[visibleDates.length - 1]);
@ -31,19 +37,32 @@ export class EventRenderer {
// Fetch events from IndexedDB
const events = await this.eventService.getByDateRange(startDate, endDate);
// Group events by date
const eventsByDate = this.groupEventsByDate(events);
// Find day columns
const dayColumns = container.querySelector('swp-day-columns');
if (!dayColumns) return;
const columns = dayColumns.querySelectorAll('swp-day-column');
// Render events into columns
columns.forEach((column, index) => {
const dateKey = visibleDates[index];
const dateEvents = eventsByDate.get(dateKey) || [];
// Render events into each column based on data attributes
columns.forEach(column => {
const dateKey = (column as HTMLElement).dataset.date;
const columnResourceId = (column as HTMLElement).dataset.resourceId;
if (!dateKey) return;
// Filter events for this column
const columnEvents = events.filter(event => {
// Must match date
if (getDateKey(event.start) !== dateKey) return false;
// If column has resourceId, event must match
if (columnResourceId && event.resourceId !== columnResourceId) return false;
// If no resourceId on column but resources in filter, show all
// (this handles 'simple' view without resources)
return true;
});
// Get or create events layer
let eventsLayer = column.querySelector('swp-events-layer');
@ -55,8 +74,8 @@ export class EventRenderer {
// Clear existing events
eventsLayer.innerHTML = '';
// Render each event
dateEvents.forEach(event => {
// Render each timed event
columnEvents.forEach(event => {
if (!event.allDay) {
const eventElement = this.createEventElement(event);
eventsLayer!.appendChild(eventElement);
@ -65,22 +84,6 @@ export class EventRenderer {
});
}
/**
* Group events by their date key
*/
private groupEventsByDate(events: ICalendarEvent[]): Map<string, ICalendarEvent[]> {
const map = new Map<string, ICalendarEvent[]>();
events.forEach(event => {
const dateKey = getDateKey(event.start);
const existing = map.get(dateKey) || [];
existing.push(event);
map.set(dateKey, existing);
});
return map;
}
/**
* Create a single event element
*