website refactor
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
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
|
||||
const runningRaces: LiveRaceData[] = races
|
||||
.filter(r => r.status === 'running')
|
||||
.map(r => ({
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
date: r.scheduledAt,
|
||||
registeredCount: r.registeredCount,
|
||||
strengthOfField: r.strengthOfField,
|
||||
}));
|
||||
|
||||
// Calculate info data
|
||||
const membersCount = Array.isArray(memberships.members) ? memberships.members.length : 0;
|
||||
const completedRacesCount = races.filter(r => r.status === 'completed').length;
|
||||
const avgSOF = races.length > 0
|
||||
? Math.round(races.reduce((sum, r) => sum + (r.strengthOfField || 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?.name || '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
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user