import { IGroupingRenderer } from '../../core/IGroupingRenderer'; import { RenderContext } from '../../core/RenderContext'; export interface IEventData { id: string; title: string; start: Date; end: Date; type?: string; allDay?: boolean; } export interface IEventStore { getByDateAndResource(date: string, resourceId?: string): Promise; } export class EventRenderer implements IGroupingRenderer { readonly type = 'event'; constructor( private eventStore: IEventStore, private hourHeight = 60, private dayStartHour = 6 ) {} render(context: RenderContext): void { this.renderAsync(context); } private async renderAsync(context: RenderContext): Promise { const columns = context.columnContainer.querySelectorAll('swp-day-column'); for (const column of columns) { const dateStr = column.dataset.date; if (!dateStr) continue; const eventsLayer = column.querySelector('swp-events-layer'); if (!eventsLayer) continue; const events = await this.eventStore.getByDateAndResource(dateStr, column.dataset.parentId); for (const event of events) { if (event.allDay) continue; const { top, height } = this.calculatePosition(event.start, event.end); const el = document.createElement('swp-event'); el.dataset.eventId = event.id; el.dataset.type = event.type || 'work'; el.style.cssText = `position:absolute;top:${top}px;height:${height}px;left:2px;right:2px`; el.innerHTML = ` ${this.formatTime(event.start)} - ${this.formatTime(event.end)} ${event.title} `; eventsLayer.appendChild(el); } } } private calculatePosition(start: Date, end: Date) { const startMin = start.getHours() * 60 + start.getMinutes() - this.dayStartHour * 60; const endMin = end.getHours() * 60 + end.getMinutes() - this.dayStartHour * 60; return { top: (startMin / 60) * this.hourHeight, height: Math.max(((endMin - startMin) / 60) * this.hourHeight, 15) }; } private formatTime(d: Date): string { return `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`; } }