diff --git a/frontend/src/routes/DocumentList.svelte b/frontend/src/routes/DocumentList.svelte index a42f3989..4a16b6eb 100644 --- a/frontend/src/routes/DocumentList.svelte +++ b/frontend/src/routes/DocumentList.svelte @@ -2,13 +2,16 @@ import { goto } from '$app/navigation'; import { m } from '$lib/paraglide/messages.js'; import { formatDate } from '$lib/utils/date'; +import { groupDocuments } from '$lib/utils/groupDocuments'; +import GroupDivider from '$lib/components/GroupDivider.svelte'; let { documents, canWrite, error, total = 0, - q = '' + q = '', + sort }: { documents: { id: string; @@ -24,7 +27,14 @@ let { error?: string | null; total?: number; q?: string; + sort?: string; } = $props(); + +const fallbackLabel = $derived(sort === 'DATE' ? m.docs_group_undated() : m.docs_group_unknown()); +const groupedDocuments = $derived.by(() => + groupDocuments(documents, sort ?? 'DATE', fallbackLabel) +); +const showDividers = $derived(groupedDocuments.length >= 2); @@ -57,107 +67,112 @@ let { {error} {:else if documents.length > 0} - + {/each} {:else}
diff --git a/frontend/src/routes/DocumentList.svelte.spec.ts b/frontend/src/routes/DocumentList.svelte.spec.ts index 2d72326b..1d7d728b 100644 --- a/frontend/src/routes/DocumentList.svelte.spec.ts +++ b/frontend/src/routes/DocumentList.svelte.spec.ts @@ -1,10 +1,12 @@ -import { describe, expect, it, vi } from 'vitest'; -import { render } from 'vitest-browser-svelte'; +import { describe, expect, it, vi, afterEach } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import DocumentList from './DocumentList.svelte'; vi.mock('$app/navigation', () => ({ goto: vi.fn() })); +afterEach(() => cleanup()); + const baseProps = { documents: [], canWrite: false, @@ -13,7 +15,14 @@ const baseProps = { q: '' }; -const makeDoc = () => ({ +type DocOverrides = { + id?: string; + documentDate?: string | null; + sender?: { firstName?: string | null; lastName: string; displayName: string } | null; + receivers?: { firstName?: string | null; lastName: string; displayName: string }[]; +}; + +const makeDoc = (overrides: DocOverrides = {}) => ({ id: '1', title: 'Testbrief', originalFilename: 'testbrief.pdf', @@ -21,8 +30,9 @@ const makeDoc = () => ({ documentDate: '2024-03-15', location: null, sender: null, - receivers: [], - tags: [] + receivers: [] as { firstName?: string | null; lastName: string; displayName: string }[], + tags: [], + ...overrides }); describe('DocumentList – result count', () => { @@ -49,3 +59,50 @@ describe('DocumentList – empty state with search term', () => { await expect.element(page.getByText(/"Urlaub"/)).toBeInTheDocument(); }); }); + +// ─── Group headers ──────────────────────────────────────────────────────────── + +describe('DocumentList – group headers', () => { + it('renders group-divider elements when DATE sort spans multiple years', async () => { + const documents = [ + makeDoc({ id: '1', documentDate: '1923-04-12' }), + makeDoc({ id: '2', documentDate: '1965-08-03' }) + ]; + render(DocumentList, { ...baseProps, documents, total: 2, sort: 'DATE' }); + await expect.element(page.getByTestId('group-divider').first()).toBeInTheDocument(); + }); + + it('does not render group-divider when DATE sort has only one distinct year', async () => { + const documents = [ + makeDoc({ id: '1', documentDate: '1938-01-01' }), + makeDoc({ id: '2', documentDate: '1938-06-15' }) + ]; + render(DocumentList, { ...baseProps, documents, total: 2, sort: 'DATE' }); + await expect.element(page.getByTestId('group-divider')).not.toBeInTheDocument(); + }); + + it('does not render group-divider for TITLE sort', async () => { + const documents = [ + makeDoc({ id: '1', documentDate: '1923-04-12' }), + makeDoc({ id: '2', documentDate: '1965-08-03' }) + ]; + render(DocumentList, { ...baseProps, documents, total: 2, sort: 'TITLE' }); + await expect.element(page.getByTestId('group-divider')).not.toBeInTheDocument(); + }); + + it('a doc with two receivers appears in both receiver groups', async () => { + const documents = [ + makeDoc({ + id: '1', + receivers: [ + { firstName: null, lastName: 'Müller', displayName: 'Anna Müller' }, + { firstName: null, lastName: 'Bauer', displayName: 'Karl Bauer' } + ] + }) + ]; + render(DocumentList, { ...baseProps, documents, total: 1, sort: 'RECEIVER' }); + const links = page.getByRole('link', { name: /Testbrief/ }); + await expect.element(links.first()).toBeInTheDocument(); + await expect.element(links.nth(1)).toBeInTheDocument(); + }); +});