fix: address code review issues from draft board scrolling and team creation changes (#35)

- DraftGrid: wrap header and rows in a single min-w-max container so
  column widths share a sizing context and can't desync
- Settings: wrap team + draft slot creation in a DB transaction so a
  slot insert failure can't leave orphaned teams with no slots
- Settings: replace Math.max(...spread) with reduce to avoid the JS
  argument limit (defensive, given the 6-16 team cap)
- Settings: remove now-unused createManyTeams import

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Parsons 2026-02-24 10:01:27 -08:00 committed by GitHub
parent f33e39264d
commit 3343e7a405
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 31 additions and 9 deletions

View file

@ -47,7 +47,8 @@ export function DraftGrid({
return (
<Card className="p-4">
{title && <h2 className="text-xl font-semibold mb-4">{title}</h2>}
<div className="w-full">
<div className="w-full overflow-x-auto">
<div className="min-w-max">
{/* Team Headers */}
<div className="flex gap-2 mb-2">
{draftSlots.map((slot) => {
@ -175,6 +176,7 @@ export function DraftGrid({
);
})}
</div>
</div>
</div>
</Card>
);

View file

@ -81,10 +81,10 @@ export function DraftGridSection({
);
return (
<div className="h-full overflow-auto p-4">
<h2 className="text-xl font-semibold mb-4">Draft Grid</h2>
<div className="overflow-x-auto">
<div className="inline-block min-w-full">
<div className="h-full flex flex-col p-4">
<h2 className="text-xl font-semibold mb-4 flex-shrink-0">Draft Grid</h2>
<div className="flex-1 overflow-auto">
<div className="inline-block min-w-full min-h-full">
{/* Team Headers */}
<div className="flex gap-2 mb-2 sticky top-0 z-10 bg-background/95 backdrop-blur-sm py-1">
{/* Spacer for round column — sticky so it covers the corner when scrolling both axes */}

View file

@ -12,11 +12,13 @@ import {
removeCommissionerByLeagueAndUser,
} from "~/models/commissioner";
import { findCurrentSeasonWithSports, updateSeason } from "~/models/season";
import { findTeamsBySeasonId, createManyTeams, deleteTeam, removeTeamOwner, assignTeamOwner } from "~/models/team";
import { findTeamsBySeasonId, deleteTeam, removeTeamOwner, assignTeamOwner } from "~/models/team";
import { findAllUsers, findUserByClerkId, isUserAdminByClerkId } from "~/models/user";
import { unlinkSportFromSeason, linkMultipleSportsToSeason } from "~/models/season-sport";
import { findAllSportsSeasons } from "~/models/sports-season";
import { findDraftSlotsBySeasonId, setDraftOrder, randomizeDraftOrder } from "~/models/draft-slot";
import { database } from "~/database/context";
import * as schema from "~/database/schema";
import { deleteAllDraftPicks } from "~/models/draft-pick";
import { clearAllQueuesForSeason } from "~/models/draft-queue";
import { deleteSeasonTimers } from "~/models/draft-timer";
@ -482,16 +484,34 @@ export async function action(args: Route.ActionArgs) {
// Add or remove teams as needed
if (newTeamCount > currentTeamCount) {
// Add new teams
const teamsToAdd = Array.from(
{ length: newTeamCount - currentTeamCount },
(_, i) => ({
seasonId: season.id,
name: `Team ${currentTeamCount + i + 1}`,
ownerId: null,
ownerId: null as null,
})
);
await createManyTeams(teamsToAdd);
// Fetch existing slots before the transaction to determine append position
const existingSlots = await findDraftSlotsBySeasonId(season.id);
const maxOrder = existingSlots.reduce((max, s) => Math.max(max, s.draftOrder), 0);
// Create teams and their draft slots atomically
const db = database();
await db.transaction(async (tx) => {
const newTeams = await tx
.insert(schema.teams)
.values(teamsToAdd)
.returning();
await tx.insert(schema.draftSlots).values(
newTeams.map((team, i) => ({
seasonId: season.id,
teamId: team.id,
draftOrder: maxOrder + i + 1,
}))
);
});
} else if (newTeamCount < currentTeamCount) {
// Remove teams without owners (from the end)
const teamsToRemove = teams