diff --git a/client/src/pages/PairingSimulator.jsx b/client/src/pages/PairingSimulator.jsx new file mode 100644 index 0000000..9633f3e --- /dev/null +++ b/client/src/pages/PairingSimulator.jsx @@ -0,0 +1,219 @@ +import { useState, useEffect } from 'react' +import { FlaskConical, AlertTriangle, CheckCircle, XCircle, GitMerge } from 'lucide-react' + +export default function PairingSimulator() { + const [dogs, setDogs] = useState([]) + const [sireId, setSireId] = useState('') + const [damId, setDamId] = useState('') + const [result, setResult] = useState(null) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const [dogsLoading, setDogsLoading] = useState(true) + + useEffect(() => { + fetch('/api/dogs') + .then(r => r.json()) + .then(data => { + setDogs(Array.isArray(data) ? data : (data.dogs || [])) + setDogsLoading(false) + }) + .catch(() => setDogsLoading(false)) + }, []) + + const males = dogs.filter(d => d.sex === 'male') + const females = dogs.filter(d => d.sex === 'female') + + async function handleSimulate(e) { + e.preventDefault() + if (!sireId || !damId) return + setLoading(true) + setError(null) + setResult(null) + try { + const res = await fetch('/api/pedigree/trial-pairing', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ sire_id: parseInt(sireId), dam_id: parseInt(damId) }) + }) + if (!res.ok) { + const err = await res.json() + throw new Error(err.error || 'Failed to calculate') + } + setResult(await res.json()) + } catch (err) { + setError(err.message) + } finally { + setLoading(false) + } + } + + function RiskBadge({ coi, recommendation }) { + const isLow = coi < 5 + const isMed = coi >= 5 && coi < 10 + const isHigh = coi >= 10 + return ( +
+ Select a sire and dam to calculate the estimated inbreeding coefficient (COI) and view common ancestors. +
+Pairing
++ {result.sire.name} + × + {result.dam.name} +
+COI
++ {result.coi.toFixed(2)}% +
++ No common ancestors found within 5 generations. This pairing has excellent genetic diversity. +
+ ) : ( +| Ancestor | +Sire Gen | +Dam Gen | +
|---|---|---|
| {anc.name} | ++ Gen {anc.sireGen} + | ++ Gen {anc.damGen} + | +