fix(hover-card): use orientation-aware relationship labels; allow spaces in mention
Some checks failed
CI / Unit & Component Tests (push) Failing after 3m35s
CI / OCR Service Tests (push) Successful in 39s
CI / Backend Unit Tests (push) Failing after 3m6s
CI / Unit & Component Tests (pull_request) Failing after 4m38s
CI / OCR Service Tests (pull_request) Successful in 42s
CI / Backend Unit Tests (pull_request) Failing after 3m5s
Some checks failed
CI / Unit & Component Tests (push) Failing after 3m35s
CI / OCR Service Tests (push) Successful in 39s
CI / Backend Unit Tests (push) Failing after 3m6s
CI / Unit & Component Tests (pull_request) Failing after 4m38s
CI / OCR Service Tests (pull_request) Successful in 42s
CI / Backend Unit Tests (pull_request) Failing after 3m5s
PersonHoverCard was showing the hovered person as their own parent when stored as the object side of a PARENT_OF row — now uses chipLabel/otherName from relationshipLabels (same helpers the person detail page uses) to resolve the correct name and label from the caller's perspective. PersonMentionEditor: add allowSpaces:true so typing a last name after a space no longer exits mention mode mid-query. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { m } from '$lib/paraglide/messages.js';
|
import { m } from '$lib/paraglide/messages.js';
|
||||||
import { formatLifeDateRange } from '$lib/utils/personLifeDates';
|
import { formatLifeDateRange } from '$lib/utils/personLifeDates';
|
||||||
|
import { chipLabel, otherName } from '$lib/relationshipLabels';
|
||||||
import type { components } from '$lib/generated/api';
|
import type { components } from '$lib/generated/api';
|
||||||
import type { LoadState } from '$lib/types/personHoverCard';
|
import type { LoadState } from '$lib/types/personHoverCard';
|
||||||
|
|
||||||
@@ -22,19 +23,6 @@ const FAMILY_REL_TYPES: ReadonlySet<RelationshipDTO['relationType']> = new Set([
|
|||||||
'SPOUSE_OF',
|
'SPOUSE_OF',
|
||||||
'SIBLING_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 NOTES_MAX = 120;
|
||||||
|
|
||||||
const familyChips = $derived(
|
const familyChips = $derived(
|
||||||
@@ -136,8 +124,8 @@ const ariaBusy = $derived(state.status === 'loading');
|
|||||||
<div class="chips" data-testid="person-hover-card-chips">
|
<div class="chips" data-testid="person-hover-card-chips">
|
||||||
{#each familyChips as chip (chip.id)}
|
{#each familyChips as chip (chip.id)}
|
||||||
<span class="chip">
|
<span class="chip">
|
||||||
<span class="chip-type">{relationLabel(chip.relationType)}</span>
|
<span class="chip-type">{chipLabel(chip, personId)}</span>
|
||||||
{chip.relatedPersonDisplayName}
|
{otherName(chip, personId)}
|
||||||
</span>
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -165,6 +165,31 @@ describe('PersonHoverCard — loaded state', () => {
|
|||||||
await expect.element(friendChip).not.toBeInTheDocument();
|
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 () => {
|
it('omits the chips section entirely when no family relationships', async () => {
|
||||||
const onlyFriend: RelationshipDTO[] = [
|
const onlyFriend: RelationshipDTO[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ onMount(() => {
|
|||||||
},
|
},
|
||||||
suggestion: {
|
suggestion: {
|
||||||
char: '@',
|
char: '@',
|
||||||
|
allowSpaces: true,
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
// EXCEPTION to frontend/CLAUDE.md "no client-side API fetch":
|
// EXCEPTION to frontend/CLAUDE.md "no client-side API fetch":
|
||||||
// Tiptap's suggestion plugin lives entirely on the client and
|
// Tiptap's suggestion plugin lives entirely on the client and
|
||||||
|
|||||||
Reference in New Issue
Block a user