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

@ -8,16 +8,23 @@ export class DateRenderer implements Renderer {
render(context: RenderContext): void {
const dates = context.filter['date'] || [];
const resourceCount = context.filter['resource']?.length || 1;
const resourceIds = context.filter['resource'] || [];
// Render dates for HVER resource (eller 1 gang hvis ingen resources)
const iterations = resourceIds.length || 1;
for (let r = 0; r < iterations; r++) {
const resourceId = resourceIds[r]; // undefined hvis ingen resources
// Render dates for HVER resource (resourceCount gange)
for (let r = 0; r < resourceCount; r++) {
for (const dateStr of dates) {
const date = this.dateService.parseISO(dateStr);
// Header
const header = document.createElement('swp-day-header');
header.dataset.date = dateStr;
if (resourceId) {
header.dataset.resourceId = resourceId;
}
header.innerHTML = `
<swp-day-name>${this.dateService.getDayName(date, 'short')}</swp-day-name>
<swp-day-date>${date.getDate()}</swp-day-date>
@ -27,6 +34,9 @@ export class DateRenderer implements Renderer {
// Column
const column = document.createElement('swp-day-column');
column.dataset.date = dateStr;
if (resourceId) {
column.dataset.resourceId = resourceId;
}
column.innerHTML = '<swp-events-layer></swp-events-layer>';
context.columnContainer.appendChild(column);
}

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
*