This commit is contained in:
2025-12-31 19:55:43 +01:00
parent 8260bf7baf
commit 167e82a52b
66 changed files with 5124 additions and 228 deletions

View File

@@ -20,6 +20,7 @@ import { DashboardOverviewUseCase } from '@core/racing/application/use-cases/Das
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter';
import { DashboardOverviewPresenter } from './presenters/DashboardOverviewPresenter';
import { DashboardService } from './DashboardService';
// Define injection tokens
export const LOGGER_TOKEN = 'Logger';
@@ -92,4 +93,19 @@ export const DashboardProviders: Provider[] = [
DASHBOARD_OVERVIEW_OUTPUT_PORT_TOKEN,
],
},
{
provide: DashboardService,
useFactory: (
logger: Logger,
dashboardOverviewUseCase: DashboardOverviewUseCase,
presenter: DashboardOverviewPresenter,
imageService: ImageServicePort,
) => new DashboardService(logger, dashboardOverviewUseCase, presenter, imageService),
inject: [
LOGGER_TOKEN,
DASHBOARD_OVERVIEW_USE_CASE_TOKEN,
DASHBOARD_OVERVIEW_OUTPUT_PORT_TOKEN,
IMAGE_SERVICE_TOKEN,
],
},
];

View File

@@ -11,6 +11,7 @@ describe('DashboardService', () => {
{ debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } as any,
useCase as any,
presenter as any,
{ getDriverAvatar: vi.fn(() => '/media/avatar/test') } as any,
);
await expect(service.getDashboardOverview('d1')).resolves.toEqual({ feed: [] });
@@ -22,6 +23,7 @@ describe('DashboardService', () => {
{ debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } as any,
{ execute: vi.fn(async () => Result.err({ code: 'REPOSITORY_ERROR', details: { message: 'boom' } })) } as any,
{ getResponseModel: vi.fn() } as any,
{ getDriverAvatar: vi.fn(() => '/media/avatar/test') } as any,
);
await expect(service.getDashboardOverview('d1')).rejects.toThrow('Failed to get dashboard overview: boom');
@@ -32,6 +34,7 @@ describe('DashboardService', () => {
{ debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } as any,
{ execute: vi.fn(async () => Result.err({ code: 'REPOSITORY_ERROR' } as any)) } as any,
{ getResponseModel: vi.fn() } as any,
{ getDriverAvatar: vi.fn(() => '/media/avatar/test') } as any,
);
await expect(service.getDashboardOverview('d1')).rejects.toThrow('Failed to get dashboard overview: Unknown error');

View File

@@ -5,9 +5,10 @@ import { DashboardOverviewPresenter } from './presenters/DashboardOverviewPresen
// Core imports
import type { Logger } from '@core/shared/application/Logger';
import type { ImageServicePort } from '@core/media/application/ports/ImageServicePort';
// Tokens
import { DASHBOARD_OVERVIEW_USE_CASE_TOKEN, LOGGER_TOKEN, DASHBOARD_OVERVIEW_OUTPUT_PORT_TOKEN } from './DashboardProviders';
import { DASHBOARD_OVERVIEW_USE_CASE_TOKEN, LOGGER_TOKEN, DASHBOARD_OVERVIEW_OUTPUT_PORT_TOKEN, IMAGE_SERVICE_TOKEN } from './DashboardProviders';
@Injectable()
export class DashboardService {
@@ -15,11 +16,27 @@ export class DashboardService {
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
@Inject(DASHBOARD_OVERVIEW_USE_CASE_TOKEN) private readonly dashboardOverviewUseCase: DashboardOverviewUseCase,
@Inject(DASHBOARD_OVERVIEW_OUTPUT_PORT_TOKEN) private readonly presenter: DashboardOverviewPresenter,
@Inject(IMAGE_SERVICE_TOKEN) private readonly imageService: ImageServicePort,
) {}
async getDashboardOverview(driverId: string): Promise<DashboardOverviewDTO> {
this.logger.debug('[DashboardService] Getting dashboard overview:', { driverId });
// Check if this is a demo user
const isDemoUser = driverId.startsWith('demo-driver-') ||
driverId.startsWith('demo-sponsor-') ||
driverId.startsWith('demo-league-owner-') ||
driverId.startsWith('demo-league-steward-') ||
driverId.startsWith('demo-league-admin-') ||
driverId.startsWith('demo-system-owner-') ||
driverId.startsWith('demo-super-admin-');
if (isDemoUser) {
// Return mock dashboard data for demo users
this.logger.info('[DashboardService] Returning mock data for demo user', { driverId });
return await this.getMockDashboardData(driverId);
}
const result = await this.dashboardOverviewUseCase.execute({ driverId });
if (result.isErr()) {
@@ -30,4 +47,185 @@ export class DashboardService {
return this.presenter.getResponseModel();
}
private async getMockDashboardData(driverId: string): Promise<DashboardOverviewDTO> {
// Determine role from driverId prefix
const isSponsor = driverId.startsWith('demo-sponsor-');
const isLeagueOwner = driverId.startsWith('demo-league-owner-');
const isLeagueSteward = driverId.startsWith('demo-league-steward-');
const isLeagueAdmin = driverId.startsWith('demo-league-admin-');
const isSystemOwner = driverId.startsWith('demo-system-owner-');
const isSuperAdmin = driverId.startsWith('demo-super-admin-');
// Get avatar URL using the image service (same as real drivers)
const avatarUrl = this.imageService.getDriverAvatar(driverId);
// Mock sponsor dashboard
if (isSponsor) {
return {
currentDriver: null,
myUpcomingRaces: [],
otherUpcomingRaces: [],
upcomingRaces: [],
activeLeaguesCount: 0,
nextRace: null,
recentResults: [],
leagueStandingsSummaries: [],
feedSummary: {
notificationCount: 0,
items: [],
},
friends: [],
};
}
// Mock league admin/owner/steward dashboard (similar to driver but with more leagues)
if (isLeagueOwner || isLeagueSteward || isLeagueAdmin) {
const roleTitle = isLeagueOwner ? 'League Owner' : isLeagueSteward ? 'League Steward' : 'League Admin';
return {
currentDriver: {
id: driverId,
name: `Demo ${roleTitle}`,
country: 'US',
avatarUrl,
rating: 1600,
globalRank: 15,
totalRaces: 8,
wins: 3,
podiums: 5,
consistency: 90,
},
myUpcomingRaces: [],
otherUpcomingRaces: [],
upcomingRaces: [],
activeLeaguesCount: 2,
nextRace: null,
recentResults: [],
leagueStandingsSummaries: [],
feedSummary: {
notificationCount: 2,
items: [
{
id: 'feed-1',
type: 'league_update',
headline: 'New league season starting',
body: 'Your league "Demo League" is about to start a new season',
timestamp: new Date().toISOString(),
ctaLabel: 'View League',
ctaHref: '/leagues',
},
],
},
friends: [],
};
}
// Mock system owner dashboard (highest privileges)
if (isSystemOwner) {
return {
currentDriver: {
id: driverId,
name: 'System Owner',
country: 'US',
avatarUrl,
rating: 2000,
globalRank: 1,
totalRaces: 50,
wins: 25,
podiums: 40,
consistency: 95,
},
myUpcomingRaces: [],
otherUpcomingRaces: [],
upcomingRaces: [],
activeLeaguesCount: 10,
nextRace: null,
recentResults: [],
leagueStandingsSummaries: [],
feedSummary: {
notificationCount: 5,
items: [
{
id: 'feed-1',
type: 'system_alert',
headline: 'System maintenance scheduled',
body: 'Platform will undergo maintenance in 24 hours',
timestamp: new Date().toISOString(),
ctaLabel: 'View Details',
ctaHref: '/admin/system',
},
],
},
friends: [],
};
}
// Mock super admin dashboard (all access)
if (isSuperAdmin) {
return {
currentDriver: {
id: driverId,
name: 'Super Admin',
country: 'US',
avatarUrl,
rating: 1800,
globalRank: 5,
totalRaces: 30,
wins: 15,
podiums: 25,
consistency: 92,
},
myUpcomingRaces: [],
otherUpcomingRaces: [],
upcomingRaces: [],
activeLeaguesCount: 5,
nextRace: null,
recentResults: [],
leagueStandingsSummaries: [],
feedSummary: {
notificationCount: 3,
items: [
{
id: 'feed-1',
type: 'admin_notification',
headline: 'Admin dashboard access granted',
body: 'You have full administrative access to all platform features',
timestamp: new Date().toISOString(),
ctaLabel: 'Admin Panel',
ctaHref: '/admin',
},
],
},
friends: [],
};
}
// Mock driver dashboard (default)
return {
currentDriver: {
id: driverId,
name: 'John Demo',
country: 'US',
avatarUrl,
rating: 1500,
globalRank: 25,
totalRaces: 5,
wins: 2,
podiums: 3,
consistency: 85,
},
myUpcomingRaces: [],
otherUpcomingRaces: [],
upcomingRaces: [],
activeLeaguesCount: 0,
nextRace: null,
recentResults: [],
leagueStandingsSummaries: [],
feedSummary: {
notificationCount: 0,
items: [],
},
friends: [],
};
}
}