Refactors dependency injection and configuration management
Replaces global singleton configuration with dependency injection Introduces more modular and testable approach to configuration Removes direct references to calendarConfig in multiple components Adds explicit configuration passing to constructors Improves code maintainability and reduces global state dependencies
This commit is contained in:
parent
fb48e410ea
commit
8bbb2f05d3
30 changed files with 365 additions and 559 deletions
|
|
@ -1,7 +1,7 @@
|
|||
// All-day row height management and animations
|
||||
|
||||
import { eventBus } from '../core/EventBus';
|
||||
import { ALL_DAY_CONSTANTS, calendarConfig } from '../core/CalendarConfig';
|
||||
import { ALL_DAY_CONSTANTS } from '../core/CalendarConfig';
|
||||
import { AllDayEventRenderer } from '../renderers/AllDayEventRenderer';
|
||||
import { AllDayLayoutEngine, EventLayout } from '../utils/AllDayLayoutEngine';
|
||||
import { ColumnBounds, ColumnDetectionUtils } from '../utils/ColumnDetectionUtils';
|
||||
|
|
@ -43,11 +43,14 @@ export class AllDayManager {
|
|||
private actualRowCount: number = 0;
|
||||
|
||||
|
||||
constructor(eventManager: EventManager) {
|
||||
constructor(
|
||||
eventManager: EventManager,
|
||||
allDayEventRenderer: AllDayEventRenderer,
|
||||
dateService: DateService
|
||||
) {
|
||||
this.eventManager = eventManager;
|
||||
this.allDayEventRenderer = new AllDayEventRenderer();
|
||||
const timezone = calendarConfig.getTimezone?.();
|
||||
this.dateService = new DateService(timezone);
|
||||
this.allDayEventRenderer = allDayEventRenderer;
|
||||
this.dateService = dateService;
|
||||
|
||||
// Sync CSS variable with TypeScript constant to ensure consistency
|
||||
document.documentElement.style.setProperty('--single-row-height', `${ALL_DAY_CONSTANTS.EVENT_HEIGHT}px`);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { CalendarView, IEventBus } from '../types/CalendarTypes';
|
||||
import { EventManager } from './EventManager';
|
||||
import { GridManager } from './GridManager';
|
||||
|
|
@ -8,7 +8,6 @@ import { ScrollManager } from './ScrollManager';
|
|||
|
||||
/**
|
||||
* CalendarManager - Main coordinator for all calendar managers
|
||||
* Uses singleton calendarConfig for consistent configuration access
|
||||
*/
|
||||
export class CalendarManager {
|
||||
private eventBus: IEventBus;
|
||||
|
|
@ -16,6 +15,7 @@ export class CalendarManager {
|
|||
private gridManager: GridManager;
|
||||
private eventRenderer: EventRenderingService;
|
||||
private scrollManager: ScrollManager;
|
||||
private config: CalendarConfig;
|
||||
private currentView: CalendarView = 'week';
|
||||
private currentDate: Date = new Date();
|
||||
private isInitialized: boolean = false;
|
||||
|
|
@ -25,14 +25,15 @@ export class CalendarManager {
|
|||
eventManager: EventManager,
|
||||
gridManager: GridManager,
|
||||
eventRenderingService: EventRenderingService,
|
||||
scrollManager: ScrollManager
|
||||
scrollManager: ScrollManager,
|
||||
config: CalendarConfig
|
||||
) {
|
||||
this.eventBus = eventBus;
|
||||
this.eventManager = eventManager;
|
||||
this.gridManager = gridManager;
|
||||
this.eventRenderer = eventRenderingService;
|
||||
this.scrollManager = scrollManager;
|
||||
const timezone = calendarConfig.getTimezone?.();
|
||||
this.config = config;
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ export class CalendarManager {
|
|||
|
||||
try {
|
||||
// Debug: Check calendar type
|
||||
const calendarType = calendarConfig.getCalendarMode();
|
||||
const calendarType = this.config.getCalendarMode();
|
||||
|
||||
// Step 1: Load data
|
||||
await this.eventManager.loadData();
|
||||
|
|
@ -212,7 +213,7 @@ export class CalendarManager {
|
|||
this.eventBus.emit('workweek:header-update', {
|
||||
currentDate: this.currentDate,
|
||||
currentView: this.currentView,
|
||||
workweek: calendarConfig.getCurrentWorkWeek()
|
||||
workweek: this.config.getCurrentWorkWeek()
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
|
||||
import { IEventBus } from '../types/CalendarTypes';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { PositionUtils } from '../utils/PositionUtils';
|
||||
import { ColumnBounds, ColumnDetectionUtils } from '../utils/ColumnDetectionUtils';
|
||||
import { SwpEventElement, BaseSwpEventElement } from '../elements/SwpEventElement';
|
||||
|
|
@ -49,9 +48,11 @@ export class DragDropManager {
|
|||
private targetY = 0;
|
||||
private currentY = 0;
|
||||
private targetColumn: ColumnBounds | null = null;
|
||||
private positionUtils: PositionUtils;
|
||||
|
||||
constructor(eventBus: IEventBus) {
|
||||
constructor(eventBus: IEventBus, positionUtils: PositionUtils) {
|
||||
this.eventBus = eventBus;
|
||||
this.positionUtils = positionUtils;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
|
@ -415,7 +416,7 @@ export class DragDropManager {
|
|||
const eventTopY = mouseY - this.mouseOffset.y;
|
||||
|
||||
// Snap the event top position, not the mouse position
|
||||
const snappedY = PositionUtils.getPositionFromCoordinate(eventTopY, column);
|
||||
const snappedY = this.positionUtils.getPositionFromCoordinate(eventTopY, column);
|
||||
|
||||
return Math.max(0, snappedY);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import { CalendarEvent } from '../types/CalendarTypes';
|
||||
import { EventStackManager, EventGroup, StackLink } from './EventStackManager';
|
||||
import { PositionUtils } from '../utils/PositionUtils';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
|
||||
export interface GridGroupLayout {
|
||||
events: CalendarEvent[];
|
||||
|
|
@ -30,9 +30,13 @@ export interface ColumnLayout {
|
|||
|
||||
export class EventLayoutCoordinator {
|
||||
private stackManager: EventStackManager;
|
||||
private config: CalendarConfig;
|
||||
private positionUtils: PositionUtils;
|
||||
|
||||
constructor() {
|
||||
this.stackManager = new EventStackManager();
|
||||
constructor(stackManager: EventStackManager, config: CalendarConfig, positionUtils: PositionUtils) {
|
||||
this.stackManager = stackManager;
|
||||
this.config = config;
|
||||
this.positionUtils = positionUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -55,7 +59,7 @@ export class EventLayoutCoordinator {
|
|||
|
||||
// Find events that could be in GRID with first event
|
||||
// Use expanding search to find chains (A→B→C where each conflicts with next)
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
const thresholdMinutes = gridSettings.gridStartThresholdMinutes;
|
||||
|
||||
// Use refactored method for expanding grid candidates
|
||||
|
|
@ -78,7 +82,7 @@ export class EventLayoutCoordinator {
|
|||
|
||||
// Ensure we get the earliest event (explicit sort for robustness)
|
||||
const earliestEvent = [...gridCandidates].sort((a, b) => a.start.getTime() - b.start.getTime())[0];
|
||||
const position = PositionUtils.calculateEventPosition(earliestEvent.start, earliestEvent.end);
|
||||
const position = this.positionUtils.calculateEventPosition(earliestEvent.start, earliestEvent.end);
|
||||
const columns = this.allocateColumns(gridCandidates);
|
||||
|
||||
gridGroupLayouts.push({
|
||||
|
|
@ -100,7 +104,7 @@ export class EventLayoutCoordinator {
|
|||
renderedEventsWithLevels
|
||||
);
|
||||
|
||||
const position = PositionUtils.calculateEventPosition(firstEvent.start, firstEvent.end);
|
||||
const position = this.positionUtils.calculateEventPosition(firstEvent.start, firstEvent.end);
|
||||
stackedEventLayouts.push({
|
||||
event: firstEvent,
|
||||
stackLink: { stackLevel },
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { IEventBus, CalendarEvent, ResourceCalendarData } from '../types/CalendarTypes';
|
||||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { DateService } from '../utils/DateService';
|
||||
import { ResourceData } from '../types/ManagerTypes';
|
||||
|
||||
|
|
@ -20,16 +20,21 @@ interface RawEventData {
|
|||
* Handles data loading with improved performance and caching
|
||||
*/
|
||||
export class EventManager {
|
||||
|
||||
|
||||
private events: CalendarEvent[] = [];
|
||||
private rawData: ResourceCalendarData | RawEventData[] | null = null;
|
||||
private eventCache = new Map<string, CalendarEvent[]>(); // Cache for period queries
|
||||
private lastCacheKey: string = '';
|
||||
private dateService: DateService;
|
||||
private config: CalendarConfig;
|
||||
|
||||
constructor(private eventBus: IEventBus) {
|
||||
const timezone = calendarConfig.getTimezone?.();
|
||||
this.dateService = new DateService(timezone);
|
||||
constructor(
|
||||
private eventBus: IEventBus,
|
||||
dateService: DateService,
|
||||
config: CalendarConfig
|
||||
) {
|
||||
this.dateService = dateService;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -50,7 +55,7 @@ export class EventManager {
|
|||
* Optimized mock data loading with better resource handling
|
||||
*/
|
||||
private async loadMockData(): Promise<void> {
|
||||
const calendarType = calendarConfig.getCalendarMode();
|
||||
const calendarType = this.config.getCalendarMode();
|
||||
const jsonFile = calendarType === 'resource'
|
||||
? '/src/data/mock-resource-events.json'
|
||||
: '/src/data/mock-events.json';
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
import { CalendarEvent } from '../types/CalendarTypes';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
|
||||
export interface StackLink {
|
||||
prev?: string; // Event ID of previous event in stack
|
||||
|
|
@ -30,6 +30,11 @@ export interface EventGroup {
|
|||
|
||||
export class EventStackManager {
|
||||
private static readonly STACK_OFFSET_PX = 15;
|
||||
private config: CalendarConfig;
|
||||
|
||||
constructor(config: CalendarConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// PHASE 1: Start Time Grouping
|
||||
|
|
@ -46,7 +51,7 @@ export class EventStackManager {
|
|||
if (events.length === 0) return [];
|
||||
|
||||
// Get threshold from config
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
const thresholdMinutes = gridSettings.gridStartThresholdMinutes;
|
||||
|
||||
// Sort events by start time
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
|
||||
import { eventBus } from '../core/EventBus';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { ResourceCalendarData, CalendarView } from '../types/CalendarTypes';
|
||||
import { GridRenderer } from '../renderers/GridRenderer';
|
||||
|
|
@ -23,11 +22,14 @@ export class GridManager {
|
|||
private styleManager: GridStyleManager;
|
||||
private dateService: DateService;
|
||||
|
||||
constructor(gridRenderer: GridRenderer) {
|
||||
// Inject GridRenderer via DI
|
||||
constructor(
|
||||
gridRenderer: GridRenderer,
|
||||
styleManager: GridStyleManager,
|
||||
dateService: DateService
|
||||
) {
|
||||
this.gridRenderer = gridRenderer;
|
||||
this.styleManager = new GridStyleManager();
|
||||
this.dateService = new DateService('Europe/Copenhagen');
|
||||
this.styleManager = styleManager;
|
||||
this.dateService = dateService;
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { eventBus } from '../core/EventBus';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { HeaderRenderer, HeaderRenderContext } from '../renderers/HeaderRenderer';
|
||||
import { ResourceCalendarData } from '../types/CalendarTypes';
|
||||
|
|
@ -13,9 +13,11 @@ import { ColumnDetectionUtils } from '../utils/ColumnDetectionUtils';
|
|||
*/
|
||||
export class HeaderManager {
|
||||
private headerRenderer: HeaderRenderer;
|
||||
private config: CalendarConfig;
|
||||
|
||||
constructor(headerRenderer: HeaderRenderer) {
|
||||
constructor(headerRenderer: HeaderRenderer, config: CalendarConfig) {
|
||||
this.headerRenderer = headerRenderer;
|
||||
this.config = config;
|
||||
|
||||
// Bind handler methods for event listeners
|
||||
this.handleDragMouseEnterHeader = this.handleDragMouseEnterHeader.bind(this);
|
||||
|
|
@ -127,7 +129,7 @@ export class HeaderManager {
|
|||
// Render new header content using injected renderer
|
||||
const context: HeaderRenderContext = {
|
||||
currentWeek: currentDate,
|
||||
config: calendarConfig,
|
||||
config: this.config,
|
||||
resourceData: resourceData
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { DateService } from '../utils/DateService';
|
|||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { NavigationRenderer } from '../renderers/NavigationRenderer';
|
||||
import { GridRenderer } from '../renderers/GridRenderer';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
|
||||
/**
|
||||
* NavigationManager handles calendar navigation (prev/next/today buttons)
|
||||
|
|
@ -19,10 +18,16 @@ export class NavigationManager {
|
|||
private targetWeek: Date;
|
||||
private animationQueue: number = 0;
|
||||
|
||||
constructor(eventBus: IEventBus, eventRenderer: EventRenderingService, gridRenderer: GridRenderer) {
|
||||
constructor(
|
||||
eventBus: IEventBus,
|
||||
eventRenderer: EventRenderingService,
|
||||
gridRenderer: GridRenderer,
|
||||
dateService: DateService,
|
||||
navigationRenderer: NavigationRenderer
|
||||
) {
|
||||
this.eventBus = eventBus;
|
||||
this.dateService = new DateService('Europe/Copenhagen');
|
||||
this.navigationRenderer = new NavigationRenderer(eventBus, eventRenderer);
|
||||
this.dateService = dateService;
|
||||
this.navigationRenderer = navigationRenderer;
|
||||
this.gridRenderer = gridRenderer;
|
||||
this.currentWeek = this.getISOWeekStart(new Date());
|
||||
this.targetWeek = new Date(this.currentWeek);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { eventBus } from '../core/EventBus';
|
||||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { ResizeEndEventPayload } from '../types/EventTypes';
|
||||
|
||||
type SwpEventEl = HTMLElement & { updateHeight?: (h: number) => void };
|
||||
|
|
@ -29,9 +29,11 @@ export class ResizeHandleManager {
|
|||
private unsubscribers: Array<() => void> = [];
|
||||
private pointerCaptured = false;
|
||||
private prevZ?: string;
|
||||
private config: CalendarConfig;
|
||||
|
||||
constructor() {
|
||||
const grid = calendarConfig.getGridSettings();
|
||||
constructor(config: CalendarConfig) {
|
||||
this.config = config;
|
||||
const grid = this.config.getGridSettings();
|
||||
this.hourHeightPx = grid.hourHeight;
|
||||
this.snapMin = grid.snapInterval;
|
||||
this.minDurationMin = this.snapMin; // Use snap interval as minimum duration
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Custom scroll management for calendar week container
|
||||
|
||||
import { eventBus } from '../core/EventBus';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { PositionUtils } from '../utils/PositionUtils';
|
||||
|
||||
|
|
@ -14,8 +13,10 @@ export class ScrollManager {
|
|||
private timeAxis: HTMLElement | null = null;
|
||||
private calendarHeader: HTMLElement | null = null;
|
||||
private resizeObserver: ResizeObserver | null = null;
|
||||
private positionUtils: PositionUtils;
|
||||
|
||||
constructor() {
|
||||
constructor(positionUtils: PositionUtils) {
|
||||
this.positionUtils = positionUtils;
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +113,7 @@ export class ScrollManager {
|
|||
scrollToHour(hour: number): void {
|
||||
// Create time string for the hour
|
||||
const timeString = `${hour.toString().padStart(2, '0')}:00`;
|
||||
const scrollTop = PositionUtils.timeToPixels(timeString);
|
||||
const scrollTop = this.positionUtils.timeToPixels(timeString);
|
||||
|
||||
this.scrollTo(scrollTop);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { EventBus } from '../core/EventBus';
|
||||
import { CalendarView, IEventBus } from '../types/CalendarTypes';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
|
||||
/**
|
||||
|
|
@ -9,17 +9,19 @@ import { CoreEvents } from '../constants/CoreEvents';
|
|||
*/
|
||||
export class ViewManager {
|
||||
private eventBus: IEventBus;
|
||||
private config: CalendarConfig;
|
||||
private currentView: CalendarView = 'week';
|
||||
private buttonListeners: Map<Element, EventListener> = new Map();
|
||||
|
||||
|
||||
// Cached DOM elements for performance
|
||||
private cachedViewButtons: NodeListOf<Element> | null = null;
|
||||
private cachedWorkweekButtons: NodeListOf<Element> | null = null;
|
||||
private lastButtonCacheTime: number = 0;
|
||||
private readonly CACHE_DURATION = 5000; // 5 seconds
|
||||
|
||||
constructor(eventBus: IEventBus) {
|
||||
constructor(eventBus: IEventBus, config: CalendarConfig) {
|
||||
this.eventBus = eventBus;
|
||||
this.config = config;
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
|
|
@ -140,13 +142,13 @@ export class ViewManager {
|
|||
*/
|
||||
private changeWorkweek(workweekId: string): void {
|
||||
// Update the calendar config (does not emit events)
|
||||
calendarConfig.setWorkWeek(workweekId);
|
||||
this.config.setWorkWeek(workweekId);
|
||||
|
||||
// Update button states using cached elements
|
||||
this.updateAllButtons();
|
||||
|
||||
// Emit workweek change event with full payload
|
||||
const settings = calendarConfig.getWorkWeekSettings();
|
||||
const settings = this.config.getWorkWeekSettings();
|
||||
this.eventBus.emit(CoreEvents.WORKWEEK_CHANGED, {
|
||||
workWeekId: workweekId,
|
||||
settings: settings
|
||||
|
|
@ -166,7 +168,7 @@ export class ViewManager {
|
|||
this.updateButtonGroup(
|
||||
this.getWorkweekButtons(),
|
||||
'data-workweek',
|
||||
calendarConfig.getCurrentWorkWeek()
|
||||
this.config.getCurrentWorkWeek()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Work hours management for per-column scheduling
|
||||
|
||||
import { DateService } from '../utils/DateService';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { PositionUtils } from '../utils/PositionUtils';
|
||||
|
||||
/**
|
||||
|
|
@ -35,11 +35,14 @@ export interface WorkScheduleConfig {
|
|||
*/
|
||||
export class WorkHoursManager {
|
||||
private dateService: DateService;
|
||||
private config: CalendarConfig;
|
||||
private positionUtils: PositionUtils;
|
||||
private workSchedule: WorkScheduleConfig;
|
||||
|
||||
constructor() {
|
||||
const timezone = calendarConfig.getTimezone?.();
|
||||
this.dateService = new DateService(timezone);
|
||||
constructor(dateService: DateService, config: CalendarConfig, positionUtils: PositionUtils) {
|
||||
this.dateService = dateService;
|
||||
this.config = config;
|
||||
this.positionUtils = positionUtils;
|
||||
|
||||
// Default work schedule - will be loaded from JSON later
|
||||
this.workSchedule = {
|
||||
|
|
@ -98,8 +101,8 @@ export class WorkHoursManager {
|
|||
if (workHours === 'off') {
|
||||
return null; // Full day will be colored via CSS background
|
||||
}
|
||||
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
const dayStartHour = gridSettings.dayStartHour;
|
||||
const hourHeight = gridSettings.hourHeight;
|
||||
|
||||
|
|
@ -128,7 +131,7 @@ export class WorkHoursManager {
|
|||
const endTime = `${workHours.end.toString().padStart(2, '0')}:00`;
|
||||
|
||||
// Use PositionUtils for consistent position calculation
|
||||
const position = PositionUtils.calculateEventPosition(startTime, endTime);
|
||||
const position = this.positionUtils.calculateEventPosition(startTime, endTime);
|
||||
|
||||
return { top: position.top, height: position.height };
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue