// Calendar configuration management import { eventBus } from './EventBus'; import { EventTypes } from '../constants/EventTypes'; import { CalendarConfig as ICalendarConfig, ViewPeriod, CalendarMode, DateViewType, CalendarType } from '../types/CalendarTypes'; /** * Layout and timing settings for the calendar grid */ interface GridSettings { // Time boundaries dayStartHour: number; dayEndHour: number; workStartHour: number; workEndHour: number; // Layout settings hourHeight: number; snapInterval: number; fitToWidth: boolean; scrollToHour: number | null; // Display options showCurrentTime: boolean; showWorkHours: boolean; } /** * View settings for date-based calendar mode */ interface DateViewSettings { period: ViewPeriod; // day/week/month weekDays: number; // Number of days to show in week view firstDayOfWeek: number; // 0=Sunday, 1=Monday showAllDay: boolean; // Show all-day event row } /** * Work week configuration settings */ interface WorkWeekSettings { id: string; workDays: number[]; // [1,2,3,4,5] for mon-fri dayNames: string[]; // ['Mon','Tue','Wed','Thu','Fri'] totalDays: number; // 5 firstWorkDay: number; // 1 = Monday } /** * View settings for resource-based calendar mode */ interface ResourceViewSettings { maxResources: number; // Maximum resources to display showAvatars: boolean; // Display user avatars avatarSize: number; // Avatar size in pixels resourceNameFormat: 'full' | 'short'; // How to display names showResourceDetails: boolean; // Show additional resource info showAllDay: boolean; // Show all-day event row } /** * Calendar configuration management */ export class CalendarConfig { private config: ICalendarConfig; private calendarMode: CalendarMode = 'date'; private selectedDate: Date | null = null; private gridSettings: GridSettings; private dateViewSettings: DateViewSettings; private resourceViewSettings: ResourceViewSettings; private currentWorkWeek: string = 'standard'; constructor() { this.config = { // Scrollbar styling scrollbarWidth: 16, // Width of scrollbar in pixels scrollbarColor: '#666', // Scrollbar thumb color scrollbarTrackColor: '#f0f0f0', // Scrollbar track color scrollbarHoverColor: '#b53f7aff', // Scrollbar thumb hover color scrollbarBorderRadius: 6, // Border radius for scrollbar thumb // Interaction settings allowDrag: true, allowResize: true, allowCreate: true, // API settings apiEndpoint: '/api/events', dateFormat: 'YYYY-MM-DD', timeFormat: 'HH:mm', // Feature flags enableSearch: true, enableTouch: true, // Event defaults defaultEventDuration: 60, // Minutes minEventDuration: 15, // Will be same as snapInterval maxEventDuration: 480 // 8 hours }; // Grid display settings this.gridSettings = { hourHeight: 60, dayStartHour: 0, dayEndHour: 24, workStartHour: 8, workEndHour: 17, snapInterval: 15, showCurrentTime: true, showWorkHours: true, fitToWidth: false, scrollToHour: 8 }; // Date view settings this.dateViewSettings = { period: 'week', weekDays: 7, firstDayOfWeek: 1, showAllDay: true }; // Resource view settings this.resourceViewSettings = { maxResources: 10, showAvatars: true, avatarSize: 32, resourceNameFormat: 'full', showResourceDetails: true, showAllDay: true }; // Set computed values this.config.minEventDuration = this.gridSettings.snapInterval; // Load calendar type from URL parameter this.loadCalendarType(); // Load from data attributes this.loadFromDOM(); } /** * Load calendar type and date from URL parameters */ private loadCalendarType(): void { const urlParams = new URLSearchParams(window.location.search); const typeParam = urlParams.get('type'); const dateParam = urlParams.get('date'); // Set calendar mode if (typeParam === 'resource' || typeParam === 'date') { this.calendarMode = typeParam; console.log(`CalendarConfig: Calendar mode set to '${this.calendarMode}' from URL parameter`); } else { this.calendarMode = 'date'; // Default console.log(`CalendarConfig: Calendar mode defaulted to '${this.calendarMode}'`); } // Set selected date if (dateParam) { const parsedDate = new Date(dateParam); if (!isNaN(parsedDate.getTime())) { this.selectedDate = parsedDate; console.log(`CalendarConfig: Selected date set to '${this.selectedDate.toISOString()}' from URL parameter`); } else { console.warn(`CalendarConfig: Invalid date parameter '${dateParam}', using current date`); this.selectedDate = new Date(); } } else { this.selectedDate = new Date(); // Default to today console.log(`CalendarConfig: Selected date defaulted to today: ${this.selectedDate.toISOString()}`); } } /** * Load configuration from DOM data attributes */ private loadFromDOM(): void { const calendar = document.querySelector('swp-calendar') as HTMLElement; if (!calendar) return; // Read data attributes const attrs = calendar.dataset; // Update date view settings if (attrs.view) this.dateViewSettings.period = attrs.view as ViewPeriod; if (attrs.weekDays) this.dateViewSettings.weekDays = parseInt(attrs.weekDays); // Update grid settings if (attrs.snapInterval) this.gridSettings.snapInterval = parseInt(attrs.snapInterval); if (attrs.dayStartHour) this.gridSettings.dayStartHour = parseInt(attrs.dayStartHour); if (attrs.dayEndHour) this.gridSettings.dayEndHour = parseInt(attrs.dayEndHour); if (attrs.hourHeight) this.gridSettings.hourHeight = parseInt(attrs.hourHeight); if (attrs.fitToWidth !== undefined) this.gridSettings.fitToWidth = attrs.fitToWidth === 'true'; // Update computed values this.config.minEventDuration = this.gridSettings.snapInterval; } /** * Get a config value */ get(key: K): ICalendarConfig[K] { return this.config[key]; } /** * Set a config value */ set(key: K, value: ICalendarConfig[K]): void { const oldValue = this.config[key]; this.config[key] = value; // Update computed values handled in specific update methods // Emit config update event eventBus.emit(EventTypes.CONFIG_UPDATE, { key, value, oldValue }); } /** * Update multiple config values */ update(updates: Partial): void { Object.entries(updates).forEach(([key, value]) => { this.set(key as keyof ICalendarConfig, value); }); } /** * Get all config */ getAll(): ICalendarConfig { return { ...this.config }; } /** * Calculate derived values */ get minuteHeight(): number { return this.gridSettings.hourHeight / 60; } get totalHours(): number { return this.gridSettings.dayEndHour - this.gridSettings.dayStartHour; } get totalMinutes(): number { return this.totalHours * 60; } get slotsPerHour(): number { return 60 / this.gridSettings.snapInterval; } get totalSlots(): number { return this.totalHours * this.slotsPerHour; } get slotHeight(): number { return this.gridSettings.hourHeight / this.slotsPerHour; } /** * Validate snap interval */ isValidSnapInterval(interval: number): boolean { return [5, 10, 15, 30, 60].includes(interval); } /** * Get grid display settings */ getGridSettings(): GridSettings { return { ...this.gridSettings }; } /** * Update grid display settings */ updateGridSettings(updates: Partial): void { this.gridSettings = { ...this.gridSettings, ...updates }; // Update computed values if (updates.snapInterval) { this.config.minEventDuration = updates.snapInterval; } // Emit grid settings update event eventBus.emit(EventTypes.CONFIG_UPDATE, { key: 'gridSettings', value: this.gridSettings, oldValue: this.gridSettings }); } /** * Get date view settings */ getDateViewSettings(): DateViewSettings { return { ...this.dateViewSettings }; } /** * Legacy method - for backwards compatibility */ getDateHeaderSettings(): DateViewSettings { return this.getDateViewSettings(); } /** * Update date view settings */ updateDateViewSettings(updates: Partial): void { this.dateViewSettings = { ...this.dateViewSettings, ...updates }; // Emit date view settings update event eventBus.emit(EventTypes.CONFIG_UPDATE, { key: 'dateViewSettings', value: this.dateViewSettings, oldValue: this.dateViewSettings }); } /** * Legacy method - for backwards compatibility */ updateDateHeaderSettings(updates: Partial): void { this.updateDateViewSettings(updates); } /** * Get resource view settings */ getResourceViewSettings(): ResourceViewSettings { return { ...this.resourceViewSettings }; } /** * Legacy method - for backwards compatibility */ getResourceHeaderSettings(): ResourceViewSettings { return this.getResourceViewSettings(); } /** * Update resource view settings */ updateResourceViewSettings(updates: Partial): void { this.resourceViewSettings = { ...this.resourceViewSettings, ...updates }; // Emit resource view settings update event eventBus.emit(EventTypes.CONFIG_UPDATE, { key: 'resourceViewSettings', value: this.resourceViewSettings, oldValue: this.resourceViewSettings }); } /** * Legacy method - for backwards compatibility */ updateResourceHeaderSettings(updates: Partial): void { this.updateResourceViewSettings(updates); } /** * Check if current mode is resource-based */ isResourceMode(): boolean { return this.calendarMode === 'resource'; } /** * Check if current mode is date-based */ isDateMode(): boolean { return this.calendarMode === 'date'; } /** * Legacy methods - for backwards compatibility */ isResourceView(): boolean { return this.isResourceMode(); } isDateView(): boolean { return this.isDateMode(); } /** * Get calendar mode */ getCalendarMode(): CalendarMode { return this.calendarMode; } /** * Set calendar mode */ setCalendarMode(mode: CalendarMode): void { const oldMode = this.calendarMode; this.calendarMode = mode; // Emit calendar mode change event eventBus.emit(EventTypes.CALENDAR_TYPE_CHANGED, { oldType: oldMode, newType: mode }); } /** * Get selected date */ getSelectedDate(): Date | null { return this.selectedDate; } /** * Set selected date */ setSelectedDate(date: Date): void { this.selectedDate = date; // Emit date change event eventBus.emit(EventTypes.SELECTED_DATE_CHANGED, { date: date }); } /** * Get work week presets */ private getWorkWeekPresets(): { [key: string]: WorkWeekSettings } { return { 'standard': { id: 'standard', workDays: [1,2,3,4,5], dayNames: ['Mon','Tue','Wed','Thu','Fri'], totalDays: 5, firstWorkDay: 1 }, 'compressed': { id: 'compressed', workDays: [1,2,3,4], dayNames: ['Mon','Tue','Wed','Thu'], totalDays: 4, firstWorkDay: 1 }, 'midweek': { id: 'midweek', workDays: [3,4,5], dayNames: ['Wed','Thu','Fri'], totalDays: 3, firstWorkDay: 3 }, 'weekend': { id: 'weekend', workDays: [6,0], dayNames: ['Sat','Sun'], totalDays: 2, firstWorkDay: 6 }, 'fullweek': { id: 'fullweek', workDays: [0,1,2,3,4,5,6], dayNames: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'], totalDays: 7, firstWorkDay: 0 } }; } /** * Get current work week settings */ getWorkWeekSettings(): WorkWeekSettings { const presets = this.getWorkWeekPresets(); return presets[this.currentWorkWeek] || presets['standard']; } /** * Set work week preset */ setWorkWeek(workWeekId: string): void { const presets = this.getWorkWeekPresets(); if (presets[workWeekId]) { this.currentWorkWeek = workWeekId; // Update dateViewSettings to match work week this.dateViewSettings.weekDays = presets[workWeekId].totalDays; // Emit work week change event eventBus.emit(EventTypes.WORKWEEK_CHANGED, { workWeekId: workWeekId, settings: presets[workWeekId] }); } } /** * Get current work week ID */ getCurrentWorkWeek(): string { return this.currentWorkWeek; } } // Create singleton instance export const calendarConfig = new CalendarConfig();