Major refactorering to get a hold on all these events

This commit is contained in:
Janus Knudsen 2025-08-09 00:31:44 +02:00
parent 2a766cf685
commit 59b3c64c55
18 changed files with 1901 additions and 357 deletions

170
src/types/CalendarState.ts Normal file
View file

@ -0,0 +1,170 @@
// Calendar state management types
/**
* Calendar initialization and runtime states
* Represents the progression from startup to ready state
*/
export enum CalendarState {
UNINITIALIZED = 'uninitialized',
INITIALIZING = 'initializing',
CONFIG_LOADED = 'config_loaded',
DATA_LOADING = 'data_loading',
DATA_LOADED = 'data_loaded',
RENDERING = 'rendering',
RENDERED = 'rendered',
READY = 'ready',
ERROR = 'error'
}
/**
* State-driven events with clear progression and timing
*/
export const StateEvents = {
// Core lifecycle events
CALENDAR_STATE_CHANGED: 'calendar:state:changed',
// Configuration phase
CONFIG_LOADING_STARTED: 'calendar:config:loading:started',
CONFIG_LOADED: 'calendar:config:loaded',
CONFIG_FAILED: 'calendar:config:failed',
// Data loading phase (can run parallel with rendering setup)
DATA_LOADING_STARTED: 'calendar:data:loading:started',
DATA_LOADED: 'calendar:data:loaded',
DATA_FAILED: 'calendar:data:failed',
// Rendering phase
RENDERING_STARTED: 'calendar:rendering:started',
DOM_STRUCTURE_READY: 'calendar:dom:structure:ready',
GRID_RENDERED: 'calendar:grid:rendered',
EVENTS_RENDERED: 'calendar:events:rendered',
RENDERING_COMPLETE: 'calendar:rendering:complete',
// System ready
CALENDAR_READY: 'calendar:ready',
// Error handling
CALENDAR_ERROR: 'calendar:error',
RECOVERY_ATTEMPTED: 'calendar:recovery:attempted',
RECOVERY_SUCCESS: 'calendar:recovery:success',
RECOVERY_FAILED: 'calendar:recovery:failed',
// User interaction events (unchanged)
VIEW_CHANGE_REQUESTED: 'calendar:view:change:requested',
VIEW_CHANGED: 'calendar:view:changed',
NAVIGATION_REQUESTED: 'calendar:navigation:requested',
} as const;
/**
* Standardized event payload structure
*/
export interface CalendarEvent {
type: string;
component: string;
timestamp: number;
data?: any;
error?: Error;
metadata?: {
duration?: number;
dependencies?: string[];
phase?: string;
retryCount?: number;
};
}
/**
* State change event payload
*/
export interface StateChangeEvent extends CalendarEvent {
type: typeof StateEvents.CALENDAR_STATE_CHANGED;
data: {
from: CalendarState;
to: CalendarState;
transitionValid: boolean;
};
}
/**
* Error event payload
*/
export interface ErrorEvent extends CalendarEvent {
type: typeof StateEvents.CALENDAR_ERROR;
error: Error;
data: {
failedComponent: string;
currentState: CalendarState;
canRecover: boolean;
};
}
/**
* Data loaded event payload
*/
export interface DataLoadedEvent extends CalendarEvent {
type: typeof StateEvents.DATA_LOADED;
data: {
eventCount: number;
calendarMode: 'date' | 'resource';
period: {
start: string;
end: string;
};
};
}
/**
* Grid rendered event payload
*/
export interface GridRenderedEvent extends CalendarEvent {
type: typeof StateEvents.GRID_RENDERED;
data: {
columnCount: number;
rowCount?: number;
gridMode: 'date' | 'resource';
domElementsCreated: string[];
};
}
/**
* Valid state transitions map
* Defines which state transitions are allowed
*/
export const VALID_STATE_TRANSITIONS: Record<CalendarState, CalendarState[]> = {
[CalendarState.UNINITIALIZED]: [CalendarState.INITIALIZING, CalendarState.ERROR],
[CalendarState.INITIALIZING]: [CalendarState.CONFIG_LOADED, CalendarState.ERROR],
[CalendarState.CONFIG_LOADED]: [CalendarState.DATA_LOADING, CalendarState.RENDERING, CalendarState.ERROR],
[CalendarState.DATA_LOADING]: [CalendarState.DATA_LOADED, CalendarState.ERROR],
[CalendarState.DATA_LOADED]: [CalendarState.RENDERING, CalendarState.RENDERED, CalendarState.ERROR],
[CalendarState.RENDERING]: [CalendarState.RENDERED, CalendarState.ERROR],
[CalendarState.RENDERED]: [CalendarState.READY, CalendarState.ERROR],
[CalendarState.READY]: [CalendarState.DATA_LOADING, CalendarState.ERROR], // Allow refresh
[CalendarState.ERROR]: [CalendarState.INITIALIZING, CalendarState.CONFIG_LOADED] // Recovery paths
};
/**
* State phases for logical grouping
*/
export enum InitializationPhase {
STARTUP = 'startup',
CONFIGURATION = 'configuration',
DATA_AND_DOM = 'data-and-dom',
EVENT_RENDERING = 'event-rendering',
FINALIZATION = 'finalization',
ERROR_RECOVERY = 'error-recovery'
}
/**
* Map states to their initialization phases
*/
export const STATE_TO_PHASE: Record<CalendarState, InitializationPhase> = {
[CalendarState.UNINITIALIZED]: InitializationPhase.STARTUP,
[CalendarState.INITIALIZING]: InitializationPhase.STARTUP,
[CalendarState.CONFIG_LOADED]: InitializationPhase.CONFIGURATION,
[CalendarState.DATA_LOADING]: InitializationPhase.DATA_AND_DOM,
[CalendarState.DATA_LOADED]: InitializationPhase.DATA_AND_DOM,
[CalendarState.RENDERING]: InitializationPhase.DATA_AND_DOM,
[CalendarState.RENDERED]: InitializationPhase.EVENT_RENDERING,
[CalendarState.READY]: InitializationPhase.FINALIZATION,
[CalendarState.ERROR]: InitializationPhase.ERROR_RECOVERY
};

View file

@ -1,11 +1,16 @@
// Calendar type definitions
export type ViewType = 'day' | 'week' | 'month';
export type CalendarView = ViewType; // Alias for compatibility
// Time period view types (how much time to display)
export type ViewPeriod = 'day' | 'week' | 'month';
export type CalendarType = 'date' | 'resource';
// Calendar mode types (how to organize the data)
export type CalendarMode = 'date' | 'resource';
export type EventType = 'meeting' | 'meal' | 'work' | 'milestone';
// Legacy aliases for backwards compatibility
export type DateViewType = ViewPeriod;
export type ViewType = DateViewType;
export type CalendarView = ViewType;
export type CalendarType = CalendarMode;
export type SyncStatus = 'synced' | 'pending' | 'error';
@ -27,37 +32,22 @@ export interface CalendarEvent {
title: string;
start: string; // ISO 8601
end: string; // ISO 8601
type: EventType;
type: string; // Flexible event type - can be any string value
allDay: boolean;
syncStatus: SyncStatus;
// Resource information (only present in resource calendar mode)
resourceName?: string;
resourceDisplayName?: string;
resourceEmployeeId?: string;
resource?: {
name: string;
displayName: string;
employeeId: string;
};
recurringId?: string;
resources?: string[];
metadata?: Record<string, any>;
}
export interface CalendarConfig {
// View settings
view: ViewType;
weekDays: number; // 4-7 days for week view
firstDayOfWeek: number; // 0 = Sunday, 1 = Monday
// Time settings
dayStartHour: number; // Calendar starts at hour
dayEndHour: number; // Calendar ends at hour
workStartHour: number; // Work hours start
workEndHour: number; // Work hours end
snapInterval: number; // Minutes: 5, 10, 15, 30, 60
// Display settings
hourHeight: number; // Pixels per hour
showCurrentTime: boolean;
showWorkHours: boolean;
fitToWidth: boolean; // Fit columns to calendar width vs horizontal scroll
// Scrollbar styling
scrollbarWidth: number; // Width of scrollbar in pixels
scrollbarColor: string; // Scrollbar thumb color
@ -116,7 +106,7 @@ export interface GridPosition {
export interface Period {
start: string;
end: string;
view: ViewType;
mode?: CalendarMode; // Optional: which calendar mode this period is for
}
export interface EventData {
@ -124,7 +114,30 @@ export interface EventData {
meta: {
start: string;
end: string;
view: ViewType;
total: number;
mode?: CalendarMode; // Which calendar mode this data is for
};
}
}
/**
* Context interfaces for different calendar modes
*/
export interface DateModeContext {
mode: 'date';
currentWeek: Date;
period: ViewPeriod;
weekDays: number;
firstDayOfWeek: number;
}
export interface ResourceModeContext {
mode: 'resource';
selectedDate: Date;
resources: Resource[];
maxResources: number;
}
/**
* Union type for type-safe mode contexts
*/
export type CalendarModeContext = DateModeContext | ResourceModeContext;