Fix snake draft Discord pick numbering and small UX tweaks #2

Merged
chrisp merged 3 commits from chore/draft-ux-tweaks into main 2026-05-22 04:18:12 +00:00
8 changed files with 35 additions and 15 deletions

View file

@ -75,7 +75,7 @@ function DraftPickCell({
if (seasonStatus === "pre_draft") { if (seasonStatus === "pre_draft") {
currentLabel = "Up Next"; currentLabel = "Up Next";
} else if (seasonStatus === "draft" && isOvernightPause) { } else if (seasonStatus === "draft" && isOvernightPause) {
currentLabel = "🌙 Overnight Pause"; currentLabel = "🌙 Pause";
} else if (seasonStatus === "draft" && draftPaused) { } else if (seasonStatus === "draft" && draftPaused) {
currentLabel = "Paused Draft"; currentLabel = "Paused Draft";
} }

View file

@ -77,7 +77,7 @@ const SortableQueueItem = memo(function SortableQueueItem({
style={style} style={style}
{...attributes} {...attributes}
className={`p-2 rounded-lg ${ className={`p-2 rounded-lg ${
canPick ? "bg-electric/10 border border-electric/40" : "bg-muted" canPick ? "bg-electric/10 border border-electric/40" : "bg-white/[0.06]"
}`} }`}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">

View file

@ -33,9 +33,9 @@ export const SidebarRecentPicks = memo(function SidebarRecentPicks({ picks }: Si
.map((pick) => ( .map((pick) => (
<div <div
key={pick.id} key={pick.id}
className="flex items-center justify-between p-2 bg-muted rounded-lg text-sm" className="flex items-center justify-between p-2 bg-white/[0.06] rounded-lg text-sm"
> >
<div className="flex items-center gap-2 min-w-0 flex-1"> <div className="flex items-start gap-2 min-w-0 flex-1">
<Badge variant="outline" className="text-xs flex-shrink-0"> <Badge variant="outline" className="text-xs flex-shrink-0">
#{pick.pickNumber} #{pick.pickNumber}
</Badge> </Badge>

View file

@ -65,7 +65,7 @@ function DraftRow({ leagueId, leagueName, seasonId, picksUntilMyTurn }: LeagueRo
<div className="flex items-start gap-3 rounded-lg border border-primary/40 bg-primary/10 px-3 py-3 sm:px-5 sm:py-4"> <div className="flex items-start gap-3 rounded-lg border border-primary/40 bg-primary/10 px-3 py-3 sm:px-5 sm:py-4">
<LeagueAvatar leagueId={leagueId} leagueName={leagueName} /> <LeagueAvatar leagueId={leagueId} leagueName={leagueName} />
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="font-semibold leading-tight truncate">{leagueName}</p> <Link to={`/leagues/${leagueId}`} className="font-semibold leading-tight truncate hover:underline block">{leagueName}</Link>
<div className="flex items-center gap-2 mt-0.5 flex-wrap"> <div className="flex items-center gap-2 mt-0.5 flex-wrap">
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<span className="h-1.5 w-1.5 animate-pulse rounded-full bg-electric" /> <span className="h-1.5 w-1.5 animate-pulse rounded-full bg-electric" />

View file

@ -330,7 +330,7 @@ export async function getTopAvailableParticipant(
export function calculatePickInfo( export function calculatePickInfo(
pickNumber: number, pickNumber: number,
teamCount: number teamCount: number
): { round: number; pickInRound: number; teamIndex: number } { ): { round: number; pickInRound: number; teamIndex: number; rawPickInRound: number } {
const round = Math.ceil(pickNumber / teamCount); const round = Math.ceil(pickNumber / teamCount);
const rawPickInRound = ((pickNumber - 1) % teamCount) + 1; const rawPickInRound = ((pickNumber - 1) % teamCount) + 1;
@ -339,7 +339,7 @@ export function calculatePickInfo(
const teamIndex = isOddRound ? rawPickInRound - 1 : teamCount - rawPickInRound; const teamIndex = isOddRound ? rawPickInRound - 1 : teamCount - rawPickInRound;
const pickInRound = teamIndex + 1; // snake-adjusted, 1-based, matches draftOrder const pickInRound = teamIndex + 1; // snake-adjusted, 1-based, matches draftOrder
return { round, pickInRound, teamIndex }; return { round, pickInRound, teamIndex, rawPickInRound };
} }
/** /**
@ -602,7 +602,7 @@ export async function executeAutoPick(params: {
}; };
} }
const { round: currentRound, pickInRound } = calculatePickInfo(pickNumber, totalTeams); const { round: currentRound, pickInRound, rawPickInRound } = calculatePickInfo(pickNumber, totalTeams);
// Determine pickedByUserId based on trigger // Determine pickedByUserId based on trigger
const pickedByUserId = triggeredBy === "commissioner" const pickedByUserId = triggeredBy === "commissioner"
@ -854,7 +854,7 @@ export async function executeAutoPick(params: {
sportName: participantToPick.sportsSeason.sport.name, sportName: participantToPick.sportsSeason.sport.name,
pickNumber, pickNumber,
round: currentRound, round: currentRound,
pickInRound, rawPickInRound,
isDraftComplete, isDraftComplete,
totalTeams, totalTeams,
draftSlots: draftSlots.map((s) => ({ teamId: s.teamId, draftOrder: s.draftOrder })), draftSlots: draftSlots.map((s) => ({ teamId: s.teamId, draftOrder: s.draftOrder })),

View file

@ -62,7 +62,7 @@ export async function action(args: ActionFunctionArgs) {
}); });
const totalTeams = draftSlots.length; const totalTeams = draftSlots.length;
const { round: currentRound, pickInRound } = calculatePickInfo(currentPickNumber, totalTeams); const { round: currentRound, pickInRound, rawPickInRound } = calculatePickInfo(currentPickNumber, totalTeams);
const currentDraftSlot = draftSlots.find((slot) => slot.draftOrder === pickInRound); const currentDraftSlot = draftSlots.find((slot) => slot.draftOrder === pickInRound);
if (!currentDraftSlot) { if (!currentDraftSlot) {
@ -339,7 +339,7 @@ export async function action(args: ActionFunctionArgs) {
sportName: participant.sportsSeason.sport.name, sportName: participant.sportsSeason.sport.name,
pickNumber: currentPickNumber, pickNumber: currentPickNumber,
round: currentRound, round: currentRound,
pickInRound, rawPickInRound,
isDraftComplete, isDraftComplete,
totalTeams, totalTeams,
draftSlots: draftSlots.map((s) => ({ teamId: s.teamId, draftOrder: s.draftOrder })), draftSlots: draftSlots.map((s) => ({ teamId: s.teamId, draftOrder: s.draftOrder })),

View file

@ -41,7 +41,7 @@ const BASE_PARAMS = {
sportName: "Soccer", sportName: "Soccer",
pickNumber: 1, pickNumber: 1,
round: 1, round: 1,
pickInRound: 1, rawPickInRound: 1,
isDraftComplete: false, isDraftComplete: false,
totalTeams: 2, totalTeams: 2,
draftSlots: DRAFT_SLOTS, draftSlots: DRAFT_SLOTS,
@ -95,6 +95,7 @@ function makeMockDb(overrides: {
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
vi.mocked(sendPickAnnouncementNotification).mockResolvedValue(undefined);
process.env.APP_URL = "https://test.brackt.com"; process.env.APP_URL = "https://test.brackt.com";
}); });
@ -230,4 +231,23 @@ describe("notifyPickMadeOnDiscord", () => {
notifyPickMadeOnDiscord({ ...BASE_PARAMS, db: db as never }) notifyPickMadeOnDiscord({ ...BASE_PARAMS, db: db as never })
).rejects.toThrow("webhook down"); ).rejects.toThrow("webhook down");
}); });
it("uses sequential (not snake-adjusted) pick number in Discord title for even rounds", async () => {
// 13-team draft, pick #22: round 2 (even/reversed), rawPickInRound=9, snake-adjusted slot=5
// Discord should say "Round 2, Pick 9" not "Round 2, Pick 5"
const db = makeMockDb({ season: makeSeason(23) });
await notifyPickMadeOnDiscord({
...BASE_PARAMS,
pickNumber: 22,
round: 2,
rawPickInRound: 9,
totalTeams: 13,
db: db as never,
});
expect(sendPickAnnouncementNotification).toHaveBeenCalledWith(
expect.objectContaining({ pickNumber: 22, round: 2, pickInRound: 9 })
);
});
}); });

View file

@ -24,7 +24,7 @@ export async function notifyPickMadeOnDiscord(params: {
sportName: string; sportName: string;
pickNumber: number; pickNumber: number;
round: number; round: number;
pickInRound: number; rawPickInRound: number;
isDraftComplete: boolean; isDraftComplete: boolean;
totalTeams: number; totalTeams: number;
draftSlots: DraftSlot[]; draftSlots: DraftSlot[];
@ -38,7 +38,7 @@ export async function notifyPickMadeOnDiscord(params: {
sportName, sportName,
pickNumber, pickNumber,
round, round,
pickInRound, rawPickInRound,
isDraftComplete, isDraftComplete,
totalTeams, totalTeams,
draftSlots, draftSlots,
@ -90,7 +90,7 @@ export async function notifyPickMadeOnDiscord(params: {
draftUrl, draftUrl,
pickNumber, pickNumber,
round, round,
pickInRound, pickInRound: rawPickInRound,
pickedTeamName, pickedTeamName,
participantName, participantName,
sportName, sportName,