fix: hover card maiden name false positive, editor placeholder on non-empty content, mention persistence #375

Merged
marcel merged 12 commits from fix/hover-card-placeholder-maiden-name into main 2026-04-29 21:33:18 +02:00
3 changed files with 29 additions and 15 deletions
Showing only changes of commit 7ccd541d40 - Show all commits

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
import { formatLifeDateRange } from '$lib/utils/personLifeDates';
import { chipLabel, otherName } from '$lib/relationshipLabels';
import type { components } from '$lib/generated/api';
import type { LoadState } from '$lib/types/personHoverCard';
@@ -22,19 +23,6 @@ const FAMILY_REL_TYPES: ReadonlySet<RelationshipDTO['relationType']> = new Set([
'SPOUSE_OF',
'SIBLING_OF'
]);
function relationLabel(type: RelationshipDTO['relationType']): string {
switch (type) {
case 'PARENT_OF':
return m.relation_parent_of();
case 'SPOUSE_OF':
return m.relation_spouse_of();
case 'SIBLING_OF':
return m.relation_sibling_of();
default:
return m.relation_other();
}
}
const NOTES_MAX = 120;
const familyChips = $derived(
@@ -136,8 +124,8 @@ const ariaBusy = $derived(state.status === 'loading');
<div class="chips" data-testid="person-hover-card-chips">
{#each familyChips as chip (chip.id)}
<span class="chip">
<span class="chip-type">{relationLabel(chip.relationType)}</span>
{chip.relatedPersonDisplayName}
<span class="chip-type">{chipLabel(chip, personId)}</span>
{otherName(chip, personId)}
</span>
{/each}
</div>

View File

@@ -165,6 +165,31 @@ describe('PersonHoverCard — loaded state', () => {
await expect.element(friendChip).not.toBeInTheDocument();
});
it('shows the other person name when hovered person is the object (relatedPersonId) in a PARENT_OF row', async () => {
// Storage: Heinrich PARENT_OF Auguste. When viewing Auguste's card,
// the chip must show "Heinrich" (the parent), not "Auguste" (herself).
const relationships: RelationshipDTO[] = [
{
id: 'r-parent',
personId: 'p-heinrich',
relatedPersonId: 'p-aug',
personDisplayName: 'Heinrich Raddatz',
relatedPersonDisplayName: 'Auguste Raddatz',
relationType: 'PARENT_OF'
}
];
render(PersonHoverCard, {
personId: 'p-aug',
cardId: 'card-1',
position: POSITION,
state: { status: 'loaded', person: AUGUSTE, relationships }
});
await expect.element(page.getByText('Heinrich Raddatz')).toBeInTheDocument();
// Auguste must NOT appear as her own parent chip name
const chips = document.querySelector('[data-testid="person-hover-card-chips"]');
expect(chips?.textContent).not.toContain('Auguste Raddatz');
});
it('omits the chips section entirely when no family relationships', async () => {
const onlyFriend: RelationshipDTO[] = [
{

View File

@@ -123,6 +123,7 @@ onMount(() => {
},
suggestion: {
char: '@',
allowSpaces: true,
// ─────────────────────────────────────────────────────────────
// EXCEPTION to frontend/CLAUDE.md "no client-side API fetch":
// Tiptap's suggestion plugin lives entirely on the client and