Show team name + username in standings, extract TeamNameDisplay component
- Add TeamNameDisplay component that renders team name (as link) with owner username below, matching the league homepage style - Update StandingsTable to use TeamNameDisplay with owner username shown below team name - Update league homepage standings section to use TeamNameDisplay - Add ownerName/teamOwnerId fields to TeamStanding type - Extend getSeasonStandings to include teamOwnerId from team relation - Fetch and attach owner display names in the full standings page loader https://claude.ai/code/session_01EYgGnuTBaRVdBDapJRTxDZ
This commit is contained in:
parent
fa0e798db7
commit
5fd9c6410b
6 changed files with 67 additions and 23 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { Link } from "react-router";
|
||||
import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "~/components/ui/table";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { TeamNameDisplay } from "~/components/ui/team-name-display";
|
||||
import { type TeamStanding } from "~/types/standings";
|
||||
|
||||
interface StandingsTableProps {
|
||||
|
|
@ -54,13 +54,12 @@ export function StandingsTable({
|
|||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="font-medium">
|
||||
<Link
|
||||
to={`/leagues/${leagueId}/standings/${seasonId}/teams/${standing.teamId}`}
|
||||
className="hover:underline hover:text-primary transition-colors"
|
||||
>
|
||||
{standing.teamName}
|
||||
</Link>
|
||||
<TableCell>
|
||||
<TeamNameDisplay
|
||||
teamName={standing.teamName}
|
||||
ownerName={standing.ownerName}
|
||||
href={`/leagues/${leagueId}/standings/${seasonId}/teams/${standing.teamId}`}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="text-right font-semibold">
|
||||
{standing.actualPoints !== null && standing.actualPoints !== undefined
|
||||
|
|
|
|||
31
app/components/ui/team-name-display.tsx
Normal file
31
app/components/ui/team-name-display.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { Link } from "react-router";
|
||||
|
||||
interface TeamNameDisplayProps {
|
||||
teamName: string;
|
||||
ownerName?: string | null;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a team name with optional owner username below it.
|
||||
* If href is provided, the team name is rendered as a link.
|
||||
*/
|
||||
export function TeamNameDisplay({ teamName, ownerName, href }: TeamNameDisplayProps) {
|
||||
return (
|
||||
<div className="min-w-0">
|
||||
{href ? (
|
||||
<Link
|
||||
to={href}
|
||||
className="font-medium text-sm hover:underline truncate block"
|
||||
>
|
||||
{teamName}
|
||||
</Link>
|
||||
) : (
|
||||
<p className="font-medium text-sm truncate">{teamName}</p>
|
||||
)}
|
||||
{ownerName && (
|
||||
<p className="text-xs text-muted-foreground truncate">{ownerName}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ export async function getSeasonStandings(
|
|||
return sorted.map((standing) => ({
|
||||
teamId: standing.teamId,
|
||||
teamName: standing.team.name,
|
||||
teamOwnerId: standing.team.ownerId,
|
||||
totalPoints: parseFloat(standing.totalPoints),
|
||||
currentRank: standing.currentRank,
|
||||
previousRank: standing.previousRank,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { StandingsTable } from "~/components/standings/StandingsTable";
|
|||
import { getSevenDayStandingsChange, getSeasonPointProgression } from "~/models/standings";
|
||||
import { isSeasonComplete, getSeasonCompletionPercentage } from "~/lib/season-helpers.server";
|
||||
import { PointProgressionChart } from "~/components/standings/PointProgressionChart";
|
||||
import { findUsersByClerkIds, getUserDisplayName } from "~/models/user";
|
||||
import type { Route } from "./+types/$leagueId.standings.$seasonId";
|
||||
|
||||
export function meta({ data }: Route.MetaArgs): Route.MetaDescriptors {
|
||||
|
|
@ -73,11 +74,26 @@ export async function loader(args: Route.LoaderArgs) {
|
|||
// Fetch standings with 7-day comparison
|
||||
const standingsWithComparison = await getSevenDayStandingsChange(seasonId, db);
|
||||
|
||||
// Fetch owner display names for all teams in standings
|
||||
const ownerIds = [
|
||||
...new Set(
|
||||
standingsWithComparison
|
||||
.map((s) => s.teamOwnerId)
|
||||
.filter((id): id is string => id != null)
|
||||
),
|
||||
];
|
||||
const userRows = await findUsersByClerkIds(ownerIds);
|
||||
const userByClerkId = new Map(userRows.map((u) => [u.clerkId, u]));
|
||||
|
||||
// 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,
|
||||
rankChange: standing.sevenDayRankChange,
|
||||
}));
|
||||
ownerName: user ? getUserDisplayName(user) : null,
|
||||
};
|
||||
});
|
||||
|
||||
// Fetch historical progression data
|
||||
const progressionData = await getSeasonPointProgression(seasonId, db);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
} from "~/components/ui/card";
|
||||
import { SportSeasonCard } from "~/components/sports/SportSeasonCard";
|
||||
import { UpcomingCalendarPanel } from "~/components/sport-season/UpcomingCalendarPanel";
|
||||
import { TeamNameDisplay } from "~/components/ui/team-name-display";
|
||||
import { getDisplayRank } from "~/lib/standings-display";
|
||||
|
||||
export function meta({ data }: Route.MetaArgs): Route.MetaDescriptors {
|
||||
|
|
@ -196,17 +197,11 @@ export default function LeagueHome({ loaderData }: Route.ComponentProps) {
|
|||
{getDisplayRank(standing, standings.length)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link
|
||||
to={`/leagues/${league.id}/standings/${season.id}/teams/${team.id}`}
|
||||
className="font-medium text-sm hover:underline truncate block"
|
||||
>
|
||||
{team.name}
|
||||
</Link>
|
||||
{ownerName && (
|
||||
<p className="text-xs text-muted-foreground truncate">
|
||||
{ownerName}
|
||||
</p>
|
||||
)}
|
||||
<TeamNameDisplay
|
||||
teamName={team.name}
|
||||
ownerName={ownerName}
|
||||
href={`/leagues/${league.id}/standings/${season.id}/teams/${team.id}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-sm font-medium tabular-nums">
|
||||
{standing ? standing.totalPoints : 0} pts
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
export interface TeamStanding {
|
||||
teamId: string;
|
||||
teamName: string;
|
||||
teamOwnerId?: string | null;
|
||||
ownerName?: string | null;
|
||||
totalPoints: number;
|
||||
currentRank: number;
|
||||
previousRank: number | null;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue