FEAT-5: Probeverpaarung entry point from animal detail (?parent=) + stored-vs-engine Farbschlag mismatch hint

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-06 00:09:22 +02:00
parent 5ee4b9874b
commit d8e94f6d05
4 changed files with 72 additions and 1 deletions

View File

@@ -1,6 +1,9 @@
import { useMemo, useState } from 'react'
import { useSearchParams } from 'react-router-dom'
import { de } from '../strings/de'
import { breed, fromDisplayString, type BreedingResult } from '../genetics'
import { getGerbil } from '../api/gerbils'
import { useApi } from '../hooks/useApi'
import ParentSelector, { type ParentValue } from '../components/ParentSelector'
import AnimalPicker from '../components/AnimalPicker'
import { isValidGenotype } from '../format/genotypeText'
@@ -18,6 +21,22 @@ export default function GenetikPage() {
const [mother, setMother] = useState<ParentValue>(EMPTY_PARENT)
const [showGenotypes, setShowGenotypes] = useState(false)
// Pre-fill a parent when arriving from an animal's detail page (?parent=<id>).
// Gender decides the side: female -> Mutter, otherwise Vater.
const [searchParams] = useSearchParams()
const parentId = searchParams.get('parent')
const prefill = useApi(
() => (parentId ? getGerbil(parentId) : Promise.resolve(null)),
[parentId],
)
const [prefilledFor, setPrefilledFor] = useState<string | null>(null)
if (prefill.data && prefilledFor !== prefill.data.id) {
setPrefilledFor(prefill.data.id)
const value: ParentValue = { genotype: prefill.data.genotype ?? '', animalName: prefill.data.name }
if (prefill.data.gender === 'female') setMother(value)
else setFather(value)
}
const bothValid = isValidGenotype(father.genotype) && isValidGenotype(mother.genotype)
const result: BreedingResult | null = useMemo(() => {

View File

@@ -73,6 +73,7 @@ export default function GerbilDetailPage() {
const g = gerbil.data
const geno = describeGenotype(g.genotype)
const lookup = (map: Map<string, string>, key: string | null) => (key ? (map.get(key) ?? '—') : '—')
const storedColorName = g.colorVarietyId ? (colorName.get(g.colorVarietyId) ?? null) : null
return (
<section className="page">
@@ -85,6 +86,9 @@ export default function GerbilDetailPage() {
<Link to={`/rennmaeuse/${g.id}/bearbeiten`} className="btn btn--primary">
{t.detail.edit}
</Link>
<Link to={`/genetik?parent=${g.id}`} className="btn">
{t.detail.testMating}
</Link>
<Link to="/rennmaeuse" className="btn">
{t.detail.back}
</Link>
@@ -117,7 +121,19 @@ export default function GerbilDetailPage() {
{geno ? (
<dl className="def-list">
<Row label={t.fields.genotype} value={<code>{geno.display}</code>} />
<Row label={t.detail.resolvedFarbschlag} value={geno.farbschlag} />
<Row
label={t.detail.resolvedPrefix}
value={
<>
{geno.farbschlag}
{storedColorName &&
geno.farbschlag !== de.genetics.unknownFarbschlag &&
storedColorName !== geno.farbschlag && (
<small className="mismatch-hint"> {t.detail.farbschlagMismatch}</small>
)}
</>
}
/>
</dl>
) : (
<p className="muted">{t.detail.genotypeNotSet}</p>