feat(pedigree): update PedigreeView stats bar + tip box to use theme vars

This commit is contained in:
2026-03-09 22:45:23 -05:00
parent 380599383c
commit f860738428

View File

@@ -22,19 +22,15 @@ function PedigreeView() {
const fetchPedigreeData = async () => { const fetchPedigreeData = async () => {
setLoading(true) setLoading(true)
setError('') setError('')
try { try {
// Fetch pedigree tree data
const pedigreeRes = await axios.get(`/api/pedigree/${id}`) const pedigreeRes = await axios.get(`/api/pedigree/${id}`)
const dogData = pedigreeRes.data const dogData = pedigreeRes.data
setDog(dogData) setDog(dogData)
// Transform data for react-d3-tree
const treeData = transformPedigreeData(dogData, generations) const treeData = transformPedigreeData(dogData, generations)
setPedigreeData(treeData) setPedigreeData(treeData)
// Fetch COI calculation
try { try {
const coiRes = await axios.get(`/api/pedigree/${id}/coi`) const coiRes = await axios.get(`/api/pedigree/${id}/coi`)
setCoiData(coiRes.data) setCoiData(coiRes.data)
@@ -42,7 +38,7 @@ function PedigreeView() {
console.warn('COI calculation unavailable:', coiError) console.warn('COI calculation unavailable:', coiError)
setCoiData(null) setCoiData(null)
} }
setLoading(false) setLoading(false)
} catch (err) { } catch (err) {
console.error('Error fetching pedigree:', err) console.error('Error fetching pedigree:', err)
@@ -72,8 +68,8 @@ function PedigreeView() {
<AlertCircle size={64} style={{ color: 'var(--danger)', margin: '0 auto 1rem' }} /> <AlertCircle size={64} style={{ color: 'var(--danger)', margin: '0 auto 1rem' }} />
<h2>Error Loading Pedigree</h2> <h2>Error Loading Pedigree</h2>
<p style={{ color: 'var(--text-secondary)', marginTop: '0.5rem' }}>{error}</p> <p style={{ color: 'var(--text-secondary)', marginTop: '0.5rem' }}>{error}</p>
<button <button
className="btn btn-primary" className="btn btn-primary"
onClick={() => navigate('/dogs')} onClick={() => navigate('/dogs')}
style={{ marginTop: '1.5rem' }} style={{ marginTop: '1.5rem' }}
> >
@@ -84,11 +80,14 @@ function PedigreeView() {
) )
} }
// Completeness bar colour — uses theme tokens
const barColor = completeness === 100 ? 'var(--success)' : 'var(--primary)'
return ( return (
<div className="container"> <div className="container">
{/* Header */} {/* Header */}
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', marginBottom: '1.5rem' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '1rem', marginBottom: '1.5rem' }}>
<button <button
className="btn btn-secondary" className="btn btn-secondary"
onClick={() => navigate(`/dogs/${id}`)} onClick={() => navigate(`/dogs/${id}`)}
style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }} style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}
@@ -96,10 +95,10 @@ function PedigreeView() {
<ArrowLeft size={20} /> <ArrowLeft size={20} />
Back to Profile Back to Profile
</button> </button>
<div style={{ flex: 1 }}> <div style={{ flex: 1 }}>
<h1 style={{ margin: 0, display: 'flex', alignItems: 'center', gap: '0.75rem' }}> <h1 style={{ margin: 0, display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
<GitBranch size={32} /> <GitBranch size={32} style={{ color: 'var(--primary)' }} />
{dog?.name}'s Pedigree {dog?.name}'s Pedigree
</h1> </h1>
{dog?.registration_number && ( {dog?.registration_number && (
@@ -113,17 +112,19 @@ function PedigreeView() {
{/* Stats Bar */} {/* Stats Bar */}
<div className="card" style={{ marginBottom: '1rem', padding: '1rem' }}> <div className="card" style={{ marginBottom: '1rem', padding: '1rem' }}>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1.5rem' }}> <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1.5rem' }}>
{/* COI */}
<div> <div>
<div style={{ fontSize: '0.875rem', color: 'var(--text-secondary)', marginBottom: '0.25rem' }}> <div style={{ fontSize: '0.875rem', color: 'var(--text-muted)', marginBottom: '0.25rem', textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 500 }}>
Coefficient of Inbreeding Coefficient of Inbreeding
</div> </div>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
<span style={{ fontSize: '1.5rem', fontWeight: '700', color: coiInfo.color }}> <span style={{ fontSize: '1.5rem', fontWeight: '700', color: coiInfo.color }}>
{coiInfo.value} {coiInfo.value}
</span> </span>
<span style={{ <span style={{
fontSize: '0.75rem', fontSize: '0.75rem',
padding: '0.25rem 0.5rem', padding: '0.25rem 0.5rem',
borderRadius: '4px', borderRadius: '4px',
background: coiInfo.color + '20', background: coiInfo.color + '20',
color: coiInfo.color, color: coiInfo.color,
@@ -133,41 +134,46 @@ function PedigreeView() {
{coiInfo.level} {coiInfo.level}
</span> </span>
</div> </div>
<div style={{ fontSize: '0.75rem', color: 'var(--text-secondary)', marginTop: '0.25rem' }}> <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)', marginTop: '0.25rem' }}>
{coiInfo.description} {coiInfo.description}
</div> </div>
</div> </div>
{/* Completeness */}
<div> <div>
<div style={{ fontSize: '0.875rem', color: 'var(--text-secondary)', marginBottom: '0.25rem' }}> <div style={{ fontSize: '0.875rem', color: 'var(--text-muted)', marginBottom: '0.25rem', textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 500 }}>
Pedigree Completeness Pedigree Completeness
</div> </div>
<div style={{ fontSize: '1.5rem', fontWeight: '700' }}> <div style={{ fontSize: '1.5rem', fontWeight: '700', color: 'var(--text-primary)' }}>
{completeness}% {completeness}%
</div> </div>
<div style={{ marginTop: '0.5rem' }}> <div style={{ marginTop: '0.5rem' }}>
<div style={{ <div style={{
height: '8px', height: '6px',
background: '#e5e7eb', background: 'var(--bg-tertiary)',
borderRadius: '4px', borderRadius: '3px',
overflow: 'hidden' overflow: 'hidden',
border: '1px solid var(--border)'
}}> }}>
<div style={{ <div style={{
height: '100%', height: '100%',
width: `${completeness}%`, width: `${completeness}%`,
background: completeness === 100 ? '#10b981' : '#3b82f6', background: barColor,
transition: 'width 0.3s ease' borderRadius: '3px',
transition: 'width 0.4s ease',
boxShadow: `0 0 6px ${barColor}`
}} /> }} />
</div> </div>
</div> </div>
</div> </div>
{/* Generations */}
<div> <div>
<div style={{ fontSize: '0.875rem', color: 'var(--text-secondary)', marginBottom: '0.25rem' }}> <div style={{ fontSize: '0.875rem', color: 'var(--text-muted)', marginBottom: '0.25rem', textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 500 }}>
Generations Displayed Generations Displayed
</div> </div>
<select <select
className="input" className="input"
value={generations} value={generations}
onChange={(e) => setGenerations(Number(e.target.value))} onChange={(e) => setGenerations(Number(e.target.value))}
style={{ marginTop: '0.25rem' }} style={{ marginTop: '0.25rem' }}
@@ -183,14 +189,14 @@ function PedigreeView() {
{/* Pedigree Tree */} {/* Pedigree Tree */}
<div className="card" style={{ padding: 0 }}> <div className="card" style={{ padding: 0 }}>
{pedigreeData ? ( {pedigreeData ? (
<PedigreeTree <PedigreeTree
dogId={id} dogId={id}
pedigreeData={pedigreeData} pedigreeData={pedigreeData}
coi={coiData?.coi} coi={coiData?.coi}
/> />
) : ( ) : (
<div style={{ textAlign: 'center', padding: '4rem' }}> <div style={{ textAlign: 'center', padding: '4rem' }}>
<GitBranch size={64} style={{ color: 'var(--text-secondary)', margin: '0 auto 1rem' }} /> <GitBranch size={64} style={{ color: 'var(--text-muted)', margin: '0 auto 1rem' }} />
<h3>No Pedigree Data Available</h3> <h3>No Pedigree Data Available</h3>
<p style={{ color: 'var(--text-secondary)' }}> <p style={{ color: 'var(--text-secondary)' }}>
Add parent information to this dog to build the pedigree tree. Add parent information to this dog to build the pedigree tree.
@@ -199,15 +205,23 @@ function PedigreeView() {
)} )}
</div> </div>
{/* Help Text */} {/* Tip */}
<div className="card" style={{ marginTop: '1rem', background: '#eff6ff', border: '1px solid #bfdbfe' }}> <div className="card" style={{
<div style={{ fontSize: '0.875rem', color: '#1e40af' }}> marginTop: '1rem',
<strong>💡 Tip:</strong> Click on any ancestor node to navigate to their profile. background: 'var(--bg-elevated)',
Use the zoom controls to explore the tree, or drag to pan around. border: '1px solid var(--border-light)'
}}>
<div style={{ fontSize: '0.875rem', color: 'var(--text-secondary)', display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
<span style={{ color: 'var(--primary)' }}>&#128161;</span>
<span>
<strong style={{ color: 'var(--text-primary)' }}>Tip:</strong>{' '}
Click any ancestor node to navigate to their profile.
Use the zoom controls or scroll to explore the tree, and drag to pan.
</span>
</div> </div>
</div> </div>
</div> </div>
) )
} }
export default PedigreeView export default PedigreeView