website refactor
This commit is contained in:
@@ -30,7 +30,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
|
||||
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<LeagueMembershipsDTO> {
|
||||
return this.get<LeagueMembershipsDTO>(`/leagues/${leagueId}/memberships`);
|
||||
async getMemberships(leagueId: string): Promise<LeagueMembershipsDTO> {
|
||||
const response = await this.get<any>(`/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<any>(`/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) */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Result<LeagueScheduleDTO, DomainError>> {
|
||||
return this.getAdminSchedule(leagueId, seasonId);
|
||||
}
|
||||
|
||||
@@ -64,20 +64,23 @@ export function LeagueOverviewTemplate({ viewData }: LeagueOverviewTemplateProps
|
||||
<Box border borderColor="zinc-800" bg="zinc-900/30" overflow="hidden">
|
||||
<table className="w-full text-left border-collapse">
|
||||
<tbody>
|
||||
{viewData.adminSummaries.concat(viewData.stewardSummaries).concat(viewData.memberSummaries).slice(0, 5).map((member) => (
|
||||
<tr key={member.driverId} className="border-b border-zinc-800/50">
|
||||
<td className="px-6 py-3">
|
||||
<Box display="flex" alignItems="center" gap={3}>
|
||||
<Box w="6" h="6" bg="zinc-800" rounded="full" />
|
||||
<Text size="sm" weight="bold" color="text-white">{member.driverName}</Text>
|
||||
</Box>
|
||||
</td>
|
||||
<td className="px-6 py-3 text-right">
|
||||
<Text size="xs" color="text-zinc-500" uppercase weight="bold">{member.roleBadgeText}</Text>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{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) => (
|
||||
<tr key={member.driverId} className="border-b border-zinc-800/50">
|
||||
<td className="px-6 py-3">
|
||||
<Box display="flex" alignItems="center" gap={3}>
|
||||
<Box w="6" h="6" bg="zinc-800" rounded="full" />
|
||||
<Text size="sm" weight="bold" color="text-white">{member.driverName}</Text>
|
||||
</Box>
|
||||
</td>
|
||||
<td className="px-6 py-3 text-right">
|
||||
<Text size="xs" color="text-zinc-500" uppercase weight="bold">{member.roleBadgeText}</Text>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{viewData.adminSummaries.length === 0 && viewData.stewardSummaries.length === 0 && viewData.memberSummaries.length === 0 && !viewData.ownerSummary && (
|
||||
<tr>
|
||||
<td className="px-6 py-8 text-center">
|
||||
<Text size="sm" color="text-zinc-600" italic>No members to display</Text>
|
||||
|
||||
Reference in New Issue
Block a user