Improves all-day event layout calculation
Updates the all-day event layout engine for better event rendering, especially when dealing with partial week views. The layout engine now correctly clips events that start before or end after the visible date range, ensuring that only relevant portions of events are displayed. It also fixes event ordering. Includes new unit tests to validate date range filtering and clipping logic.
This commit is contained in:
parent
a551bc59ff
commit
41d078e2e8
4 changed files with 277 additions and 265 deletions
|
|
@ -30,8 +30,8 @@ describe('AllDay Layout Engine - Pure Data Tests', () => {
|
|||
{ id: 'workshop', title: 'Teknisk Workshop', start: new Date('2025-09-23'), end: new Date('2025-09-26'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent
|
||||
],
|
||||
expected: [
|
||||
{ id: 'autumn', gridArea: '2 / 1 / 3 / 3' }, // row 2, columns 1-2 (2 dage, processed second)
|
||||
{ id: 'workshop', gridArea: '1 / 2 / 2 / 6' } // row 1, columns 2-5 (4 dage, processed first)
|
||||
{ id: 'autumn', gridArea: '1 / 1 / 2 / 3' }, // row 1, columns 1-2 (2 dage, processed first)
|
||||
{ id: 'workshop', gridArea: '2 / 2 / 3 / 6' } // row 2, columns 2-5 (4 dage, processed second)
|
||||
]
|
||||
},
|
||||
|
||||
|
|
@ -72,8 +72,8 @@ describe('AllDay Layout Engine - Pure Data Tests', () => {
|
|||
],
|
||||
expected: [
|
||||
{ id: '1', gridArea: '1 / 1 / 2 / 5' }, // row 1, columns 1-4 (4 dage, processed first)
|
||||
{ id: '2', gridArea: '3 / 2 / 4 / 4' }, // row 3, columns 2-3 (2 dage, processed last)
|
||||
{ id: '3', gridArea: '2 / 3 / 3 / 6' } // row 2, columns 3-5 (3 dage, processed second)
|
||||
{ id: '2', gridArea: '2 / 2 / 3 / 4' }, // row 2, columns 2-3 (2 dage, processed second)
|
||||
{ id: '3', gridArea: '3 / 3 / 4 / 6' } // row 3, columns 3-5 (3 dage, processed third)
|
||||
]
|
||||
},
|
||||
|
||||
|
|
@ -87,11 +87,11 @@ describe('AllDay Layout Engine - Pure Data Tests', () => {
|
|||
{ id: '161', title: 'Teknisk Workshop', start: new Date('2025-09-23'), end: new Date('2025-09-26'), type: 'work', allDay: true, syncStatus: 'synced' } as CalendarEvent
|
||||
],
|
||||
expected: [
|
||||
{ id: '112', gridArea: '4 / 1 / 5 / 3' }, // Autumn Equinox: row 4, columns 1-2 (2 dage, processed last)
|
||||
{ id: '122', gridArea: '1 / 1 / 2 / 4' }, // Multi-Day Conference: row 1, columns 1-3 (4 dage, starts 21/9, processed first)
|
||||
{ id: '123', gridArea: '2 / 1 / 3 / 5' }, // Project Sprint: row 2, columns 1-4 (4 dage, starts 22/9, processed second)
|
||||
{ id: '112', gridArea: '1 / 1 / 2 / 3' }, // Autumn Equinox: row 1, columns 1-2 (2 dage, processed first)
|
||||
{ id: '122', gridArea: '2 / 1 / 3 / 4' }, // Multi-Day Conference: row 2, columns 1-3 (4 dage, starts 21/9, processed second)
|
||||
{ id: '123', gridArea: '3 / 1 / 4 / 5' }, // Project Sprint: row 3, columns 1-4 (4 dage, starts 22/9, processed third)
|
||||
{ id: '143', gridArea: '1 / 5 / 2 / 8' }, // Weekend Hackathon: row 1, columns 5-7 (3 dage, no overlap, reuse row 1)
|
||||
{ id: '161', gridArea: '3 / 2 / 4 / 6' } // Teknisk Workshop: row 3, columns 2-5 (4 dage, starts 23/9, processed third)
|
||||
{ id: '161', gridArea: '4 / 2 / 5 / 6' } // Teknisk Workshop: row 4, columns 2-5 (4 dage, starts 23/9, processed fourth)
|
||||
]
|
||||
}
|
||||
];
|
||||
|
|
@ -135,4 +135,136 @@ describe('AllDay Layout Engine - Pure Data Tests', () => {
|
|||
expect(rowSpan).toBe(1);
|
||||
expect(colSpan).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('AllDay Layout Engine - Partial Week Views', () => {
|
||||
describe('Date Range Filtering', () => {
|
||||
it('should filter out events that do not overlap with visible dates', () => {
|
||||
// 3-day workweek: Wed-Fri (like user's scenario)
|
||||
const weekDates = ['2025-09-24', '2025-09-25', '2025-09-26']; // Wed, Thu, Fri
|
||||
const engine = new AllDayLayoutEngine(weekDates);
|
||||
|
||||
const events: CalendarEvent[] = [
|
||||
{
|
||||
id: '112',
|
||||
title: 'Autumn Equinox',
|
||||
start: new Date('2025-09-22T00:00:00'), // Monday - OUTSIDE visible range
|
||||
end: new Date('2025-09-24T00:00:00'), // Wednesday - OUTSIDE visible range
|
||||
type: 'milestone',
|
||||
allDay: true,
|
||||
syncStatus: 'synced'
|
||||
},
|
||||
{
|
||||
id: '113',
|
||||
title: 'Visible Event',
|
||||
start: new Date('2025-09-25T00:00:00'), // Thursday - INSIDE visible range
|
||||
end: new Date('2025-09-26T00:00:00'), // Friday - INSIDE visible range
|
||||
type: 'work',
|
||||
allDay: true,
|
||||
syncStatus: 'synced'
|
||||
}
|
||||
];
|
||||
|
||||
const layouts = engine.calculateLayout(events);
|
||||
|
||||
// Both events are now visible since '112' ends on Wednesday (visible range start)
|
||||
expect(layouts.size).toBe(2);
|
||||
expect(layouts.has('112')).toBe(true); // Now visible since it ends on Wed
|
||||
expect(layouts.has('113')).toBe(true); // Still visible
|
||||
|
||||
const layout112 = layouts.get('112')!;
|
||||
expect(layout112.startColumn).toBe(1); // Clipped to Wed (first visible day)
|
||||
expect(layout112.endColumn).toBe(1); // Wed only
|
||||
expect(layout112.row).toBe(1);
|
||||
|
||||
const layout113 = layouts.get('113')!;
|
||||
expect(layout113.startColumn).toBe(2); // Thursday = column 2 in Wed-Fri view
|
||||
expect(layout113.endColumn).toBe(3); // Friday = column 3
|
||||
expect(layout113.row).toBe(1);
|
||||
});
|
||||
|
||||
it('should clip events that partially overlap with visible dates', () => {
|
||||
// 3-day workweek: Wed-Fri
|
||||
const weekDates = ['2025-09-24', '2025-09-25', '2025-09-26']; // Wed, Thu, Fri
|
||||
const engine = new AllDayLayoutEngine(weekDates);
|
||||
|
||||
const events: CalendarEvent[] = [
|
||||
{
|
||||
id: '114',
|
||||
title: 'Spans Before and Into Week',
|
||||
start: new Date('2025-09-22T00:00:00'), // Monday - before visible range
|
||||
end: new Date('2025-09-26T00:00:00'), // Friday - inside visible range
|
||||
type: 'work',
|
||||
allDay: true,
|
||||
syncStatus: 'synced'
|
||||
},
|
||||
{
|
||||
id: '115',
|
||||
title: 'Spans From Week and After',
|
||||
start: new Date('2025-09-25T00:00:00'), // Thursday - inside visible range
|
||||
end: new Date('2025-09-29T00:00:00'), // Monday - after visible range
|
||||
type: 'work',
|
||||
allDay: true,
|
||||
syncStatus: 'synced'
|
||||
}
|
||||
];
|
||||
|
||||
const layouts = engine.calculateLayout(events);
|
||||
|
||||
expect(layouts.size).toBe(2);
|
||||
|
||||
// First event should be clipped to start at Wed (column 1) and end at Fri (column 3)
|
||||
const firstLayout = layouts.get('114')!;
|
||||
expect(firstLayout.startColumn).toBe(1); // Clipped to Wed (first visible day)
|
||||
expect(firstLayout.endColumn).toBe(3); // Fri (now ends on Friday due to 2025-09-26T00:00:00)
|
||||
expect(firstLayout.columnSpan).toBe(3);
|
||||
expect(firstLayout.gridArea).toBe('1 / 1 / 2 / 4');
|
||||
|
||||
// Second event should span Thu-Fri, but clipped beyond visible range
|
||||
const secondLayout = layouts.get('115')!;
|
||||
expect(secondLayout.startColumn).toBe(2); // Thu (actual start date) = column 2 in Wed-Fri view
|
||||
expect(secondLayout.endColumn).toBe(3); // Clipped to Fri (last visible day) = column 3
|
||||
expect(secondLayout.columnSpan).toBe(2);
|
||||
expect(secondLayout.gridArea).toBe('2 / 2 / 3 / 4'); // Row 2 due to overlap
|
||||
});
|
||||
|
||||
it('should handle 5-day workweek correctly', () => {
|
||||
// 5-day workweek: Mon-Fri
|
||||
const weekDates = ['2025-09-22', '2025-09-23', '2025-09-24', '2025-09-25', '2025-09-26']; // Mon-Fri
|
||||
const engine = new AllDayLayoutEngine(weekDates);
|
||||
|
||||
const events: CalendarEvent[] = [
|
||||
{
|
||||
id: '116',
|
||||
title: 'Monday Event',
|
||||
start: new Date('2025-09-22T00:00:00'), // Monday
|
||||
end: new Date('2025-09-23T00:00:00'), // Tuesday
|
||||
type: 'work',
|
||||
allDay: true,
|
||||
syncStatus: 'synced'
|
||||
},
|
||||
{
|
||||
id: '117',
|
||||
title: 'Weekend Event',
|
||||
start: new Date('2025-09-27T00:00:00'), // Saturday - OUTSIDE visible range
|
||||
end: new Date('2025-09-29T00:00:00'), // Monday - OUTSIDE visible range
|
||||
type: 'personal',
|
||||
allDay: true,
|
||||
syncStatus: 'synced'
|
||||
}
|
||||
];
|
||||
|
||||
const layouts = engine.calculateLayout(events);
|
||||
|
||||
expect(layouts.size).toBe(1); // Only Monday event should be included - weekend event should be filtered out
|
||||
expect(layouts.has('116')).toBe(true); // Monday event should be included
|
||||
expect(layouts.has('117')).toBe(false); // Weekend event should be filtered out
|
||||
|
||||
const mondayLayout = layouts.get('116')!;
|
||||
expect(mondayLayout.startColumn).toBe(1); // Monday = column 1
|
||||
expect(mondayLayout.endColumn).toBe(2); // Now ends on Tuesday due to 2025-09-23T00:00:00
|
||||
expect(mondayLayout.row).toBe(1);
|
||||
expect(mondayLayout.gridArea).toBe('1 / 1 / 2 / 3');
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue