Calendar/src/managers/NavigationManager.ts
Janus Knudsen fafad16926 Removes excessive logging statements
Cleans up the codebase by removing unnecessary console log statements.

These logs were primarily used for debugging and are no longer needed in the production code.
This reduces noise in the console and improves overall performance.
2025-08-31 22:39:09 +02:00

256 lines
No EOL
7.7 KiB
TypeScript

import { IEventBus } from '../types/CalendarTypes.js';
import { EventRenderingService } from '../renderers/EventRendererManager.js';
import { DateCalculator } from '../utils/DateCalculator.js';
import { CoreEvents } from '../constants/CoreEvents.js';
import { NavigationRenderer } from '../renderers/NavigationRenderer.js';
import { calendarConfig } from '../core/CalendarConfig.js';
/**
* NavigationManager handles calendar navigation (prev/next/today buttons)
* with simplified CSS Grid approach
*/
export class NavigationManager {
private eventBus: IEventBus;
private navigationRenderer: NavigationRenderer;
private dateCalculator: DateCalculator;
private currentWeek: Date;
private targetWeek: Date;
private animationQueue: number = 0;
constructor(eventBus: IEventBus, eventRenderer: EventRenderingService) {
this.eventBus = eventBus;
this.dateCalculator = new DateCalculator(calendarConfig);
this.navigationRenderer = new NavigationRenderer(eventBus, calendarConfig, eventRenderer);
this.currentWeek = this.dateCalculator.getISOWeekStart(new Date());
this.targetWeek = new Date(this.currentWeek);
this.init();
}
private init(): void {
this.setupEventListeners();
// Don't update week info immediately - wait for DOM to be ready
}
private setupEventListeners(): void {
// Initial DOM update when calendar is initialized
this.eventBus.on(CoreEvents.INITIALIZED, () => {
this.updateWeekInfo();
});
// Listen for filter changes and apply to pre-rendered grids
this.eventBus.on(CoreEvents.FILTER_CHANGED, (e: Event) => {
const detail = (e as CustomEvent).detail;
this.navigationRenderer.applyFilterToPreRenderedGrids(detail);
});
// Listen for navigation button clicks
document.addEventListener('click', (e) => {
const target = e.target as HTMLElement;
const navButton = target.closest('[data-action]') as HTMLElement;
if (!navButton) return;
const action = navButton.dataset.action;
switch (action) {
case 'prev':
this.navigateToPreviousWeek();
break;
case 'next':
this.navigateToNextWeek();
break;
case 'today':
this.navigateToToday();
break;
}
});
// Listen for external navigation requests
this.eventBus.on(CoreEvents.DATE_CHANGED, (event: Event) => {
const customEvent = event as CustomEvent;
const dateFromEvent = customEvent.detail.currentDate;
// Validate date before processing
if (!dateFromEvent) {
return;
}
const targetDate = new Date(dateFromEvent);
if (isNaN(targetDate.getTime())) {
return;
}
this.navigateToDate(targetDate);
});
}
private navigateToPreviousWeek(): void {
this.targetWeek.setDate(this.targetWeek.getDate() - 7);
const weekToShow = new Date(this.targetWeek);
this.animationQueue++;
this.animateTransition('prev', weekToShow);
}
private navigateToNextWeek(): void {
this.targetWeek.setDate(this.targetWeek.getDate() + 7);
const weekToShow = new Date(this.targetWeek);
this.animationQueue++;
this.animateTransition('next', weekToShow);
}
private navigateToToday(): void {
const today = new Date();
const todayWeekStart = this.dateCalculator.getISOWeekStart(today);
// Reset to today
this.targetWeek = new Date(todayWeekStart);
const currentTime = this.currentWeek.getTime();
const targetTime = todayWeekStart.getTime();
if (currentTime < targetTime) {
this.animationQueue++;
this.animateTransition('next', todayWeekStart);
} else if (currentTime > targetTime) {
this.animationQueue++;
this.animateTransition('prev', todayWeekStart);
}
}
private navigateToDate(date: Date): void {
const weekStart = this.dateCalculator.getISOWeekStart(date);
this.targetWeek = new Date(weekStart);
const currentTime = this.currentWeek.getTime();
const targetTime = weekStart.getTime();
if (currentTime < targetTime) {
this.animationQueue++;
this.animateTransition('next', weekStart);
} else if (currentTime > targetTime) {
this.animationQueue++;
this.animateTransition('prev', weekStart);
}
}
/**
* Animation transition using pre-rendered containers when available
*/
private animateTransition(direction: 'prev' | 'next', targetWeek: Date): void {
const container = document.querySelector('swp-calendar-container');
const currentGrid = container?.querySelector('swp-grid-container:not([data-prerendered])');
if (!container || !currentGrid) {
return;
}
let newGrid: HTMLElement;
// Always create a fresh container for consistent behavior
newGrid = this.navigationRenderer.renderContainer(container as HTMLElement, targetWeek);
// Clear any existing transforms before animation
newGrid.style.transform = '';
(currentGrid as HTMLElement).style.transform = '';
// Animate transition using Web Animations API
const slideOutAnimation = (currentGrid as HTMLElement).animate([
{ transform: 'translateX(0)', opacity: '1' },
{ transform: direction === 'next' ? 'translateX(-100%)' : 'translateX(100%)', opacity: '0.5' }
], {
duration: 400,
easing: 'ease-in-out',
fill: 'forwards'
});
const slideInAnimation = newGrid.animate([
{ transform: direction === 'next' ? 'translateX(100%)' : 'translateX(-100%)' },
{ transform: 'translateX(0)' }
], {
duration: 400,
easing: 'ease-in-out',
fill: 'forwards'
});
// Handle animation completion
slideInAnimation.addEventListener('finish', () => {
// Cleanup: Remove all old grids except the new one
const allGrids = container.querySelectorAll('swp-grid-container');
for (let i = 0; i < allGrids.length - 1; i++) {
allGrids[i].remove();
}
// Reset positioning
newGrid.style.position = 'relative';
newGrid.removeAttribute('data-prerendered');
// Update state
this.currentWeek = new Date(targetWeek);
this.animationQueue--;
// If this was the last queued animation, ensure we're in sync
if (this.animationQueue === 0) {
this.currentWeek = new Date(this.targetWeek);
}
// Update week info and notify other managers
this.updateWeekInfo();
// Emit period change event for ScrollManager
this.eventBus.emit(CoreEvents.PERIOD_CHANGED, {
direction,
weekStart: this.currentWeek
});
});
}
private updateWeekInfo(): void {
const weekNumber = this.dateCalculator.getWeekNumber(this.currentWeek);
const weekEnd = this.dateCalculator.addDays(this.currentWeek, 6);
const dateRange = this.dateCalculator.formatDateRange(this.currentWeek, weekEnd);
// Notify other managers about week info update - DOM manipulation should happen via events
this.eventBus.emit(CoreEvents.WEEK_CHANGED, {
weekNumber,
dateRange,
weekStart: this.currentWeek,
weekEnd
});
}
/**
* Get current week start date
*/
getCurrentWeek(): Date {
return new Date(this.currentWeek);
}
/**
* Get target week (where navigation is heading)
*/
getTargetWeek(): Date {
return new Date(this.targetWeek);
}
/**
* Check if navigation animation is in progress
*/
isAnimating(): boolean {
return this.animationQueue > 0;
}
/**
* Force navigation to specific week without animation
*/
setWeek(weekStart: Date): void {
this.currentWeek = new Date(weekStart);
this.targetWeek = new Date(weekStart);
this.updateWeekInfo();
}
// Rendering methods moved to NavigationRenderer for better separation of concerns
}