Calendar/src/components/NavigationButtons.ts

160 lines
4.1 KiB
TypeScript
Raw Normal View History

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 <swp-nav-group> 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<Element, EventListener> = 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);
}
}