From cee9469f489a052e78cfaee6a322ce5d7a0e11d9 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 12 May 2026 09:22:18 +0000 Subject: [PATCH] Fix MLB streak doubling bug, hide empty standings columns, improve mobile layout - mlb.ts: use streakCode alone (the API already returns the full string like "W3"); appending streakNumber was doubling the digit, causing "L33" display - Update mlb.test.ts mocks to match real API format (streakCode "W3" not "W") - RegularSeasonStandings: conditionally hide GB/L10/STK columns when no rows have data, so pre-season or stats-free sports don't show blank columns - Mobile two-row layout: GP/PCT/GB/L10 move to a secondary sub-row (sm:hidden) so all data stays visible without horizontal scroll on small screens; STK and W/L remain on the primary row; reduce min-w from 740px to 360px https://claude.ai/code/session_01RADi3LhYMPbRDm5no1ZpdF --- .../sport-season/RegularSeasonStandings.tsx | 86 ++++++++++++++----- .../__tests__/RegularSeasonStandings.test.tsx | 32 +++++++ .../standings-sync/__tests__/mlb.test.ts | 6 +- app/services/standings-sync/mlb.ts | 6 +- 4 files changed, 103 insertions(+), 27 deletions(-) diff --git a/app/components/sport-season/RegularSeasonStandings.tsx b/app/components/sport-season/RegularSeasonStandings.tsx index 8bd5b4d..2036748 100644 --- a/app/components/sport-season/RegularSeasonStandings.tsx +++ b/app/components/sport-season/RegularSeasonStandings.tsx @@ -236,19 +236,25 @@ function StandingsTable({ showOtLosses: boolean; showSoccerTable?: boolean; }) { - // # Team GP W L [OTL] [PTS] PCT GB L10 STK Mgr - // OTL and PTS are both shown for hockey (showOtLosses = true). - // Soccer table mode shows D/GF/GA/GD/Pts instead of PCT/GB/form columns. - const totalCols = showSoccerTable ? 11 : 10 + (showOtLosses ? 2 : 0); + const allRows = sections.flatMap((s) => s.rows); + const hasStreak = allRows.some((r) => r.streak != null); + const hasLastTen = allRows.some((r) => r.lastTen != null); + const hasGB = allRows.some((r) => r.gamesBack != null); + + // # Team GP W [D] L [GF GA GD PTS] [OTL PTS] [PCT] [GB] [L10] [STK] Mgr + // Soccer: 11 fixed columns. Non-soccer: 5 base + GP + optional cols. + const totalCols = showSoccerTable + ? 11 + : 5 + 1 /* GP */ + (showOtLosses ? 2 : 0) + 1 /* PCT */ + (hasGB ? 1 : 0) + (hasLastTen ? 1 : 0) + (hasStreak ? 1 : 0); return (
- +
- + {showSoccerTable && } @@ -258,10 +264,10 @@ function StandingsTable({ {showSoccerTable && } {showOtLosses && } {showOtLosses && } - {!showSoccerTable && } - {!showSoccerTable && } - {!showSoccerTable && } - {!showSoccerTable && } + {!showSoccerTable && } + {!showSoccerTable && hasGB && } + {!showSoccerTable && hasLastTen && } + {!showSoccerTable && hasStreak && } @@ -308,16 +314,19 @@ function StandingsTable({ const isUserTeam = userParticipantIds.includes(row.participantId); const ownership = teamOwnerships[row.participantId]; + // Non-soccer rows get a secondary sub-row on mobile showing GP/PCT/GB/L10 + const hasSecondaryStats = !showSoccerTable; + sectionRows.push( - - @@ -355,21 +364,21 @@ function StandingsTable({ )} {!showSoccerTable && ( - )} - {!showSoccerTable && ( - )} - {!showSoccerTable && ( - )} - {!showSoccerTable && ( + {!showSoccerTable && hasStreak && ( ); + + // Secondary stats sub-row for mobile (hidden on sm+) + if (hasSecondaryStats) { + sectionRows.push( + + + + ); + } }); return sectionRows; diff --git a/app/components/sport-season/__tests__/RegularSeasonStandings.test.tsx b/app/components/sport-season/__tests__/RegularSeasonStandings.test.tsx index 4d9e681..0a6db08 100644 --- a/app/components/sport-season/__tests__/RegularSeasonStandings.test.tsx +++ b/app/components/sport-season/__tests__/RegularSeasonStandings.test.tsx @@ -109,6 +109,38 @@ describe("RegularSeasonStandings", () => { expect(screen.queryByText("OTL")).not.toBeInTheDocument(); }); + it("hides STK column when no rows have streak data", () => { + render( + + ); + expect(screen.queryByText("STK")).not.toBeInTheDocument(); + }); + + it("shows STK column when at least one row has streak data", () => { + render( + + ); + expect(screen.getByText("STK")).toBeInTheDocument(); + }); + + it("hides L10 column when no rows have lastTen data", () => { + render( + + ); + expect(screen.queryByText("L10")).not.toBeInTheDocument(); + }); it("shows soccer table columns when showSoccerTable=true", () => { render( diff --git a/app/services/standings-sync/__tests__/mlb.test.ts b/app/services/standings-sync/__tests__/mlb.test.ts index 119cc83..0968412 100644 --- a/app/services/standings-sync/__tests__/mlb.test.ts +++ b/app/services/standings-sync/__tests__/mlb.test.ts @@ -20,7 +20,7 @@ const SAMPLE_MLB_RESPONSE = { divisionRank: "1", leagueRank: "1", gamesBack: "-", - streak: { streakCode: "W", streakNumber: 3 }, + streak: { streakCode: "W3", streakNumber: 3 }, records: { splitRecords: [ { type: "home", wins: 24, losses: 15 }, @@ -43,7 +43,7 @@ const SAMPLE_MLB_RESPONSE = { divisionRank: "2", leagueRank: "4", gamesBack: "5.0", - streak: { streakCode: "L", streakNumber: 2 }, + streak: { streakCode: "L2", streakNumber: 2 }, records: { splitRecords: [ { type: "home", wins: 22, losses: 18 }, @@ -71,7 +71,7 @@ const SAMPLE_MLB_RESPONSE = { divisionRank: "1", leagueRank: "1", gamesBack: "-", - streak: { streakCode: "W", streakNumber: 1 }, + streak: { streakCode: "W1", streakNumber: 1 }, records: { splitRecords: [ { type: "home", wins: 22, losses: 17 }, diff --git a/app/services/standings-sync/mlb.ts b/app/services/standings-sync/mlb.ts index 4bc90ba..f3d0c18 100644 --- a/app/services/standings-sync/mlb.ts +++ b/app/services/standings-sync/mlb.ts @@ -115,10 +115,8 @@ export class MlbStandingsAdapter implements StandingsSyncAdapter { // Conference rank: use the per-league rank computed above const conferenceRank = conferenceRankMap.get(team.team.id) ?? null; - // Streak: e.g. "W3" or "L2" - const streak = team.streak - ? `${team.streak.streakCode}${team.streak.streakNumber}` - : undefined; + // Streak: streakCode from the MLB API already contains the full string e.g. "W3" or "L2" + const streak = team.streak?.streakCode ?? undefined; // Split records const splits = team.records?.splitRecords ?? [];
# TeamGPGP WDLPTSOTLPTSPCTGBL10STKPCTGBL10STKMgr
{rank} - + + {row.participant.shortName ?? row.participant.name} {section.showDivisionLabel && row.division && ( @@ -326,7 +335,7 @@ function StandingsTable({ )} + {row.gamesPlayed} {row.wins} + {formatWinPct(row.winPct, row.wins, row.gamesPlayed)} + {!showSoccerTable && hasGB && ( + {formatGB(row.gamesBack)} + {!showSoccerTable && hasLastTen && ( + {row.lastTen ?? "—"} {row.streak ? (
+
+ + GP{" "} + {row.gamesPlayed} + + + PCT{" "} + {formatWinPct(row.winPct, row.wins, row.gamesPlayed)} + + {hasGB && ( + + GB{" "} + {formatGB(row.gamesBack)} + + )} + {hasLastTen && ( + + L10{" "} + {row.lastTen ?? "—"} + + )} +
+