From 403a043d5142c5e0b0b7aa25680b3b17753e9508 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 2 Jun 2026 20:32:52 +0200 Subject: [PATCH] feat(persons): retarget frequent-correspondents card to document search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Häufige Korrespondenten" card linked into the standalone Briefwechsel view. Retarget each chip to the existing document search pre-filtered by sender and receiver (/documents?senderId=A&receiverId=B), naming both persons in a search-action title, swapping the chat-bubble icon for a magnifier, and clarifying that the ×N badge counts shared letters in both directions (not the unidirectional search result count). Co-Authored-By: Claude Opus 4.8 --- frontend/messages/de.json | 3 ++ frontend/messages/en.json | 3 ++ frontend/messages/es.json | 3 ++ frontend/src/routes/persons/[id]/+page.svelte | 6 ++- .../persons/[id]/CoCorrespondentsList.svelte | 21 ++++++--- .../[id]/CoCorrespondentsList.svelte.test.ts | 43 ++++++++++++++----- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/frontend/messages/de.json b/frontend/messages/de.json index 0c2d734a..7b37d4d2 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -190,6 +190,9 @@ "person_role_receiver": "Empfangen", "person_co_correspondents_heading": "Häufige Korrespondenten", "person_correspondents_hint": "klicken für Konversation", + "person_correspondents_search_title": "Briefe von {A} an {B} durchsuchen", + "person_correspondents_search_hint": "klicken, um Briefe zu durchsuchen", + "person_correspondents_badge_title": "Gemeinsame Briefe in beide Richtungen", "person_show_more": "+ {count} weitere anzeigen", "conv_label_person_a": "Person A (Absender)", "conv_label_person_b": "Korrespondent", diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 45f3bc39..b2897cf7 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -190,6 +190,9 @@ "person_role_receiver": "Received", "person_co_correspondents_heading": "Frequent correspondents", "person_correspondents_hint": "click to view conversation", + "person_correspondents_search_title": "Search letters from {A} to {B}", + "person_correspondents_search_hint": "click to search letters", + "person_correspondents_badge_title": "Shared letters in both directions", "person_show_more": "+ {count} more", "conv_label_person_a": "Person A (Sender)", "conv_label_person_b": "Correspondent", diff --git a/frontend/messages/es.json b/frontend/messages/es.json index ed304b14..773988c4 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -190,6 +190,9 @@ "person_role_receiver": "Recibido", "person_co_correspondents_heading": "Corresponsales frecuentes", "person_correspondents_hint": "clic para ver conversación", + "person_correspondents_search_title": "Buscar cartas de {A} a {B}", + "person_correspondents_search_hint": "haz clic para buscar cartas", + "person_correspondents_badge_title": "Cartas compartidas en ambas direcciones", "person_show_more": "+ {count} más", "conv_label_person_a": "Persona A (Remitente)", "conv_label_person_b": "Corresponsal", diff --git a/frontend/src/routes/persons/[id]/+page.svelte b/frontend/src/routes/persons/[id]/+page.svelte index 3518f82b..631799d3 100644 --- a/frontend/src/routes/persons/[id]/+page.svelte +++ b/frontend/src/routes/persons/[id]/+page.svelte @@ -68,7 +68,11 @@ const coCorrespondents = $derived.by(() => {
- +
{m.person_co_correspondents_heading()} - {m.person_correspondents_hint()} + {m.person_correspondents_search_hint()}
{#each coCorrespondents as c (c.id)} @@ -41,8 +45,11 @@ function initials(name: string): string { {initials(c.name)} {c.name} - ×{c.count} - + ×{c.count} + diff --git a/frontend/src/routes/persons/[id]/CoCorrespondentsList.svelte.test.ts b/frontend/src/routes/persons/[id]/CoCorrespondentsList.svelte.test.ts index 5c9af779..c5262ee3 100644 --- a/frontend/src/routes/persons/[id]/CoCorrespondentsList.svelte.test.ts +++ b/frontend/src/routes/persons/[id]/CoCorrespondentsList.svelte.test.ts @@ -1,6 +1,7 @@ import { describe, it, expect, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; +import { m } from '$lib/paraglide/messages.js'; import CoCorrespondentsList from './CoCorrespondentsList.svelte'; afterEach(cleanup); @@ -8,7 +9,7 @@ afterEach(cleanup); describe('CoCorrespondentsList', () => { it('renders nothing when the coCorrespondents list is empty', async () => { render(CoCorrespondentsList, { - props: { coCorrespondents: [], personId: 'p-1' } + props: { coCorrespondents: [], personId: 'p-1', personName: 'Anna Schmidt' } }); await expect @@ -16,18 +17,19 @@ describe('CoCorrespondentsList', () => { .not.toBeInTheDocument(); }); - it('renders the heading and hint when there is at least one co-correspondent', async () => { + it('renders the heading and search hint when there is at least one co-correspondent', async () => { render(CoCorrespondentsList, { props: { coCorrespondents: [{ id: 'c-1', name: 'Max Mustermann', count: 3 }], - personId: 'p-1' + personId: 'p-1', + personName: 'Anna Schmidt' } }); await expect .element(page.getByRole('heading', { name: /häufige korrespondenten/i })) .toBeVisible(); - await expect.element(page.getByText('klicken für Konversation')).toBeVisible(); + await expect.element(page.getByText(m.person_correspondents_search_hint())).toBeVisible(); }); it('renders one chip per co-correspondent with name and count', async () => { @@ -37,7 +39,8 @@ describe('CoCorrespondentsList', () => { { id: 'c-1', name: 'Max Mustermann', count: 3 }, { id: 'c-2', name: 'Erika Beispiel', count: 1 } ], - personId: 'p-1' + personId: 'p-1', + personName: 'Anna Schmidt' } }); @@ -47,24 +50,40 @@ describe('CoCorrespondentsList', () => { await expect.element(page.getByText('×1')).toBeVisible(); }); - it('points each chip to the bilateral conversation route with the correct ids', async () => { + it('points each chip to the document search pre-filtered by sender and receiver', async () => { render(CoCorrespondentsList, { props: { coCorrespondents: [{ id: 'c-1', name: 'Max Mustermann', count: 3 }], - personId: 'p-1' + personId: 'p-1', + personName: 'Anna Schmidt' } }); await expect .element(page.getByRole('link', { name: /max mustermann/i })) - .toHaveAttribute('href', '/briefwechsel?senderId=p-1&receiverId=c-1'); + .toHaveAttribute('href', '/documents?senderId=p-1&receiverId=c-1'); + }); + + it('labels the link as a search action naming both persons', async () => { + render(CoCorrespondentsList, { + props: { + coCorrespondents: [{ id: 'c-1', name: 'Max Mustermann', count: 3 }], + personId: 'p-1', + personName: 'Anna Schmidt' + } + }); + + const link = page.getByRole('link', { name: /max mustermann/i }); + await expect.element(link).toHaveAttribute('title', /Anna Schmidt/); + await expect.element(link).toHaveAttribute('title', /Max Mustermann/); }); it('builds initials from up to two name parts', async () => { render(CoCorrespondentsList, { props: { coCorrespondents: [{ id: 'c-1', name: 'Max Mustermann Beispiel', count: 1 }], - personId: 'p-1' + personId: 'p-1', + personName: 'Anna Schmidt' } }); @@ -75,7 +94,8 @@ describe('CoCorrespondentsList', () => { render(CoCorrespondentsList, { props: { coCorrespondents: [{ id: 'c-1', name: 'Cher', count: 2 }], - personId: 'p-1' + personId: 'p-1', + personName: 'Anna Schmidt' } }); @@ -88,7 +108,8 @@ describe('CoCorrespondentsList', () => { render(CoCorrespondentsList, { props: { coCorrespondents: [{ id: 'c-1', name: ' Max', count: 1 }], - personId: 'p-1' + personId: 'p-1', + personName: 'Anna Schmidt' } });