81 lines
2.2 KiB
TypeScript
81 lines
2.2 KiB
TypeScript
/**
|
|
* LeagueStandingsPresenter - Pure data transformer
|
|
* Transforms API response to view model without DI dependencies.
|
|
*/
|
|
|
|
import { apiClient, type LeagueStandingsViewModel as ApiLeagueStandingsViewModel } from '@/lib/apiClient';
|
|
|
|
export interface LeagueStandingsEntryViewModel {
|
|
driverId: string;
|
|
driverName: string;
|
|
position: number;
|
|
points: number;
|
|
wins: number;
|
|
podiums: number;
|
|
races: number;
|
|
avatarUrl?: string | undefined;
|
|
}
|
|
|
|
export interface LeagueStandingsViewModel {
|
|
leagueId: string;
|
|
standings: LeagueStandingsEntryViewModel[];
|
|
totalDrivers: number;
|
|
}
|
|
|
|
export interface ILeagueStandingsPresenter {
|
|
present(leagueId: string): Promise<void>;
|
|
getViewModel(): LeagueStandingsViewModel | null;
|
|
reset(): void;
|
|
}
|
|
|
|
/**
|
|
* Transform API response to view model
|
|
*/
|
|
function transformApiResponse(leagueId: string, apiResponse: ApiLeagueStandingsViewModel): LeagueStandingsViewModel {
|
|
const standings: LeagueStandingsEntryViewModel[] = apiResponse.standings.map((entry) => {
|
|
const viewModel: LeagueStandingsEntryViewModel = {
|
|
driverId: entry.driverId,
|
|
driverName: entry.driver?.name ?? 'Unknown Driver',
|
|
position: entry.position,
|
|
points: entry.points,
|
|
wins: entry.wins,
|
|
podiums: entry.podiums,
|
|
races: entry.races,
|
|
};
|
|
if (entry.driver?.avatarUrl) {
|
|
viewModel.avatarUrl = entry.driver.avatarUrl;
|
|
}
|
|
return viewModel;
|
|
});
|
|
|
|
return {
|
|
leagueId,
|
|
standings,
|
|
totalDrivers: standings.length,
|
|
};
|
|
}
|
|
|
|
export class LeagueStandingsPresenter implements ILeagueStandingsPresenter {
|
|
private viewModel: LeagueStandingsViewModel | null = null;
|
|
|
|
reset(): void {
|
|
this.viewModel = null;
|
|
}
|
|
|
|
async present(leagueId: string): Promise<void> {
|
|
const apiResponse = await apiClient.leagues.getStandings(leagueId);
|
|
this.viewModel = transformApiResponse(leagueId, apiResponse);
|
|
}
|
|
|
|
getViewModel(): LeagueStandingsViewModel | null {
|
|
return this.viewModel;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenience function to fetch and transform standings
|
|
*/
|
|
export async function fetchLeagueStandings(leagueId: string): Promise<LeagueStandingsViewModel> {
|
|
const apiResponse = await apiClient.leagues.getStandings(leagueId);
|
|
return transformApiResponse(leagueId, apiResponse);
|
|
} |