Files
gridpilot.gg/apps/website/lib/builders/view-data/LeagueDetailViewDataBuilder.ts
2026-01-16 01:00:03 +01:00

92 lines
3.3 KiB
TypeScript

import type { LeagueWithCapacityAndScoringDTO } from '@/lib/types/generated/LeagueWithCapacityAndScoringDTO';
import type { LeagueMembershipsDTO } from '@/lib/types/generated/LeagueMembershipsDTO';
import type { RaceDTO } from '@/lib/types/generated/RaceDTO';
import type { GetDriverOutputDTO } from '@/lib/types/generated/GetDriverOutputDTO';
import type { LeagueScoringConfigDTO } from '@/lib/types/generated/LeagueScoringConfigDTO';
import type { LeagueDetailViewData, LeagueInfoData, LiveRaceData, DriverSummaryData, SponsorInfo } from '@/lib/view-data/LeagueDetailViewData';
/**
* LeagueDetailViewDataBuilder
*
* Transforms API DTOs into LeagueDetailViewData for server-side rendering.
* Deterministic; side-effect free; no HTTP calls.
*/
export class LeagueDetailViewDataBuilder {
static build(input: {
league: LeagueWithCapacityAndScoringDTO;
owner: GetDriverOutputDTO | null;
scoringConfig: LeagueScoringConfigDTO | null;
memberships: LeagueMembershipsDTO;
races: RaceDTO[];
sponsors: any[];
}): LeagueDetailViewData {
const { league, owner, scoringConfig, memberships, races, sponsors } = input;
// Calculate running races - using available fields from RaceDTO
const runningRaces: LiveRaceData[] = races
.filter(r => r.name.includes('Running')) // Placeholder filter
.map(r => ({
id: r.id,
name: r.name,
date: r.date,
registeredCount: 0,
strengthOfField: 0,
}));
// Calculate info data
const membersCount = Array.isArray(memberships.members) ? memberships.members.length : 0;
const completedRacesCount = races.filter(r => r.name.includes('Completed')).length; // Placeholder
const avgSOF = races.length > 0
? Math.round(races.reduce((sum, _r) => sum + 0, 0) / races.length)
: null;
const info: LeagueInfoData = {
name: league.name,
description: league.description || '',
membersCount,
racesCount: completedRacesCount,
avgSOF,
structure: `Solo • ${league.settings?.maxDrivers ?? 32} max`,
scoring: scoringConfig?.scoringPresetId || 'Standard',
createdAt: league.createdAt,
discordUrl: league.socialLinks?.discordUrl,
youtubeUrl: league.socialLinks?.youtubeUrl,
websiteUrl: league.socialLinks?.websiteUrl,
};
// Convert owner to driver summary
const ownerSummary: DriverSummaryData | null = owner ? {
driverId: owner.id,
driverName: owner.name,
avatarUrl: owner.avatarUrl || null,
rating: null,
rank: null,
roleBadgeText: 'Owner',
roleBadgeClasses: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/30',
profileUrl: `/drivers/${owner.id}`,
} : null;
// Convert sponsors
const sponsorInfo: SponsorInfo[] = sponsors.map(s => ({
id: s.id,
name: s.name,
tier: s.tier,
logoUrl: s.logoUrl,
websiteUrl: s.websiteUrl,
tagline: s.tagline,
}));
return {
leagueId: league.id,
name: league.name,
description: league.description || '',
info,
runningRaces,
sponsors: sponsorInfo,
ownerSummary,
adminSummaries: [], // Would need additional data
stewardSummaries: [], // Would need additional data
sponsorInsights: null, // Only for sponsor mode
};
}
}