Address code review: type hygiene, explicit types, parallel fetching, style fix
- Remove teamOwnerId from TeamStanding type (was an internal server concern, not display data) - Remove teamOwnerId from getSeasonStandings return value - Add TeamStandingWithChange interface extending TeamStanding with sevenDayRankChange/sevenDayOldRank fields - Annotate getSevenDayStandingsChange with explicit Promise<TeamStandingWithChange[]> return type - Re-export TeamStandingWithChange from models/standings.ts - Standings loader: query teams table directly for ownerIds instead of relying on teamOwnerId in standings data - Standings loader: parallelize all independent queries (standings, teams, progressionData, seasonComplete, completionPercentage) with Promise.all - Restore font-medium on StandingsTable team TableCell https://claude.ai/code/session_01EYgGnuTBaRVdBDapJRTxDZ
This commit is contained in:
parent
5fd9c6410b
commit
fb8e672f77
4 changed files with 36 additions and 31 deletions
|
|
@ -54,7 +54,7 @@ export function StandingsTable({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell className="font-medium">
|
||||||
<TeamNameDisplay
|
<TeamNameDisplay
|
||||||
teamName={standing.teamName}
|
teamName={standing.teamName}
|
||||||
ownerName={standing.ownerName}
|
ownerName={standing.ownerName}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { database } from "~/database/context";
|
import { database } from "~/database/context";
|
||||||
import * as schema from "~/database/schema";
|
import * as schema from "~/database/schema";
|
||||||
import { eq, and, desc } from "drizzle-orm";
|
import { eq, and, desc } from "drizzle-orm";
|
||||||
import type { TeamStanding, TeamStandingSnapshot } from "~/types/standings";
|
import type { TeamStanding, TeamStandingSnapshot, TeamStandingWithChange } from "~/types/standings";
|
||||||
import { calculateBracketPoints, calculateFantasyPoints } from "~/models/scoring-rules";
|
import { calculateBracketPoints, calculateFantasyPoints } from "~/models/scoring-rules";
|
||||||
|
|
||||||
// Re-export types from shared types file
|
// Re-export types from shared types file
|
||||||
export type { TeamStanding, TeamStandingSnapshot } from "~/types/standings";
|
export type { TeamStanding, TeamStandingSnapshot, TeamStandingWithChange } from "~/types/standings";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current standings for a season
|
* Get current standings for a season
|
||||||
|
|
@ -29,7 +29,6 @@ export async function getSeasonStandings(
|
||||||
return sorted.map((standing) => ({
|
return sorted.map((standing) => ({
|
||||||
teamId: standing.teamId,
|
teamId: standing.teamId,
|
||||||
teamName: standing.team.name,
|
teamName: standing.team.name,
|
||||||
teamOwnerId: standing.team.ownerId,
|
|
||||||
totalPoints: parseFloat(standing.totalPoints),
|
totalPoints: parseFloat(standing.totalPoints),
|
||||||
currentRank: standing.currentRank,
|
currentRank: standing.currentRank,
|
||||||
previousRank: standing.previousRank,
|
previousRank: standing.previousRank,
|
||||||
|
|
@ -292,7 +291,7 @@ export async function getTeamStandingsHistory(
|
||||||
export async function getSevenDayStandingsChange(
|
export async function getSevenDayStandingsChange(
|
||||||
seasonId: string,
|
seasonId: string,
|
||||||
providedDb?: ReturnType<typeof database>
|
providedDb?: ReturnType<typeof database>
|
||||||
) {
|
): Promise<TeamStandingWithChange[]> {
|
||||||
const db = providedDb || database();
|
const db = providedDb || database();
|
||||||
|
|
||||||
const sevenDaysAgo = new Date();
|
const sevenDaysAgo = new Date();
|
||||||
|
|
|
||||||
|
|
@ -71,36 +71,38 @@ export async function loader(args: Route.LoaderArgs) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch standings with 7-day comparison
|
// Fetch standings, teams (for owner lookup), and independent data in parallel
|
||||||
const standingsWithComparison = await getSevenDayStandingsChange(seasonId, db);
|
const [standingsWithComparison, teams, progressionData, seasonComplete, completionPercentage] =
|
||||||
|
await Promise.all([
|
||||||
|
getSevenDayStandingsChange(seasonId, db),
|
||||||
|
db.query.teams.findMany({
|
||||||
|
where: eq(schema.teams.seasonId, seasonId),
|
||||||
|
columns: { id: true, ownerId: true },
|
||||||
|
}),
|
||||||
|
getSeasonPointProgression(seasonId, db),
|
||||||
|
isSeasonComplete(seasonId, db),
|
||||||
|
getSeasonCompletionPercentage(seasonId, db),
|
||||||
|
]);
|
||||||
|
|
||||||
// Fetch owner display names for all teams in standings
|
// Build teamId -> ownerName map
|
||||||
const ownerIds = [
|
const ownerIds = [...new Set(teams.map((t) => t.ownerId).filter((id): id is string => id != null))];
|
||||||
...new Set(
|
|
||||||
standingsWithComparison
|
|
||||||
.map((s) => s.teamOwnerId)
|
|
||||||
.filter((id): id is string => id != null)
|
|
||||||
),
|
|
||||||
];
|
|
||||||
const userRows = await findUsersByClerkIds(ownerIds);
|
const userRows = await findUsersByClerkIds(ownerIds);
|
||||||
const userByClerkId = new Map(userRows.map((u) => [u.clerkId, u]));
|
const userByClerkId = new Map(userRows.map((u) => [u.clerkId, u]));
|
||||||
|
const ownerNameByTeamId = new Map(
|
||||||
|
teams
|
||||||
|
.filter((t): t is typeof t & { ownerId: string } => t.ownerId != null)
|
||||||
|
.map((t) => {
|
||||||
|
const user = userByClerkId.get(t.ownerId);
|
||||||
|
return [t.id, user ? getUserDisplayName(user) : null] as const;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// Map to format expected by component (use sevenDayRankChange instead of previousRank)
|
// Map to format expected by component (use sevenDayRankChange instead of previousRank)
|
||||||
const formattedStandings = standingsWithComparison.map((standing) => {
|
const formattedStandings = standingsWithComparison.map((standing) => ({
|
||||||
const user = standing.teamOwnerId ? userByClerkId.get(standing.teamOwnerId) : undefined;
|
|
||||||
return {
|
|
||||||
...standing,
|
...standing,
|
||||||
rankChange: standing.sevenDayRankChange,
|
rankChange: standing.sevenDayRankChange,
|
||||||
ownerName: user ? getUserDisplayName(user) : null,
|
ownerName: ownerNameByTeamId.get(standing.teamId) ?? null,
|
||||||
};
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
// Fetch historical progression data
|
|
||||||
const progressionData = await getSeasonPointProgression(seasonId, db);
|
|
||||||
|
|
||||||
// Check season completion status
|
|
||||||
const seasonComplete = await isSeasonComplete(seasonId, db);
|
|
||||||
const completionPercentage = await getSeasonCompletionPercentage(seasonId, db);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
league,
|
league,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
export interface TeamStanding {
|
export interface TeamStanding {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
teamName: string;
|
teamName: string;
|
||||||
teamOwnerId?: string | null;
|
|
||||||
ownerName?: string | null;
|
ownerName?: string | null;
|
||||||
totalPoints: number;
|
totalPoints: number;
|
||||||
currentRank: number;
|
currentRank: number;
|
||||||
|
|
@ -34,3 +33,8 @@ export interface TeamStandingSnapshot {
|
||||||
rank: number;
|
rank: number;
|
||||||
totalPoints: number;
|
totalPoints: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TeamStandingWithChange extends TeamStanding {
|
||||||
|
sevenDayRankChange: number;
|
||||||
|
sevenDayOldRank: number | null;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue