feat(web): Kalender-Tag nach Kalender gruppieren, Kreise je Kalender berechnen (calendar-month)
- groupDayBySource gruppiert Tagestermine nach sourceId (nicht Farbe), Reihenfolge = erstes Auftreten, Farbe = Farbe des ersten Termins der Gruppe - buildDayBadges baut daraus bis zu drei Plaketten-Kreise, ab dem vierten Kalender einen grauen Restkreis mit Summe - Tests 8/9 in calendar-month.test.ts (TDD: RED bestaetigt vor Implementierung) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,12 +3,14 @@ import type { CalendarEvent } from '@/lib/calendar-api';
|
||||
import {
|
||||
addDays,
|
||||
buildCalendarDays,
|
||||
buildDayBadges,
|
||||
computeFetchWindow,
|
||||
dateKey,
|
||||
formatEventDate,
|
||||
formatEventTime,
|
||||
formatMonthLabel,
|
||||
gridStartFor,
|
||||
groupDayBySource,
|
||||
groupEventsByDate,
|
||||
resolveCalendarConfig,
|
||||
selectUpcomingEvents,
|
||||
@@ -149,4 +151,99 @@ describe('calendar-month', () => {
|
||||
expect(start.getHours()).toBe(0);
|
||||
expect(addDays(new Date(2026, 6, 30), 2).getDate()).toBe(1);
|
||||
});
|
||||
|
||||
it('Test 8: groupDayBySource gruppiert nach sourceId in Reihenfolge des ersten Auftretens', () => {
|
||||
const day = new Date(2026, 6, 20, 9, 0);
|
||||
const hourLater = new Date(2026, 6, 20, 10, 0);
|
||||
|
||||
// (a) drei Termine, alle s1 mit derselben Farbe
|
||||
const sameSource = [
|
||||
ev('e1', day, hourLater, { sourceId: 's1', color: '#c44040' }),
|
||||
ev('e2', day, hourLater, { sourceId: 's1', color: '#c44040' }),
|
||||
ev('e3', day, hourLater, { sourceId: 's1', color: '#c44040' }),
|
||||
];
|
||||
expect(groupDayBySource(sameSource)).toEqual([{ sourceId: 's1', color: '#c44040', count: 3 }]);
|
||||
|
||||
// (b) Reihenfolge s2, s1, s2 wird NICHT umsortiert
|
||||
const mixedOrder = [
|
||||
ev('e1', day, hourLater, { sourceId: 's2' }),
|
||||
ev('e2', day, hourLater, { sourceId: 's1' }),
|
||||
ev('e3', day, hourLater, { sourceId: 's2' }),
|
||||
];
|
||||
const groupedMixed = groupDayBySource(mixedOrder);
|
||||
expect(groupedMixed.map((g) => g.sourceId)).toEqual(['s2', 's1']);
|
||||
expect(groupedMixed[0].count).toBe(2);
|
||||
expect(groupedMixed[1].count).toBe(1);
|
||||
|
||||
// (c) Termine ohne color -> color der Gruppe ist undefined
|
||||
const noColor = [ev('e1', day, hourLater, { sourceId: 's1', color: undefined })];
|
||||
expect(groupDayBySource(noColor)[0].color).toBeUndefined();
|
||||
|
||||
// (d) zwei Kalender mit derselben Farbe bleiben zwei Gruppen (Gruppierung nach sourceId)
|
||||
const sameColorDifferentSource = [
|
||||
ev('e1', day, hourLater, { sourceId: 's1', color: '#123456' }),
|
||||
ev('e2', day, hourLater, { sourceId: 's2', color: '#123456' }),
|
||||
];
|
||||
expect(groupDayBySource(sameColorDifferentSource)).toHaveLength(2);
|
||||
|
||||
// (e) Farbe der Gruppe ist die Farbe des ERSTEN Termins der Gruppe
|
||||
const laterColorChange = [
|
||||
ev('e1', day, hourLater, { sourceId: 's1', color: '#111111' }),
|
||||
ev('e2', day, hourLater, { sourceId: 's1', color: '#222222' }),
|
||||
];
|
||||
expect(groupDayBySource(laterColorChange)).toEqual([
|
||||
{ sourceId: 's1', color: '#111111', count: 2 },
|
||||
]);
|
||||
|
||||
// (f) leeres Array
|
||||
expect(groupDayBySource([])).toEqual([]);
|
||||
});
|
||||
|
||||
it('Test 9: buildDayBadges liefert je Kalender einen Eintrag, ab dem vierten einen grauen Restkreis', () => {
|
||||
const day = new Date(2026, 6, 20);
|
||||
const single = [ev('e1', day, day, { sourceId: 's1', color: '#111111' })];
|
||||
expect(buildDayBadges(single)).toEqual([
|
||||
{ key: 's1', color: '#111111', count: 1, rest: false },
|
||||
]);
|
||||
|
||||
const two = [
|
||||
ev('e1', day, day, { sourceId: 's1', color: '#111111' }),
|
||||
ev('e2', day, day, { sourceId: 's2', color: '#222222' }),
|
||||
];
|
||||
expect(buildDayBadges(two)).toEqual([
|
||||
{ key: 's1', color: '#111111', count: 1, rest: false },
|
||||
{ key: 's2', color: '#222222', count: 1, rest: false },
|
||||
]);
|
||||
|
||||
const three = [
|
||||
ev('e1', day, day, { sourceId: 's1', color: '#111111' }),
|
||||
ev('e2', day, day, { sourceId: 's2', color: '#222222' }),
|
||||
ev('e3', day, day, { sourceId: 's3', color: '#333333' }),
|
||||
];
|
||||
const threeResult = buildDayBadges(three);
|
||||
expect(threeResult).toHaveLength(3);
|
||||
expect(threeResult.every((b) => b.rest === false)).toBe(true);
|
||||
|
||||
const four = [
|
||||
ev('e1', day, day, { sourceId: 's1', color: '#111111' }),
|
||||
ev('e2a', day, day, { sourceId: 's2', color: '#222222' }),
|
||||
ev('e2b', day, day, { sourceId: 's2', color: '#222222' }),
|
||||
ev('e3', day, day, { sourceId: 's3', color: '#333333' }),
|
||||
ev('e4a', day, day, { sourceId: 's4', color: '#444444' }),
|
||||
ev('e4b', day, day, { sourceId: 's4', color: '#444444' }),
|
||||
ev('e4c', day, day, { sourceId: 's4', color: '#444444' }),
|
||||
];
|
||||
expect(buildDayBadges(four)).toEqual([
|
||||
{ key: 's1', color: '#111111', count: 1, rest: false },
|
||||
{ key: 's2', color: '#222222', count: 2, rest: false },
|
||||
{ key: '__rest__', color: undefined, count: 4, rest: true },
|
||||
]);
|
||||
|
||||
expect(buildDayBadges(four, 2)).toEqual([
|
||||
{ key: 's1', color: '#111111', count: 1, rest: false },
|
||||
{ key: '__rest__', color: undefined, count: 6, rest: true },
|
||||
]);
|
||||
|
||||
expect(buildDayBadges([])).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user