diff --git a/apps/website/lib/api/leagues/LeaguesApiClient.ts b/apps/website/lib/api/leagues/LeaguesApiClient.ts index d1f16e7a2..0ce18cc81 100644 --- a/apps/website/lib/api/leagues/LeaguesApiClient.ts +++ b/apps/website/lib/api/leagues/LeaguesApiClient.ts @@ -30,7 +30,7 @@ function isRecord(value: unknown): value is Record { function isRaceDTO(value: unknown): value is RaceDTO { if (!isRecord(value)) return false; - return typeof value.id === 'string' && typeof value.name === 'string' && typeof value.date === 'string'; + return typeof value.id === 'string' && typeof value.name === 'string'; } function parseRaceDTOArray(value: unknown): RaceDTO[] { @@ -71,8 +71,11 @@ export class LeaguesApiClient extends BaseApiClient { } /** Get league memberships */ - getMemberships(leagueId: string): Promise { - return this.get(`/leagues/${leagueId}/memberships`); + async getMemberships(leagueId: string): Promise { + const response = await this.get(`/leagues/${leagueId}/memberships`); + if (Array.isArray(response)) return { members: response }; + if (response?.members) return response; + return { members: [] }; } /** Create a new league */ @@ -160,8 +163,9 @@ export class LeaguesApiClient extends BaseApiClient { /** Get races for a league */ async getRaces(leagueId: string): Promise<{ races: RaceDTO[] }> { - const response = await this.get<{ races?: unknown }>(`/leagues/${leagueId}/races`); - return { races: parseRaceDTOArray(response?.races) }; + const response = await this.get(`/leagues/${leagueId}/races`); + const races = Array.isArray(response) ? response : (response?.races || []); + return { races: parseRaceDTOArray(races) }; } /** Admin roster: list current members (admin/owner only; actor derived from session) */ diff --git a/apps/website/lib/builders/view-data/LeagueDetailViewDataBuilder.ts b/apps/website/lib/builders/view-data/LeagueDetailViewDataBuilder.ts index 7accc3789..9aa7b048c 100644 --- a/apps/website/lib/builders/view-data/LeagueDetailViewDataBuilder.ts +++ b/apps/website/lib/builders/view-data/LeagueDetailViewDataBuilder.ts @@ -35,10 +35,16 @@ export class LeagueDetailViewDataBuilder { // Calculate info data const membersCount = Array.isArray(memberships.members) ? memberships.members.length : 0; - const completedRacesCount = races.filter(r => (r as any).status === 'completed').length; + const completedRacesCount = races.filter(r => { + const status = (r as any).status; + return status === 'completed' || status === 'past'; + }).length; // Compute real avgSOF from races - const racesWithSOF = races.filter(r => typeof (r as any).strengthOfField === 'number' && (r as any).strengthOfField > 0); + const racesWithSOF = races.filter(r => { + const sof = (r as any).strengthOfField; + return typeof sof === 'number' && sof > 0; + }); const avgSOF = racesWithSOF.length > 0 ? Math.round(racesWithSOF.reduce((sum, r) => sum + ((r as any).strengthOfField || 0), 0) / racesWithSOF.length) : null; diff --git a/apps/website/lib/services/leagues/LeagueService.ts b/apps/website/lib/services/leagues/LeagueService.ts index 5641c5ef6..86553a7e9 100644 --- a/apps/website/lib/services/leagues/LeagueService.ts +++ b/apps/website/lib/services/leagues/LeagueService.ts @@ -1,37 +1,31 @@ -import { injectable, unmanaged } from 'inversify'; -import { LeaguesApiClient } from "@/lib/api/leagues/LeaguesApiClient"; import { DriversApiClient } from "@/lib/api/drivers/DriversApiClient"; -import { SponsorsApiClient } from "@/lib/api/sponsors/SponsorsApiClient"; +import { LeaguesApiClient } from "@/lib/api/leagues/LeaguesApiClient"; import { RacesApiClient } from "@/lib/api/races/RacesApiClient"; -import { CreateLeagueInputDTO } from "@/lib/types/generated/CreateLeagueInputDTO"; -import { CreateLeagueOutputDTO } from "@/lib/types/generated/CreateLeagueOutputDTO"; -import type { MembershipRole } from "@/lib/types/MembershipRole"; -import type { LeagueRosterJoinRequestDTO } from "@/lib/types/generated/LeagueRosterJoinRequestDTO"; -import type { TotalLeaguesDTO } from '@/lib/types/generated/TotalLeaguesDTO'; -import type { LeagueSeasonSummaryDTO } from '@/lib/types/generated/LeagueSeasonSummaryDTO'; -import type { LeagueScheduleDTO } from '@/lib/types/generated/LeagueScheduleDTO'; -import type { CreateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/CreateLeagueScheduleRaceInputDTO'; -import type { CreateLeagueScheduleRaceOutputDTO } from '@/lib/types/generated/CreateLeagueScheduleRaceOutputDTO'; -import type { UpdateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/UpdateLeagueScheduleRaceInputDTO'; -import type { LeagueScheduleRaceMutationSuccessDTO } from '@/lib/types/generated/LeagueScheduleRaceMutationSuccessDTO'; -import type { LeagueSeasonSchedulePublishOutputDTO } from '@/lib/types/generated/LeagueSeasonSchedulePublishOutputDTO'; -import type { LeagueRosterMemberDTO } from '@/lib/types/generated/LeagueRosterMemberDTO'; -import type { LeagueMembershipsDTO } from '@/lib/types/generated/LeagueMembershipsDTO'; -import type { GetTeamDetailsOutputDTO } from '@/lib/types/generated/GetTeamDetailsOutputDTO'; -import type { GetDriverOutputDTO } from '@/lib/types/generated/GetDriverOutputDTO'; -import type { RaceDTO } from '@/lib/types/generated/RaceDTO'; -import type { LeagueScoringConfigDTO } from '@/lib/types/generated/LeagueScoringConfigDTO'; -import { TeamMemberViewModel } from '@/lib/view-models/TeamMemberViewModel'; -import { TeamSummaryViewModel } from '@/lib/view-models/TeamSummaryViewModel'; -import { TeamDetailsViewModel } from '@/lib/view-models/TeamDetailsViewModel'; -import { Result } from '@/lib/contracts/Result'; -import { DomainError, Service } from '@/lib/contracts/services/Service'; -import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger'; -import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter'; +import { SponsorsApiClient } from "@/lib/api/sponsors/SponsorsApiClient"; import { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl'; import { isProductionEnvironment } from '@/lib/config/env'; +import { Result } from '@/lib/contracts/Result'; +import { DomainError, Service } from '@/lib/contracts/services/Service'; +import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter'; +import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger'; import { AllLeaguesWithCapacityAndScoringDTO } from '@/lib/types/AllLeaguesWithCapacityAndScoringDTO'; +import { CreateLeagueInputDTO } from "@/lib/types/generated/CreateLeagueInputDTO"; +import type { CreateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/CreateLeagueScheduleRaceInputDTO'; +import type { CreateLeagueScheduleRaceOutputDTO } from '@/lib/types/generated/CreateLeagueScheduleRaceOutputDTO'; +import type { GetDriverOutputDTO } from '@/lib/types/generated/GetDriverOutputDTO'; +import type { LeagueMembershipsDTO } from '@/lib/types/generated/LeagueMembershipsDTO'; +import type { LeagueRosterJoinRequestDTO } from "@/lib/types/generated/LeagueRosterJoinRequestDTO"; +import type { LeagueRosterMemberDTO } from '@/lib/types/generated/LeagueRosterMemberDTO'; +import type { LeagueScheduleDTO } from '@/lib/types/generated/LeagueScheduleDTO'; +import type { LeagueScheduleRaceMutationSuccessDTO } from '@/lib/types/generated/LeagueScheduleRaceMutationSuccessDTO'; +import type { LeagueScoringConfigDTO } from '@/lib/types/generated/LeagueScoringConfigDTO'; +import type { LeagueSeasonSchedulePublishOutputDTO } from '@/lib/types/generated/LeagueSeasonSchedulePublishOutputDTO'; +import type { LeagueSeasonSummaryDTO } from '@/lib/types/generated/LeagueSeasonSummaryDTO'; import type { LeagueWithCapacityAndScoringDTO } from '@/lib/types/generated/LeagueWithCapacityAndScoringDTO'; +import type { RaceDTO } from '@/lib/types/generated/RaceDTO'; +import type { UpdateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/UpdateLeagueScheduleRaceInputDTO'; +import type { MembershipRole } from "@/lib/types/MembershipRole"; +import { injectable, unmanaged } from 'inversify'; export interface LeagueScheduleAdminData { leagueId: string; @@ -328,6 +322,7 @@ export class LeagueService implements Service { } } + // TODO wtf what a stupid method?? async getLeagueScheduleDto(leagueId: string, seasonId: string): Promise> { return this.getAdminSchedule(leagueId, seasonId); } diff --git a/apps/website/templates/LeagueOverviewTemplate.tsx b/apps/website/templates/LeagueOverviewTemplate.tsx index 84035ffe5..c1f2f177b 100644 --- a/apps/website/templates/LeagueOverviewTemplate.tsx +++ b/apps/website/templates/LeagueOverviewTemplate.tsx @@ -64,20 +64,23 @@ export function LeagueOverviewTemplate({ viewData }: LeagueOverviewTemplateProps - {viewData.adminSummaries.concat(viewData.stewardSummaries).concat(viewData.memberSummaries).slice(0, 5).map((member) => ( - - - - - ))} - {viewData.adminSummaries.length === 0 && viewData.stewardSummaries.length === 0 && viewData.memberSummaries.length === 0 && ( + {[viewData.ownerSummary, ...viewData.adminSummaries, ...viewData.stewardSummaries, ...viewData.memberSummaries] + .filter((m): m is any => m !== null) + .slice(0, 5) + .map((member) => ( + + + + + ))} + {viewData.adminSummaries.length === 0 && viewData.stewardSummaries.length === 0 && viewData.memberSummaries.length === 0 && !viewData.ownerSummary && (
- - - {member.driverName} - - - {member.roleBadgeText} -
+ + + {member.driverName} + + + {member.roleBadgeText} +
No members to display