Add Dashboard page

This commit is contained in:
2026-03-08 22:53:19 -05:00
parent 4edfe2bfd6
commit 450c18e58f

View File

@@ -0,0 +1,113 @@
import { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { Dog, Activity, Heart, AlertCircle } from 'lucide-react'
import axios from 'axios'
function Dashboard() {
const [stats, setStats] = useState({
totalDogs: 0,
males: 0,
females: 0,
totalLitters: 0,
activeHeatCycles: 0
})
const [recentDogs, setRecentDogs] = useState([])
const [loading, setLoading] = useState(true)
useEffect(() => {
fetchDashboardData()
}, [])
const fetchDashboardData = async () => {
try {
const [dogsRes, littersRes, heatCyclesRes] = await Promise.all([
axios.get('/api/dogs'),
axios.get('/api/litters'),
axios.get('/api/breeding/heat-cycles/active')
])
const dogs = dogsRes.data
setStats({
totalDogs: dogs.length,
males: dogs.filter(d => d.sex === 'male').length,
females: dogs.filter(d => d.sex === 'female').length,
totalLitters: littersRes.data.length,
activeHeatCycles: heatCyclesRes.data.length
})
setRecentDogs(dogs.slice(0, 6))
setLoading(false)
} catch (error) {
console.error('Error fetching dashboard data:', error)
setLoading(false)
}
}
if (loading) {
return <div className="container loading">Loading dashboard...</div>
}
return (
<div className="container">
<h1 style={{ marginBottom: '2rem' }}>Dashboard</h1>
<div className="grid grid-3" style={{ marginBottom: '3rem' }}>
<div className="card" style={{ textAlign: 'center' }}>
<Dog size={48} style={{ color: 'var(--primary)', margin: '0 auto 1rem' }} />
<h3 style={{ fontSize: '2rem', marginBottom: '0.5rem' }}>{stats.totalDogs}</h3>
<p style={{ color: 'var(--text-secondary)' }}>Total Dogs</p>
<p style={{ fontSize: '0.875rem', marginTop: '0.5rem' }}>
{stats.males} Males {stats.females} Females
</p>
</div>
<div className="card" style={{ textAlign: 'center' }}>
<Activity size={48} style={{ color: 'var(--success)', margin: '0 auto 1rem' }} />
<h3 style={{ fontSize: '2rem', marginBottom: '0.5rem' }}>{stats.totalLitters}</h3>
<p style={{ color: 'var(--text-secondary)' }}>Total Litters</p>
</div>
<div className="card" style={{ textAlign: 'center' }}>
<Heart size={48} style={{ color: 'var(--danger)', margin: '0 auto 1rem' }} />
<h3 style={{ fontSize: '2rem', marginBottom: '0.5rem' }}>{stats.activeHeatCycles}</h3>
<p style={{ color: 'var(--text-secondary)' }}>Active Heat Cycles</p>
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1.5rem' }}>
<h2>Recent Dogs</h2>
<Link to="/dogs" className="btn btn-primary">View All</Link>
</div>
{recentDogs.length === 0 ? (
<div className="card" style={{ textAlign: 'center', padding: '3rem' }}>
<AlertCircle size={48} style={{ color: 'var(--text-secondary)', margin: '0 auto 1rem' }} />
<h3>No dogs registered yet</h3>
<p style={{ color: 'var(--text-secondary)', marginBottom: '1.5rem' }}>Start by adding your first dog to the system</p>
<Link to="/dogs" className="btn btn-primary">Add Dog</Link>
</div>
) : (
<div className="grid grid-3">
{recentDogs.map(dog => (
<Link key={dog.id} to={`/dogs/${dog.id}`} className="card" style={{ textDecoration: 'none', color: 'inherit' }}>
<div style={{ aspectRatio: '1', background: 'var(--bg-secondary)', borderRadius: '0.375rem', marginBottom: '1rem', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
{dog.photo_urls && dog.photo_urls.length > 0 ? (
<img src={dog.photo_urls[0]} alt={dog.name} style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: '0.375rem' }} />
) : (
<Dog size={48} style={{ color: 'var(--text-secondary)' }} />
)}
</div>
<h3>{dog.name}</h3>
<p style={{ color: 'var(--text-secondary)', fontSize: '0.875rem' }}>{dog.breed} {dog.sex}</p>
{dog.registration_number && (
<p style={{ color: 'var(--text-secondary)', fontSize: '0.75rem', marginTop: '0.25rem' }}>{dog.registration_number}</p>
)}
</Link>
))}
</div>
)}
</div>
)
}
export default Dashboard