Files
breedr/client/src/pages/LitterList.jsx

159 lines
5.4 KiB
JavaScript
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 { useEffect, useState } from 'react'
import { Activity, Plus, Edit2, Trash2, ChevronRight } from 'lucide-react'
import { useNavigate } from 'react-router-dom'
import axios from 'axios'
import LitterForm from '../components/LitterForm'
function LitterList() {
const [litters, setLitters] = useState([])
const [loading, setLoading] = useState(true)
const [showForm, setShowForm] = useState(false)
const [editingLitter, setEditingLitter] = useState(null)
const [prefill, setPrefill] = useState(null)
const navigate = useNavigate()
useEffect(() => {
fetchLitters()
// Auto-open form with prefill from BreedingCalendar "Record Litter" CTA
const stored = sessionStorage.getItem('prefillLitter')
if (stored) {
try {
const data = JSON.parse(stored)
setPrefill(data)
setEditingLitter(null)
setShowForm(true)
} catch (e) { /* ignore */ }
sessionStorage.removeItem('prefillLitter')
}
}, [])
const fetchLitters = async () => {
try {
const res = await axios.get('/api/litters')
setLitters(res.data)
} catch (error) {
console.error('Error fetching litters:', error)
} finally {
setLoading(false)
}
}
const handleCreate = () => {
setEditingLitter(null)
setPrefill(null)
setShowForm(true)
}
const handleEdit = (e, litter) => {
e.stopPropagation()
setEditingLitter(litter)
setPrefill(null)
setShowForm(true)
}
const handleDelete = async (e, id) => {
e.stopPropagation()
if (!window.confirm('Delete this litter record? Puppies will be unlinked but not deleted.')) return
try {
await axios.delete(`/api/litters/${id}`)
fetchLitters()
} catch (error) {
console.error('Error deleting litter:', error)
}
}
const handleSave = () => {
fetchLitters()
}
if (loading) {
return <div className="container loading">Loading litters...</div>
}
return (
<div className="container">
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '2rem' }}>
<h1>Litters</h1>
<button className="btn btn-primary" onClick={handleCreate}>
<Plus size={18} style={{ marginRight: '0.5rem' }} />
New Litter
</button>
</div>
{litters.length === 0 ? (
<div className="card" style={{ textAlign: 'center', padding: '4rem' }}>
<Activity size={64} style={{ color: 'var(--text-secondary)', margin: '0 auto 1rem' }} />
<h2>No litters recorded yet</h2>
<p style={{ color: 'var(--text-secondary)', marginBottom: '1.5rem' }}>Create a litter after a breeding cycle to track puppies</p>
<button className="btn btn-primary" onClick={handleCreate}>
<Plus size={18} style={{ marginRight: '0.5rem' }} />
Create First Litter
</button>
</div>
) : (
<div style={{ display: 'grid', gap: '1rem' }}>
{litters.map(litter => (
<div
key={litter.id}
className="card"
style={{ cursor: 'pointer', transition: 'border-color 0.2s' }}
onClick={() => navigate(`/litters/${litter.id}`)}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
<div style={{ flex: 1 }}>
<h3 style={{ marginBottom: '0.5rem' }}>
🐾 {litter.sire_name} × {litter.dam_name}
</h3>
<div style={{ display: 'flex', gap: '1.5rem', flexWrap: 'wrap', color: 'var(--text-secondary)', fontSize: '0.9rem' }}>
<span>📅 Bred: {new Date(litter.breeding_date).toLocaleDateString()}</span>
{litter.whelping_date && (
<span>💕 Whelped: {new Date(litter.whelping_date).toLocaleDateString()}</span>
)}
<span style={{ color: 'var(--accent)', fontWeight: 600 }}>
{litter.actual_puppy_count ?? litter.puppies?.length ?? litter.puppy_count ?? 0} puppies
</span>
</div>
{litter.notes && (
<p style={{ marginTop: '0.5rem', fontSize: '0.85rem', color: 'var(--text-secondary)', fontStyle: 'italic' }}>
{litter.notes}
</p>
)}
</div>
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
<button
className="btn-icon"
title="Edit litter"
onClick={(e) => handleEdit(e, litter)}
>
<Edit2 size={16} />
</button>
<button
className="btn-icon"
title="Delete litter"
onClick={(e) => handleDelete(e, litter.id)}
style={{ color: '#e53e3e' }}
>
<Trash2 size={16} />
</button>
<ChevronRight size={20} style={{ color: 'var(--text-secondary)' }} />
</div>
</div>
</div>
))}
</div>
)}
{showForm && (
<LitterForm
litter={editingLitter}
prefill={prefill}
onClose={() => setShowForm(false)}
onSave={handleSave}
/>
)}
</div>
)
}
export default LitterList