148 lines
4.8 KiB
TypeScript
148 lines
4.8 KiB
TypeScript
|
|
/**
|
||
|
|
* MonthViewStrategy - Strategy for month view rendering
|
||
|
|
* Completely different from week view - no time axis, cell-based events
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { ViewStrategy, ViewContext, ViewLayoutConfig } from './ViewStrategy';
|
||
|
|
import { DateCalculator } from '../utils/DateCalculator';
|
||
|
|
import { calendarConfig } from '../core/CalendarConfig';
|
||
|
|
|
||
|
|
export class MonthViewStrategy implements ViewStrategy {
|
||
|
|
private dateCalculator: DateCalculator;
|
||
|
|
|
||
|
|
constructor() {
|
||
|
|
this.dateCalculator = new DateCalculator(calendarConfig);
|
||
|
|
}
|
||
|
|
|
||
|
|
getLayoutConfig(): ViewLayoutConfig {
|
||
|
|
return {
|
||
|
|
needsTimeAxis: false, // No time axis in month view!
|
||
|
|
columnCount: 7, // Always 7 days (Mon-Sun)
|
||
|
|
scrollable: false, // Month fits in viewport
|
||
|
|
eventPositioning: 'cell-based' // Events go in day cells
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
renderGrid(context: ViewContext): void {
|
||
|
|
console.group(`📅 MONTH VIEW: Rendering grid for ${context.currentDate.toDateString()}`);
|
||
|
|
|
||
|
|
// Clear existing content
|
||
|
|
context.container.innerHTML = '';
|
||
|
|
|
||
|
|
// Create month grid (completely different from week!)
|
||
|
|
this.createMonthGrid(context);
|
||
|
|
|
||
|
|
console.log('Month grid rendered with 7x6 layout');
|
||
|
|
console.groupEnd();
|
||
|
|
}
|
||
|
|
|
||
|
|
private createMonthGrid(context: ViewContext): void {
|
||
|
|
const monthGrid = document.createElement('div');
|
||
|
|
monthGrid.className = 'month-grid';
|
||
|
|
monthGrid.style.display = 'grid';
|
||
|
|
monthGrid.style.gridTemplateColumns = 'repeat(7, 1fr)';
|
||
|
|
monthGrid.style.gridTemplateRows = 'auto repeat(6, 1fr)';
|
||
|
|
monthGrid.style.height = '100%';
|
||
|
|
|
||
|
|
// Add day headers (Mon, Tue, Wed, etc.)
|
||
|
|
this.createDayHeaders(monthGrid);
|
||
|
|
|
||
|
|
// Add 6 weeks of day cells
|
||
|
|
this.createDayCells(monthGrid, context.currentDate);
|
||
|
|
|
||
|
|
// Render events in day cells
|
||
|
|
this.renderMonthEvents(monthGrid, context.allDayEvents);
|
||
|
|
|
||
|
|
context.container.appendChild(monthGrid);
|
||
|
|
}
|
||
|
|
|
||
|
|
private createDayHeaders(container: HTMLElement): void {
|
||
|
|
const dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
||
|
|
|
||
|
|
dayNames.forEach(dayName => {
|
||
|
|
const header = document.createElement('div');
|
||
|
|
header.className = 'month-day-header';
|
||
|
|
header.textContent = dayName;
|
||
|
|
header.style.padding = '8px';
|
||
|
|
header.style.fontWeight = 'bold';
|
||
|
|
header.style.textAlign = 'center';
|
||
|
|
header.style.borderBottom = '1px solid #e0e0e0';
|
||
|
|
container.appendChild(header);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private createDayCells(container: HTMLElement, monthDate: Date): void {
|
||
|
|
const dates = this.getMonthDates(monthDate);
|
||
|
|
|
||
|
|
dates.forEach(date => {
|
||
|
|
const cell = document.createElement('div');
|
||
|
|
cell.className = 'month-day-cell';
|
||
|
|
cell.dataset.date = this.dateCalculator.formatISODate(date);
|
||
|
|
cell.style.border = '1px solid #e0e0e0';
|
||
|
|
cell.style.minHeight = '100px';
|
||
|
|
cell.style.padding = '4px';
|
||
|
|
cell.style.position = 'relative';
|
||
|
|
|
||
|
|
// Day number
|
||
|
|
const dayNumber = document.createElement('div');
|
||
|
|
dayNumber.className = 'month-day-number';
|
||
|
|
dayNumber.textContent = date.getDate().toString();
|
||
|
|
dayNumber.style.fontWeight = 'bold';
|
||
|
|
dayNumber.style.marginBottom = '4px';
|
||
|
|
|
||
|
|
// Check if today
|
||
|
|
if (this.dateCalculator.isToday(date)) {
|
||
|
|
dayNumber.style.color = '#1976d2';
|
||
|
|
cell.style.backgroundColor = '#f5f5f5';
|
||
|
|
}
|
||
|
|
|
||
|
|
cell.appendChild(dayNumber);
|
||
|
|
container.appendChild(cell);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private getMonthDates(monthDate: Date): Date[] {
|
||
|
|
// Get first day of month
|
||
|
|
const firstOfMonth = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1);
|
||
|
|
|
||
|
|
// Get Monday of the week containing first day
|
||
|
|
const startDate = this.dateCalculator.getISOWeekStart(firstOfMonth);
|
||
|
|
|
||
|
|
// Generate 42 days (6 weeks)
|
||
|
|
const dates: Date[] = [];
|
||
|
|
for (let i = 0; i < 42; i++) {
|
||
|
|
dates.push(this.dateCalculator.addDays(startDate, i));
|
||
|
|
}
|
||
|
|
|
||
|
|
return dates;
|
||
|
|
}
|
||
|
|
|
||
|
|
private renderMonthEvents(container: HTMLElement, events: any[]): void {
|
||
|
|
// TODO: Implement month event rendering
|
||
|
|
// Events will be small blocks in day cells
|
||
|
|
console.log(`MonthViewStrategy: Would render ${events.length} events`);
|
||
|
|
}
|
||
|
|
|
||
|
|
getNextPeriod(currentDate: Date): Date {
|
||
|
|
return new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
getPreviousPeriod(currentDate: Date): Date {
|
||
|
|
return new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
getPeriodLabel(date: Date): string {
|
||
|
|
const monthNames = ['January', 'February', 'March', 'April', 'May', 'June',
|
||
|
|
'July', 'August', 'September', 'October', 'November', 'December'];
|
||
|
|
|
||
|
|
return `${monthNames[date.getMonth()]} ${date.getFullYear()}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
getDisplayDates(baseDate: Date): Date[] {
|
||
|
|
return this.getMonthDates(baseDate);
|
||
|
|
}
|
||
|
|
|
||
|
|
destroy(): void {
|
||
|
|
console.log('MonthViewStrategy: Cleaning up');
|
||
|
|
}
|
||
|
|
}
|