import { IEventBus, CalendarView } from '../types/CalendarTypes'; import { CoreEvents } from '../constants/CoreEvents'; import { DateService } from '../utils/DateService'; import { Configuration } from '../configurations/CalendarConfig'; import { INavButtonClickedEventPayload } from '../types/EventTypes'; /** * NavigationButtons - Manages navigation button UI and navigation logic * * RESPONSIBILITY: * =============== * This manager owns all logic related to the UI element * and performs the actual navigation calculations. * * RESPONSIBILITIES: * - Handles button clicks on swp-nav-button elements * - Validates navigation actions (prev, next, today) * - Calculates next/previous dates based on current view * - Emits NAVIGATION_COMPLETED events with new date * - Manages button UI listeners * * EVENT FLOW: * =========== * User clicks button → calculateNewDate() → emit NAVIGATION_COMPLETED → GridManager re-renders */ export class NavigationButtons { private eventBus: IEventBus; private buttonListeners: Map = new Map(); private dateService: DateService; private config: Configuration; private currentDate: Date = new Date(); private currentView: CalendarView = 'week'; constructor( eventBus: IEventBus, dateService: DateService, config: Configuration ) { this.eventBus = eventBus; this.dateService = dateService; this.config = config; this.setupButtonListeners(); this.subscribeToEvents(); } /** * Subscribe to events */ private subscribeToEvents(): void { // Listen for view changes this.eventBus.on(CoreEvents.VIEW_CHANGED, (e: Event) => { const detail = (e as CustomEvent).detail; this.currentView = detail.currentView; }); } /** * Setup click listeners on all navigation buttons */ private setupButtonListeners(): void { const buttons = document.querySelectorAll('swp-nav-button[data-action]'); buttons.forEach(button => { const clickHandler = (event: Event) => { event.preventDefault(); const action = button.getAttribute('data-action'); if (action && this.isValidAction(action)) { this.handleNavigation(action); } }; button.addEventListener('click', clickHandler); this.buttonListeners.set(button, clickHandler); }); } /** * Handle navigation action */ private handleNavigation(action: string): void { switch (action) { case 'prev': this.navigatePrevious(); break; case 'next': this.navigateNext(); break; case 'today': this.navigateToday(); break; } } /** * Navigate in specified direction */ private navigate(direction: 'next' | 'previous'): void { const offset = direction === 'next' ? 1 : -1; let newDate: Date; switch (this.currentView) { case 'week': newDate = this.dateService.addWeeks(this.currentDate, offset); break; case 'month': newDate = this.dateService.addMonths(this.currentDate, offset); break; case 'day': newDate = this.dateService.addDays(this.currentDate, offset); break; default: newDate = this.dateService.addWeeks(this.currentDate, offset); } this.currentDate = newDate; const payload: INavButtonClickedEventPayload = { direction: direction, newDate: newDate }; this.eventBus.emit(CoreEvents.NAV_BUTTON_CLICKED, payload); } /** * Navigate to next period */ private navigateNext(): void { this.navigate('next'); } /** * Navigate to previous period */ private navigatePrevious(): void { this.navigate('previous'); } /** * Navigate to today */ private navigateToday(): void { this.currentDate = new Date(); const payload: INavButtonClickedEventPayload = { direction: 'today', newDate: this.currentDate }; this.eventBus.emit(CoreEvents.NAV_BUTTON_CLICKED, payload); } /** * Validate if string is a valid navigation action */ private isValidAction(action: string): boolean { return ['prev', 'next', 'today'].includes(action); } }