import { useMemo, useState, type ReactNode } from 'react' import { Link, useParams } from 'react-router-dom' import { de } from '../strings/de' import { getGerbil, updateGerbil } from '../api/gerbils' import { listColorVarieties, listContacts, listEnclosures, listLitters } from '../api/lookups' import { useApi, useMutation } from '../hooks/useApi' import { formatDate, genderLabel, statusLabel } from '../format/labels' import { fromDisplayString, genotypeToFarbschlag, toDisplayString } from '../genetics' import FarbschlagImage from '../components/FarbschlagImage' import Charakterbogen from '../components/Charakterbogen' // FEAT-6 (Oscar): Tab-Inhalte + Profilfoto import GerbilHealthTab from '../components/GerbilHealthTab' import GerbilPhotosTab from '../components/GerbilPhotosTab' import GerbilProfilePhoto from '../components/GerbilProfilePhoto' import GerbilWeightTab from '../components/GerbilWeightTab' type DetailTab = 'photos' | 'health' | 'weight' /** Parse a stored genotype string and derive its normalized form + Farbschlag. */ function describeGenotype(genotype: string | null): { display: string; farbschlag: string } | null { if (!genotype || !genotype.trim()) return null try { const g = fromDisplayString(genotype) return { display: toDisplayString(g), farbschlag: genotypeToFarbschlag(g) } } catch { // Unparseable: show the raw value, no derived Farbschlag. return { display: genotype, farbschlag: de.genetics.unknownFarbschlag } } } function Row({ label, value }: { label: string; value: ReactNode }) { return (
{label}
{value ?? '—'}
) } export default function GerbilDetailPage() { const t = de.pages.gerbils const { id = '' } = useParams() const [tab, setTab] = useState('photos') const gerbil = useApi(() => getGerbil(id), [id]) const forSale = useMutation(() => updateGerbil(id, { status: 'ForSale' })) // FEAT-14: Charakterbogen (persisted on the Gerbil). const [charTraits, setCharTraits] = useState([]) const [charNote, setCharNote] = useState('') const [charInit, setCharInit] = useState(null) const saveCharacter = useMutation(() => updateGerbil(id, { characterTraits: charTraits, characterNote: charNote.trim() || null }), ) const colorVarieties = useApi(() => listColorVarieties(), []) const enclosures = useApi(() => listEnclosures(), []) const contacts = useApi(() => listContacts(), []) const litters = useApi(() => listLitters(), []) const colorName = useMemo( () => new Map((colorVarieties.data ?? []).map((c) => [c.id, c.name])), [colorVarieties.data], ) const enclosureName = useMemo( () => new Map((enclosures.data ?? []).map((e) => [e.id, e.name])), [enclosures.data], ) const contactName = useMemo( () => new Map((contacts.data ?? []).map((c) => [c.id, c.name])), [contacts.data], ) const litterName = useMemo( () => new Map((litters.data ?? []).map((l) => [l.id, l.name])), [litters.data], ) if (gerbil.loading) return

{de.common.loading}

if (gerbil.error || !gerbil.data) { return (

{gerbil.error ?? t.detail.notFound}

{t.detail.back}
) } const g = gerbil.data const geno = describeGenotype(g.genotype) const lookup = (map: Map, key: string | null) => (key ? (map.get(key) ?? '—') : '—') const storedColorName = g.colorVarietyId ? (colorName.get(g.colorVarietyId) ?? null) : null // Seed the Charakterbogen once from the loaded gerbil (adjust-state-during-render). if (charInit !== g.id) { setCharInit(g.id) setCharTraits(g.characterTraits ?? []) setCharNote(g.characterNote ?? '') } return (

{g.name}

{statusLabel(g.status)}
{t.detail.edit} {t.detail.testMating} {g.status !== 'ForSale' && ( )} {de.pages.stammbaum.openButton} {/* FEAT-13: Abgabe abschließen — Vertrag-Assistent mit diesem Tier vorausgewählt. */} {g.status !== 'Deceased' && g.status !== 'GivenAway' && ( {de.pages.vertraege.wizard.title} )} {t.detail.back}

{t.detail.masterData}

{g.status === 'Deceased' && ( <> )} {g.status === 'GivenAway' && ( )} {storedColorName} ) : ( '—' ) } />

{t.detail.genetics}

{geno ? (
{geno.display}} /> {geno.farbschlag} {storedColorName && geno.farbschlag !== de.genetics.unknownFarbschlag && storedColorName !== geno.farbschlag && ( ⚠ {t.detail.farbschlagMismatch} )} } />
) : (

{t.detail.genotypeNotSet}

)}

{de.character.sectionTitle}

{saveCharacter.error && {saveCharacter.error}}

{t.detail.moreData}

{(['photos', 'health', 'weight'] as const).map((key) => ( ))}
{tab === 'photos' && } {tab === 'health' && } {tab === 'weight' && }
) }