- Extract groupPicksByTeamAndSport into shared picks-utils.ts to remove duplication between TeamRosterView and DraftSummaryView - Fix TeamRosterView: make teamPicks a proper useMemo dep on selectedTeamId, add useEffect to reset stale selection if draftSlots changes - Add accessible label/htmlFor to TeamRosterView team Select - Remove dead `season` prop from DraftSummaryView (was inherited from TeamsDraftedGrid but never used) - Fix DraftSummaryView: sport name cells are now <th scope="row">, column headers have scope="col", Total header uses solid bg-muted to match Sport - Replace || null with explicit > 0 check in Total cell for clarity - Consolidate to summaryViewProps/rosterViewProps in route for consistency Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
121 lines
3.5 KiB
TypeScript
121 lines
3.5 KiB
TypeScript
import { memo, useEffect, useMemo, useState } from "react";
|
|
import { Badge } from "~/components/ui/badge";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "~/components/ui/select";
|
|
import { type DraftPick, groupPicksByTeamAndSport } from "./picks-utils";
|
|
|
|
interface TeamRosterViewProps {
|
|
draftSlots: Array<{ id: string; team: { id: string; name: string } }>;
|
|
ownerMap?: Record<string, string>;
|
|
picks: DraftPick[];
|
|
sports: Array<{ id: string; name: string }>;
|
|
}
|
|
|
|
export const TeamRosterView = memo(function TeamRosterView({
|
|
draftSlots,
|
|
ownerMap = {},
|
|
picks,
|
|
sports,
|
|
}: TeamRosterViewProps) {
|
|
const [selectedTeamId, setSelectedTeamId] = useState(
|
|
draftSlots[0]?.team.id ?? ""
|
|
);
|
|
|
|
// Reset selection if the selected team is no longer present in the slot list
|
|
useEffect(() => {
|
|
if (
|
|
draftSlots.length > 0 &&
|
|
!draftSlots.some((s) => s.team.id === selectedTeamId)
|
|
) {
|
|
setSelectedTeamId(draftSlots[0].team.id);
|
|
}
|
|
}, [draftSlots, selectedTeamId]);
|
|
|
|
const picksByTeamAndSport = useMemo(
|
|
() => groupPicksByTeamAndSport(picks),
|
|
[picks]
|
|
);
|
|
|
|
const teamPicks = useMemo(
|
|
() => picksByTeamAndSport.get(selectedTeamId),
|
|
[picksByTeamAndSport, selectedTeamId]
|
|
);
|
|
|
|
const sportsWithPicks = useMemo(
|
|
() => sports.filter((s) => (teamPicks?.get(s.id)?.length ?? 0) > 0),
|
|
[sports, teamPicks]
|
|
);
|
|
|
|
const totalPicks = useMemo(() => {
|
|
let count = 0;
|
|
teamPicks?.forEach((sp) => (count += sp.length));
|
|
return count;
|
|
}, [teamPicks]);
|
|
|
|
if (draftSlots.length === 0) {
|
|
return (
|
|
<div className="flex items-center justify-center h-full p-8 text-muted-foreground">
|
|
<p>No teams in this draft.</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="h-full overflow-y-auto">
|
|
<div className="p-4 space-y-4">
|
|
<div className="space-y-1">
|
|
<label
|
|
htmlFor="roster-team-select"
|
|
className="text-xs font-medium text-muted-foreground"
|
|
>
|
|
Team
|
|
</label>
|
|
<Select value={selectedTeamId} onValueChange={setSelectedTeamId}>
|
|
<SelectTrigger id="roster-team-select" className="w-full">
|
|
<SelectValue placeholder="Select a team" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{draftSlots.map((slot) => (
|
|
<SelectItem key={slot.id} value={slot.team.id}>
|
|
{ownerMap[slot.team.id] || slot.team.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
{totalPicks === 0 ? (
|
|
<p className="text-sm text-muted-foreground text-center py-6">
|
|
No picks yet
|
|
</p>
|
|
) : (
|
|
sportsWithPicks.map((sport) => {
|
|
const sportPicks = teamPicks?.get(sport.id) ?? [];
|
|
return (
|
|
<div key={sport.id}>
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<h3 className="text-sm font-semibold">{sport.name}</h3>
|
|
<Badge variant="secondary" className="text-xs px-1.5 py-0">
|
|
{sportPicks.length}
|
|
</Badge>
|
|
</div>
|
|
<ul className="space-y-1 pl-2">
|
|
{sportPicks.map((pick) => (
|
|
<li key={pick.id} className="text-sm text-foreground">
|
|
{pick.participant.name}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
);
|
|
})
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
});
|