Calendar/src/renderers/HeaderRenderer.ts

162 lines
5.3 KiB
TypeScript
Raw Normal View History

2025-08-07 00:15:44 +02:00
// Header rendering strategy interface and implementations
import { CalendarConfig } from '../core/CalendarConfig';
import { ResourceCalendarData } from '../types/CalendarTypes';
/**
* Interface for header rendering strategies
*/
export interface HeaderRenderer {
render(calendarHeader: HTMLElement, context: HeaderRenderContext): void;
2025-08-07 00:15:44 +02:00
}
/**
* Context for header rendering
*/
export interface HeaderRenderContext {
currentWeek: Date;
config: CalendarConfig;
allDayEvents?: any[];
resourceData?: ResourceCalendarData | null;
}
/**
* Date-based header renderer (original functionality)
*/
export class DateHeaderRenderer implements HeaderRenderer {
render(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
2025-08-07 00:15:44 +02:00
const { currentWeek, config, allDayEvents = [] } = context;
const dates = this.getWeekDates(currentWeek, config);
2025-08-07 00:15:44 +02:00
const weekDays = config.get('weekDays');
const daysToShow = dates.slice(0, weekDays);
const workWeekSettings = config.getWorkWeekSettings();
daysToShow.forEach((date, index) => {
2025-08-07 00:15:44 +02:00
const header = document.createElement('swp-day-header');
if (this.isToday(date)) {
(header as any).dataset.today = 'true';
}
header.innerHTML = `
<swp-day-name>${workWeekSettings.dayNames[index]}</swp-day-name>
2025-08-07 00:15:44 +02:00
<swp-day-date>${date.getDate()}</swp-day-date>
`;
(header as any).dataset.date = this.formatDate(date);
calendarHeader.appendChild(header);
2025-08-07 00:15:44 +02:00
});
// Render all-day events in row 2
this.renderAllDayEvents(calendarHeader, context);
2025-08-07 00:15:44 +02:00
}
private renderAllDayEvents(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
2025-08-07 00:15:44 +02:00
const { currentWeek, config, allDayEvents = [] } = context;
const dates = this.getWeekDates(currentWeek, config);
2025-08-07 00:15:44 +02:00
const weekDays = config.get('weekDays');
const daysToShow = dates.slice(0, weekDays);
// Process each all-day event to calculate its span
allDayEvents.forEach(event => {
const startDate = new Date(event.start);
const endDate = new Date(event.end);
// Find start and end column indices
let startColumnIndex = -1;
let endColumnIndex = -1;
daysToShow.forEach((date, index) => {
const dateStr = this.formatDate(date);
const startDateStr = this.formatDate(startDate);
if (dateStr === startDateStr) {
startColumnIndex = index;
}
// For end date, we need to check if the event spans to this day
if (date <= endDate) {
endColumnIndex = index;
}
});
// Only render if the event starts within the visible week
if (startColumnIndex >= 0) {
// If end column is not found or is before start, default to single day
if (endColumnIndex < startColumnIndex) {
endColumnIndex = startColumnIndex;
}
const allDayEvent = document.createElement('swp-allday-event');
allDayEvent.textContent = event.title;
// Set grid column span: start column (1-based) to end column + 1 (1-based)
const gridColumnStart = startColumnIndex + 1;
const gridColumnEnd = endColumnIndex + 2;
allDayEvent.style.gridColumn = `${gridColumnStart} / ${gridColumnEnd}`;
allDayEvent.style.backgroundColor = event.metadata?.color || '#ff9800';
calendarHeader.appendChild(allDayEvent);
2025-08-07 00:15:44 +02:00
}
});
}
private getWeekDates(weekStart: Date, config: CalendarConfig): Date[] {
2025-08-07 00:15:44 +02:00
const dates: Date[] = [];
const workWeekSettings = config.getWorkWeekSettings();
// Calculate dates based on actual work days (e.g., [1,2,3,4] for Mon-Thu)
workWeekSettings.workDays.forEach(dayOfWeek => {
2025-08-07 00:15:44 +02:00
const date = new Date(weekStart);
// Set to the start of the week (Sunday = 0)
date.setDate(weekStart.getDate() - weekStart.getDay());
// Add the specific day of week
date.setDate(date.getDate() + dayOfWeek);
2025-08-07 00:15:44 +02:00
dates.push(date);
});
2025-08-07 00:15:44 +02:00
return dates;
}
private isToday(date: Date): boolean {
const today = new Date();
return date.toDateString() === today.toDateString();
}
private formatDate(date: Date): string {
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
}
}
/**
* Resource-based header renderer
*/
export class ResourceHeaderRenderer implements HeaderRenderer {
render(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
2025-08-07 00:15:44 +02:00
const { resourceData } = context;
if (!resourceData) {
console.warn('ResourceHeaderRenderer: No resource data available for resource headers');
return;
}
resourceData.resources.forEach((resource) => {
const header = document.createElement('swp-resource-header');
header.setAttribute('data-resource', resource.name);
header.setAttribute('data-employee-id', resource.employeeId);
header.innerHTML = `
<swp-resource-avatar>
<img src="${resource.avatarUrl}" alt="${resource.displayName}" onerror="this.style.display='none'">
</swp-resource-avatar>
<swp-resource-name>${resource.displayName}</swp-resource-name>
`;
calendarHeader.appendChild(header);
2025-08-07 00:15:44 +02:00
});
console.log(`ResourceHeaderRenderer: Rendered ${resourceData.resources.length} resource headers`);
}
}