diff --git a/frontend/src/lib/timeline/TimelineView.svelte b/frontend/src/lib/timeline/TimelineView.svelte index e1732816..2eef69f3 100644 --- a/frontend/src/lib/timeline/TimelineView.svelte +++ b/frontend/src/lib/timeline/TimelineView.svelte @@ -3,6 +3,9 @@ import * as m from '$lib/paraglide/messages.js'; import YearBand from './YearBand.svelte'; import GapSpan from './GapSpan.svelte'; import LetterCard from './LetterCard.svelte'; +import EventPill from './EventPill.svelte'; +import WorldBand from './WorldBand.svelte'; +import { entryKey } from './entryKey'; import type { components } from '$lib/generated/api'; type TimelineDTO = components['schemas']['TimelineDTO']; @@ -59,8 +62,22 @@ const isEmpty = $derived(timeline.years.length === 0 && timeline.undated.length

{m.timeline_undated_section()}

diff --git a/frontend/src/lib/timeline/TimelineView.svelte.spec.ts b/frontend/src/lib/timeline/TimelineView.svelte.spec.ts index 6d6422b3..ec878a5a 100644 --- a/frontend/src/lib/timeline/TimelineView.svelte.spec.ts +++ b/frontend/src/lib/timeline/TimelineView.svelte.spec.ts @@ -89,6 +89,70 @@ describe('TimelineView', () => { expect(document.querySelector('[data-testid="undated-section"]')).not.toBeNull(); }); + it('renders an undated curated EVENT as a pill, not a broken letter card (REQ-008/016)', () => { + render(TimelineView, { + timeline: makeTimelineDTO({ + undated: [ + makeEntry({ + kind: 'EVENT', + type: 'PERSONAL', + derived: false, + eventId: 'e1', + precision: 'UNKNOWN', + eventDate: undefined, + title: 'Auswanderung', + senderName: '', + receiverName: '', + documentId: undefined + }) + ] + }) + }); + // The event renders inside the undated section… + expect(document.querySelector('[data-testid="undated-section"]')).not.toBeNull(); + expect(document.body.textContent).toContain('Auswanderung'); + // …as an EventPill (its edit affordance), never as a letter card linking + // to /documents/undefined with "Unbekannt → Unbekannt". + expect(document.querySelector('[data-testid="event-edit"]')).not.toBeNull(); + expect(document.querySelector('a[href="/documents/undefined"]')).toBeNull(); + expect(document.body.textContent).not.toContain('Unbekannt'); + }); + + it('renders an undated HISTORICAL EVENT as a world band, not a letter card (REQ-009/016)', () => { + render(TimelineView, { + timeline: makeTimelineDTO({ + undated: [ + makeEntry({ + kind: 'EVENT', + type: 'HISTORICAL', + derived: false, + precision: 'UNKNOWN', + eventDate: undefined, + title: 'Weltwirtschaftskrise', + senderName: '', + receiverName: '', + documentId: undefined + }) + ] + }) + }); + expect(document.querySelector('[data-testid="undated-section"]')).not.toBeNull(); + expect(document.body.textContent).toContain('Weltwirtschaftskrise'); + // HISTORICAL → WorldBand carries the sr-only "Weltgeschehen" cue (REQ-018), + // not a broken document link. + expect(document.body.textContent).toContain('Weltgeschehen'); + expect(document.querySelector('a[href="/documents/undefined"]')).toBeNull(); + }); + + it('still renders an undated LETTER as a letter card (REQ-016)', () => { + render(TimelineView, { + timeline: makeTimelineDTO({ + undated: [makeEntry({ precision: 'UNKNOWN', eventDate: undefined, documentId: 'u1' })] + }) + }); + expect(document.querySelector('a[href="/documents/u1"]')).not.toBeNull(); + }); + it('renders two derived events in one band without key collision (no-double-null-key)', () => { const a = makeEntry({ kind: 'EVENT',