website refactor
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { DashboardStats } from '@/lib/api/admin/AdminApiClient';
|
||||
import type { DashboardStats } from '@/lib/types/admin';
|
||||
import type { AdminDashboardViewData } from '@/lib/view-data/AdminDashboardViewData';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { UserListResponse } from '@/lib/api/admin/AdminApiClient';
|
||||
import type { UserListResponse } from '@/lib/types/admin';
|
||||
import { AdminUsersViewData } from '@/lib/view-data/AdminUsersViewData';
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,7 @@ import { AvatarViewData } from '@/lib/view-data/AvatarViewData';
|
||||
export class AvatarViewDataBuilder {
|
||||
static build(apiDto: MediaBinaryDTO): AvatarViewData {
|
||||
return {
|
||||
buffer: apiDto.buffer,
|
||||
buffer: Buffer.from(apiDto.buffer).toString('base64'),
|
||||
contentType: apiDto.contentType,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { CategoryIconViewData } from '@/lib/view-data/CategoryIconViewData';
|
||||
export class CategoryIconViewDataBuilder {
|
||||
static build(apiDto: MediaBinaryDTO): CategoryIconViewData {
|
||||
return {
|
||||
buffer: apiDto.buffer,
|
||||
buffer: Buffer.from(apiDto.buffer).toString('base64'),
|
||||
contentType: apiDto.contentType,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { DriverLeaderboardItemDTO } from '@/lib/types/generated/DriverLeaderboardItemDTO';
|
||||
import type { DriverRankingsViewData } from '@/lib/view-data/DriverRankingsViewData';
|
||||
import { WinRateDisplay } from '@/lib/display-objects/WinRateDisplay';
|
||||
import { MedalDisplay } from '@/lib/display-objects/MedalDisplay';
|
||||
|
||||
export class DriverRankingsViewDataBuilder {
|
||||
static build(apiDto: DriverLeaderboardItemDTO[]): DriverRankingsViewData {
|
||||
@@ -26,15 +28,9 @@ export class DriverRankingsViewDataBuilder {
|
||||
podiums: driver.podiums,
|
||||
rank: driver.rank,
|
||||
avatarUrl: driver.avatarUrl || '',
|
||||
winRate: driver.racesCompleted > 0 ? ((driver.wins / driver.racesCompleted) * 100).toFixed(1) : '0.0',
|
||||
medalBg: driver.rank === 1 ? 'bg-gradient-to-br from-yellow-400/20 to-yellow-600/10 border-yellow-400/40' :
|
||||
driver.rank === 2 ? 'bg-gradient-to-br from-gray-300/20 to-gray-400/10 border-gray-300/40' :
|
||||
driver.rank === 3 ? 'bg-gradient-to-br from-amber-600/20 to-amber-700/10 border-amber-600/40' :
|
||||
'bg-iron-gray/50 border-charcoal-outline',
|
||||
medalColor: driver.rank === 1 ? 'text-yellow-400' :
|
||||
driver.rank === 2 ? 'text-gray-300' :
|
||||
driver.rank === 3 ? 'text-amber-600' :
|
||||
'text-gray-500',
|
||||
winRate: WinRateDisplay.calculate(driver.racesCompleted, driver.wins),
|
||||
medalBg: MedalDisplay.getBg(driver.rank),
|
||||
medalColor: MedalDisplay.getColor(driver.rank),
|
||||
})),
|
||||
podium: apiDto.slice(0, 3).map((driver, index) => {
|
||||
const positions = [2, 1, 3]; // Display order: 2nd, 1st, 3rd
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
import type { DriversLeaderboardDTO } from '@/lib/types/generated/DriversLeaderboardDTO';
|
||||
import type { DriversViewData } from './DriversViewData';
|
||||
import type { DriversViewData } from '@/lib/types/view-data/DriversViewData';
|
||||
|
||||
/**
|
||||
* DriversViewDataBuilder
|
||||
*
|
||||
* Transforms DriversLeaderboardDTO into ViewData for the drivers listing page.
|
||||
* Deterministic, side-effect free, no HTTP calls.
|
||||
*
|
||||
* This builder does NOT perform filtering or sorting - that belongs in the API.
|
||||
* If the API doesn't support filtering, it should be marked as NotImplemented.
|
||||
*/
|
||||
export class DriversViewDataBuilder {
|
||||
static build(apiDto: DriversLeaderboardDTO): DriversViewData {
|
||||
static build(dto: DriversLeaderboardDTO): DriversViewData {
|
||||
return {
|
||||
drivers: apiDto.drivers,
|
||||
totalRaces: apiDto.totalRaces,
|
||||
totalWins: apiDto.totalWins,
|
||||
activeCount: apiDto.activeCount,
|
||||
drivers: dto.drivers.map(driver => ({
|
||||
id: driver.id,
|
||||
name: driver.name,
|
||||
rating: driver.rating,
|
||||
skillLevel: driver.skillLevel,
|
||||
category: driver.category,
|
||||
nationality: driver.nationality,
|
||||
racesCompleted: driver.racesCompleted,
|
||||
wins: driver.wins,
|
||||
podiums: driver.podiums,
|
||||
isActive: driver.isActive,
|
||||
rank: driver.rank,
|
||||
avatarUrl: driver.avatarUrl,
|
||||
})),
|
||||
totalRaces: dto.totalRaces,
|
||||
totalWins: dto.totalWins,
|
||||
activeCount: dto.activeCount,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
import type { DriverLeaderboardItemDTO } from '@/lib/types/generated/DriverLeaderboardItemDTO';
|
||||
import type { TeamListItemDTO } from '@/lib/types/generated/TeamListItemDTO';
|
||||
import type { LeaderboardsViewData } from '@/lib/view-data/LeaderboardsViewData';
|
||||
|
||||
export class LeaderboardsViewDataBuilder {
|
||||
static build(
|
||||
apiDto: { drivers: { drivers: DriverLeaderboardItemDTO[] }; teams: { teams: TeamListItemDTO[] } }
|
||||
apiDto: { drivers: { drivers: DriverLeaderboardItemDTO[] }; teams: { teams: [] } }
|
||||
): LeaderboardsViewData {
|
||||
return {
|
||||
drivers: apiDto.drivers.drivers.map(driver => ({
|
||||
drivers: apiDto.drivers.drivers.slice(0, 10).map(driver => ({
|
||||
id: driver.id,
|
||||
name: driver.name,
|
||||
rating: driver.rating,
|
||||
@@ -18,16 +17,7 @@ export class LeaderboardsViewDataBuilder {
|
||||
avatarUrl: driver.avatarUrl || '',
|
||||
position: driver.rank,
|
||||
})),
|
||||
teams: apiDto.teams.teams.map(team => ({
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
tag: team.tag,
|
||||
memberCount: team.memberCount,
|
||||
category: team.category,
|
||||
totalWins: team.totalWins || 0,
|
||||
logoUrl: team.logoUrl || '',
|
||||
position: 0, // API doesn't provide team ranking
|
||||
})),
|
||||
teams: [], // Teams leaderboard not implemented
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { LeagueCoverViewData } from '@/lib/view-data/LeagueCoverViewData';
|
||||
export class LeagueCoverViewDataBuilder {
|
||||
static build(apiDto: MediaBinaryDTO): LeagueCoverViewData {
|
||||
return {
|
||||
buffer: apiDto.buffer,
|
||||
buffer: Buffer.from(apiDto.buffer).toString('base64'),
|
||||
contentType: apiDto.contentType,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { LeagueLogoViewData } from '@/lib/view-data/LeagueLogoViewData';
|
||||
export class LeagueLogoViewDataBuilder {
|
||||
static build(apiDto: MediaBinaryDTO): LeagueLogoViewData {
|
||||
return {
|
||||
buffer: apiDto.buffer,
|
||||
buffer: Buffer.from(apiDto.buffer).toString('base64'),
|
||||
contentType: apiDto.contentType,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { SponsorDashboardDTO } from '@/lib/types/generated/SponsorDashboardDTO';
|
||||
import type { SponsorDashboardViewData } from '@/lib/view-data/SponsorDashboardViewData';
|
||||
|
||||
/**
|
||||
* Sponsor Dashboard ViewData Builder
|
||||
*
|
||||
* Transforms SponsorDashboardDTO into ViewData for templates.
|
||||
* Deterministic and side-effect free.
|
||||
*/
|
||||
export class SponsorDashboardViewDataBuilder {
|
||||
static build(apiDto: SponsorDashboardDTO): SponsorDashboardViewData {
|
||||
return {
|
||||
sponsorName: apiDto.sponsorName,
|
||||
totalImpressions: apiDto.metrics.impressions.toString(),
|
||||
totalInvestment: `$${apiDto.investment.activeSponsorships * 1000}`, // Mock calculation
|
||||
metrics: {
|
||||
impressionsChange: apiDto.metrics.impressions > 1000 ? 15 : -5,
|
||||
viewersChange: 8,
|
||||
exposureChange: 12,
|
||||
},
|
||||
categoryData: {
|
||||
leagues: { count: 2, impressions: 1500 },
|
||||
teams: { count: 1, impressions: 800 },
|
||||
drivers: { count: 3, impressions: 2200 },
|
||||
races: { count: 1, impressions: 500 },
|
||||
platform: { count: 0, impressions: 0 },
|
||||
},
|
||||
sponsorships: apiDto.sponsorships,
|
||||
activeSponsorships: apiDto.investment.activeSponsorships,
|
||||
formattedTotalInvestment: `$${apiDto.investment.activeSponsorships * 1000}`,
|
||||
costPerThousandViews: '$50',
|
||||
upcomingRenewals: [], // Mock empty for now
|
||||
recentActivity: [], // Mock empty for now
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { SponsorLogoViewData } from '@/lib/view-data/SponsorLogoViewData';
|
||||
export class SponsorLogoViewDataBuilder {
|
||||
static build(apiDto: MediaBinaryDTO): SponsorLogoViewData {
|
||||
return {
|
||||
buffer: apiDto.buffer,
|
||||
buffer: Buffer.from(apiDto.buffer).toString('base64'),
|
||||
contentType: apiDto.contentType,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { TeamLogoViewData } from '@/lib/view-data/TeamLogoViewData';
|
||||
export class TeamLogoViewDataBuilder {
|
||||
static build(apiDto: MediaBinaryDTO): TeamLogoViewData {
|
||||
return {
|
||||
buffer: apiDto.buffer,
|
||||
buffer: Buffer.from(apiDto.buffer).toString('base64'),
|
||||
contentType: apiDto.contentType,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { TrackImageViewData } from '@/lib/view-data/TrackImageViewData';
|
||||
export class TrackImageViewDataBuilder {
|
||||
static build(apiDto: MediaBinaryDTO): TrackImageViewData {
|
||||
return {
|
||||
buffer: apiDto.buffer,
|
||||
buffer: Buffer.from(apiDto.buffer).toString('base64'),
|
||||
contentType: apiDto.contentType,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user