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

@ -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;
};
};
}