2025-07-24 22:17:38 +02:00
|
|
|
// Calendar configuration management
|
|
|
|
|
|
|
|
|
|
import { eventBus } from './EventBus';
|
2025-08-20 20:22:51 +02:00
|
|
|
import { CoreEvents } from '../constants/CoreEvents';
|
2025-08-20 21:51:49 +02:00
|
|
|
import { CalendarConfig as ICalendarConfig, ViewPeriod, CalendarMode } from '../types/CalendarTypes';
|
2025-09-12 22:21:56 +02:00
|
|
|
import { TimeFormatter, TimeFormatSettings } from '../utils/TimeFormatter';
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-08-24 23:31:11 +02:00
|
|
|
/**
|
|
|
|
|
* All-day event layout constants
|
|
|
|
|
*/
|
|
|
|
|
export const ALL_DAY_CONSTANTS = {
|
|
|
|
|
EVENT_HEIGHT: 22, // Height of single all-day event
|
|
|
|
|
EVENT_GAP: 2, // Gap between stacked events
|
|
|
|
|
CONTAINER_PADDING: 4, // Container padding (top + bottom)
|
|
|
|
|
get SINGLE_ROW_HEIGHT() {
|
|
|
|
|
return this.EVENT_HEIGHT + this.EVENT_GAP + this.CONTAINER_PADDING; // 28px
|
|
|
|
|
}
|
|
|
|
|
} as const;
|
|
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
/**
|
2025-08-09 00:31:44 +02:00
|
|
|
* Layout and timing settings for the calendar grid
|
2025-07-24 22:17:38 +02:00
|
|
|
*/
|
2025-08-09 00:31:44 +02:00
|
|
|
interface GridSettings {
|
|
|
|
|
// Time boundaries
|
|
|
|
|
dayStartHour: number;
|
|
|
|
|
dayEndHour: number;
|
|
|
|
|
workStartHour: number;
|
|
|
|
|
workEndHour: number;
|
|
|
|
|
|
|
|
|
|
// Layout settings
|
|
|
|
|
hourHeight: number;
|
|
|
|
|
snapInterval: number;
|
|
|
|
|
fitToWidth: boolean;
|
2025-07-24 22:17:38 +02:00
|
|
|
scrollToHour: number | null;
|
2025-08-09 00:31:44 +02:00
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 22:27:17 +02:00
|
|
|
/**
|
|
|
|
|
* Work week configuration settings
|
|
|
|
|
*/
|
|
|
|
|
interface WorkWeekSettings {
|
|
|
|
|
id: string;
|
2025-08-20 00:39:31 +02:00
|
|
|
workDays: number[]; // ISO 8601: [1,2,3,4,5] for mon-fri (1=Mon, 7=Sun)
|
2025-08-18 22:27:17 +02:00
|
|
|
totalDays: number; // 5
|
2025-08-20 00:39:31 +02:00
|
|
|
firstWorkDay: number; // ISO: 1 = Monday, 7 = Sunday
|
2025-08-18 22:27:17 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
/**
|
|
|
|
|
* 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
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-12 22:21:56 +02:00
|
|
|
/**
|
|
|
|
|
* Time format configuration settings
|
|
|
|
|
*/
|
|
|
|
|
interface TimeFormatConfig {
|
|
|
|
|
timezone: string;
|
|
|
|
|
use24HourFormat: boolean;
|
|
|
|
|
locale: string;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
/**
|
|
|
|
|
* Calendar configuration management
|
|
|
|
|
*/
|
|
|
|
|
export class CalendarConfig {
|
|
|
|
|
private config: ICalendarConfig;
|
2025-08-09 00:31:44 +02:00
|
|
|
private calendarMode: CalendarMode = 'date';
|
2025-08-07 00:15:44 +02:00
|
|
|
private selectedDate: Date | null = null;
|
2025-08-09 00:31:44 +02:00
|
|
|
private gridSettings: GridSettings;
|
|
|
|
|
private dateViewSettings: DateViewSettings;
|
|
|
|
|
private resourceViewSettings: ResourceViewSettings;
|
2025-08-18 22:27:17 +02:00
|
|
|
private currentWorkWeek: string = 'standard';
|
2025-09-12 22:21:56 +02:00
|
|
|
private timeFormatConfig: TimeFormatConfig;
|
2025-07-24 22:17:38 +02:00
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
this.config = {
|
2025-08-05 23:03:08 +02:00
|
|
|
// 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
|
|
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
// 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
|
|
|
|
|
};
|
|
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
// 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
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-12 22:21:56 +02:00
|
|
|
// Time format settings - default to Denmark
|
|
|
|
|
this.timeFormatConfig = {
|
|
|
|
|
timezone: 'Europe/Copenhagen',
|
|
|
|
|
use24HourFormat: true,
|
|
|
|
|
locale: 'da-DK'
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
// Set computed values
|
2025-08-09 00:31:44 +02:00
|
|
|
this.config.minEventDuration = this.gridSettings.snapInterval;
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-09-12 22:21:56 +02:00
|
|
|
// Initialize TimeFormatter with default settings
|
|
|
|
|
TimeFormatter.configure(this.timeFormatConfig);
|
|
|
|
|
|
2025-08-07 00:15:44 +02:00
|
|
|
// Load calendar type from URL parameter
|
|
|
|
|
this.loadCalendarType();
|
|
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
// 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');
|
|
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
// Set calendar mode
|
2025-08-07 00:15:44 +02:00
|
|
|
if (typeParam === 'resource' || typeParam === 'date') {
|
2025-08-09 00:31:44 +02:00
|
|
|
this.calendarMode = typeParam;
|
2025-08-07 00:15:44 +02:00
|
|
|
} else {
|
2025-08-09 00:31:44 +02:00
|
|
|
this.calendarMode = 'date'; // Default
|
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;
|
|
|
|
|
} else {
|
|
|
|
|
this.selectedDate = new Date();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this.selectedDate = new Date(); // Default to today
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
// 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;
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
// Update computed values handled in specific update methods
|
2025-07-24 22:17:38 +02:00
|
|
|
|
|
|
|
|
// Emit config update event
|
2025-08-20 21:38:54 +02:00
|
|
|
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
2025-07-24 22:17:38 +02:00
|
|
|
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 {
|
2025-08-09 00:31:44 +02:00
|
|
|
return this.gridSettings.hourHeight / 60;
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get totalHours(): number {
|
2025-08-09 00:31:44 +02:00
|
|
|
return this.gridSettings.dayEndHour - this.gridSettings.dayStartHour;
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get totalMinutes(): number {
|
|
|
|
|
return this.totalHours * 60;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get slotsPerHour(): number {
|
2025-08-09 00:31:44 +02:00
|
|
|
return 60 / this.gridSettings.snapInterval;
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get totalSlots(): number {
|
|
|
|
|
return this.totalHours * this.slotsPerHour;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get slotHeight(): number {
|
2025-08-09 00:31:44 +02:00
|
|
|
return this.gridSettings.hourHeight / this.slotsPerHour;
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validate snap interval
|
|
|
|
|
*/
|
|
|
|
|
isValidSnapInterval(interval: number): boolean {
|
|
|
|
|
return [5, 10, 15, 30, 60].includes(interval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-08-09 00:31:44 +02:00
|
|
|
* Get grid display settings
|
2025-07-24 22:17:38 +02:00
|
|
|
*/
|
2025-08-09 00:31:44 +02:00
|
|
|
getGridSettings(): GridSettings {
|
|
|
|
|
return { ...this.gridSettings };
|
|
|
|
|
}
|
2025-07-24 22:17:38 +02:00
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 20:04:47 +02:00
|
|
|
// Grid settings changes trigger general refresh - avoid specific event
|
2025-08-20 21:38:54 +02:00
|
|
|
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
2025-08-09 00:31:44 +02:00
|
|
|
key: 'gridSettings',
|
2025-09-03 20:04:47 +02:00
|
|
|
value: this.gridSettings
|
2025-08-09 00:31:44 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get date view settings
|
|
|
|
|
*/
|
|
|
|
|
getDateViewSettings(): DateViewSettings {
|
|
|
|
|
return { ...this.dateViewSettings };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update date view settings
|
|
|
|
|
*/
|
|
|
|
|
updateDateViewSettings(updates: Partial<DateViewSettings>): void {
|
|
|
|
|
this.dateViewSettings = { ...this.dateViewSettings, ...updates };
|
|
|
|
|
|
2025-09-03 20:04:47 +02:00
|
|
|
// Date view settings changes trigger general refresh - avoid specific event
|
2025-08-20 21:38:54 +02:00
|
|
|
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
2025-08-09 00:31:44 +02:00
|
|
|
key: 'dateViewSettings',
|
2025-09-03 20:04:47 +02:00
|
|
|
value: this.dateViewSettings
|
2025-08-09 00:31:44 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get resource view settings
|
|
|
|
|
*/
|
|
|
|
|
getResourceViewSettings(): ResourceViewSettings {
|
|
|
|
|
return { ...this.resourceViewSettings };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update resource view settings
|
|
|
|
|
*/
|
|
|
|
|
updateResourceViewSettings(updates: Partial<ResourceViewSettings>): void {
|
|
|
|
|
this.resourceViewSettings = { ...this.resourceViewSettings, ...updates };
|
|
|
|
|
|
2025-09-03 20:04:47 +02:00
|
|
|
// Resource view settings changes trigger general refresh - avoid specific event
|
2025-08-20 21:38:54 +02:00
|
|
|
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
2025-08-09 00:31:44 +02:00
|
|
|
key: 'resourceViewSettings',
|
2025-09-03 20:04:47 +02:00
|
|
|
value: this.resourceViewSettings
|
2025-08-09 00:31:44 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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';
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-07 00:15:44 +02:00
|
|
|
|
|
|
|
|
/**
|
2025-08-09 00:31:44 +02:00
|
|
|
* Get calendar mode
|
2025-08-07 00:15:44 +02:00
|
|
|
*/
|
2025-08-09 00:31:44 +02:00
|
|
|
getCalendarMode(): CalendarMode {
|
|
|
|
|
return this.calendarMode;
|
2025-08-07 00:15:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-08-09 00:31:44 +02:00
|
|
|
* Set calendar mode
|
2025-08-07 00:15:44 +02:00
|
|
|
*/
|
2025-08-09 00:31:44 +02:00
|
|
|
setCalendarMode(mode: CalendarMode): void {
|
|
|
|
|
const oldMode = this.calendarMode;
|
|
|
|
|
this.calendarMode = mode;
|
2025-08-07 00:15:44 +02:00
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
// Emit calendar mode change event
|
2025-08-20 21:38:54 +02:00
|
|
|
eventBus.emit(CoreEvents.VIEW_CHANGED, {
|
2025-08-09 00:31:44 +02:00
|
|
|
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
|
2025-08-20 21:38:54 +02:00
|
|
|
eventBus.emit(CoreEvents.DATE_CHANGED, {
|
2025-08-07 00:15:44 +02:00
|
|
|
date: date
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-08-18 22:27:17 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get work week presets
|
|
|
|
|
*/
|
|
|
|
|
private getWorkWeekPresets(): { [key: string]: WorkWeekSettings } {
|
|
|
|
|
return {
|
|
|
|
|
'standard': {
|
|
|
|
|
id: 'standard',
|
2025-08-20 00:39:31 +02:00
|
|
|
workDays: [1,2,3,4,5], // Monday-Friday (ISO)
|
2025-08-18 22:27:17 +02:00
|
|
|
totalDays: 5,
|
|
|
|
|
firstWorkDay: 1
|
|
|
|
|
},
|
|
|
|
|
'compressed': {
|
|
|
|
|
id: 'compressed',
|
2025-08-20 00:39:31 +02:00
|
|
|
workDays: [1,2,3,4], // Monday-Thursday (ISO)
|
2025-08-18 22:27:17 +02:00
|
|
|
totalDays: 4,
|
|
|
|
|
firstWorkDay: 1
|
|
|
|
|
},
|
|
|
|
|
'midweek': {
|
|
|
|
|
id: 'midweek',
|
2025-08-20 00:39:31 +02:00
|
|
|
workDays: [3,4,5], // Wednesday-Friday (ISO)
|
2025-08-18 22:27:17 +02:00
|
|
|
totalDays: 3,
|
|
|
|
|
firstWorkDay: 3
|
|
|
|
|
},
|
|
|
|
|
'weekend': {
|
|
|
|
|
id: 'weekend',
|
2025-08-20 00:39:31 +02:00
|
|
|
workDays: [6,7], // Saturday-Sunday (ISO)
|
2025-08-18 22:27:17 +02:00
|
|
|
totalDays: 2,
|
|
|
|
|
firstWorkDay: 6
|
|
|
|
|
},
|
|
|
|
|
'fullweek': {
|
|
|
|
|
id: 'fullweek',
|
2025-08-20 00:39:31 +02:00
|
|
|
workDays: [1,2,3,4,5,6,7], // Monday-Sunday (ISO)
|
2025-08-18 22:27:17 +02:00
|
|
|
totalDays: 7,
|
2025-08-20 00:39:31 +02:00
|
|
|
firstWorkDay: 1
|
2025-08-18 22:27:17 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
2025-08-20 20:22:51 +02:00
|
|
|
eventBus.emit(CoreEvents.WORKWEEK_CHANGED, {
|
2025-08-18 22:27:17 +02:00
|
|
|
workWeekId: workWeekId,
|
|
|
|
|
settings: presets[workWeekId]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get current work week ID
|
|
|
|
|
*/
|
|
|
|
|
getCurrentWorkWeek(): string {
|
|
|
|
|
return this.currentWorkWeek;
|
|
|
|
|
}
|
2025-08-20 00:39:31 +02:00
|
|
|
|
2025-09-12 22:21:56 +02:00
|
|
|
/**
|
|
|
|
|
* Get time format settings
|
|
|
|
|
*/
|
|
|
|
|
getTimeFormatSettings(): TimeFormatConfig {
|
|
|
|
|
return { ...this.timeFormatConfig };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update time format settings
|
|
|
|
|
*/
|
|
|
|
|
updateTimeFormatSettings(updates: Partial<TimeFormatConfig>): void {
|
|
|
|
|
this.timeFormatConfig = { ...this.timeFormatConfig, ...updates };
|
|
|
|
|
|
|
|
|
|
// Update TimeFormatter with new settings
|
|
|
|
|
TimeFormatter.configure(this.timeFormatConfig);
|
|
|
|
|
|
|
|
|
|
// Emit time format change event
|
|
|
|
|
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
|
|
|
|
key: 'timeFormatSettings',
|
|
|
|
|
value: this.timeFormatConfig
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set timezone (convenience method)
|
|
|
|
|
*/
|
|
|
|
|
setTimezone(timezone: string): void {
|
|
|
|
|
this.updateTimeFormatSettings({ timezone });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set 12/24 hour format (convenience method)
|
|
|
|
|
*/
|
|
|
|
|
set24HourFormat(use24Hour: boolean): void {
|
|
|
|
|
this.updateTimeFormatSettings({ use24HourFormat: use24Hour });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get configured timezone
|
|
|
|
|
*/
|
|
|
|
|
getTimezone(): string {
|
|
|
|
|
return this.timeFormatConfig.timezone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if using 24-hour format
|
|
|
|
|
*/
|
|
|
|
|
is24HourFormat(): boolean {
|
|
|
|
|
return this.timeFormatConfig.use24HourFormat;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create singleton instance
|
|
|
|
|
export const calendarConfig = new CalendarConfig();
|