website refactor

This commit is contained in:
2026-01-16 01:00:03 +01:00
parent ce7be39155
commit a98e3e3166
286 changed files with 5522 additions and 5261 deletions

View File

@@ -18,9 +18,9 @@ export class AdminUsersViewDataBuilder {
roles: user.roles,
status: user.status,
isSystemAdmin: user.isSystemAdmin,
createdAt: user.createdAt.toISOString(),
updatedAt: user.updatedAt.toISOString(),
lastLoginAt: user.lastLoginAt?.toISOString(),
createdAt: typeof user.createdAt === 'string' ? user.createdAt : (user.createdAt as unknown as Date).toISOString(),
updatedAt: typeof user.updatedAt === 'string' ? user.updatedAt : (user.updatedAt as unknown as Date).toISOString(),
lastLoginAt: user.lastLoginAt ? (typeof user.lastLoginAt === 'string' ? user.lastLoginAt : (user.lastLoginAt as unknown as Date).toISOString()) : undefined,
primaryDriverId: user.primaryDriverId,
}));

View File

@@ -1,15 +0,0 @@
import type { DriverProfileDriverSummaryDTO } from '@/lib/types/generated/DriverProfileDriverSummaryDTO';
import type { DriverProfileStatsDTO } from '@/lib/types/generated/DriverProfileStatsDTO';
import type { DriverProfileFinishDistributionDTO } from '@/lib/types/generated/DriverProfileFinishDistributionDTO';
import type { DriverProfileTeamMembershipDTO } from '@/lib/types/generated/DriverProfileTeamMembershipDTO';
import type { DriverProfileSocialSummaryDTO } from '@/lib/types/generated/DriverProfileSocialSummaryDTO';
import type { DriverProfileExtendedProfileDTO } from '@/lib/types/generated/DriverProfileExtendedProfileDTO';
export interface DriverProfileViewData {
currentDriver: DriverProfileDriverSummaryDTO | null;
stats: DriverProfileStatsDTO | null;
finishDistribution: DriverProfileFinishDistributionDTO | null;
teamMemberships: DriverProfileTeamMembershipDTO[];
socialSummary: DriverProfileSocialSummaryDTO;
extendedProfile: DriverProfileExtendedProfileDTO | null;
}

View File

@@ -1,5 +1,5 @@
import type { GetDriverProfileOutputDTO } from '@/lib/types/generated/GetDriverProfileOutputDTO';
import type { DriverProfileViewData } from './DriverProfileViewData';
import type { DriverProfileViewData } from '@/lib/types/view-data/DriverProfileViewData';
/**
* DriverProfileViewDataBuilder
@@ -10,12 +10,82 @@ import type { DriverProfileViewData } from './DriverProfileViewData';
export class DriverProfileViewDataBuilder {
static build(apiDto: GetDriverProfileOutputDTO): DriverProfileViewData {
return {
currentDriver: apiDto.currentDriver || null,
stats: apiDto.stats || null,
finishDistribution: apiDto.finishDistribution || null,
teamMemberships: apiDto.teamMemberships,
socialSummary: apiDto.socialSummary,
extendedProfile: apiDto.extendedProfile || null,
currentDriver: apiDto.currentDriver ? {
id: apiDto.currentDriver.id,
name: apiDto.currentDriver.name,
country: apiDto.currentDriver.country,
avatarUrl: apiDto.currentDriver.avatarUrl || '',
iracingId: typeof apiDto.currentDriver.iracingId === 'string' ? parseInt(apiDto.currentDriver.iracingId, 10) : (apiDto.currentDriver.iracingId ?? null),
joinedAt: apiDto.currentDriver.joinedAt,
rating: apiDto.currentDriver.rating ?? null,
globalRank: apiDto.currentDriver.globalRank ?? null,
consistency: apiDto.currentDriver.consistency ?? null,
bio: apiDto.currentDriver.bio ?? null,
totalDrivers: apiDto.currentDriver.totalDrivers ?? null,
} : null,
stats: apiDto.stats ? {
totalRaces: apiDto.stats.totalRaces,
wins: apiDto.stats.wins,
podiums: apiDto.stats.podiums,
dnfs: apiDto.stats.dnfs,
avgFinish: apiDto.stats.avgFinish ?? null,
bestFinish: apiDto.stats.bestFinish ?? null,
worstFinish: apiDto.stats.worstFinish ?? null,
finishRate: apiDto.stats.finishRate ?? null,
winRate: apiDto.stats.winRate ?? null,
podiumRate: apiDto.stats.podiumRate ?? null,
percentile: apiDto.stats.percentile ?? null,
rating: apiDto.stats.rating ?? null,
consistency: apiDto.stats.consistency ?? null,
overallRank: apiDto.stats.overallRank ?? null,
} : null,
finishDistribution: apiDto.finishDistribution ? {
totalRaces: apiDto.finishDistribution.totalRaces,
wins: apiDto.finishDistribution.wins,
podiums: apiDto.finishDistribution.podiums,
topTen: apiDto.finishDistribution.topTen,
dnfs: apiDto.finishDistribution.dnfs,
other: apiDto.finishDistribution.other,
} : null,
teamMemberships: apiDto.teamMemberships.map(m => ({
teamId: m.teamId,
teamName: m.teamName,
teamTag: m.teamTag ?? null,
role: m.role,
joinedAt: m.joinedAt,
isCurrent: m.isCurrent,
})),
socialSummary: {
friendsCount: apiDto.socialSummary.friendsCount,
friends: apiDto.socialSummary.friends.map(f => ({
id: f.id,
name: f.name,
country: f.country,
avatarUrl: f.avatarUrl || '',
})),
},
extendedProfile: apiDto.extendedProfile ? {
socialHandles: apiDto.extendedProfile.socialHandles.map(h => ({
platform: h.platform,
handle: h.handle,
url: h.url,
})),
achievements: apiDto.extendedProfile.achievements.map(a => ({
id: a.id,
title: a.title,
description: a.description,
icon: a.icon,
rarity: a.rarity,
earnedAt: a.earnedAt,
})),
racingStyle: apiDto.extendedProfile.racingStyle,
favoriteTrack: apiDto.extendedProfile.favoriteTrack,
favoriteCar: apiDto.extendedProfile.favoriteCar,
timezone: apiDto.extendedProfile.timezone,
availableHours: apiDto.extendedProfile.availableHours,
lookingForTeam: apiDto.extendedProfile.lookingForTeam,
openToRequests: apiDto.extendedProfile.openToRequests,
} : null,
};
}
}

View File

@@ -1,9 +0,0 @@
import type { DriversLeaderboardDTO } from '@/lib/types/generated/DriversLeaderboardDTO';
import type { DriverLeaderboardItemDTO } from '@/lib/types/generated/DriverLeaderboardItemDTO';
export interface DriversViewData {
drivers: DriverLeaderboardItemDTO[];
totalRaces: number;
totalWins: number;
activeCount: number;
}

View File

@@ -37,7 +37,7 @@ export class LeagueDetailViewDataBuilder {
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)
? Math.round(races.reduce((sum, _r) => sum + 0, 0) / races.length)
: null;
const info: LeagueInfoData = {

View File

@@ -5,9 +5,11 @@ export class LeagueSponsorshipsViewDataBuilder {
static build(apiDto: LeagueSponsorshipsApiDto): LeagueSponsorshipsViewData {
return {
leagueId: apiDto.leagueId,
activeTab: 'overview',
onTabChange: () => {},
league: apiDto.league,
sponsorshipSlots: apiDto.sponsorshipSlots,
sponsorshipRequests: apiDto.sponsorshipRequests,
};
}
}
}

View File

@@ -1,13 +1,29 @@
import { LeagueWalletViewData } from '@/lib/view-data/leagues/LeagueWalletViewData';
import { LeagueWalletViewData, LeagueWalletTransactionViewData } from '@/lib/view-data/leagues/LeagueWalletViewData';
import { LeagueWalletApiDto } from '@/lib/types/tbd/LeagueWalletApiDto';
export class LeagueWalletViewDataBuilder {
static build(apiDto: LeagueWalletApiDto): LeagueWalletViewData {
const transactions: LeagueWalletTransactionViewData[] = apiDto.transactions.map(t => ({
...t,
formattedAmount: `${t.amount} ${apiDto.currency}`,
amountColor: t.amount >= 0 ? 'green' : 'red',
formattedDate: new Date(t.createdAt).toLocaleDateString(),
statusColor: t.status === 'completed' ? 'green' : t.status === 'pending' ? 'yellow' : 'red',
typeColor: 'blue',
}));
return {
leagueId: apiDto.leagueId,
balance: apiDto.balance,
formattedBalance: `${apiDto.balance} ${apiDto.currency}`,
totalRevenue: apiDto.balance, // Mock
formattedTotalRevenue: `${apiDto.balance} ${apiDto.currency}`,
totalFees: 0, // Mock
formattedTotalFees: `0 ${apiDto.currency}`,
pendingPayouts: 0, // Mock
formattedPendingPayouts: `0 ${apiDto.currency}`,
currency: apiDto.currency,
transactions: apiDto.transactions,
transactions,
};
}
}
}

View File

@@ -7,7 +7,7 @@ import { RaceResultsViewData, RaceResultsResult, RaceResultsPenalty } from '@/li
* Deterministic, side-effect free.
*/
export class RaceResultsViewDataBuilder {
static build(apiDto: any): RaceResultsViewData {
static build(apiDto: unknown): RaceResultsViewData {
if (!apiDto) {
return {
raceSOF: null,
@@ -18,8 +18,11 @@ export class RaceResultsViewDataBuilder {
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const dto = apiDto as any;
// Transform results
const results: RaceResultsResult[] = (apiDto.results || []).map((result: any) => ({
const results: RaceResultsResult[] = (dto.results || []).map((result: any) => ({
position: result.position,
driverId: result.driverId,
driverName: result.driverName,
@@ -35,7 +38,7 @@ export class RaceResultsViewDataBuilder {
}));
// Transform penalties
const penalties: RaceResultsPenalty[] = (apiDto.penalties || []).map((penalty: any) => ({
const penalties: RaceResultsPenalty[] = (dto.penalties || []).map((penalty: any) => ({
driverId: penalty.driverId,
driverName: penalty.driverName || 'Unknown',
type: penalty.type as 'time_penalty' | 'grid_penalty' | 'points_deduction' | 'disqualification' | 'warning' | 'license_points',
@@ -45,15 +48,15 @@ export class RaceResultsViewDataBuilder {
}));
return {
raceTrack: apiDto.race?.track,
raceScheduledAt: apiDto.race?.scheduledAt,
totalDrivers: apiDto.stats?.totalDrivers,
leagueName: apiDto.league?.name,
raceSOF: apiDto.strengthOfField || null,
raceTrack: dto.race?.track,
raceScheduledAt: dto.race?.scheduledAt,
totalDrivers: dto.stats?.totalDrivers,
leagueName: dto.league?.name,
raceSOF: dto.strengthOfField || null,
results,
penalties,
pointsSystem: apiDto.pointsSystem || {},
fastestLapTime: apiDto.fastestLapTime || 0,
pointsSystem: dto.pointsSystem || {},
fastestLapTime: dto.fastestLapTime || 0,
};
}
}

View File

@@ -7,7 +7,7 @@ import { RaceStewardingViewData, Protest, Penalty, Driver } from '@/lib/view-dat
* Deterministic, side-effect free.
*/
export class RaceStewardingViewDataBuilder {
static build(apiDto: any): RaceStewardingViewData {
static build(apiDto: unknown): RaceStewardingViewData {
if (!apiDto) {
return {
race: null,
@@ -22,17 +22,20 @@ export class RaceStewardingViewDataBuilder {
};
}
const race = apiDto.race ? {
id: apiDto.race.id,
track: apiDto.race.track,
scheduledAt: apiDto.race.scheduledAt,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const dto = apiDto as any;
const race = dto.race ? {
id: dto.race.id,
track: dto.race.track,
scheduledAt: dto.race.scheduledAt,
} : null;
const league = apiDto.league ? {
id: apiDto.league.id,
const league = dto.league ? {
id: dto.league.id,
} : null;
const pendingProtests: Protest[] = (apiDto.pendingProtests || []).map((p: any) => ({
const pendingProtests: Protest[] = (dto.pendingProtests || []).map((p: any) => ({
id: p.id,
protestingDriverId: p.protestingDriverId,
accusedDriverId: p.accusedDriverId,
@@ -46,7 +49,7 @@ export class RaceStewardingViewDataBuilder {
decisionNotes: p.decisionNotes,
}));
const resolvedProtests: Protest[] = (apiDto.resolvedProtests || []).map((p: any) => ({
const resolvedProtests: Protest[] = (dto.resolvedProtests || []).map((p: any) => ({
id: p.id,
protestingDriverId: p.protestingDriverId,
accusedDriverId: p.accusedDriverId,
@@ -60,7 +63,7 @@ export class RaceStewardingViewDataBuilder {
decisionNotes: p.decisionNotes,
}));
const penalties: Penalty[] = (apiDto.penalties || []).map((p: any) => ({
const penalties: Penalty[] = (dto.penalties || []).map((p: any) => ({
id: p.id,
driverId: p.driverId,
type: p.type,
@@ -69,7 +72,7 @@ export class RaceStewardingViewDataBuilder {
notes: p.notes,
}));
const driverMap: Record<string, Driver> = apiDto.driverMap || {};
const driverMap: Record<string, Driver> = dto.driverMap || {};
return {
race,
@@ -78,9 +81,9 @@ export class RaceStewardingViewDataBuilder {
resolvedProtests,
penalties,
driverMap,
pendingCount: apiDto.pendingCount || pendingProtests.length,
resolvedCount: apiDto.resolvedCount || resolvedProtests.length,
penaltiesCount: apiDto.penaltiesCount || penalties.length,
pendingCount: dto.pendingCount || pendingProtests.length,
resolvedCount: dto.resolvedCount || resolvedProtests.length,
penaltiesCount: dto.penaltiesCount || penalties.length,
};
}
}

View File

@@ -1,4 +1,4 @@
import { RacesAllViewData, RacesAllRace } from '@/lib/view-data/races/RacesAllViewData';
import { RacesAllViewData } from '@/lib/view-data/races/RacesAllViewData';
/**
* Races All View Data Builder

View File

@@ -1,4 +1,4 @@
import type { TeamDetailPageDto } from '@/lib/page-queries/page-queries/TeamDetailPageQuery';
import type { TeamDetailPageDto } from '@/lib/page-queries/TeamDetailPageQuery';
import type { TeamDetailViewData, TeamDetailData, TeamMemberData, SponsorMetric, TeamTab } from '@/lib/view-data/TeamDetailViewData';
import { Users, Zap, Calendar } from 'lucide-react';

View File

@@ -1,5 +1,6 @@
import type { TeamsPageDto } from '@/lib/page-queries/page-queries/TeamsPageQuery';
import type { TeamsPageDto } from '@/lib/page-queries/TeamsPageQuery';
import type { TeamsViewData, TeamSummaryData } from '@/lib/view-data/TeamsViewData';
import type { TeamListItemDTO } from '@/lib/types/generated/TeamListItemDTO';
/**
* TeamsViewDataBuilder - Transforms TeamsPageDto into ViewData for TeamsTemplate
@@ -7,7 +8,7 @@ import type { TeamsViewData, TeamSummaryData } from '@/lib/view-data/TeamsViewDa
*/
export class TeamsViewDataBuilder {
static build(apiDto: TeamsPageDto): TeamsViewData {
const teams: TeamSummaryData[] = apiDto.teams.map((team): TeamSummaryData => ({
const teams: TeamSummaryData[] = apiDto.teams.map((team: TeamListItemDTO): TeamSummaryData => ({
teamId: team.id,
teamName: team.name,
leagueName: team.leagues[0] || '',
@@ -17,4 +18,4 @@ export class TeamsViewDataBuilder {
return { teams };
}
}
}