diff --git a/frontend/src/admin/LineupTab.jsx b/frontend/src/admin/LineupTab.jsx index 224dd31b..4f69cf34 100644 --- a/frontend/src/admin/LineupTab.jsx +++ b/frontend/src/admin/LineupTab.jsx @@ -126,6 +126,16 @@ export default function LineupTab({ selectedEventId, selectedEvent, events, show } }, [selectedEventId, showToast]) + // The roster API now returns inactive/retired profiles too (#619, so + // RosterTab can manage them) — filter them back out here so the lineup + // builder never offers a retired band as a schedulable option. Origin/genre + // suggestion lists below intentionally keep using the unfiltered `allBands` + // — reusing a retired band's origin/genre value is harmless. + const activeBands = useMemo( + () => allBands.filter(band => band.is_active !== 0 && band.is_active !== false), + [allBands] + ) + const originCitySuggestions = useMemo(() => { const values = new Set() allBands.forEach(band => { @@ -690,7 +700,7 @@ export default function LineupTab({ selectedEventId, selectedEvent, events, show {viewMode === 'picker' && !readOnly && ( setViewMode('list')} diff --git a/frontend/src/admin/RosterTab.jsx b/frontend/src/admin/RosterTab.jsx index a33500e2..4067cec1 100644 --- a/frontend/src/admin/RosterTab.jsx +++ b/frontend/src/admin/RosterTab.jsx @@ -159,6 +159,25 @@ function SortIcon({ col, sortConfig }) { ) } +// The roster API now returns inactive/retired profiles alongside active ones +// (#619) — `is_active` comes straight off the D1 row (INTEGER NOT NULL +// DEFAULT 1), so it's always 0 or 1, but check both the number and legacy +// boolean shape defensively rather than relying on falsiness of `is_active`. +function isInactive(band) { + return band.is_active === 0 || band.is_active === false +} + +// Same pill styling as the existing Status column below — reused here so an +// inactive profile is visible right next to its name too, not just in a +// column that can scroll out of view. +function InactiveBadge() { + return ( + + Inactive + + ) +} + /** * RosterTab - Manage Global Artist Roster (Band Profiles) * @@ -174,6 +193,10 @@ export default function RosterTab({ showToast, readOnly = false }) { const [editingId, setEditingId] = useState(null) const [sortConfig, setSortConfig] = useState({ key: 'name', direction: 'asc' }) const [searchTerm, setSearchTerm] = useState('') + // 'all' | 'active' | 'inactive' — defaults to 'all' (#619) so a retired + // profile is never hidden by default; the admin roster must be able to see + // and edit everything it manages. + const [statusFilter, setStatusFilter] = useState('all') // Selection state for bulk actions const [selectedIds, setSelectedIds] = useState(new Set()) @@ -250,9 +273,11 @@ export default function RosterTab({ showToast, readOnly = false }) { } const filteredBands = useMemo(() => { - if (!searchTerm.trim()) return bands const query = searchTerm.trim().toLowerCase() return bands.filter(band => { + if (statusFilter === 'active' && isInactive(band)) return false + if (statusFilter === 'inactive' && !isInactive(band)) return false + if (!query) return true const originText = formatOrigin(band) return ( band.name?.toLowerCase().includes(query) || @@ -261,15 +286,15 @@ export default function RosterTab({ showToast, readOnly = false }) { band.contact_email?.toLowerCase().includes(query) ) }) - }, [bands, searchTerm]) + }, [bands, searchTerm, statusFilter]) const sortedBands = useMemo(() => { if (!sortConfig.key) return filteredBands return [...filteredBands].sort((a, b) => { if (sortConfig.key === 'is_active') { - const aVal = a.is_active === 0 || a.is_active === false ? 0 : 1 - const bVal = b.is_active === 0 || b.is_active === false ? 0 : 1 + const aVal = isInactive(a) ? 0 : 1 + const bVal = isInactive(b) ? 0 : 1 return sortConfig.direction === 'asc' ? aVal - bVal : bVal - aVal } if (sortConfig.key === 'origin') { @@ -565,6 +590,16 @@ export default function RosterTab({ showToast, readOnly = false }) { placeholder="Search name, origin, genre" className="min-h-[44px] px-3 py-2 rounded bg-bg-navy text-white border border-white/10 focus:border-accent-500 focus:outline-hidden w-64" /> + {!showAddForm && !editingId && !readOnly && (