159 lines
5.4 KiB
JavaScript
159 lines
5.4 KiB
JavaScript
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
|