wip
This commit is contained in:
parent
f29613e55f
commit
28ed131b9e
6 changed files with 151 additions and 90 deletions
|
|
@ -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',
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
// Convert to pixels
|
// Calculate duration in minutes
|
||||||
const top = startMinutes * (hourHeight / 60);
|
const duration = (endDate.getTime() - startDate.getTime()) / (1000 * 60);
|
||||||
|
|
||||||
|
// Convert to pixels - this gives absolute position from top of time-grid
|
||||||
|
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 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue