Batch update, WIP

This commit is contained in:
Janus C. H. Knudsen 2025-11-03 22:04:37 +01:00
parent 8ec5f52872
commit 989c9bd69d
25 changed files with 68 additions and 123 deletions

View file

@ -97,68 +97,12 @@ export class Configuration {
return Configuration._instance; return Configuration._instance;
} }
// Computed properties
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;
}
// Backward compatibility getters
getGridSettings(): IGridSettings {
return this.gridSettings;
}
getDateViewSettings(): IDateViewSettings {
return this.dateViewSettings;
}
// Helper methods
getWorkWeekSettings(): IWorkWeekSettings { getWorkWeekSettings(): IWorkWeekSettings {
return WORK_WEEK_PRESETS[this.currentWorkWeek] || WORK_WEEK_PRESETS['standard']; return WORK_WEEK_PRESETS[this.currentWorkWeek] || WORK_WEEK_PRESETS['standard'];
} }
getCurrentWorkWeek(): string {
return this.currentWorkWeek;
}
getTimezone(): string {
return this.timeFormatConfig.timezone;
}
getLocale(): string {
return this.timeFormatConfig.locale;
}
getTimeFormatSettings(): ITimeFormatConfig {
return this.timeFormatConfig;
}
is24HourFormat(): boolean {
return this.timeFormatConfig.use24HourFormat;
}
getDateFormat(): 'locale' | 'technical' {
return this.timeFormatConfig.dateFormat;
}
setWorkWeek(workWeekId: string): void { setWorkWeek(workWeekId: string): void {
if (WORK_WEEK_PRESETS[workWeekId]) { if (WORK_WEEK_PRESETS[workWeekId]) {
this.currentWorkWeek = workWeekId; this.currentWorkWeek = workWeekId;
@ -169,10 +113,6 @@ export class Configuration {
setSelectedDate(date: Date): void { setSelectedDate(date: Date): void {
this.selectedDate = date; this.selectedDate = date;
} }
isValidSnapInterval(interval: number): boolean {
return [5, 10, 15, 30, 60].includes(interval);
}
} }
// Backward compatibility alias // Backward compatibility alias

View file

@ -14,3 +14,12 @@ export interface IGridSettings {
showCurrentTime: boolean; showCurrentTime: boolean;
showWorkHours: boolean; showWorkHours: boolean;
} }
/**
* Grid settings utility functions
*/
export namespace GridSettingsUtils {
export function isValidSnapInterval(interval: number): boolean {
return [5, 10, 15, 30, 60].includes(interval);
}
}

View file

@ -1,5 +1,5 @@
import { ICalendarEvent } from '../types/CalendarTypes'; import { ICalendarEvent } from '../types/CalendarTypes';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { TimeFormatter } from '../utils/TimeFormatter'; import { TimeFormatter } from '../utils/TimeFormatter';
import { PositionUtils } from '../utils/PositionUtils'; import { PositionUtils } from '../utils/PositionUtils';
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
@ -137,7 +137,7 @@ export class SwpEventElement extends BaseSwpEventElement {
this.style.height = `${newHeight}px`; this.style.height = `${newHeight}px`;
// 2. Calculate new end time based on height // 2. Calculate new end time based on height
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const { hourHeight, snapInterval } = gridSettings; const { hourHeight, snapInterval } = gridSettings;
// Get current start time // Get current start time
@ -230,7 +230,7 @@ export class SwpEventElement extends BaseSwpEventElement {
* Calculate start/end minutes from Y position * Calculate start/end minutes from Y position
*/ */
private calculateTimesFromPosition(snappedY: number): { startMinutes: number; endMinutes: number } { private calculateTimesFromPosition(snappedY: number): { startMinutes: number; endMinutes: number } {
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const { hourHeight, dayStartHour, snapInterval } = gridSettings; const { hourHeight, dayStartHour, snapInterval } = gridSettings;
// Get original duration // Get original duration

View file

@ -1,8 +1,8 @@
// Main entry point for Calendar Plantempus // Main entry point for Calendar Plantempus
import { Container } from '@novadi/core'; import { Container } from '@novadi/core';
import { eventBus } from './core/EventBus'; import { eventBus } from './core/EventBus';
import { ConfigManager } from './configuration/ConfigManager'; import { ConfigManager } from './configurations/ConfigManager';
import { Configuration } from './configuration/CalendarConfig'; import { Configuration } from './configurations/CalendarConfig';
import { URLManager } from './utils/URLManager'; import { URLManager } from './utils/URLManager';
import { IEventBus } from './types/CalendarTypes'; import { IEventBus } from './types/CalendarTypes';

View file

@ -1,7 +1,7 @@
// All-day row height management and animations // All-day row height management and animations
import { eventBus } from '../core/EventBus'; import { eventBus } from '../core/EventBus';
import { ALL_DAY_CONSTANTS } from '../configuration/CalendarConfig'; import { ALL_DAY_CONSTANTS } from '../configurations/CalendarConfig';
import { AllDayEventRenderer } from '../renderers/AllDayEventRenderer'; import { AllDayEventRenderer } from '../renderers/AllDayEventRenderer';
import { AllDayLayoutEngine, IEventLayout } from '../utils/AllDayLayoutEngine'; import { AllDayLayoutEngine, IEventLayout } from '../utils/AllDayLayoutEngine';
import { IColumnBounds, ColumnDetectionUtils } from '../utils/ColumnDetectionUtils'; import { IColumnBounds, ColumnDetectionUtils } from '../utils/ColumnDetectionUtils';

View file

@ -1,5 +1,5 @@
import { CoreEvents } from '../constants/CoreEvents'; import { CoreEvents } from '../constants/CoreEvents';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { CalendarView, IEventBus } from '../types/CalendarTypes'; import { CalendarView, IEventBus } from '../types/CalendarTypes';
import { EventManager } from './EventManager'; import { EventManager } from './EventManager';
import { GridManager } from './GridManager'; import { GridManager } from './GridManager';
@ -206,7 +206,7 @@ export class CalendarManager {
this.eventBus.emit('workweek:header-update', { this.eventBus.emit('workweek:header-update', {
currentDate: this.currentDate, currentDate: this.currentDate,
currentView: this.currentView, currentView: this.currentView,
workweek: this.config.getCurrentWorkWeek() workweek: this.config.currentWorkWeek
}); });
} }

View file

@ -8,7 +8,7 @@
import { ICalendarEvent } from '../types/CalendarTypes'; import { ICalendarEvent } from '../types/CalendarTypes';
import { EventStackManager, IEventGroup, IStackLink } from './EventStackManager'; import { EventStackManager, IEventGroup, IStackLink } from './EventStackManager';
import { PositionUtils } from '../utils/PositionUtils'; import { PositionUtils } from '../utils/PositionUtils';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
export interface IGridGroupLayout { export interface IGridGroupLayout {
events: ICalendarEvent[]; events: ICalendarEvent[];
@ -59,7 +59,7 @@ export class EventLayoutCoordinator {
// Find events that could be in GRID with first event // Find events that could be in GRID with first event
// Use expanding search to find chains (A→B→C where each conflicts with next) // Use expanding search to find chains (A→B→C where each conflicts with next)
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const thresholdMinutes = gridSettings.gridStartThresholdMinutes; const thresholdMinutes = gridSettings.gridStartThresholdMinutes;
// Use refactored method for expanding grid candidates // Use refactored method for expanding grid candidates

View file

@ -1,6 +1,6 @@
import { IEventBus, ICalendarEvent } from '../types/CalendarTypes'; import { IEventBus, ICalendarEvent } from '../types/CalendarTypes';
import { CoreEvents } from '../constants/CoreEvents'; import { CoreEvents } from '../constants/CoreEvents';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
import { IEventRepository } from '../repositories/IEventRepository'; import { IEventRepository } from '../repositories/IEventRepository';

View file

@ -14,7 +14,7 @@
*/ */
import { ICalendarEvent } from '../types/CalendarTypes'; import { ICalendarEvent } from '../types/CalendarTypes';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
export interface IStackLink { export interface IStackLink {
prev?: string; // Event ID of previous event in stack prev?: string; // Event ID of previous event in stack
@ -51,7 +51,7 @@ export class EventStackManager {
if (events.length === 0) return []; if (events.length === 0) return [];
// Get threshold from config // Get threshold from config
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const thresholdMinutes = gridSettings.gridStartThresholdMinutes; const thresholdMinutes = gridSettings.gridStartThresholdMinutes;
// Sort events by start time // Sort events by start time

View file

@ -1,5 +1,5 @@
import { eventBus } from '../core/EventBus'; import { eventBus } from '../core/EventBus';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { CoreEvents } from '../constants/CoreEvents'; import { CoreEvents } from '../constants/CoreEvents';
import { IHeaderRenderer, IHeaderRenderContext } from '../renderers/DateHeaderRenderer'; import { IHeaderRenderer, IHeaderRenderContext } from '../renderers/DateHeaderRenderer';
import { IDragMouseEnterHeaderEventPayload, IDragMouseLeaveHeaderEventPayload, IHeaderReadyEventPayload } from '../types/EventTypes'; import { IDragMouseEnterHeaderEventPayload, IDragMouseLeaveHeaderEventPayload, IHeaderReadyEventPayload } from '../types/EventTypes';

View file

@ -1,6 +1,6 @@
import { eventBus } from '../core/EventBus'; import { eventBus } from '../core/EventBus';
import { CoreEvents } from '../constants/CoreEvents'; import { CoreEvents } from '../constants/CoreEvents';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { IResizeEndEventPayload } from '../types/EventTypes'; import { IResizeEndEventPayload } from '../types/EventTypes';
type SwpEventEl = HTMLElement & { updateHeight?: (h: number) => void }; type SwpEventEl = HTMLElement & { updateHeight?: (h: number) => void };
@ -33,7 +33,7 @@ export class ResizeHandleManager {
constructor(config: Configuration) { constructor(config: Configuration) {
this.config = config; this.config = config;
const grid = this.config.getGridSettings(); const grid = this.config.gridSettings;
this.hourHeightPx = grid.hourHeight; this.hourHeightPx = grid.hourHeight;
this.snapMin = grid.snapInterval; this.snapMin = grid.snapInterval;
this.minDurationMin = this.snapMin; // Use snap interval as minimum duration this.minDurationMin = this.snapMin; // Use snap interval as minimum duration

View file

@ -1,5 +1,5 @@
import { CalendarView, IEventBus } from '../types/CalendarTypes'; import { CalendarView, IEventBus } from '../types/CalendarTypes';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { CoreEvents } from '../constants/CoreEvents'; import { CoreEvents } from '../constants/CoreEvents';
@ -113,7 +113,7 @@ export class ViewManager {
this.updateButtonGroup( this.updateButtonGroup(
this.getWorkweekButtons(), this.getWorkweekButtons(),
'data-workweek', 'data-workweek',
this.config.getCurrentWorkWeek() this.config.currentWorkWeek
); );
} }

View file

@ -1,7 +1,7 @@
// Work hours management for per-column scheduling // Work hours management for per-column scheduling
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { PositionUtils } from '../utils/PositionUtils'; import { PositionUtils } from '../utils/PositionUtils';
/** /**
@ -102,7 +102,7 @@ export class WorkHoursManager {
return null; // Full day will be colored via CSS background return null; // Full day will be colored via CSS background
} }
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const dayStartHour = gridSettings.dayStartHour; const dayStartHour = gridSettings.dayStartHour;
const hourHeight = gridSettings.hourHeight; const hourHeight = gridSettings.hourHeight;

View file

@ -1,6 +1,6 @@
// Column rendering strategy interface and implementations // Column rendering strategy interface and implementations
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
import { WorkHoursManager } from '../managers/WorkHoursManager'; import { WorkHoursManager } from '../managers/WorkHoursManager';
@ -36,10 +36,10 @@ export class DateColumnRenderer implements IColumnRenderer {
render(columnContainer: HTMLElement, context: IColumnRenderContext): void { render(columnContainer: HTMLElement, context: IColumnRenderContext): void {
const { currentWeek, config } = context; const { currentWeek, config } = context;
const workWeekSettings = config.getWorkWeekSettings(); const workWeekSettings = config.getWorkWeekSettings();
const dates = this.dateService.getWorkWeekDates(currentWeek, workWeekSettings.workDays); const dates = this.dateService.getWorkWeekDates(currentWeek, workWeekSettings.workDays);
const dateSettings = config.getDateViewSettings(); const dateSettings = config.dateViewSettings;
const daysToShow = dates.slice(0, dateSettings.weekDays); const daysToShow = dates.slice(0, dateSettings.weekDays);

View file

@ -1,6 +1,6 @@
// Header rendering strategy interface and implementations // Header rendering strategy interface and implementations
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
/** /**
@ -33,13 +33,13 @@ export class DateHeaderRenderer implements IHeaderRenderer {
calendarHeader.appendChild(allDayContainer); calendarHeader.appendChild(allDayContainer);
// Initialize date service with timezone and locale from config // Initialize date service with timezone and locale from config
const timezone = config.getTimezone(); const timezone = config.timeFormatConfig.timezone;
const locale = config.getLocale(); const locale = config.timeFormatConfig.locale;
this.dateService = new DateService(config); this.dateService = new DateService(config);
const workWeekSettings = config.getWorkWeekSettings(); const workWeekSettings = config.getWorkWeekSettings();
const dates = this.dateService.getWorkWeekDates(currentWeek, workWeekSettings.workDays); const dates = this.dateService.getWorkWeekDates(currentWeek, workWeekSettings.workDays);
const weekDays = config.getDateViewSettings().weekDays; const weekDays = config.dateViewSettings.weekDays;
const daysToShow = dates.slice(0, weekDays); const daysToShow = dates.slice(0, weekDays);
daysToShow.forEach((date, index) => { daysToShow.forEach((date, index) => {

View file

@ -1,7 +1,7 @@
// Event rendering strategy interface and implementations // Event rendering strategy interface and implementations
import { ICalendarEvent } from '../types/CalendarTypes'; import { ICalendarEvent } from '../types/CalendarTypes';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { SwpEventElement } from '../elements/SwpEventElement'; import { SwpEventElement } from '../elements/SwpEventElement';
import { PositionUtils } from '../utils/PositionUtils'; import { PositionUtils } from '../utils/PositionUtils';
import { IColumnBounds } from '../utils/ColumnDetectionUtils'; import { IColumnBounds } from '../utils/ColumnDetectionUtils';
@ -312,7 +312,7 @@ export class DateEventRenderer implements IEventRenderer {
// (e.g., if container starts at 07:00 and event starts at 08:15, offset = 75 min) // (e.g., if container starts at 07:00 and event starts at 08:15, offset = 75 min)
const timeDiffMs = event.start.getTime() - containerStart.getTime(); const timeDiffMs = event.start.getTime() - containerStart.getTime();
const timeDiffMinutes = timeDiffMs / (1000 * 60); const timeDiffMinutes = timeDiffMs / (1000 * 60);
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const relativeTop = timeDiffMinutes > 0 ? (timeDiffMinutes / 60) * gridSettings.hourHeight : 0; const relativeTop = timeDiffMinutes > 0 ? (timeDiffMinutes / 60) * gridSettings.hourHeight : 0;
// Events in grid columns are positioned absolutely within their column container // Events in grid columns are positioned absolutely within their column container

View file

@ -1,4 +1,4 @@
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { CalendarView } from '../types/CalendarTypes'; import { CalendarView } from '../types/CalendarTypes';
import { IColumnRenderer, IColumnRenderContext } from './ColumnRenderer'; import { IColumnRenderer, IColumnRenderContext } from './ColumnRenderer';
import { eventBus } from '../core/EventBus'; import { eventBus } from '../core/EventBus';
@ -179,7 +179,7 @@ export class GridRenderer {
private createOptimizedTimeAxis(): HTMLElement { private createOptimizedTimeAxis(): HTMLElement {
const timeAxis = document.createElement('swp-time-axis'); const timeAxis = document.createElement('swp-time-axis');
const timeAxisContent = document.createElement('swp-time-axis-content'); const timeAxisContent = document.createElement('swp-time-axis-content');
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const startHour = gridSettings.dayStartHour; const startHour = gridSettings.dayStartHour;
const endHour = gridSettings.dayEndHour; const endHour = gridSettings.dayEndHour;

View file

@ -29,13 +29,13 @@ import {
fromZonedTime, fromZonedTime,
formatInTimeZone formatInTimeZone
} from 'date-fns-tz'; } from 'date-fns-tz';
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
export class DateService { export class DateService {
private timezone: string; private timezone: string;
constructor(config: Configuration) { constructor(config: Configuration) {
this.timezone = config.getTimezone(); this.timezone = config.timeFormatConfig.timezone;
} }
// ============================================ // ============================================

View file

@ -1,4 +1,4 @@
import { Configuration } from '../configuration/CalendarConfig'; import { Configuration } from '../configurations/CalendarConfig';
import { IColumnBounds } from './ColumnDetectionUtils'; import { IColumnBounds } from './ColumnDetectionUtils';
import { DateService } from './DateService'; import { DateService } from './DateService';
import { TimeFormatter } from './TimeFormatter'; import { TimeFormatter } from './TimeFormatter';
@ -22,7 +22,7 @@ export class PositionUtils {
* Convert minutes to pixels * Convert minutes to pixels
*/ */
public minutesToPixels(minutes: number): number { public minutesToPixels(minutes: number): number {
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const pixelsPerHour = gridSettings.hourHeight; const pixelsPerHour = gridSettings.hourHeight;
return (minutes / 60) * pixelsPerHour; return (minutes / 60) * pixelsPerHour;
} }
@ -31,7 +31,7 @@ export class PositionUtils {
* Convert pixels to minutes * Convert pixels to minutes
*/ */
public pixelsToMinutes(pixels: number): number { public pixelsToMinutes(pixels: number): number {
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const pixelsPerHour = gridSettings.hourHeight; const pixelsPerHour = gridSettings.hourHeight;
return (pixels / pixelsPerHour) * 60; return (pixels / pixelsPerHour) * 60;
} }
@ -41,7 +41,7 @@ export class PositionUtils {
*/ */
public timeToPixels(timeString: string): number { public timeToPixels(timeString: string): number {
const totalMinutes = this.dateService.timeToMinutes(timeString); const totalMinutes = this.dateService.timeToMinutes(timeString);
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const dayStartMinutes = gridSettings.dayStartHour * 60; const dayStartMinutes = gridSettings.dayStartHour * 60;
const minutesFromDayStart = totalMinutes - dayStartMinutes; const minutesFromDayStart = totalMinutes - dayStartMinutes;
@ -53,7 +53,7 @@ export class PositionUtils {
*/ */
public dateToPixels(date: Date): number { public dateToPixels(date: Date): number {
const totalMinutes = this.dateService.getMinutesSinceMidnight(date); const totalMinutes = this.dateService.getMinutesSinceMidnight(date);
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const dayStartMinutes = gridSettings.dayStartHour * 60; const dayStartMinutes = gridSettings.dayStartHour * 60;
const minutesFromDayStart = totalMinutes - dayStartMinutes; const minutesFromDayStart = totalMinutes - dayStartMinutes;
@ -65,7 +65,7 @@ export class PositionUtils {
*/ */
public pixelsToTime(pixels: number): string { public pixelsToTime(pixels: number): string {
const minutes = this.pixelsToMinutes(pixels); const minutes = this.pixelsToMinutes(pixels);
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const dayStartMinutes = gridSettings.dayStartHour * 60; const dayStartMinutes = gridSettings.dayStartHour * 60;
const totalMinutes = dayStartMinutes + minutes; const totalMinutes = dayStartMinutes + minutes;
@ -109,7 +109,7 @@ export class PositionUtils {
* Snap position til grid interval * Snap position til grid interval
*/ */
public snapToGrid(pixels: number): number { public snapToGrid(pixels: number): number {
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const snapInterval = gridSettings.snapInterval; const snapInterval = gridSettings.snapInterval;
const snapPixels = this.minutesToPixels(snapInterval); const snapPixels = this.minutesToPixels(snapInterval);
@ -121,7 +121,7 @@ export class PositionUtils {
*/ */
public snapTimeToInterval(timeString: string): string { public snapTimeToInterval(timeString: string): string {
const totalMinutes = this.dateService.timeToMinutes(timeString); const totalMinutes = this.dateService.timeToMinutes(timeString);
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const snapInterval = gridSettings.snapInterval; const snapInterval = gridSettings.snapInterval;
const snappedMinutes = Math.round(totalMinutes / snapInterval) * snapInterval; const snappedMinutes = Math.round(totalMinutes / snapInterval) * snapInterval;
@ -182,7 +182,7 @@ export class PositionUtils {
*/ */
public isWithinWorkHours(timeString: string): boolean { public isWithinWorkHours(timeString: string): boolean {
const [hours] = timeString.split(':').map(Number); const [hours] = timeString.split(':').map(Number);
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
return hours >= gridSettings.workStartHour && hours < gridSettings.workEndHour; return hours >= gridSettings.workStartHour && hours < gridSettings.workEndHour;
} }
@ -191,7 +191,7 @@ export class PositionUtils {
*/ */
public isWithinDayBounds(timeString: string): boolean { public isWithinDayBounds(timeString: string): boolean {
const [hours] = timeString.split(':').map(Number); const [hours] = timeString.split(':').map(Number);
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
return hours >= gridSettings.dayStartHour && hours < gridSettings.dayEndHour; return hours >= gridSettings.dayStartHour && hours < gridSettings.dayEndHour;
} }
@ -207,7 +207,7 @@ export class PositionUtils {
* Hent maksimum event højde i pixels (hele dagen) * Hent maksimum event højde i pixels (hele dagen)
*/ */
public getMaximumEventHeight(): number { public getMaximumEventHeight(): number {
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.gridSettings;
const dayDurationHours = gridSettings.dayEndHour - gridSettings.dayStartHour; const dayDurationHours = gridSettings.dayEndHour - gridSettings.dayStartHour;
return dayDurationHours * gridSettings.hourHeight; return dayDurationHours * gridSettings.hourHeight;
} }

View file

@ -9,32 +9,24 @@
*/ */
import { DateService } from './DateService'; import { DateService } from './DateService';
import { ITimeFormatConfig } from '../configurations/TimeFormatConfig';
export interface ITimeFormatSettings {
timezone: string;
use24HourFormat: boolean;
locale: string;
dateFormat: 'locale' | 'technical';
showSeconds: boolean;
}
export class TimeFormatter { export class TimeFormatter {
private static settings: ITimeFormatSettings = { private static settings: ITimeFormatConfig | null = null;
timezone: 'Europe/Copenhagen', // Default to Denmark
use24HourFormat: true, // 24-hour format standard in Denmark
locale: 'da-DK', // Danish locale
dateFormat: 'technical', // Use technical format yyyy-mm-dd hh:mm:ss
showSeconds: false // Don't show seconds by default
};
// DateService will be initialized lazily to avoid circular dependency with CalendarConfig // DateService will be initialized lazily to avoid circular dependency with CalendarConfig
private static dateService: DateService | null = null; private static dateService: DateService | null = null;
private static getDateService(): DateService { private static getDateService(): DateService {
if (!TimeFormatter.dateService) { if (!TimeFormatter.dateService) {
if (!TimeFormatter.settings) {
throw new Error('TimeFormatter must be configured before use. Call TimeFormatter.configure() first.');
}
// Create a minimal config object for DateService // Create a minimal config object for DateService
const config = { const config = {
getTimezone: () => TimeFormatter.settings.timezone timeFormatConfig: {
timezone: TimeFormatter.settings.timezone
}
}; };
TimeFormatter.dateService = new DateService(config as any); TimeFormatter.dateService = new DateService(config as any);
} }
@ -43,9 +35,10 @@ export class TimeFormatter {
/** /**
* Configure time formatting settings * Configure time formatting settings
* Must be called before using TimeFormatter
*/ */
static configure(settings: Partial<ITimeFormatSettings>): void { static configure(settings: ITimeFormatConfig): void {
TimeFormatter.settings = { ...TimeFormatter.settings, ...settings }; TimeFormatter.settings = settings;
// Reset DateService to pick up new timezone // Reset DateService to pick up new timezone
TimeFormatter.dateService = null; TimeFormatter.dateService = null;
} }
@ -71,6 +64,9 @@ export class TimeFormatter {
* @returns Formatted time string (e.g., "09:00") * @returns Formatted time string (e.g., "09:00")
*/ */
private static format24Hour(date: Date): string { private static format24Hour(date: Date): string {
if (!TimeFormatter.settings) {
throw new Error('TimeFormatter must be configured before use. Call TimeFormatter.configure() first.');
}
const localDate = TimeFormatter.convertToLocalTime(date); const localDate = TimeFormatter.convertToLocalTime(date);
return TimeFormatter.getDateService().formatTime(localDate, TimeFormatter.settings.showSeconds); return TimeFormatter.getDateService().formatTime(localDate, TimeFormatter.settings.showSeconds);
} }