Files
gridpilot.gg/apps/website/lib/builders/view-data/RulebookViewDataBuilder.ts
Marc Mintel 6c07abe5e7
Some checks failed
Contract Testing / contract-snapshot (pull_request) Has been cancelled
Contract Testing / contract-tests (pull_request) Has been cancelled
view data fixes
2026-01-25 00:12:30 +01:00

63 lines
2.2 KiB
TypeScript

/**
* Rulebook View Data Builder
*
* Transforms API DTO to ViewData for templates.
*/
import type { RulebookViewData } from '@/lib/view-data/RulebookViewData';
import { ViewDataBuilder } from "../../contracts/builders/ViewDataBuilder";
interface RulebookApiDto {
leagueId: string;
scoringConfig: {
gameName: string;
scoringPresetName: string;
championships: Array<{
type: string;
sessionTypes: string[];
pointsPreview: Array<{
sessionType: string;
position: number;
points: number;
}>;
bonusSummary: string[];
}>;
dropPolicySummary: string;
};
}
export class RulebookViewDataBuilder {
/**
* Transform API DTO to ViewData
*
* @param apiDto - The DTO from the service
* @returns ViewData for the rulebook page
*/
public static build(apiDto: RulebookApiDto): RulebookViewData {
const primaryChampionship = apiDto.scoringConfig.championships.find(c => c.type === 'driver') ?? apiDto.scoringConfig.championships[0];
const positionPoints: { position: number; points: number }[] = (primaryChampionship?.pointsPreview || [])
.filter((p: unknown): p is { sessionType: string; position: number; points: number } => {
const point = p as { sessionType?: string; position?: number; points?: number };
return point.sessionType === primaryChampionship?.sessionTypes[0];
})
.map(p => ({ position: p.position, points: p.points }))
.sort((a, b) => a.position - b.position);
return {
leagueId: apiDto.leagueId,
gameName: apiDto.scoringConfig.gameName,
scoringPresetName: apiDto.scoringConfig.scoringPresetName || 'Custom',
championshipsCount: apiDto.scoringConfig.championships.length,
sessionTypes: primaryChampionship?.sessionTypes.join(', ') || 'Main',
dropPolicySummary: apiDto.scoringConfig.dropPolicySummary,
hasActiveDropPolicy: !!apiDto.scoringConfig.dropPolicySummary && !apiDto.scoringConfig.dropPolicySummary.toLowerCase().includes('all'),
positionPoints,
bonusPoints: primaryChampionship?.bonusSummary || [],
hasBonusPoints: (primaryChampionship?.bonusSummary.length || 0) > 0,
};
}
}
RulebookViewDataBuilder satisfies ViewDataBuilder<RulebookApiDto, RulebookViewData>;