diff --git a/src/configurations/CalendarConfig.ts b/src/configurations/CalendarConfig.ts index 6be9421..4340128 100644 --- a/src/configurations/CalendarConfig.ts +++ b/src/configurations/CalendarConfig.ts @@ -3,6 +3,7 @@ import { IGridSettings } from './GridSettings'; import { IDateViewSettings } from './DateViewSettings'; import { ITimeFormatConfig } from './TimeFormatConfig'; import { IWorkWeekSettings } from './WorkWeekSettings'; +import { CalendarView } from '../types/CalendarTypes'; /** * All-day event layout constants @@ -65,6 +66,7 @@ export class Configuration { public dateViewSettings: IDateViewSettings; public timeFormatConfig: ITimeFormatConfig; public currentWorkWeek: string; + public currentView: CalendarView; public selectedDate: Date; public apiEndpoint: string = '/api'; @@ -74,6 +76,7 @@ export class Configuration { dateViewSettings: IDateViewSettings, timeFormatConfig: ITimeFormatConfig, currentWorkWeek: string, + currentView: CalendarView, selectedDate: Date = new Date() ) { this.config = config; @@ -81,6 +84,7 @@ export class Configuration { this.dateViewSettings = dateViewSettings; this.timeFormatConfig = timeFormatConfig; this.currentWorkWeek = currentWorkWeek; + this.currentView = currentView; this.selectedDate = selectedDate; // Store as singleton instance for web components diff --git a/src/configurations/ConfigManager.ts b/src/configurations/ConfigManager.ts index f568e7a..c4532af 100644 --- a/src/configurations/ConfigManager.ts +++ b/src/configurations/ConfigManager.ts @@ -92,7 +92,8 @@ export class ConfigManager { data.gridSettings, data.dateViewSettings, data.timeFormatConfig, - data.currentWorkWeek + data.currentWorkWeek, + data.currentView || 'week' ); // Configure TimeFormatter diff --git a/src/index.ts b/src/index.ts index a8ad50a..064ec33 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,7 +12,7 @@ import { EventRenderingService } from './renderers/EventRendererManager'; import { GridManager } from './managers/GridManager'; import { ScrollManager } from './managers/ScrollManager'; import { NavigationManager } from './managers/NavigationManager'; -import { ViewManager } from './managers/ViewManager'; +import { ViewSelectorManager } from './managers/ViewSelectorManager'; import { CalendarManager } from './managers/CalendarManager'; import { DragDropManager } from './managers/DragDropManager'; import { AllDayManager } from './managers/AllDayManager'; @@ -124,7 +124,7 @@ async function initializeCalendar(): Promise { builder.registerType(GridManager).as(); builder.registerType(ScrollManager).as(); builder.registerType(NavigationManager).as(); - builder.registerType(ViewManager).as(); + builder.registerType(ViewSelectorManager).as(); builder.registerType(DragDropManager).as(); builder.registerType(AllDayManager).as(); builder.registerType(ResizeHandleManager).as(); @@ -146,7 +146,7 @@ async function initializeCalendar(): Promise { const resizeHandleManager = app.resolveType(); const headerManager = app.resolveType(); const dragDropManager = app.resolveType(); - const viewManager = app.resolveType(); + const viewSelectorManager = app.resolveType(); const navigationManager = app.resolveType(); const edgeScrollManager = app.resolveType(); const allDayManager = app.resolveType(); diff --git a/src/managers/ViewManager.ts b/src/managers/ViewManager.ts deleted file mode 100644 index ffead14..0000000 --- a/src/managers/ViewManager.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { CalendarView, IEventBus } from '../types/CalendarTypes'; -import { Configuration } from '../configurations/CalendarConfig'; -import { CoreEvents } from '../constants/CoreEvents'; - - -export class ViewManager { - private eventBus: IEventBus; - private config: Configuration; - private currentView: CalendarView = 'week'; - private buttonListeners: Map = new Map(); - - constructor(eventBus: IEventBus, config: Configuration) { - this.eventBus = eventBus; - this.config = config; - this.setupEventListeners(); - } - - private setupEventListeners(): void { - this.setupEventBusListeners(); - this.setupButtonHandlers(); - } - - - private setupEventBusListeners(): void { - this.eventBus.on(CoreEvents.INITIALIZED, () => { - this.initializeView(); - }); - - this.eventBus.on(CoreEvents.DATE_CHANGED, () => { - this.refreshCurrentView(); - }); - } - - private setupButtonHandlers(): void { - this.setupButtonGroup('swp-view-button[data-view]', 'data-view', (value) => { - if (this.isValidView(value)) { - this.changeView(value as CalendarView); - } - }); - - // NOTE: Workweek preset buttons are now handled by WorkweekPresetsManager - } - - - private setupButtonGroup(selector: string, attribute: string, handler: (value: string) => void): void { - const buttons = document.querySelectorAll(selector); - buttons.forEach(button => { - const clickHandler = (event: Event) => { - event.preventDefault(); - const value = button.getAttribute(attribute); - if (value) { - handler(value); - } - }; - button.addEventListener('click', clickHandler); - this.buttonListeners.set(button, clickHandler); - }); - } - - private getViewButtons(): NodeListOf { - return document.querySelectorAll('swp-view-button[data-view]'); - } - - - private initializeView(): void { - this.updateAllButtons(); - this.emitViewRendered(); - } - - private changeView(newView: CalendarView): void { - if (newView === this.currentView) return; - - const previousView = this.currentView; - this.currentView = newView; - - this.updateAllButtons(); - - this.eventBus.emit(CoreEvents.VIEW_CHANGED, { - previousView, - currentView: newView - }); - } - private updateAllButtons(): void { - this.updateButtonGroup( - this.getViewButtons(), - 'data-view', - this.currentView - ); - - // NOTE: Workweek button states are now managed by WorkweekPresetsManager - } - - private updateButtonGroup(buttons: NodeListOf, attribute: string, activeValue: string): void { - buttons.forEach(button => { - const buttonValue = button.getAttribute(attribute); - if (buttonValue === activeValue) { - button.setAttribute('data-active', 'true'); - } else { - button.removeAttribute('data-active'); - } - }); - } - - private emitViewRendered(): void { - this.eventBus.emit(CoreEvents.VIEW_RENDERED, { - view: this.currentView - }); - } - - private refreshCurrentView(): void { - this.emitViewRendered(); - } - - private isValidView(view: string): view is CalendarView { - return ['day', 'week', 'month'].includes(view); - } - - -} diff --git a/src/managers/ViewSelectorManager.ts b/src/managers/ViewSelectorManager.ts new file mode 100644 index 0000000..77b2340 --- /dev/null +++ b/src/managers/ViewSelectorManager.ts @@ -0,0 +1,152 @@ +import { CalendarView, IEventBus } from '../types/CalendarTypes'; +import { CoreEvents } from '../constants/CoreEvents'; +import { Configuration } from '../configurations/CalendarConfig'; + +/** + * ViewSelectorManager - Manages view selector UI and state + * + * RESPONSIBILITY: + * =============== + * This manager owns all logic related to the UI element. + * It follows the principle that each functional UI element has its own manager. + * + * RESPONSIBILITIES: + * - Handles button clicks on swp-view-button elements + * - Manages current view state (day/week/month) + * - Validates view values + * - Emits VIEW_CHANGED and VIEW_RENDERED events + * - Updates button UI states (data-active attributes) + * + * EVENT FLOW: + * =========== + * User clicks button → changeView() → validate → update state → emit event → update UI + * + * IMPLEMENTATION STATUS: + * ====================== + * - Week view: FULLY IMPLEMENTED + * - Day view: NOT IMPLEMENTED (button exists but no rendering) + * - Month view: NOT IMPLEMENTED (button exists but no rendering) + * + * SUBSCRIBERS: + * ============ + * - GridRenderer: Uses view parameter (currently only supports 'week') + * - Future: DayRenderer, MonthRenderer when implemented + */ +export class ViewSelectorManager { + private eventBus: IEventBus; + private config: Configuration; + private buttonListeners: Map = new Map(); + + constructor(eventBus: IEventBus, config: Configuration) { + this.eventBus = eventBus; + this.config = config; + + this.setupButtonListeners(); + this.setupEventListeners(); + } + + /** + * Setup click listeners on all view selector buttons + */ + private setupButtonListeners(): void { + const buttons = document.querySelectorAll('swp-view-button[data-view]'); + + buttons.forEach(button => { + const clickHandler = (event: Event) => { + event.preventDefault(); + const view = button.getAttribute('data-view'); + if (view && this.isValidView(view)) { + this.changeView(view as CalendarView); + } + }; + + button.addEventListener('click', clickHandler); + this.buttonListeners.set(button, clickHandler); + }); + + // Initialize button states + this.updateButtonStates(); + } + + /** + * Setup event bus listeners + */ + private setupEventListeners(): void { + this.eventBus.on(CoreEvents.INITIALIZED, () => { + this.initializeView(); + }); + + this.eventBus.on(CoreEvents.DATE_CHANGED, () => { + this.refreshCurrentView(); + }); + } + + /** + * Change the active view + */ + private changeView(newView: CalendarView): void { + if (newView === this.config.currentView) { + return; // No change + } + + const previousView = this.config.currentView; + this.config.currentView = newView; + + // Update button UI states + this.updateButtonStates(); + + // Emit event for subscribers + this.eventBus.emit(CoreEvents.VIEW_CHANGED, { + previousView, + currentView: newView + }); + } + + /** + * Update button states (data-active attributes) + */ + private updateButtonStates(): void { + const buttons = document.querySelectorAll('swp-view-button[data-view]'); + + buttons.forEach(button => { + const buttonView = button.getAttribute('data-view'); + + if (buttonView === this.config.currentView) { + button.setAttribute('data-active', 'true'); + } else { + button.removeAttribute('data-active'); + } + }); + } + + /** + * Initialize view on INITIALIZED event + */ + private initializeView(): void { + this.updateButtonStates(); + this.emitViewRendered(); + } + + /** + * Emit VIEW_RENDERED event + */ + private emitViewRendered(): void { + this.eventBus.emit(CoreEvents.VIEW_RENDERED, { + view: this.config.currentView + }); + } + + /** + * Refresh current view on DATE_CHANGED event + */ + private refreshCurrentView(): void { + this.emitViewRendered(); + } + + /** + * Validate if string is a valid CalendarView type + */ + private isValidView(view: string): view is CalendarView { + return ['day', 'week', 'month'].includes(view); + } +} diff --git a/wwwroot/data/calendar-config.json b/wwwroot/data/calendar-config.json index e4bd5a1..ec3fdd8 100644 --- a/wwwroot/data/calendar-config.json +++ b/wwwroot/data/calendar-config.json @@ -58,6 +58,7 @@ } }, "currentWorkWeek": "standard", + "currentView": "week", "scrollbar": { "width": 16, "color": "#666",