import { useEffect, useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import { useQuery } from '@tanstack/react-query'
import { getRabbits } from '../api'
import Card from '../components/Card'
import Badge from '../components/Badge'
import EmptyState from '../components/EmptyState'
import PageHeader from '../components/PageHeader'
import Button from '../components/Button'
import RabbitCard from '../components/RabbitCard'
import { Select } from '../components/FormControls'
import ErrorPanel from '../components/ErrorPanel'
import { SEX_LABELS, formatAge, formatWeight } from '../lib/format'
import { useWeightUnit } from '../hooks/useWeightUnit'
const SEX_TABS = [
{ value: '', label: 'All' },
{ value: 'buck', label: 'Bucks' },
{ value: 'doe', label: 'Does' },
{ value: 'kits', label: 'Kits' },
// Sex not recorded yet — named 'Unknown' so it isn't confused with the
// 'Other' status (which the Status filter groups under Archived).
{ value: 'unknown', label: 'Unknown' },
]
const SORT_OPTIONS = [
{ value: 'name', label: 'Name', apiSort: 'name' },
{ value: 'age', label: 'Age', apiSort: 'dob' },
{ value: 'recent', label: 'Recent', apiSort: 'created_at' },
{ value: 'weight', label: 'Weight', apiSort: 'weight_lbs' },
]
// The Herd page defaults to the active herd so it matches the Dashboard's "Herd"
// count and doesn't bury working animals under archived/sold/reference records.
// 'archived' (other + deceased) and 'all' (no status filter) are handled
// specially in the query below.
const DEFAULT_STATUS = 'active'
const STATUS_OPTIONS = [
{ value: 'active', label: 'Active' },
{ value: 'for_sale', label: 'For Sale' },
{ value: 'on_hold', label: 'On Hold' },
{ value: 'sold', label: 'Sold' },
{ value: 'archived', label: 'Archived' },
{ value: 'all', label: 'All' },
]
const SEARCH_DEBOUNCE_MS = 300
function SearchIcon() {
return (
)
}
function GridIcon() {
return (
)
}
function ListIcon() {
return (
)
}
function SearchBox({ q, onSearchChange }) {
const [searchInput, setSearchInput] = useState(q)
useEffect(() => {
const timeout = setTimeout(() => {
if (searchInput !== q) onSearchChange(searchInput)
}, SEARCH_DEBOUNCE_MS)
return () => clearTimeout(timeout)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchInput])
return (
setSearchInput(e.target.value)}
placeholder="Name, ear #, color"
aria-label="Search herd by name, ear number or color"
className="w-full min-w-0 bg-transparent md:w-48 font-body text-sm text-text-primary placeholder:text-text-secondary focus:outline-none"
/>
)
}
// On phones only the sex tabs and search show by default; Status, Sort and the
// grid/list toggle fold behind a "Filters" button (badged with how many differ
// from the defaults) so the herd starts above the fold.
function FilterBar({ sex, status, sort, q, view, onSexChange, onStatusChange, onSortChange, onSearchChange, onViewChange }) {
const [filtersOpen, setFiltersOpen] = useState(false)
const changedCount = (status !== DEFAULT_STATUS ? 1 : 0) + (sort !== 'name' ? 1 : 0)
return (