Calendar/src/core/CalendarConfig.ts

512 lines
13 KiB
TypeScript
Raw Normal View History

// 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[]; // ISO 8601: [1,2,3,4,5] for mon-fri (1=Mon, 7=Sun)
totalDays: number; // 5
firstWorkDay: number; // ISO: 1 = Monday, 7 = Sunday
}
/**
* 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';
2025-08-07 00:15:44 +02:00
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;
2025-08-07 00:15:44 +02:00
// Load calendar type from URL parameter
this.loadCalendarType();
// Load from data attributes
this.loadFromDOM();
}
2025-08-07 00:15:44 +02:00
/**
* 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
2025-08-07 00:15:44 +02:00
if (typeParam === 'resource' || typeParam === 'date') {
this.calendarMode = typeParam;
console.log(`CalendarConfig: Calendar mode set to '${this.calendarMode}' from URL parameter`);
2025-08-07 00:15:44 +02:00
} else {
this.calendarMode = 'date'; // Default
console.log(`CalendarConfig: Calendar mode defaulted to '${this.calendarMode}'`);
2025-08-07 00:15:44 +02:00
}
// 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<K extends keyof ICalendarConfig>(key: K): ICalendarConfig[K] {
return this.config[key];
}
/**
* Set a config value
*/
set<K extends keyof ICalendarConfig>(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<ICalendarConfig>): 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<GridSettings>): 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<DateViewSettings>): 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<DateViewSettings>): 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<ResourceViewSettings>): 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<ResourceViewSettings>): 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();
}
2025-08-07 00:15:44 +02:00
/**
* Get calendar mode
2025-08-07 00:15:44 +02:00
*/
getCalendarMode(): CalendarMode {
return this.calendarMode;
2025-08-07 00:15:44 +02:00
}
/**
* Set calendar mode
2025-08-07 00:15:44 +02:00
*/
setCalendarMode(mode: CalendarMode): void {
const oldMode = this.calendarMode;
this.calendarMode = mode;
2025-08-07 00:15:44 +02:00
// Emit calendar mode change event
2025-08-07 00:15:44 +02:00
eventBus.emit(EventTypes.CALENDAR_TYPE_CHANGED, {
oldType: oldMode,
newType: mode
2025-08-07 00:15:44 +02:00
});
}
/**
* 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], // Monday-Friday (ISO)
totalDays: 5,
firstWorkDay: 1
},
'compressed': {
id: 'compressed',
workDays: [1,2,3,4], // Monday-Thursday (ISO)
totalDays: 4,
firstWorkDay: 1
},
'midweek': {
id: 'midweek',
workDays: [3,4,5], // Wednesday-Friday (ISO)
totalDays: 3,
firstWorkDay: 3
},
'weekend': {
id: 'weekend',
workDays: [6,7], // Saturday-Sunday (ISO)
totalDays: 2,
firstWorkDay: 6
},
'fullweek': {
id: 'fullweek',
workDays: [1,2,3,4,5,6,7], // Monday-Sunday (ISO)
totalDays: 7,
firstWorkDay: 1
}
};
}
/**
* 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();