2025-07-24 22:17:38 +02:00
|
|
|
// Main entry point for Calendar Plantempus
|
2025-10-30 21:46:38 +01:00
|
|
|
import { Container } from '@novadi/core';
|
2025-09-23 20:44:15 +02:00
|
|
|
import { eventBus } from './core/EventBus';
|
2025-11-03 22:04:37 +01:00
|
|
|
import { ConfigManager } from './configurations/ConfigManager';
|
|
|
|
|
import { Configuration } from './configurations/CalendarConfig';
|
2025-09-23 20:44:15 +02:00
|
|
|
import { URLManager } from './utils/URLManager';
|
2025-11-20 15:25:38 +01:00
|
|
|
import { ICalendarEvent, IEventBus } from './types/CalendarTypes';
|
2025-10-30 21:46:38 +01:00
|
|
|
|
|
|
|
|
// Import all managers
|
2025-10-14 22:53:28 +02:00
|
|
|
import { EventManager } from './managers/EventManager';
|
2025-10-30 21:46:38 +01:00
|
|
|
import { EventRenderingService } from './renderers/EventRendererManager';
|
|
|
|
|
import { GridManager } from './managers/GridManager';
|
|
|
|
|
import { ScrollManager } from './managers/ScrollManager';
|
|
|
|
|
import { NavigationManager } from './managers/NavigationManager';
|
2025-11-08 14:30:18 +01:00
|
|
|
import { NavigationButtons } from './components/NavigationButtons';
|
|
|
|
|
import { ViewSelector } from './components/ViewSelector';
|
2025-10-30 21:46:38 +01:00
|
|
|
import { CalendarManager } from './managers/CalendarManager';
|
|
|
|
|
import { DragDropManager } from './managers/DragDropManager';
|
|
|
|
|
import { AllDayManager } from './managers/AllDayManager';
|
|
|
|
|
import { ResizeHandleManager } from './managers/ResizeHandleManager';
|
|
|
|
|
import { EdgeScrollManager } from './managers/EdgeScrollManager';
|
|
|
|
|
import { HeaderManager } from './managers/HeaderManager';
|
2025-11-08 14:30:18 +01:00
|
|
|
import { WorkweekPresets } from './components/WorkweekPresets';
|
2025-10-30 21:46:38 +01:00
|
|
|
|
2025-11-05 00:37:57 +01:00
|
|
|
// Import repositories and storage
|
2025-11-03 14:54:57 +01:00
|
|
|
import { MockEventRepository } from './repositories/MockEventRepository';
|
2025-11-20 15:25:38 +01:00
|
|
|
import { MockBookingRepository } from './repositories/MockBookingRepository';
|
|
|
|
|
import { MockCustomerRepository } from './repositories/MockCustomerRepository';
|
|
|
|
|
import { MockResourceRepository } from './repositories/MockResourceRepository';
|
2025-11-21 23:23:04 +01:00
|
|
|
import { MockAuditRepository } from './repositories/MockAuditRepository';
|
2025-11-18 16:37:33 +01:00
|
|
|
import { IApiRepository } from './repositories/IApiRepository';
|
2025-11-21 23:23:04 +01:00
|
|
|
import { IAuditEntry } from './types/AuditTypes';
|
2025-11-05 00:37:57 +01:00
|
|
|
import { ApiEventRepository } from './repositories/ApiEventRepository';
|
2025-11-18 16:37:33 +01:00
|
|
|
import { ApiBookingRepository } from './repositories/ApiBookingRepository';
|
|
|
|
|
import { ApiCustomerRepository } from './repositories/ApiCustomerRepository';
|
|
|
|
|
import { ApiResourceRepository } from './repositories/ApiResourceRepository';
|
2025-11-20 21:45:09 +01:00
|
|
|
import { IndexedDBContext } from './storage/IndexedDBContext';
|
2025-11-17 17:36:51 +01:00
|
|
|
import { IStore } from './storage/IStore';
|
2025-11-21 23:23:04 +01:00
|
|
|
import { AuditStore } from './storage/audit/AuditStore';
|
|
|
|
|
import { AuditService } from './storage/audit/AuditService';
|
2025-11-17 17:36:51 +01:00
|
|
|
import { BookingStore } from './storage/bookings/BookingStore';
|
|
|
|
|
import { CustomerStore } from './storage/customers/CustomerStore';
|
|
|
|
|
import { ResourceStore } from './storage/resources/ResourceStore';
|
|
|
|
|
import { EventStore } from './storage/events/EventStore';
|
2025-11-18 16:37:33 +01:00
|
|
|
import { IEntityService } from './storage/IEntityService';
|
|
|
|
|
import { EventService } from './storage/events/EventService';
|
|
|
|
|
import { BookingService } from './storage/bookings/BookingService';
|
|
|
|
|
import { CustomerService } from './storage/customers/CustomerService';
|
|
|
|
|
import { ResourceService } from './storage/resources/ResourceService';
|
2025-11-05 00:37:57 +01:00
|
|
|
|
|
|
|
|
// Import workers
|
|
|
|
|
import { SyncManager } from './workers/SyncManager';
|
2025-11-20 15:25:38 +01:00
|
|
|
import { DataSeeder } from './workers/DataSeeder';
|
2025-11-03 14:54:57 +01:00
|
|
|
|
2025-10-30 21:46:38 +01:00
|
|
|
// Import renderers
|
2025-11-01 16:28:45 +01:00
|
|
|
import { DateHeaderRenderer, type IHeaderRenderer } from './renderers/DateHeaderRenderer';
|
2025-11-03 21:30:50 +01:00
|
|
|
import { DateColumnRenderer, type IColumnRenderer } from './renderers/ColumnRenderer';
|
2025-11-01 16:28:45 +01:00
|
|
|
import { DateEventRenderer, type IEventRenderer } from './renderers/EventRenderer';
|
2025-10-30 23:47:30 +01:00
|
|
|
import { AllDayEventRenderer } from './renderers/AllDayEventRenderer';
|
2025-10-30 21:46:38 +01:00
|
|
|
import { GridRenderer } from './renderers/GridRenderer';
|
2025-11-07 23:23:19 +01:00
|
|
|
import { WeekInfoRenderer } from './renderers/WeekInfoRenderer';
|
2025-10-30 23:47:30 +01:00
|
|
|
|
|
|
|
|
// Import utilities and services
|
2025-10-30 22:05:06 +01:00
|
|
|
import { DateService } from './utils/DateService';
|
2025-10-30 23:47:30 +01:00
|
|
|
import { TimeFormatter } from './utils/TimeFormatter';
|
|
|
|
|
import { PositionUtils } from './utils/PositionUtils';
|
|
|
|
|
import { AllDayLayoutEngine } from './utils/AllDayLayoutEngine';
|
|
|
|
|
import { WorkHoursManager } from './managers/WorkHoursManager';
|
|
|
|
|
import { EventStackManager } from './managers/EventStackManager';
|
|
|
|
|
import { EventLayoutCoordinator } from './managers/EventLayoutCoordinator';
|
2025-11-18 22:34:12 +01:00
|
|
|
import { IColumnDataSource } from './types/ColumnDataSource';
|
|
|
|
|
import { DateColumnDataSource } from './datasources/DateColumnDataSource';
|
2025-11-22 19:42:12 +01:00
|
|
|
import { ResourceColumnDataSource } from './datasources/ResourceColumnDataSource';
|
|
|
|
|
import { ResourceHeaderRenderer } from './renderers/ResourceHeaderRenderer';
|
|
|
|
|
import { ResourceColumnRenderer } from './renderers/ResourceColumnRenderer';
|
2025-11-20 15:25:38 +01:00
|
|
|
import { IBooking } from './types/BookingTypes';
|
|
|
|
|
import { ICustomer } from './types/CustomerTypes';
|
|
|
|
|
import { IResource } from './types/ResourceTypes';
|
2025-09-04 00:16:35 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle deep linking functionality after managers are initialized
|
|
|
|
|
*/
|
2025-10-30 23:47:30 +01:00
|
|
|
async function handleDeepLinking(eventManager: EventManager, urlManager: URLManager): Promise<void> {
|
2025-09-04 00:16:35 +02:00
|
|
|
try {
|
|
|
|
|
const eventId = urlManager.parseEventIdFromURL();
|
2025-10-14 22:53:28 +02:00
|
|
|
|
2025-09-04 00:16:35 +02:00
|
|
|
if (eventId) {
|
|
|
|
|
console.log(`Deep linking to event ID: ${eventId}`);
|
2025-10-14 22:53:28 +02:00
|
|
|
|
2025-09-04 00:16:35 +02:00
|
|
|
// Wait a bit for managers to be fully ready
|
2025-11-05 00:37:57 +01:00
|
|
|
setTimeout(async () => {
|
|
|
|
|
const success = await eventManager.navigateToEvent(eventId);
|
2025-09-04 00:16:35 +02:00
|
|
|
if (!success) {
|
|
|
|
|
console.warn(`Deep linking failed: Event with ID ${eventId} not found`);
|
|
|
|
|
}
|
|
|
|
|
}, 500);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.warn('Deep linking failed:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-24 22:17:38 +02:00
|
|
|
|
|
|
|
|
/**
|
2025-10-30 21:46:38 +01:00
|
|
|
* Initialize the calendar application using NovaDI
|
2025-07-24 22:17:38 +02:00
|
|
|
*/
|
2025-08-09 00:31:44 +02:00
|
|
|
async function initializeCalendar(): Promise<void> {
|
|
|
|
|
try {
|
2025-11-03 21:30:50 +01:00
|
|
|
// Load configuration from JSON
|
|
|
|
|
const config = await ConfigManager.load();
|
2025-10-14 22:53:28 +02:00
|
|
|
|
2025-10-30 21:46:38 +01:00
|
|
|
// Create NovaDI container
|
|
|
|
|
const container = new Container();
|
|
|
|
|
const builder = container.builder();
|
2025-10-14 22:53:28 +02:00
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
// Enable debug mode for development
|
|
|
|
|
eventBus.setDebug(true);
|
2025-10-14 22:53:28 +02:00
|
|
|
|
2025-10-30 21:46:38 +01:00
|
|
|
// Bind core services as instances
|
|
|
|
|
builder.registerInstance(eventBus).as<IEventBus>();
|
|
|
|
|
|
2025-11-03 21:30:50 +01:00
|
|
|
// Register configuration instance
|
|
|
|
|
builder.registerInstance(config).as<Configuration>();
|
|
|
|
|
|
2025-11-17 17:36:51 +01:00
|
|
|
// Register storage stores (IStore implementations)
|
|
|
|
|
// Open/Closed Principle: Adding new entity only requires adding one line here
|
|
|
|
|
builder.registerType(BookingStore).as<IStore>();
|
|
|
|
|
builder.registerType(CustomerStore).as<IStore>();
|
|
|
|
|
builder.registerType(ResourceStore).as<IStore>();
|
|
|
|
|
builder.registerType(EventStore).as<IStore>();
|
2025-11-21 23:23:04 +01:00
|
|
|
builder.registerType(AuditStore).as<IStore>();
|
2025-11-17 17:36:51 +01:00
|
|
|
|
2025-11-05 20:35:21 +01:00
|
|
|
// Register storage and repository services
|
2025-11-20 21:45:09 +01:00
|
|
|
builder.registerType(IndexedDBContext).as<IndexedDBContext>();
|
2025-11-18 16:37:33 +01:00
|
|
|
|
2025-11-20 15:25:38 +01:00
|
|
|
// Register Mock repositories (development/testing - load from JSON files)
|
|
|
|
|
// Each entity type has its own Mock repository implementing IApiRepository<T>
|
|
|
|
|
builder.registerType(MockEventRepository).as<IApiRepository<ICalendarEvent>>();
|
|
|
|
|
builder.registerType(MockBookingRepository).as<IApiRepository<IBooking>>();
|
|
|
|
|
builder.registerType(MockCustomerRepository).as<IApiRepository<ICustomer>>();
|
|
|
|
|
builder.registerType(MockResourceRepository).as<IApiRepository<IResource>>();
|
2025-11-21 23:23:04 +01:00
|
|
|
builder.registerType(MockAuditRepository).as<IApiRepository<IAuditEntry>>();
|
2025-11-18 16:37:33 +01:00
|
|
|
|
2025-11-22 23:38:52 +01:00
|
|
|
|
2025-11-25 23:48:30 +01:00
|
|
|
let calendarMode = 'resource' ;
|
2025-11-22 19:42:12 +01:00
|
|
|
// Register DataSource and HeaderRenderer based on mode
|
|
|
|
|
if (calendarMode === 'resource') {
|
|
|
|
|
builder.registerType(ResourceColumnDataSource).as<IColumnDataSource>();
|
|
|
|
|
builder.registerType(ResourceHeaderRenderer).as<IHeaderRenderer>();
|
|
|
|
|
} else {
|
|
|
|
|
builder.registerType(DateColumnDataSource).as<IColumnDataSource>();
|
|
|
|
|
builder.registerType(DateHeaderRenderer).as<IHeaderRenderer>();
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-20 15:25:38 +01:00
|
|
|
// Register entity services (sync status management)
|
2025-11-18 16:37:33 +01:00
|
|
|
// Open/Closed Principle: Adding new entity only requires adding one line here
|
2025-11-20 15:25:38 +01:00
|
|
|
builder.registerType(EventService).as<IEntityService<ICalendarEvent>>();
|
2025-11-22 23:38:52 +01:00
|
|
|
builder.registerType(EventService).as<EventService>();
|
2025-11-20 15:25:38 +01:00
|
|
|
builder.registerType(BookingService).as<IEntityService<IBooking>>();
|
|
|
|
|
builder.registerType(CustomerService).as<IEntityService<ICustomer>>();
|
|
|
|
|
builder.registerType(ResourceService).as<IEntityService<IResource>>();
|
2025-11-22 19:42:12 +01:00
|
|
|
builder.registerType(ResourceService).as<ResourceService>();
|
2025-11-21 23:23:04 +01:00
|
|
|
builder.registerType(AuditService).as<AuditService>();
|
2025-11-18 16:37:33 +01:00
|
|
|
|
2025-11-05 20:35:21 +01:00
|
|
|
// Register workers
|
|
|
|
|
builder.registerType(SyncManager).as<SyncManager>();
|
2025-11-20 15:25:38 +01:00
|
|
|
builder.registerType(DataSeeder).as<DataSeeder>();
|
2025-11-03 14:54:57 +01:00
|
|
|
|
2025-11-01 01:10:10 +01:00
|
|
|
// Register renderers
|
2025-11-22 19:42:12 +01:00
|
|
|
// Note: IHeaderRenderer and IColumnRenderer are registered above based on calendarMode
|
|
|
|
|
if (calendarMode === 'resource') {
|
|
|
|
|
builder.registerType(ResourceColumnRenderer).as<IColumnRenderer>();
|
|
|
|
|
} else {
|
|
|
|
|
builder.registerType(DateColumnRenderer).as<IColumnRenderer>();
|
|
|
|
|
}
|
2025-11-03 14:54:57 +01:00
|
|
|
builder.registerType(DateEventRenderer).as<IEventRenderer>();
|
2025-10-30 21:46:38 +01:00
|
|
|
|
2025-10-30 23:47:30 +01:00
|
|
|
// Register core services and utilities
|
2025-11-03 14:54:57 +01:00
|
|
|
builder.registerType(DateService).as<DateService>();
|
|
|
|
|
builder.registerType(EventStackManager).as<EventStackManager>();
|
|
|
|
|
builder.registerType(EventLayoutCoordinator).as<EventLayoutCoordinator>();
|
|
|
|
|
builder.registerType(WorkHoursManager).as<WorkHoursManager>();
|
|
|
|
|
builder.registerType(URLManager).as<URLManager>();
|
|
|
|
|
builder.registerType(TimeFormatter).as<TimeFormatter>();
|
|
|
|
|
builder.registerType(PositionUtils).as<PositionUtils>();
|
2025-10-30 23:47:30 +01:00
|
|
|
// Note: AllDayLayoutEngine is instantiated per-operation with specific dates, not a singleton
|
2025-11-07 23:23:19 +01:00
|
|
|
builder.registerType(WeekInfoRenderer).as<WeekInfoRenderer>();
|
2025-11-03 14:54:57 +01:00
|
|
|
builder.registerType(AllDayEventRenderer).as<AllDayEventRenderer>();
|
|
|
|
|
|
|
|
|
|
builder.registerType(EventRenderingService).as<EventRenderingService>();
|
|
|
|
|
builder.registerType(GridRenderer).as<GridRenderer>();
|
|
|
|
|
builder.registerType(GridManager).as<GridManager>();
|
|
|
|
|
builder.registerType(ScrollManager).as<ScrollManager>();
|
|
|
|
|
builder.registerType(NavigationManager).as<NavigationManager>();
|
2025-11-08 14:30:18 +01:00
|
|
|
builder.registerType(NavigationButtons).as<NavigationButtons>();
|
|
|
|
|
builder.registerType(ViewSelector).as<ViewSelector>();
|
2025-11-03 14:54:57 +01:00
|
|
|
builder.registerType(DragDropManager).as<DragDropManager>();
|
|
|
|
|
builder.registerType(AllDayManager).as<AllDayManager>();
|
|
|
|
|
builder.registerType(ResizeHandleManager).as<ResizeHandleManager>();
|
|
|
|
|
builder.registerType(EdgeScrollManager).as<EdgeScrollManager>();
|
|
|
|
|
builder.registerType(HeaderManager).as<HeaderManager>();
|
|
|
|
|
builder.registerType(CalendarManager).as<CalendarManager>();
|
2025-11-08 14:30:18 +01:00
|
|
|
builder.registerType(WorkweekPresets).as<WorkweekPresets>();
|
2025-11-03 14:54:57 +01:00
|
|
|
|
2025-11-07 21:05:59 +01:00
|
|
|
builder.registerType(ConfigManager).as<ConfigManager>();
|
2025-11-03 14:54:57 +01:00
|
|
|
builder.registerType(EventManager).as<EventManager>();
|
2025-10-30 21:46:38 +01:00
|
|
|
|
|
|
|
|
// Build the container
|
|
|
|
|
const app = builder.build();
|
|
|
|
|
|
2025-11-20 15:25:38 +01:00
|
|
|
// Initialize database and seed data BEFORE initializing managers
|
2025-11-20 21:45:09 +01:00
|
|
|
const indexedDBContext = app.resolveType<IndexedDBContext>();
|
|
|
|
|
await indexedDBContext.initialize();
|
2025-11-20 15:25:38 +01:00
|
|
|
|
|
|
|
|
const dataSeeder = app.resolveType<DataSeeder>();
|
|
|
|
|
await dataSeeder.seedIfEmpty();
|
|
|
|
|
|
2025-10-14 22:53:28 +02:00
|
|
|
// Get managers from container
|
2025-10-30 21:46:38 +01:00
|
|
|
const eb = app.resolveType<IEventBus>();
|
|
|
|
|
const calendarManager = app.resolveType<CalendarManager>();
|
|
|
|
|
const eventManager = app.resolveType<EventManager>();
|
|
|
|
|
const resizeHandleManager = app.resolveType<ResizeHandleManager>();
|
|
|
|
|
const headerManager = app.resolveType<HeaderManager>();
|
|
|
|
|
const dragDropManager = app.resolveType<DragDropManager>();
|
2025-11-08 14:30:18 +01:00
|
|
|
const viewSelectorManager = app.resolveType<ViewSelector>();
|
2025-10-30 21:46:38 +01:00
|
|
|
const navigationManager = app.resolveType<NavigationManager>();
|
2025-11-08 14:30:18 +01:00
|
|
|
const navigationButtonsManager = app.resolveType<NavigationButtons>();
|
2025-10-30 21:46:38 +01:00
|
|
|
const edgeScrollManager = app.resolveType<EdgeScrollManager>();
|
|
|
|
|
const allDayManager = app.resolveType<AllDayManager>();
|
2025-10-30 23:47:30 +01:00
|
|
|
const urlManager = app.resolveType<URLManager>();
|
2025-11-08 14:30:18 +01:00
|
|
|
const workweekPresetsManager = app.resolveType<WorkweekPresets>();
|
2025-11-07 21:05:59 +01:00
|
|
|
const configManager = app.resolveType<ConfigManager>();
|
2025-10-14 22:53:28 +02:00
|
|
|
|
|
|
|
|
// Initialize managers
|
|
|
|
|
await calendarManager.initialize?.();
|
|
|
|
|
await resizeHandleManager.initialize?.();
|
|
|
|
|
|
2025-11-21 23:23:04 +01:00
|
|
|
// Resolve AuditService (starts listening for entity events)
|
|
|
|
|
const auditService = app.resolveType<AuditService>();
|
|
|
|
|
|
|
|
|
|
// Resolve SyncManager (starts background sync automatically)
|
|
|
|
|
const syncManager = app.resolveType<SyncManager>();
|
2025-11-05 00:37:57 +01:00
|
|
|
|
2025-09-04 00:16:35 +02:00
|
|
|
// Handle deep linking after managers are initialized
|
2025-10-30 23:47:30 +01:00
|
|
|
await handleDeepLinking(eventManager, urlManager);
|
2025-10-14 22:53:28 +02:00
|
|
|
|
2025-09-23 20:44:15 +02:00
|
|
|
// Expose to window for debugging (with proper typing)
|
2025-10-14 22:53:28 +02:00
|
|
|
(window as Window & {
|
2025-09-23 20:44:15 +02:00
|
|
|
calendarDebug?: {
|
|
|
|
|
eventBus: typeof eventBus;
|
2025-10-30 21:46:38 +01:00
|
|
|
app: typeof app;
|
2025-10-14 22:53:28 +02:00
|
|
|
calendarManager: typeof calendarManager;
|
|
|
|
|
eventManager: typeof eventManager;
|
2025-11-07 21:05:59 +01:00
|
|
|
workweekPresetsManager: typeof workweekPresetsManager;
|
2025-11-21 23:23:04 +01:00
|
|
|
auditService: typeof auditService;
|
|
|
|
|
syncManager: typeof syncManager;
|
2025-10-14 22:53:28 +02:00
|
|
|
};
|
2025-09-23 20:44:15 +02:00
|
|
|
}).calendarDebug = {
|
2025-08-17 23:44:30 +02:00
|
|
|
eventBus,
|
2025-10-30 21:46:38 +01:00
|
|
|
app,
|
2025-10-14 22:53:28 +02:00
|
|
|
calendarManager,
|
|
|
|
|
eventManager,
|
2025-11-07 21:05:59 +01:00
|
|
|
workweekPresetsManager,
|
2025-11-21 23:23:04 +01:00
|
|
|
auditService,
|
|
|
|
|
syncManager,
|
2025-08-17 23:44:30 +02:00
|
|
|
};
|
2025-10-14 22:53:28 +02:00
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
} catch (error) {
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
2025-07-24 22:17:38 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-09 00:31:44 +02:00
|
|
|
// Initialize when DOM is ready - now handles async properly
|
2025-07-24 22:17:38 +02:00
|
|
|
if (document.readyState === 'loading') {
|
2025-08-09 00:31:44 +02:00
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
|
initializeCalendar().catch(error => {
|
2025-10-31 15:26:07 +01:00
|
|
|
console.error('Calendar initialization failed:', error);
|
2025-10-15 20:09:12 +02:00
|
|
|
});
|
2025-08-09 00:31:44 +02:00
|
|
|
});
|
2025-07-24 22:17:38 +02:00
|
|
|
} else {
|
2025-08-09 00:31:44 +02:00
|
|
|
initializeCalendar().catch(error => {
|
2025-10-31 15:26:07 +01:00
|
|
|
console.error('Calendar initialization failed:', error);
|
2025-08-09 00:31:44 +02:00
|
|
|
});
|
2025-12-06 01:22:04 +01:00
|
|
|
}
|
|
|
|
|
|