Files
GerbilManager/gerbil-manager-web/src/pages/WurfDetailPage.tsx

140 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useMemo } from 'react'
import { Link, useParams } from 'react-router-dom'
import { de } from '../strings/de'
import { getLitter } from '../api/litters'
import { getGerbil, listGerbils } from '../api/gerbils'
import { condition } from '../api/gridify'
import { useApi } from '../hooks/useApi'
import { formatDate } from '../format/labels'
import { isValidGenotype } from '../format/genotypeText'
import { breed, fromDisplayString, type BreedingResult } from '../genetics'
import BreedingResultView from '../components/BreedingResultView'
export default function WurfDetailPage() {
const t = de.pages.litters
const { id = '' } = useParams()
const litter = useApi(() => getLitter(id), [id])
const fatherId = litter.data?.fatherId ?? null
const motherId = litter.data?.motherId ?? null
const father = useApi(() => (fatherId ? getGerbil(fatherId) : Promise.resolve(null)), [fatherId])
const mother = useApi(() => (motherId ? getGerbil(motherId) : Promise.resolve(null)), [motherId])
// Juveniles = gerbils whose litterId is this litter.
const juveniles = useApi(
() =>
id
? listGerbils({
filter: condition({ field: 'litterId', op: '==', value: id }),
orderBy: 'name',
page: 1,
pageSize: 1000,
})
: Promise.resolve(null),
[id],
)
// Expected Farbschlag distribution for this pairing (client-side GEN-1).
const expected: BreedingResult | null = useMemo(() => {
const fg = father.data?.genotype
const mg = mother.data?.genotype
if (!fg || !mg || !isValidGenotype(fg) || !isValidGenotype(mg)) return null
return breed(fromDisplayString(fg), fromDisplayString(mg))
}, [father.data, mother.data])
if (litter.loading) return <p className="muted">{de.common.loading}</p>
if (litter.error || !litter.data) {
return (
<section className="page">
<p className="muted">{litter.error ?? t.detail.notFound}</p>
<Link to="/wuerfe" className="btn">
{t.detail.back}
</Link>
</section>
)
}
const l = litter.data
const registered = juveniles.data?.totalCount ?? 0
const parentLink = (id: string | null, g: { name: string } | null) =>
id && g ? <Link to={`/rennmaeuse/${id}`}>{g.name}</Link> : t.detail.unknownParent
return (
<section className="page">
<header className="page-head">
<h2>{l.name}</h2>
<div className="head-actions">
<Link to={`/wuerfe/${l.id}/bearbeiten`} className="btn btn--primary">
{t.detail.edit}
</Link>
<Link to="/wuerfe" className="btn">
{t.detail.back}
</Link>
</div>
</header>
<dl className="def-list">
<div className="def-row">
<dt>{t.fields.date}</dt>
<dd>{formatDate(l.date)}</dd>
</div>
<div className="def-row">
<dt>{t.detail.parents}</dt>
<dd>
{parentLink(fatherId, father.data)} × {parentLink(motherId, mother.data)}
</dd>
</div>
<div className="def-row">
<dt>{t.detail.registered}</dt>
<dd>
{registered}
{l.totalBorn != null ? ` / ${l.totalBorn}` : ''}
</dd>
</div>
<div className="def-row">
<dt>{t.fields.expectedGoHomeDate}</dt>
<dd>{formatDate(l.expectedGoHomeDate)}</dd>
</div>
{l.notes && (
<div className="def-row">
<dt>{t.fields.notes}</dt>
<dd>{l.notes}</dd>
</div>
)}
</dl>
<div className="page-head">
<h3>{t.detail.juveniles}</h3>
<Link
to={`/rennmaeuse/neu?litterId=${l.id}${l.date ? `&dob=${l.date}` : ''}`}
className="btn btn--primary"
>
+ {t.detail.registerJuvenile}
</Link>
</div>
{juveniles.loading && <p className="muted">{de.common.loading}</p>}
{!juveniles.loading && registered === 0 && <p className="muted">{t.detail.noJuveniles}</p>}
{registered > 0 && (
<ul className="card-list">
{(juveniles.data?.items ?? []).map((g) => (
<li key={g.id}>
<Link to={`/rennmaeuse/${g.id}`} className="gerbil-card">
<span className="gerbil-card__name">{g.name}</span>
<span className="gerbil-card__meta">{de.pages.gerbils.genderLabels[g.gender]}</span>
</Link>
</li>
))}
</ul>
)}
<h3>{t.detail.expectedColors}</h3>
{expected ? (
<BreedingResultView result={expected} title={t.detail.expectedColors} />
) : (
<p className="muted">{t.detail.needParentsGenotype}</p>
)}
</section>
)
}