Fix snake draft Discord pick numbering and small UX tweaks #2
8 changed files with 35 additions and 15 deletions
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -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 })),
|
||||||
|
|
|
||||||
|
|
@ -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 })),
|
||||||
|
|
|
||||||
|
|
@ -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 })
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue