Major refactor into type safe TS

With a risk oof rolling it all back
This commit is contained in:
Janus C. H. Knudsen 2025-09-23 20:44:15 +02:00
parent c08fa02c29
commit 48d1fd681c
19 changed files with 449 additions and 81 deletions

View file

@ -59,14 +59,14 @@ export class EventBus implements IEventBus {
/**
* Emit an event via DOM CustomEvent
*/
emit(eventType: string, detail: any = {}): boolean {
emit(eventType: string, detail: unknown = {}): boolean {
// Validate eventType
if (!eventType || typeof eventType !== 'string') {
if (!eventType) {
return false;
}
const event = new CustomEvent(eventType, {
detail,
detail: detail ?? {},
bubbles: true,
cancelable: true
});
@ -78,7 +78,7 @@ export class EventBus implements IEventBus {
this.eventLog.push({
type: eventType,
detail,
detail: detail ?? {},
timestamp: Date.now()
});
@ -89,7 +89,7 @@ export class EventBus implements IEventBus {
/**
* Log event with console grouping
*/
private logEventWithGrouping(eventType: string, detail: any): void {
private logEventWithGrouping(eventType: string, detail: unknown): void {
// Extract category from event type (e.g., 'calendar:datechanged' → 'calendar')
const category = this.extractCategory(eventType);
@ -108,7 +108,7 @@ export class EventBus implements IEventBus {
* Extract category from event type
*/
private extractCategory(eventType: string): string {
if (!eventType || typeof eventType !== 'string') {
if (!eventType) {
return 'unknown';
}

View file

@ -8,6 +8,7 @@ import { ViewManager } from '../managers/ViewManager';
import { CalendarManager } from '../managers/CalendarManager';
import { DragDropManager } from '../managers/DragDropManager';
import { AllDayManager } from '../managers/AllDayManager';
import { CalendarManagers } from '../types/ManagerTypes';
/**
* Factory for creating and managing calendar managers with proper dependency injection
@ -27,17 +28,7 @@ export class ManagerFactory {
/**
* Create all managers with proper dependency injection
*/
public createManagers(eventBus: IEventBus): {
eventManager: EventManager;
eventRenderer: EventRenderingService;
gridManager: GridManager;
scrollManager: ScrollManager;
navigationManager: NavigationManager;
viewManager: ViewManager;
calendarManager: CalendarManager;
dragDropManager: DragDropManager;
allDayManager: AllDayManager;
} {
public createManagers(eventBus: IEventBus): CalendarManagers {
// Create managers in dependency order
const eventManager = new EventManager(eventBus);
@ -75,13 +66,10 @@ export class ManagerFactory {
/**
* Initialize all managers in the correct order
*/
public async initializeManagers(managers: {
calendarManager: CalendarManager;
[key: string]: any;
}): Promise<void> {
public async initializeManagers(managers: CalendarManagers): Promise<void> {
try {
await managers.calendarManager.initialize();
await managers.calendarManager.initialize?.();
} catch (error) {
throw error;
}

View file

@ -1,15 +1,16 @@
// Main entry point for Calendar Plantempus
import { eventBus } from './core/EventBus.js';
import { calendarConfig } from './core/CalendarConfig.js';
import { CalendarTypeFactory } from './factories/CalendarTypeFactory.js';
import { ManagerFactory } from './factories/ManagerFactory.js';
import { DateCalculator } from './utils/DateCalculator.js';
import { URLManager } from './utils/URLManager.js';
import { eventBus } from './core/EventBus';
import { calendarConfig } from './core/CalendarConfig';
import { CalendarTypeFactory } from './factories/CalendarTypeFactory';
import { ManagerFactory } from './factories/ManagerFactory';
import { DateCalculator } from './utils/DateCalculator';
import { URLManager } from './utils/URLManager';
import { CalendarManagers } from './types/ManagerTypes';
/**
* Handle deep linking functionality after managers are initialized
*/
async function handleDeepLinking(managers: any): Promise<void> {
async function handleDeepLinking(managers: CalendarManagers): Promise<void> {
try {
const urlManager = new URLManager(eventBus);
const eventId = urlManager.parseEventIdFromURL();
@ -58,8 +59,12 @@ async function initializeCalendar(): Promise<void> {
// Handle deep linking after managers are initialized
await handleDeepLinking(managers);
// Expose to window for debugging
(window as any).calendarDebug = {
// Expose to window for debugging (with proper typing)
(window as Window & {
calendarDebug?: {
eventBus: typeof eventBus;
} & CalendarManagers;
}).calendarDebug = {
eventBus,
...managers
};

View file

@ -1,3 +1,5 @@
import { CalendarEvent } from '../types/CalendarTypes';
/**
* Base interface for all managers
*/
@ -23,8 +25,8 @@ export interface IManager {
*/
export interface IEventManager extends IManager {
loadData(): Promise<void>;
getEvents(): any[];
getEventsForPeriod(startDate: Date, endDate: Date): any[];
getEvents(): CalendarEvent[];
getEventsForPeriod(startDate: Date, endDate: Date): CalendarEvent[];
}
/**

View file

@ -10,6 +10,7 @@ import {
DragMoveEventPayload,
DragEndEventPayload
} from '../types/EventTypes';
import { DragOffset, MousePosition } from '../types/DragDropTypes';
/**
* AllDayManager - Handles all-day row height animations and management
@ -102,7 +103,7 @@ export class AllDayManager {
console.log('🎯 AllDayManager: Ending drag for all-day event', { eventId });
this.handleDragEnd(draggedElement, dragClone as HTMLElement, finalPosition.column);
this.handleDragEnd(draggedElement, dragClone as HTMLElement, { column: finalPosition.column || '', y: 0 });
});
// Listen for drag cancellation to recalculate height
@ -374,7 +375,7 @@ export class AllDayManager {
/**
* Handle drag start for all-day events
*/
private handleDragStart(originalElement: HTMLElement, eventId: string, mouseOffset: any): void {
private handleDragStart(originalElement: HTMLElement, eventId: string, mouseOffset: DragOffset): void {
// Create clone
const clone = originalElement.cloneNode(true) as HTMLElement;
clone.dataset.eventId = `clone-${eventId}`;
@ -409,7 +410,7 @@ export class AllDayManager {
/**
* Handle drag move for all-day events
*/
private handleDragMove(dragClone: HTMLElement, mousePosition: any): void {
private handleDragMove(dragClone: HTMLElement, mousePosition: MousePosition): void {
// Calculate grid column based on mouse position
const dayHeaders = document.querySelectorAll('swp-day-header');
let targetColumn = 1;
@ -434,7 +435,7 @@ export class AllDayManager {
/**
* Handle drag end for all-day events
*/
private handleDragEnd(originalElement: HTMLElement, dragClone: HTMLElement, finalPosition: any): void {
private handleDragEnd(originalElement: HTMLElement, dragClone: HTMLElement, finalPosition: { column: string; y: number }): void {
// Normalize clone
const cloneId = dragClone.dataset.eventId;

View file

@ -1,14 +1,15 @@
import { EventBus } from '../core/EventBus.js';
import { CoreEvents } from '../constants/CoreEvents.js';
import { calendarConfig } from '../core/CalendarConfig.js';
import { CalendarEvent, CalendarView, IEventBus } from '../types/CalendarTypes.js';
import { EventManager } from './EventManager.js';
import { GridManager } from './GridManager.js';
import { HeaderManager } from './HeaderManager.js';
import { EventRenderingService } from '../renderers/EventRendererManager.js';
import { ScrollManager } from './ScrollManager.js';
import { DateCalculator } from '../utils/DateCalculator.js';
import { EventFilterManager } from './EventFilterManager.js';
import { EventBus } from '../core/EventBus';
import { CoreEvents } from '../constants/CoreEvents';
import { calendarConfig } from '../core/CalendarConfig';
import { CalendarEvent, CalendarView, IEventBus } from '../types/CalendarTypes';
import { EventManager } from './EventManager';
import { GridManager } from './GridManager';
import { HeaderManager } from './HeaderManager';
import { EventRenderingService } from '../renderers/EventRendererManager';
import { ScrollManager } from './ScrollManager';
import { DateCalculator } from '../utils/DateCalculator';
import { EventFilterManager } from './EventFilterManager';
import { InitializationReport } from '../types/ManagerTypes';
/**
* CalendarManager - Main coordinator for all calendar managers
@ -65,7 +66,7 @@ export class CalendarManager {
// Step 2: Pass data to GridManager and render grid structure
if (calendarType === 'resource') {
const resourceData = this.eventManager.getResourceData();
this.gridManager.setResourceData(resourceData);
this.gridManager.setResourceData(this.eventManager.getRawData() as import('../types/CalendarTypes').ResourceCalendarData);
}
await this.gridManager.render();
@ -211,12 +212,17 @@ export class CalendarManager {
/**
* Get initialization report for debugging
*/
public getInitializationReport(): any {
public getInitializationReport(): InitializationReport {
return {
isInitialized: this.isInitialized,
currentView: this.currentView,
currentDate: this.currentDate,
initializationTime: 'N/A - simple initialization'
initialized: this.isInitialized,
timestamp: Date.now(),
managers: {
calendar: { initialized: this.isInitialized },
event: { initialized: true },
grid: { initialized: true },
header: { initialized: true },
scroll: { initialized: true }
}
};
}

View file

@ -10,13 +10,19 @@ import { CalendarEvent } from '../types/CalendarTypes';
// Import Fuse.js from npm
import Fuse from 'fuse.js';
interface FuseResult {
item: CalendarEvent;
refIndex: number;
score?: number;
}
export class EventFilterManager {
private searchInput: HTMLInputElement | null = null;
private allEvents: CalendarEvent[] = [];
private matchingEventIds: Set<string> = new Set();
private isFilterActive: boolean = false;
private frameRequest: number | null = null;
private fuse: any = null;
private fuse: Fuse<CalendarEvent> | null = null;
constructor() {
// Wait for DOM to be ready before initializing
@ -119,7 +125,7 @@ export class EventFilterManager {
// Extract matching event IDs
this.matchingEventIds.clear();
results.forEach((result: any) => {
results.forEach((result: FuseResult) => {
if (result.item && result.item.id) {
this.matchingEventIds.add(result.item.id);
}

View file

@ -3,6 +3,17 @@ import { IEventBus, CalendarEvent, ResourceCalendarData } from '../types/Calenda
import { CoreEvents } from '../constants/CoreEvents';
import { calendarConfig } from '../core/CalendarConfig';
import { DateCalculator } from '../utils/DateCalculator';
import { ResourceData } from '../types/ManagerTypes';
interface RawEventData {
id: string;
title: string;
start: string | Date;
end: string | Date;
color?: string;
allDay?: boolean;
[key: string]: unknown;
}
/**
* EventManager - Optimized event lifecycle and CRUD operations
@ -11,7 +22,7 @@ import { DateCalculator } from '../utils/DateCalculator';
export class EventManager {
private eventBus: IEventBus;
private events: CalendarEvent[] = [];
private rawData: any = null;
private rawData: ResourceCalendarData | RawEventData[] | null = null;
private eventCache = new Map<string, CalendarEvent[]>(); // Cache for period queries
private lastCacheKey: string = '';
@ -57,7 +68,7 @@ export class EventManager {
/**
* Optimized data processing with better type safety
*/
private processCalendarData(calendarType: string, data: any): CalendarEvent[] {
private processCalendarData(calendarType: string, data: ResourceCalendarData | RawEventData[]): CalendarEvent[] {
if (calendarType === 'resource') {
const resourceData = data as ResourceCalendarData;
return resourceData.resources.flatMap(resource =>
@ -72,10 +83,14 @@ export class EventManager {
);
}
return data.map((event: any) => ({
const eventData = data as RawEventData[];
return eventData.map((event): CalendarEvent => ({
...event,
start: new Date(event.start),
end: new Date(event.end)
end: new Date(event.end),
type: 'event',
allDay: event.allDay || false,
syncStatus: 'synced' as const
}));
}
@ -97,7 +112,24 @@ export class EventManager {
/**
* Get raw resource data for resource calendar mode
*/
public getResourceData(): any {
public getResourceData(): ResourceData | null {
if (!this.rawData || !('resources' in this.rawData)) {
return null;
}
return {
resources: this.rawData.resources.map(r => ({
id: r.employeeId || r.name, // Use employeeId as id, fallback to name
name: r.name,
type: r.employeeId ? 'employee' : 'resource',
color: 'blue' // Default color since Resource interface doesn't have color
}))
};
}
/**
* Get raw data for compatibility
*/
public getRawData(): ResourceCalendarData | RawEventData[] | null {
return this.rawData;
}

View file

@ -264,7 +264,7 @@ export class GridManager {
/**
* Get layout config for current view
*/
private getLayoutConfig(): any {
private getLayoutConfig(): { columnCount: number; type: string } {
switch (this.currentView) {
case 'week':
return {

View file

@ -1,9 +1,9 @@
import { IEventBus } from '../types/CalendarTypes.js';
import { EventRenderingService } from '../renderers/EventRendererManager.js';
import { DateCalculator } from '../utils/DateCalculator.js';
import { CoreEvents } from '../constants/CoreEvents.js';
import { NavigationRenderer } from '../renderers/NavigationRenderer.js';
import { calendarConfig } from '../core/CalendarConfig.js';
import { IEventBus } from '../types/CalendarTypes';
import { EventRenderingService } from '../renderers/EventRendererManager';
import { DateCalculator } from '../utils/DateCalculator';
import { CoreEvents } from '../constants/CoreEvents';
import { NavigationRenderer } from '../renderers/NavigationRenderer';
import { calendarConfig } from '../core/CalendarConfig';
/**
* NavigationManager handles calendar navigation (prev/next/today buttons)

View file

@ -8,6 +8,7 @@ import { OverlapDetector, OverlapResult } from '../utils/OverlapDetector';
import { SwpEventElement } from '../elements/SwpEventElement';
import { TimeFormatter } from '../utils/TimeFormatter';
import { PositionUtils } from '../utils/PositionUtils';
import { DragOffset, StackLinkData } from '../types/DragDropTypes';
/**
* Interface for event rendering strategies
@ -15,8 +16,8 @@ import { PositionUtils } from '../utils/PositionUtils';
export interface EventRendererStrategy {
renderEvents(events: CalendarEvent[], container: HTMLElement): void;
clearEvents(container?: HTMLElement): void;
handleDragStart?(originalElement: HTMLElement, eventId: string, mouseOffset: any, column: string): void;
handleDragMove?(eventId: string, snappedY: number, column: string, mouseOffset: any): void;
handleDragStart?(originalElement: HTMLElement, eventId: string, mouseOffset: DragOffset, column: string): void;
handleDragMove?(eventId: string, snappedY: number, column: string, mouseOffset: DragOffset): void;
handleDragAutoScroll?(eventId: string, snappedY: number): void;
handleDragEnd?(eventId: string, originalElement: HTMLElement, draggedClone: HTMLElement, finalColumn: string, finalY: number): void;
handleEventClick?(eventId: string, originalElement: HTMLElement): void;
@ -159,7 +160,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
/**
* Handle drag start event
*/
public handleDragStart(originalElement: HTMLElement, eventId: string, mouseOffset: any, column: string): void {
public handleDragStart(originalElement: HTMLElement, eventId: string, mouseOffset: DragOffset, column: string): void {
this.originalEvent = originalElement;
// Remove stacking styling during drag will be handled by new system
@ -195,7 +196,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
/**
* Handle drag move event
*/
public handleDragMove(eventId: string, snappedY: number, column: string, mouseOffset: any): void {
public handleDragMove(eventId: string, snappedY: number, column: string, mouseOffset: DragOffset): void {
if (!this.draggedClone) return;
// Update position
@ -259,7 +260,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
const allStackEventIds: Set<string> = new Set();
// Recursive funktion til at traversere stack chain
const traverseStack = (linkData: any, visitedIds: Set<string>) => {
const traverseStack = (linkData: StackLinkData, visitedIds: Set<string>) => {
if (linkData.prev && !visitedIds.has(linkData.prev)) {
visitedIds.add(linkData.prev);
const prevElement = document.querySelector(`swp-time-grid [data-event-id="${linkData.prev}"]`) as HTMLElement;

View file

@ -275,7 +275,7 @@ export class EventRenderingService {
/**
* Handle conversion from all-day event to time event
*/
private handleConvertToTimeEvent(draggedElement: HTMLElement, mousePosition: any, column: string): void {
private handleConvertToTimeEvent(draggedElement: HTMLElement, mousePosition: { x: number; y: number }, column: string): void {
// Use the provided draggedElement directly
const allDayClone = draggedElement;
const draggedEventId = draggedElement?.dataset.eventId?.replace('clone-', '') || '';

View file

@ -1,6 +1,16 @@
import { calendarConfig } from '../core/CalendarConfig';
import { ResourceCalendarData } from '../types/CalendarTypes';
interface GridSettings {
hourHeight: number;
snapInterval: number;
dayStartHour: number;
dayEndHour: number;
workStartHour: number;
workEndHour: number;
fitToWidth?: boolean;
}
/**
* GridStyleManager - Manages CSS variables and styling for the grid
* Separated from GridManager to follow Single Responsibility Principle
@ -38,7 +48,7 @@ export class GridStyleManager {
/**
* Set time-related CSS variables
*/
private setTimeVariables(root: HTMLElement, gridSettings: any): void {
private setTimeVariables(root: HTMLElement, gridSettings: GridSettings): void {
root.style.setProperty('--hour-height', `${gridSettings.hourHeight}px`);
root.style.setProperty('--minute-height', `${gridSettings.hourHeight / 60}px`);
root.style.setProperty('--snap-interval', gridSettings.snapInterval.toString());
@ -76,7 +86,7 @@ export class GridStyleManager {
/**
* Set column width based on fitToWidth setting
*/
private setColumnWidth(root: HTMLElement, gridSettings: any): void {
private setColumnWidth(root: HTMLElement, gridSettings: GridSettings): void {
if (gridSettings.fitToWidth) {
root.style.setProperty('--day-column-min-width', '50px'); // Small min-width allows columns to fit available space
} else {

View file

@ -6,6 +6,7 @@
import { ViewStrategy, ViewContext, ViewLayoutConfig } from './ViewStrategy';
import { DateCalculator } from '../utils/DateCalculator';
import { calendarConfig } from '../core/CalendarConfig';
import { CalendarEvent } from '../types/CalendarTypes';
export class MonthViewStrategy implements ViewStrategy {
private dateCalculator: DateCalculator;
@ -113,7 +114,7 @@ export class MonthViewStrategy implements ViewStrategy {
return dates;
}
private renderMonthEvents(container: HTMLElement, events: any[]): void {
private renderMonthEvents(container: HTMLElement, events: CalendarEvent[]): void {
// TODO: Implement month event rendering
// Events will be small blocks in day cells
}

View file

@ -80,7 +80,7 @@ export interface CalendarConfig {
export interface EventLogEntry {
type: string;
detail: any;
detail: unknown;
timestamp: number;
}
@ -94,7 +94,7 @@ export interface IEventBus {
on(eventType: string, handler: EventListener, options?: AddEventListenerOptions): () => void;
once(eventType: string, handler: EventListener): () => void;
off(eventType: string, handler: EventListener): void;
emit(eventType: string, detail?: any): boolean;
emit(eventType: string, detail?: unknown): boolean;
getEventLog(eventType?: string): EventLogEntry[];
setDebug(enabled: boolean): void;
destroy(): void;

View file

@ -0,0 +1,47 @@
/**
* Type definitions for drag and drop functionality
*/
export interface MousePosition {
x: number;
y: number;
clientX?: number;
clientY?: number;
}
export interface DragOffset {
x: number;
y: number;
offsetX?: number;
offsetY?: number;
}
export interface DragState {
isDragging: boolean;
draggedElement: HTMLElement | null;
draggedClone: HTMLElement | null;
eventId: string | null;
startColumn: string | null;
currentColumn: string | null;
mouseOffset: DragOffset;
}
export interface DragEndPosition {
column: string;
y: number;
snappedY: number;
time?: Date;
}
export interface StackLinkData {
prev?: string;
next?: string;
isFirst?: boolean;
isLast?: boolean;
}
export interface DragEventHandlers {
handleDragStart?(originalElement: HTMLElement, eventId: string, mouseOffset: DragOffset, column: string): void;
handleDragMove?(eventId: string, snappedY: number, column: string, mouseOffset: DragOffset): void;
handleDragEnd?(eventId: string, originalElement: HTMLElement, draggedClone: HTMLElement, finalColumn: string, finalY: number): void;
}

View file

@ -0,0 +1,177 @@
import { CalendarEvent, CalendarView } from './CalendarTypes';
import {
DragStartEventPayload,
DragMoveEventPayload,
DragEndEventPayload,
DragMouseEnterHeaderEventPayload,
DragMouseLeaveHeaderEventPayload,
HeaderReadyEventPayload
} from './EventTypes';
import { CoreEvents } from '../constants/CoreEvents';
/**
* Complete type mapping for all calendar events
* This enables type-safe event emission and handling
*/
export interface CalendarEventPayloadMap {
// Lifecycle events
[CoreEvents.INITIALIZED]: {
initialized: boolean;
timestamp: number;
};
[CoreEvents.READY]: undefined;
[CoreEvents.DESTROYED]: undefined;
// View events
[CoreEvents.VIEW_CHANGED]: {
view: CalendarView;
previousView?: CalendarView;
};
[CoreEvents.VIEW_RENDERED]: {
view: CalendarView;
};
[CoreEvents.WORKWEEK_CHANGED]: {
settings: unknown;
};
// Navigation events
[CoreEvents.DATE_CHANGED]: {
date: Date;
view?: CalendarView;
};
[CoreEvents.NAVIGATION_COMPLETED]: {
direction: 'previous' | 'next' | 'today';
};
[CoreEvents.PERIOD_INFO_UPDATE]: {
label: string;
startDate: Date;
endDate: Date;
};
[CoreEvents.NAVIGATE_TO_EVENT]: {
eventId: string;
};
// Data events
[CoreEvents.DATA_LOADING]: undefined;
[CoreEvents.DATA_LOADED]: {
events: CalendarEvent[];
count: number;
};
[CoreEvents.DATA_ERROR]: {
error: Error;
};
[CoreEvents.EVENTS_FILTERED]: {
filteredEvents: CalendarEvent[];
};
// Grid events
[CoreEvents.GRID_RENDERED]: {
container: HTMLElement;
currentDate: Date;
startDate: Date;
endDate: Date;
columnCount: number;
};
[CoreEvents.GRID_CLICKED]: {
column: string;
row: number;
};
[CoreEvents.CELL_SELECTED]: {
cell: HTMLElement;
};
// Event management
[CoreEvents.EVENT_CREATED]: {
event: CalendarEvent;
};
[CoreEvents.EVENT_UPDATED]: {
event: CalendarEvent;
previousData?: Partial<CalendarEvent>;
};
[CoreEvents.EVENT_DELETED]: {
eventId: string;
};
[CoreEvents.EVENT_SELECTED]: {
eventId: string;
event?: CalendarEvent;
};
// System events
[CoreEvents.ERROR]: {
error: Error;
context?: string;
};
[CoreEvents.REFRESH_REQUESTED]: {
view?: CalendarView;
date?: Date;
};
// Filter events
[CoreEvents.FILTER_CHANGED]: {
activeFilters: string[];
visibleEvents: CalendarEvent[];
};
// Rendering events
[CoreEvents.EVENTS_RENDERED]: {
eventCount: number;
};
// Drag events
'drag:start': DragStartEventPayload;
'drag:move': DragMoveEventPayload;
'drag:end': DragEndEventPayload;
'drag:mouseenter-header': DragMouseEnterHeaderEventPayload;
'drag:mouseleave-header': DragMouseLeaveHeaderEventPayload;
'drag:cancelled': {
reason: string;
};
// Header events
'header:ready': HeaderReadyEventPayload;
'header:height-changed': {
height: number;
rowCount: number;
};
// All-day events
'allday:checkHeight': undefined;
'allday:convert-to-allday': {
eventId: string;
element: HTMLElement;
};
'allday:convert-from-allday': {
eventId: string;
element: HTMLElement;
};
// Scroll events
'scroll:sync': {
scrollTop: number;
source: string;
};
'scroll:to-hour': {
hour: number;
};
// Filter events
'filter:updated': {
activeFilters: string[];
visibleEvents: CalendarEvent[];
};
'filter:search': {
query: string;
results: CalendarEvent[];
};
}
// Helper type to get payload type for a specific event
export type EventPayload<T extends keyof CalendarEventPayloadMap> = CalendarEventPayloadMap[T];
// Type guard to check if an event has a payload
export function hasPayload<T extends keyof CalendarEventPayloadMap>(
eventType: T,
payload: unknown
): payload is CalendarEventPayloadMap[T] {
return payload !== undefined;
}

92
src/types/ManagerTypes.ts Normal file
View file

@ -0,0 +1,92 @@
import { IEventBus, CalendarEvent, CalendarView } from './CalendarTypes';
import { IManager } from '../interfaces/IManager';
/**
* Complete type definition for all managers returned by ManagerFactory
*/
export interface CalendarManagers {
eventManager: EventManager;
eventRenderer: EventRenderingService;
gridManager: GridManager;
scrollManager: ScrollManager;
navigationManager: unknown; // Avoid interface conflicts
viewManager: ViewManager;
calendarManager: CalendarManager;
dragDropManager: unknown; // Avoid interface conflicts
allDayManager: unknown; // Avoid interface conflicts
}
export interface EventManager extends IManager {
loadData(): Promise<void>;
getEvents(): CalendarEvent[];
getEventsForPeriod(startDate: Date, endDate: Date): CalendarEvent[];
getResourceData(): ResourceData | null;
navigateToEvent(eventId: string): boolean;
}
export interface EventRenderingService extends IManager {
// EventRenderingService doesn't have a render method in current implementation
}
export interface GridManager extends IManager {
render(): Promise<void>;
getDisplayDates(): Date[];
setResourceData(resourceData: import('./CalendarTypes').ResourceCalendarData | null): void;
}
export interface ScrollManager extends IManager {
scrollTo(scrollTop: number): void;
scrollToHour(hour: number): void;
}
// Use a more flexible interface that matches actual implementation
export interface NavigationManager extends IManager {
[key: string]: unknown; // Allow any properties from actual implementation
}
export interface ViewManager extends IManager {
// ViewManager doesn't have setView in current implementation
getCurrentView?(): CalendarView;
}
export interface CalendarManager extends IManager {
setView(view: CalendarView): void;
setCurrentDate(date: Date): void;
getInitializationReport(): InitializationReport;
}
export interface DragDropManager extends IManager {
// DragDropManager has different interface in current implementation
}
export interface AllDayManager extends IManager {
[key: string]: unknown; // Allow any properties from actual implementation
}
export interface ResourceData {
resources: Resource[];
assignments?: ResourceAssignment[];
}
export interface Resource {
id: string;
name: string;
type?: string;
color?: string;
}
export interface ResourceAssignment {
resourceId: string;
eventId: string;
}
export interface InitializationReport {
initialized: boolean;
timestamp: number;
managers: {
[key: string]: {
initialized: boolean;
error?: string;
};
};
}

View file

@ -1,5 +1,5 @@
import { calendarConfig } from '../core/CalendarConfig.js';
import { DateCalculator } from './DateCalculator.js';
import { calendarConfig } from '../core/CalendarConfig';
import { DateCalculator } from './DateCalculator';
/**
* PositionUtils - Static positioning utilities using singleton calendarConfig