174 lines
5.5 KiB
TypeScript
174 lines
5.5 KiB
TypeScript
|
|
import { EventBus } from '../core/EventBus';
|
||
|
|
import { CalendarView, IEventBus } from '../types/CalendarTypes';
|
||
|
|
import { calendarConfig } from '../core/CalendarConfig';
|
||
|
|
import { EventTypes } from '../constants/EventTypes';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ViewManager - Håndterer skift mellem dag/uge/måned visninger
|
||
|
|
* Arbejder med custom tags fra POC design
|
||
|
|
*/
|
||
|
|
export class ViewManager {
|
||
|
|
private eventBus: IEventBus;
|
||
|
|
private currentView: CalendarView = 'week';
|
||
|
|
|
||
|
|
constructor(eventBus: IEventBus) {
|
||
|
|
this.eventBus = eventBus;
|
||
|
|
this.setupEventListeners();
|
||
|
|
}
|
||
|
|
|
||
|
|
private setupEventListeners(): void {
|
||
|
|
this.eventBus.on(EventTypes.CALENDAR_INITIALIZED, () => {
|
||
|
|
this.initializeView();
|
||
|
|
});
|
||
|
|
|
||
|
|
this.eventBus.on(EventTypes.VIEW_CHANGE_REQUESTED, (event: Event) => {
|
||
|
|
const customEvent = event as CustomEvent;
|
||
|
|
const { currentView } = customEvent.detail;
|
||
|
|
this.changeView(currentView);
|
||
|
|
});
|
||
|
|
|
||
|
|
this.eventBus.on(EventTypes.DATE_CHANGED, () => {
|
||
|
|
this.refreshCurrentView();
|
||
|
|
});
|
||
|
|
|
||
|
|
// Setup view button handlers
|
||
|
|
this.setupViewButtonHandlers();
|
||
|
|
}
|
||
|
|
|
||
|
|
private setupViewButtonHandlers(): void {
|
||
|
|
const viewButtons = document.querySelectorAll('swp-view-button[data-view]');
|
||
|
|
viewButtons.forEach(button => {
|
||
|
|
button.addEventListener('click', (event) => {
|
||
|
|
event.preventDefault();
|
||
|
|
const view = button.getAttribute('data-view') as CalendarView;
|
||
|
|
if (view && this.isValidView(view)) {
|
||
|
|
this.changeView(view);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private initializeView(): void {
|
||
|
|
this.renderTimeAxis();
|
||
|
|
this.renderWeekHeaders();
|
||
|
|
this.renderDayColumns();
|
||
|
|
this.updateViewButtons();
|
||
|
|
|
||
|
|
this.eventBus.emit(EventTypes.VIEW_RENDERED, {
|
||
|
|
view: this.currentView
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private changeView(newView: CalendarView): void {
|
||
|
|
if (newView === this.currentView) return;
|
||
|
|
|
||
|
|
const previousView = this.currentView;
|
||
|
|
this.currentView = newView;
|
||
|
|
|
||
|
|
console.log(`ViewManager: Changing view from ${previousView} to ${newView}`);
|
||
|
|
|
||
|
|
this.updateViewButtons();
|
||
|
|
|
||
|
|
this.eventBus.emit(EventTypes.VIEW_CHANGED, {
|
||
|
|
previousView,
|
||
|
|
currentView: newView
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private renderTimeAxis(): void {
|
||
|
|
const timeAxis = document.querySelector('swp-time-axis');
|
||
|
|
if (!timeAxis) return;
|
||
|
|
|
||
|
|
const startHour = calendarConfig.get('dayStartHour');
|
||
|
|
const endHour = calendarConfig.get('dayEndHour');
|
||
|
|
|
||
|
|
timeAxis.innerHTML = '';
|
||
|
|
|
||
|
|
for (let hour = startHour; hour <= endHour; hour++) {
|
||
|
|
const marker = document.createElement('swp-hour-marker');
|
||
|
|
const period = hour >= 12 ? 'PM' : 'AM';
|
||
|
|
const displayHour = hour > 12 ? hour - 12 : (hour === 0 ? 12 : hour);
|
||
|
|
marker.textContent = `${displayHour} ${period}`;
|
||
|
|
timeAxis.appendChild(marker);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private renderWeekHeaders(): void {
|
||
|
|
const weekHeader = document.querySelector('swp-week-header');
|
||
|
|
if (!weekHeader) return;
|
||
|
|
|
||
|
|
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||
|
|
|
||
|
|
weekHeader.innerHTML = '';
|
||
|
|
|
||
|
|
for (let i = 0; i < 7; i++) {
|
||
|
|
const header = document.createElement('swp-day-header');
|
||
|
|
header.innerHTML = `
|
||
|
|
<swp-day-name>${days[i]}</swp-day-name>
|
||
|
|
<swp-day-date>${i + 1}</swp-day-date>
|
||
|
|
`;
|
||
|
|
header.dataset.dayIndex = i.toString();
|
||
|
|
|
||
|
|
// Check if today (this will be updated by NavigationManager later)
|
||
|
|
if (i === 1) { // Mock today as Monday for now
|
||
|
|
header.setAttribute('data-today', 'true');
|
||
|
|
}
|
||
|
|
|
||
|
|
weekHeader.appendChild(header);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private renderDayColumns(): void {
|
||
|
|
const dayColumns = document.querySelector('swp-day-columns');
|
||
|
|
if (!dayColumns) return;
|
||
|
|
|
||
|
|
dayColumns.innerHTML = '';
|
||
|
|
|
||
|
|
for (let i = 0; i < 7; i++) {
|
||
|
|
const column = document.createElement('swp-day-column');
|
||
|
|
column.dataset.dayIndex = i.toString();
|
||
|
|
|
||
|
|
const eventsLayer = document.createElement('swp-events-layer');
|
||
|
|
column.appendChild(eventsLayer);
|
||
|
|
|
||
|
|
dayColumns.appendChild(column);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private updateViewButtons(): void {
|
||
|
|
const viewButtons = document.querySelectorAll('swp-view-button[data-view]');
|
||
|
|
viewButtons.forEach(button => {
|
||
|
|
const buttonView = button.getAttribute('data-view') as CalendarView;
|
||
|
|
if (buttonView === this.currentView) {
|
||
|
|
button.setAttribute('data-active', 'true');
|
||
|
|
} else {
|
||
|
|
button.removeAttribute('data-active');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private refreshCurrentView(): void {
|
||
|
|
this.renderWeekHeaders();
|
||
|
|
this.renderDayColumns();
|
||
|
|
|
||
|
|
this.eventBus.emit(EventTypes.VIEW_RENDERED, {
|
||
|
|
view: this.currentView
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private isValidView(view: string): view is CalendarView {
|
||
|
|
return ['day', 'week', 'month'].includes(view);
|
||
|
|
}
|
||
|
|
|
||
|
|
public getCurrentView(): CalendarView {
|
||
|
|
return this.currentView;
|
||
|
|
}
|
||
|
|
|
||
|
|
public refresh(): void {
|
||
|
|
this.refreshCurrentView();
|
||
|
|
}
|
||
|
|
|
||
|
|
public destroy(): void {
|
||
|
|
// Event listeners bliver automatisk fjernet af EventBus
|
||
|
|
}
|
||
|
|
}
|