feat(rennmausakte): Hinweis-Chip für Geschwisterverpaarung in der Tierakte

Stammt ein Tier aus einer Vollgeschwister-Verpaarung (Vater und Mutter teilen
dieselbe litterId), zeigt die Rennmausakte jetzt einen Chip
"⚭ Geschwisterverpaarung" in der Fakten-Zeile — neben Geschlecht, Geburtsdatum
und Farbschlag, in Akzentfarbe hervorgehoben (zuchtrelevant).

e2e-Test: Chip erscheint für 'Inzucht Kind' (Eltern aus demselben Wurf),
nicht für 'Krümel' (Eltern aus verschiedenen Würfen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 14:32:36 +02:00
parent 3715e32303
commit 070a896072
4 changed files with 39 additions and 0 deletions

View File

@@ -104,6 +104,20 @@ test('Detailseite: Wurf-Feld ist ein Link zur Wurf-Detailseite (WURF-LINK)', asy
await expect(page.getByRole('heading', { name: 'Wurf K' })).toBeVisible()
})
test('Detailseite zeigt Geschwisterverpaarungs-Hinweis nur wenn die Eltern Vollgeschwister sind (SIBLING-PAIRING)', async ({ page }) => {
skipUnlessMock()
// 'Inzucht Kind': Eltern Zwilling Bock + Zwilling Maus aus demselben Wurf
// 'w-zwillinge' → Vollgeschwister → Hinweis sichtbar.
await page.goto('/rennmaeuse/inzucht-kind')
await expect(page.getByRole('heading', { name: 'Inzucht Kind' })).toBeVisible()
await expect(page.locator('.ak-fact--sibling')).toContainText(t.detail.siblingPairing)
// 'Krümel': Eltern Fridolin × Luna aus verschiedenen Würfen → kein Hinweis.
await page.goto('/rennmaeuse/kruemel')
await expect(page.getByRole('heading', { name: 'Krümel' })).toBeVisible()
await expect(page.locator('.ak-fact--sibling')).toHaveCount(0)
})
test('Detailseite: Herkunft zeigt originBreeder als Text wenn kein Kontakt (WURF-LINK-Addendum)', async ({ page }) => {
skipUnlessMock()
// Fridolin hat originContactId=null + originBreeder='Zoohandlung Meier' → plain text, kein Link

View File

@@ -137,6 +137,15 @@ export default function GerbilDetailPage() {
const lookup = (map: Map<string, string>, key: string | null) => (key ? (map.get(key) ?? '—') : '—')
const storedColorName = g.colorVarietyId ? (colorName.get(g.colorVarietyId) ?? null) : null
// Geschwisterverpaarung: Vater und Mutter dieses Tiers stammen aus demselben
// Wurf (Vollgeschwister) — erkennbar an gemeinsamer litterId der Eltern.
const isSiblingPairing =
!!father.data &&
!!mother.data &&
father.data.id !== mother.data.id &&
!!father.data.litterId &&
father.data.litterId === mother.data.litterId
const parentLink = (
pid: string | null,
p: Parameters<typeof gerbilName>[0] | null,
@@ -204,6 +213,12 @@ export default function GerbilDetailPage() {
{storedColorName}
</span>
)}
{isSiblingPairing && (
<span className="ak-fact ak-fact--sibling" title={t.detail.siblingPairingTitle}>
<span aria-hidden="true"></span>
{t.detail.siblingPairing}
</span>
)}
</div>
<div className="ak-actions">

View File

@@ -139,6 +139,12 @@
font-weight: 600;
color: var(--color-text);
}
/* Geschwisterverpaarung: hervorgehoben, da zuchtrelevant (Inzucht). */
.ak-fact--sibling {
background: color-mix(in srgb, var(--color-accent) 12%, var(--color-surface));
border-color: var(--color-accent);
color: var(--color-accent);
}
/* ---------- Actions ---------- */
.ak-actions {

View File

@@ -122,6 +122,10 @@ export const de = {
parentLittersEmpty: 'Keine Würfe als Elternteil erfasst.',
parentLittersRoleVater: 'Vater',
parentLittersRoleMutter: 'Mutter',
// Hinweis: Eltern dieses Tiers sind Vollgeschwister (gleicher Wurf).
siblingPairing: 'Geschwisterverpaarung',
siblingPairingTitle:
'Die Eltern dieses Tiers stammen aus demselben Wurf (Vollgeschwister).',
},
// Formular (anlegen/bearbeiten)
form: {