This commit is contained in:
Janus Knudsen 2025-08-02 23:59:52 +02:00
parent f29613e55f
commit 28ed131b9e
6 changed files with 151 additions and 90 deletions

View file

@ -31,10 +31,22 @@ export class EventManager {
} }
private loadMockData(): void { private loadMockData(): void {
// Mock events baseret på POC data med korrekt CalendarEvent struktur // Mock events for current week (July 27 - August 2, 2025)
this.events = [ this.events = [
// Sunday July 27, 2025
{ {
id: '1', id: '1',
title: 'Weekend Planning',
start: '2025-07-27T10:00:00',
end: '2025-07-27T11:00:00',
type: 'work',
allDay: false,
syncStatus: 'synced',
metadata: { duration: 60 }
},
// Monday July 28, 2025
{
id: '2',
title: 'Team Standup', title: 'Team Standup',
start: '2025-07-28T09:00:00', start: '2025-07-28T09:00:00',
end: '2025-07-28T09:30:00', end: '2025-07-28T09:30:00',
@ -44,8 +56,8 @@ export class EventManager {
metadata: { duration: 30 } metadata: { duration: 30 }
}, },
{ {
id: '2', id: '3',
title: 'Client Meeting', title: 'Project Kickoff',
start: '2025-07-28T14:00:00', start: '2025-07-28T14:00:00',
end: '2025-07-28T15:30:00', end: '2025-07-28T15:30:00',
type: 'meeting', type: 'meeting',
@ -53,16 +65,7 @@ export class EventManager {
syncStatus: 'synced', syncStatus: 'synced',
metadata: { duration: 90 } metadata: { duration: 90 }
}, },
{ // Tuesday July 29, 2025
id: '3',
title: 'Lunch',
start: '2025-07-28T12:00:00',
end: '2025-07-28T13:00:00',
type: 'meal',
allDay: false,
syncStatus: 'synced',
metadata: { duration: 60 }
},
{ {
id: '4', id: '4',
title: 'Deep Work Session', title: 'Deep Work Session',
@ -75,17 +78,7 @@ export class EventManager {
}, },
{ {
id: '5', id: '5',
title: 'Team Standup', title: 'Lunch Meeting',
start: '2025-07-29T09:00:00',
end: '2025-07-29T09:30:00',
type: 'meeting',
allDay: false,
syncStatus: 'synced',
metadata: { duration: 30 }
},
{
id: '6',
title: 'Lunch',
start: '2025-07-29T12:30:00', start: '2025-07-29T12:30:00',
end: '2025-07-29T13:30:00', end: '2025-07-29T13:30:00',
type: 'meal', type: 'meal',
@ -93,9 +86,10 @@ export class EventManager {
syncStatus: 'synced', syncStatus: 'synced',
metadata: { duration: 60 } metadata: { duration: 60 }
}, },
// Wednesday July 30, 2025
{ {
id: '7', id: '6',
title: 'Project Review', title: 'Client Review',
start: '2025-07-30T15:00:00', start: '2025-07-30T15:00:00',
end: '2025-07-30T16:00:00', end: '2025-07-30T16:00:00',
type: 'meeting', type: 'meeting',
@ -103,71 +97,54 @@ export class EventManager {
syncStatus: 'synced', syncStatus: 'synced',
metadata: { duration: 60 } metadata: { duration: 60 }
}, },
// Thursday July 31, 2025
{
id: '7',
title: 'Sprint Planning',
start: '2025-07-31T09:00:00',
end: '2025-07-31T10:30:00',
type: 'meeting',
allDay: false,
syncStatus: 'synced',
metadata: { duration: 90 }
},
{ {
id: '8', id: '8',
title: 'Lunch', title: 'Code Review',
start: '2025-07-30T12:00:00', start: '2025-07-31T14:00:00',
end: '2025-07-30T13:00:00', end: '2025-07-31T15:00:00',
type: 'meal', type: 'work',
allDay: false, allDay: false,
syncStatus: 'synced', syncStatus: 'synced',
metadata: { duration: 60 } metadata: { duration: 60 }
}, },
// Friday August 1, 2025
{ {
id: '9', id: '9',
title: 'Sprint Planning', title: 'Team Standup',
start: '2025-07-31T10:00:00', start: '2025-08-01T09:00:00',
end: '2025-07-31T12:00:00', end: '2025-08-01T09:30:00',
type: 'meeting', type: 'meeting',
allDay: false, allDay: false,
syncStatus: 'synced', syncStatus: 'synced',
metadata: { duration: 120 }
},
{
id: '10',
title: 'Coffee Break',
start: '2025-07-31T15:00:00',
end: '2025-07-31T15:30:00',
type: 'meal',
allDay: false,
syncStatus: 'synced',
metadata: { duration: 30 } metadata: { duration: 30 }
}, },
{ {
id: '11', id: '10',
title: 'Documentation', title: 'Client Meeting',
start: '2025-08-01T13:00:00', start: '2025-08-01T14:00:00',
end: '2025-08-01T16:00:00', end: '2025-08-01T15:30:00',
type: 'work',
allDay: false,
syncStatus: 'synced',
metadata: { duration: 180 }
},
{
id: '12',
title: 'Early Morning Workout',
start: '2025-07-29T06:00:00',
end: '2025-07-29T07:00:00',
type: 'work',
allDay: false,
syncStatus: 'synced',
metadata: { duration: 60 }
},
{
id: '13',
title: 'Late Evening Call',
start: '2025-07-30T21:00:00',
end: '2025-07-30T22:00:00',
type: 'meeting', type: 'meeting',
allDay: false, allDay: false,
syncStatus: 'synced', syncStatus: 'synced',
metadata: { duration: 60 } metadata: { duration: 90 }
}, },
// Saturday August 2, 2025
{ {
id: '14', id: '11',
title: 'Midnight Release', title: 'Weekend Project',
start: '2025-07-31T23:00:00', start: '2025-08-02T10:00:00',
end: '2025-08-01T01:00:00', end: '2025-08-02T12:00:00',
type: 'work', type: 'work',
allDay: false, allDay: false,
syncStatus: 'synced', syncStatus: 'synced',

View file

@ -2,6 +2,7 @@ import { EventBus } from '../core/EventBus';
import { IEventBus, CalendarEvent } from '../types/CalendarTypes'; import { IEventBus, CalendarEvent } from '../types/CalendarTypes';
import { EventTypes } from '../constants/EventTypes'; import { EventTypes } from '../constants/EventTypes';
import { calendarConfig } from '../core/CalendarConfig'; import { calendarConfig } from '../core/CalendarConfig';
import { DateUtils } from '../utils/DateUtils';
/** /**
* EventRenderer - Render events i DOM med positionering * EventRenderer - Render events i DOM med positionering
@ -52,13 +53,76 @@ export class EventRenderer {
} }
private renderEvents(events: CalendarEvent[]): void { private renderEvents(events: CalendarEvent[]): void {
console.log('EventRenderer: renderEvents called with', events.length, 'events');
// Clear existing events first // Clear existing events first
this.clearEvents(); this.clearEvents();
// For now, just emit event rendered - proper rendering will be implemented later // Get current week dates for filtering
this.eventBus.emit(EventTypes.EVENT_RENDERED, { const currentWeekDates = this.getCurrentWeekDates();
count: events.length console.log('EventRenderer: Current week dates:', currentWeekDates.map(d => DateUtils.formatDate(d)));
// Filter events for current week
const currentWeekEvents = events.filter(event => {
const eventDate = new Date(event.start);
const eventDateStr = DateUtils.formatDate(eventDate);
const isInCurrentWeek = currentWeekDates.some(weekDate =>
DateUtils.formatDate(weekDate) === eventDateStr
);
console.log('EventRenderer: Event', event.title, 'on', eventDateStr, 'is in current week:', isInCurrentWeek);
return isInCurrentWeek;
}); });
console.log('EventRenderer: Rendering', currentWeekEvents.length, 'events for current week');
// Render each event in the correct day column
currentWeekEvents.forEach(event => {
const eventDate = new Date(event.start);
const dayColumn = this.findDayColumn(eventDate);
if (dayColumn) {
const eventsLayer = dayColumn.querySelector('swp-events-layer');
if (eventsLayer) {
console.log('EventRenderer: Rendering event', event.title, 'in day column for', DateUtils.formatDate(eventDate));
this.renderEvent(event, eventsLayer);
} else {
console.warn('EventRenderer: No events layer found in day column for', DateUtils.formatDate(eventDate));
}
} else {
console.warn('EventRenderer: No day column found for event date', DateUtils.formatDate(eventDate));
}
});
// Emit event rendered
this.eventBus.emit(EventTypes.EVENT_RENDERED, {
count: currentWeekEvents.length
});
}
/**
* Get current week dates (Sunday to Saturday)
*/
private getCurrentWeekDates(): Date[] {
const today = new Date();
const weekStart = DateUtils.getWeekStart(today, 0); // Sunday start
const dates: Date[] = [];
for (let i = 0; i < 7; i++) {
const date = DateUtils.addDays(weekStart, i);
dates.push(date);
}
return dates;
}
/**
* Find day column for specific date
*/
private findDayColumn(date: Date): HTMLElement | null {
const dateStr = DateUtils.formatDate(date);
const dayColumn = document.querySelector(`swp-day-column[data-date="${dateStr}"]`) as HTMLElement;
console.log('EventRenderer: Looking for day column with date', dateStr, 'found:', !!dayColumn);
return dayColumn;
} }
private renderEvent(event: CalendarEvent, container: Element): void { private renderEvent(event: CalendarEvent, container: Element): void {
@ -95,17 +159,42 @@ export class EventRenderer {
const startDate = new Date(event.start); const startDate = new Date(event.start);
const endDate = new Date(event.end); const endDate = new Date(event.end);
const startHour = calendarConfig.get('dayStartHour'); // Use dayStartHour to match time-axis positioning
const dayStartHour = calendarConfig.get('dayStartHour'); // 0 (midnight)
const hourHeight = calendarConfig.get('hourHeight'); const hourHeight = calendarConfig.get('hourHeight');
// Calculate minutes from day start // Calculate minutes from day start (midnight)
const startMinutes = (startDate.getHours() - startHour) * 60 + startDate.getMinutes(); const eventHour = startDate.getHours();
const duration = (endDate.getTime() - startDate.getTime()) / (1000 * 60); // Duration in minutes const eventMinutes = startDate.getMinutes();
const startMinutes = (eventHour - dayStartHour) * 60 + eventMinutes;
// Calculate duration in minutes
const duration = (endDate.getTime() - startDate.getTime()) / (1000 * 60);
// Convert to pixels // Convert to pixels - this gives absolute position from top of time-grid
const top = startMinutes * (hourHeight / 60); const absoluteTop = startMinutes * (hourHeight / 60);
const height = duration * (hourHeight / 60); const height = duration * (hourHeight / 60);
// Get current scroll position to adjust for viewport
const scrollableContent = document.querySelector('swp-scrollable-content') as HTMLElement;
const scrollTop = scrollableContent ? scrollableContent.scrollTop : 0;
// Calculate relative position within the visible viewport
// Events are positioned relative to their day-column, not the scrollable content
// So we use the absolute position directly
const top = absoluteTop;
console.log('EventRenderer: Position calculation for', event.title, {
eventTime: `${eventHour}:${eventMinutes.toString().padStart(2, '0')}`,
dayStartHour,
startMinutes,
duration,
absoluteTop,
scrollTop,
finalTop: top,
height
});
return { top, height }; return { top, height };
} }

View file

@ -40,12 +40,8 @@ export class GridManager {
} }
private getWeekStart(date: Date): Date { private getWeekStart(date: Date): Date {
const weekStart = new Date(date); // Use DateUtils for consistent week calculation (Sunday = 0)
const day = weekStart.getDay(); return DateUtils.getWeekStart(date, 0);
const diff = weekStart.getDate() - day; // Sunday is 0
weekStart.setDate(diff);
weekStart.setHours(0, 0, 0, 0);
return weekStart;
} }
private findElements(): void { private findElements(): void {

View file

@ -32,7 +32,7 @@
/* Grid colors */ /* Grid colors */
--color-grid-line: #e0e0e0; --color-grid-line: #e0e0e0;
--color-grid-line-light: rgba(0, 0, 0, 0.05); --color-grid-line-light: rgba(0, 0, 0, 0.05);
--color-work-hours: rgba(0, 100, 0, 0.02); --color-work-hours: rgba(0, 100, 0, 0.06);
--color-current-time: #ff0000; --color-current-time: #ff0000;
/* Event colors */ /* Event colors */

View file

@ -303,7 +303,7 @@ swp-time-grid::before {
/* Grid lines */ /* Grid lines */
swp-grid-lines { swp-grid-lines {
position: absolute; position: absolute;
top: 0; top: 15px;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;

View file

@ -213,7 +213,6 @@ swp-time-axis {
position: sticky; position: sticky;
left: 0; left: 0;
z-index: 4; z-index: 4;
padding-top: 80px; /* Match header height */
} }
swp-hour-marker { swp-hour-marker {