Centralizes event position calculations into `PositionUtils` for consistency and reusability across managers and renderers. Improves drag-and-drop functionality by emitting events for all-day event conversion and streamlining position calculations during drag operations. Introduces `AllDayManager` and `AllDayEventRenderer` to manage and render all-day events in the calendar header. This allows dragging events to the header to convert them to all-day events.
7.1 KiB
TypeScript Code Review - Calendar Plantempus
Dato: September 2025
Reviewer: Roo
Fokus: Dybdegående analyse efter TimeFormatter implementation
Executive Summary
Efter implementering af TimeFormatter og gennemgang af codebasen, har jeg identificeret både styrker og forbedringspotentiale. Koden viser god separation of concerns og event-driven arkitektur, men har stadig områder der kan optimeres.
🟢 Styrker
1. Event-Driven Architecture
- Konsistent EventBus pattern gennem hele applikationen
- Ingen direkte dependencies mellem moduler
- God brug af custom events for kommunikation
2. Separation of Concerns
- Managers: Håndterer business logic (AllDayManager, DragDropManager, etc.)
- Renderers: Fokuserer på DOM manipulation
- Utils: Isolerede utility funktioner
- Elements: Factory pattern for DOM element creation
3. Performance Optimering
- DOM Caching: Konsistent caching af DOM elementer
- Throttling: Event throttling i HeaderManager (16ms delay)
- Pixel-based calculations: Fjernet komplekse time-based overlap beregninger
4. TypeScript Best Practices
- Stærk typing med interfaces
- Proper null/undefined checks
- Readonly constants hvor relevant
🔴 Kritiske Issues
1. "new_" Prefix Methods (EventRenderer.ts)
// PROBLEM: Midlertidige metode navne
protected new_handleEventOverlaps()
protected new_renderOverlappingEvents()
protected new_applyStackStyling()
protected new_applyColumnSharingStyling()
Impact: Forvirrende navngivning, indikerer ufærdig refactoring
Løsning: Fjern prefix og ryd op i gamle metoder
2. Duplikeret Cache Logic
// AllDayManager.ts
private cachedAllDayContainer: HTMLElement | null = null;
private cachedCalendarHeader: HTMLElement | null = null;
// HeaderManager.ts
private cachedCalendarHeader: HTMLElement | null = null;
// DragDropManager.ts
private cachedElements: CachedElements = {...}
Impact: 30+ linjer duplikeret kode
Løsning: Opret generisk DOMCacheManager
3. Manglende Error Boundaries
// SimpleEventOverlapManager.ts
const linkData = element.dataset.stackLink;
try {
return JSON.parse(linkData);
} catch (e) {
console.warn('Failed to parse stack link data:', linkData, e);
return null;
}
Impact: Silently failing JSON parsing
Løsning: Proper error handling med user feedback
🟡 Code Smells & Improvements
1. Magic Numbers
// SimpleEventOverlapManager.ts
const startDifference = Math.abs(top1 - top2);
if (startDifference > 40) { // Magic number!
return OverlapType.STACKING;
}
// DragDropManager.ts
private readonly dragThreshold = 5; // Should be configurable
private readonly scrollSpeed = 10;
private readonly scrollThreshold = 30;
Løsning: Flyt til configuration constants
2. Complex Method Signatures
// AllDayManager.ts - 73 linjer!
public checkAndAnimateAllDayHeight(): void {
// Massive method doing too much
}
Løsning: Split i mindre, fokuserede metoder
3. Inconsistent Naming
// Mix af naming conventions
getCalendarHeader() // get prefix
findElements() // no prefix
detectColumn() // action verb
cachedElements // noun
Løsning: Standardiser naming convention
4. Memory Leaks Risk
// DragDropManager.ts
private boundHandlers = {
mouseMove: this.handleMouseMove.bind(this),
mouseDown: this.handleMouseDown.bind(this),
mouseUp: this.handleMouseUp.bind(this)
};
God praksis! Men ikke konsistent anvendt alle steder
📊 Metrics & Analysis
Complexity Analysis
| File | Lines | Cyclomatic Complexity | Maintainability |
|---|---|---|---|
| AllDayManager.ts | 281 | Medium (8) | Good |
| DragDropManager.ts | 521 | High (15) | Needs refactoring |
| SimpleEventOverlapManager.ts | 473 | Very High (20) | Critical |
| HeaderManager.ts | 119 | Low (4) | Excellent |
| GridManager.ts | 348 | Medium (10) | Good |
Code Duplication
- Cache management: ~15% duplication
- Event handling: ~10% duplication
- Position calculations: ~8% duplication
🎯 Prioriterede Forbedringer
Priority 1: Critical Fixes
- Fjern "new_" prefix fra EventRenderer metoder
- Fix TimeFormatter timezone - Håndter mock data korrekt som UTC
- Implementer DOMCacheManager - Reducer duplication
Priority 2: Architecture Improvements
- GridPositionCalculator - Centralisér position beregninger
- EventThrottler - Generisk throttling utility
- AllDayRowCalculator - Udtræk kompleks logik fra AllDayManager
Priority 3: Code Quality
- Reduce method complexity - Split store metoder
- Standardize naming - Konsistent naming convention
- Add JSDoc - Mangler på mange public methods
Priority 4: Testing
- Unit tests for TimeFormatter
- Integration tests for overlap detection
- Performance tests for large event sets
💡 Architectural Recommendations
1. Introduce Service Layer
// Forslag: EventService
class EventService {
private formatter: TimeFormatter;
private calculator: GridPositionCalculator;
private overlapManager: SimpleEventOverlapManager;
// Centralized event operations
}
2. Configuration Management
interface CalendarConstants {
DRAG_THRESHOLD: number;
SCROLL_SPEED: number;
STACK_OFFSET: number;
OVERLAP_THRESHOLD: number;
}
3. Error Handling Strategy
class CalendarError extends Error {
constructor(
message: string,
public code: string,
public recoverable: boolean
) {
super(message);
}
}
🚀 Performance Optimizations
1. Virtual Scrolling
For måneds-view med mange events, overvej virtual scrolling
2. Web Workers
Flyt tunge beregninger (overlap detection) til Web Worker
3. RequestIdleCallback
Brug for non-critical updates som analytics
✅ Positive Highlights
- TimeFormatter Implementation: Elegant og clean
- Event-driven Architecture: Konsistent og velfungerende
- TypeScript Usage: God type safety
- DOM Manipulation: Effektiv med custom elements
- Separation of Concerns: Klar opdeling af ansvar
📋 Recommended Action Plan
Immediate (1-2 dage)
- Fjern "new_" prefix fra EventRenderer
- Implementer DOMCacheManager
- Fix magic numbers
Short-term (3-5 dage)
- Opret GridPositionCalculator
- Implementer EventThrottler
- Refactor SimpleEventOverlapManager complexity
Long-term (1-2 uger)
- Add comprehensive unit tests
- Implement service layer
- Performance optimizations
Konklusion
Koden er generelt velstruktureret med god separation of concerns og konsistent event-driven arkitektur. TimeFormatter implementationen er elegant og løser timezone problemet godt.
Hovedudfordringerne ligger i:
- Ufærdig refactoring (new_ prefix)
- Duplikeret cache logic
- Høj complexity i overlap detection
- Manglende tests
Med de foreslåede forbedringer vil kodebasen blive mere maintainable, performant og robust.
Overall Score: 7.5/10 - God kvalitet med plads til forbedring