brackt/app/components/draft/DraftSummaryView.tsx
Chris Parsons 599bba8949
refactor: address code review findings in Roster/Summary draft views (#57)
- 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>
2026-03-02 16:46:35 -08:00

114 lines
3.9 KiB
TypeScript

import { memo, useMemo } from "react";
import { type DraftPick, groupPicksByTeamAndSport } from "./picks-utils";
interface DraftSummaryViewProps {
draftSlots: Array<{ id: string; team: { id: string; name: string } }>;
ownerMap?: Record<string, string>;
picks: DraftPick[];
sports: Array<{ id: string; name: string }>;
}
export const DraftSummaryView = memo(function DraftSummaryView({
draftSlots,
ownerMap = {},
picks,
sports,
}: DraftSummaryViewProps) {
const picksByTeamAndSport = useMemo(
() => groupPicksByTeamAndSport(picks),
[picks]
);
const totalPicksBySport = useMemo(() => {
const map = new Map<string, number>();
sports.forEach((sport) => {
let count = 0;
picksByTeamAndSport.forEach((teamMap) => {
count += teamMap.get(sport.id)?.length ?? 0;
});
map.set(sport.id, count);
});
return map;
}, [picksByTeamAndSport, sports]);
if (sports.length === 0) {
return (
<div className="flex items-center justify-center h-full p-8 text-muted-foreground">
<p>No sports have been configured for this season.</p>
</div>
);
}
return (
<div className="w-full h-full overflow-auto">
<table className="w-full border-collapse">
<thead className="sticky top-0 bg-background z-10">
<tr>
<th
scope="col"
className="border-r border-b border-border p-2 text-left font-semibold bg-muted sticky left-0 z-20 min-w-[120px]"
>
Sport
</th>
<th
scope="col"
className="border-r border-b border-border p-2 text-center font-semibold bg-muted min-w-[48px]"
>
Total
</th>
{draftSlots.map((slot, index) => {
const displayName = ownerMap[slot.team.id] || slot.team.name;
const isLast = index === draftSlots.length - 1;
return (
<th
key={slot.id}
scope="col"
className={`border-b border-border p-2 text-center font-semibold bg-muted/50 min-w-[60px] ${!isLast ? "border-r" : ""}`}
>
<span className="text-sm">{displayName}</span>
</th>
);
})}
</tr>
</thead>
<tbody>
{sports.map((sport, sportIndex) => {
const isLastRow = sportIndex === sports.length - 1;
const sportTotal = totalPicksBySport.get(sport.id) ?? 0;
return (
<tr key={sport.id}>
<th
scope="row"
className={`border-r border-border p-2 font-medium text-sm text-left bg-muted sticky left-0 z-10 ${!isLastRow ? "border-b" : ""}`}
>
{sport.name}
</th>
<td
className={`border-r border-border p-2 text-center text-sm font-semibold bg-muted/30 ${!isLastRow ? "border-b" : ""}`}
>
{sportTotal > 0 ? sportTotal : null}
</td>
{draftSlots.map((slot, slotIndex) => {
const count =
picksByTeamAndSport.get(slot.team.id)?.get(sport.id)
?.length ?? 0;
const isLast = slotIndex === draftSlots.length - 1;
return (
<td
key={`${slot.team.id}-${sport.id}`}
className={`border-border p-2 text-center text-sm ${
count >= 2 ? "bg-accent/30 font-semibold" : "bg-background"
} ${!isLastRow ? "border-b" : ""} ${!isLast ? "border-r" : ""}`}
>
{count > 0 ? count : null}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
);
});