website refactor
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { UserDto } from '@/lib/api/admin/AdminApiClient';
|
||||
import type { UserDto } from '@/lib/types/admin';
|
||||
|
||||
/**
|
||||
* AdminUserViewModel
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import type { UserDto, DashboardStats, UserListResponse } from '@/lib/api/admin/AdminApiClient';
|
||||
import { AdminUserViewModel, DashboardStatsViewModel, UserListViewModel } from './AdminUserViewModel';
|
||||
|
||||
/**
|
||||
* AdminViewModelPresenter
|
||||
*
|
||||
* Presenter layer for transforming API DTOs to ViewModels.
|
||||
* Runs in client code only ('use client').
|
||||
* Deterministic, side-effect free transformations.
|
||||
*/
|
||||
export class AdminViewModelPresenter {
|
||||
/**
|
||||
* Map a single user DTO to a View Model
|
||||
*/
|
||||
static mapUser(apiDto: UserDto): AdminUserViewModel {
|
||||
return new AdminUserViewModel(apiDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map an array of user DTOs to View Models
|
||||
*/
|
||||
static mapUsers(apiDtos: UserDto[]): AdminUserViewModel[] {
|
||||
return apiDtos.map(apiDto => this.mapUser(apiDto));
|
||||
}
|
||||
|
||||
/**
|
||||
* Map dashboard stats DTO to View Model
|
||||
*/
|
||||
static mapDashboardStats(apiDto: DashboardStats): DashboardStatsViewModel {
|
||||
return new DashboardStatsViewModel(apiDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map user list response to View Model
|
||||
*/
|
||||
static mapUserList(viewData: UserListResponse): UserListViewModel {
|
||||
return new UserListViewModel({
|
||||
users: viewData.users,
|
||||
total: viewData.total,
|
||||
page: viewData.page,
|
||||
limit: viewData.limit,
|
||||
totalPages: viewData.totalPages,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
import type { LeagueMembershipsViewModel } from './LeagueMembershipsViewModel';
|
||||
import type { RaceResultsDetailViewModel } from './RaceResultsDetailViewModel';
|
||||
import type { RaceWithSOFViewModel } from './RaceWithSOFViewModel';
|
||||
|
||||
// TODO fucking violating our architecture, it should be a ViewModel
|
||||
|
||||
export interface TransformedRaceResultsData {
|
||||
raceTrack?: string;
|
||||
raceScheduledAt?: string;
|
||||
totalDrivers?: number;
|
||||
leagueName?: string;
|
||||
raceSOF: number | null;
|
||||
results: Array<{
|
||||
position: number;
|
||||
driverId: string;
|
||||
driverName: string;
|
||||
driverAvatar: string;
|
||||
country: string;
|
||||
car: string;
|
||||
laps: number;
|
||||
time: string;
|
||||
fastestLap: string;
|
||||
points: number;
|
||||
incidents: number;
|
||||
isCurrentUser: boolean;
|
||||
}>;
|
||||
penalties: Array<{
|
||||
driverId: string;
|
||||
driverName: string;
|
||||
type: 'time_penalty' | 'grid_penalty' | 'points_deduction' | 'disqualification' | 'warning' | 'license_points';
|
||||
value: number;
|
||||
reason: string;
|
||||
notes?: string;
|
||||
}>;
|
||||
pointsSystem: Record<string, number>;
|
||||
fastestLapTime: number;
|
||||
memberships?: Array<{
|
||||
driverId: string;
|
||||
role: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export class RaceResultsDataTransformer {
|
||||
static transform(
|
||||
resultsData: RaceResultsDetailViewModel | null,
|
||||
sofData: RaceWithSOFViewModel | null,
|
||||
currentDriverId: string,
|
||||
membershipsData?: LeagueMembershipsViewModel
|
||||
): TransformedRaceResultsData {
|
||||
if (!resultsData) {
|
||||
return {
|
||||
raceSOF: null,
|
||||
results: [],
|
||||
penalties: [],
|
||||
pointsSystem: {},
|
||||
fastestLapTime: 0,
|
||||
};
|
||||
}
|
||||
|
||||
// Transform results
|
||||
const results = resultsData.results.map((result) => ({
|
||||
position: result.position,
|
||||
driverId: result.driverId,
|
||||
driverName: result.driverName,
|
||||
driverAvatar: result.avatarUrl,
|
||||
country: 'US', // Default since view model doesn't have car
|
||||
car: 'Unknown', // Default since view model doesn't have car
|
||||
laps: 0, // Default since view model doesn't have laps
|
||||
time: '0:00.00', // Default since view model doesn't have time
|
||||
fastestLap: result.fastestLap.toString(), // Convert number to string
|
||||
points: 0, // Default since view model doesn't have points
|
||||
incidents: result.incidents,
|
||||
isCurrentUser: result.driverId === currentDriverId,
|
||||
}));
|
||||
|
||||
// Transform penalties
|
||||
const penalties = resultsData.penalties.map((penalty) => ({
|
||||
driverId: penalty.driverId,
|
||||
driverName: resultsData.results.find((r) => r.driverId === penalty.driverId)?.driverName || 'Unknown',
|
||||
type: penalty.type as 'time_penalty' | 'grid_penalty' | 'points_deduction' | 'disqualification' | 'warning' | 'license_points',
|
||||
value: penalty.value || 0,
|
||||
reason: 'Penalty applied', // Default since view model doesn't have reason
|
||||
notes: undefined, // Default since view model doesn't have notes
|
||||
}));
|
||||
|
||||
// Transform memberships
|
||||
const memberships = membershipsData?.memberships.map((membership) => ({
|
||||
driverId: membership.driverId,
|
||||
role: membership.role || 'member',
|
||||
}));
|
||||
|
||||
return {
|
||||
raceTrack: resultsData.race?.track,
|
||||
raceScheduledAt: resultsData.race?.scheduledAt,
|
||||
totalDrivers: resultsData.stats?.totalDrivers,
|
||||
leagueName: resultsData.league?.name,
|
||||
raceSOF: sofData?.strengthOfField || null,
|
||||
results,
|
||||
penalties,
|
||||
pointsSystem: resultsData.pointsSystem || {},
|
||||
fastestLapTime: resultsData.fastestLapTime || 0,
|
||||
memberships,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -87,5 +87,3 @@ export * from './UploadMediaViewModel';
|
||||
export * from './UserProfileViewModel';
|
||||
export * from './WalletTransactionViewModel';
|
||||
export * from './WalletViewModel';
|
||||
|
||||
export * from './AdminViewModelPresenter';
|
||||
Reference in New Issue
Block a user