Files
gridpilot.gg/apps/website/lib/page-queries/TeamDetailPageQuery.ts
2026-01-17 22:55:03 +01:00

116 lines
3.8 KiB
TypeScript

import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
import { Result } from '@/lib/contracts/Result';
import { TeamService } from '@/lib/services/teams/TeamService';
import { TeamDetailViewDataBuilder } from '@/lib/builders/view-data/TeamDetailViewDataBuilder';
import type { TeamDetailViewData } from '@/lib/view-data/TeamDetailViewData';
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
import { SessionGateway } from '@/lib/gateways/SessionGateway';
import type { TeamMemberViewModel } from '@/lib/view-models/TeamMemberViewModel';
/**
* TeamDetailPageDto - Raw serializable data for team detail page
* Contains only raw data, no derived/computed properties
*/
export interface TeamDetailPageDto {
team: {
id: string;
name: string;
tag: string;
description?: string;
ownerId: string;
leagues: string[];
createdAt?: string;
specialization?: string;
region?: string;
languages?: string[];
category?: string;
membership?: {
role: string;
joinedAt: string;
isActive: boolean;
} | null;
canManage: boolean;
};
memberships: Array<{
driverId: string;
driverName: string;
role: 'owner' | 'manager' | 'member';
joinedAt: string;
isActive: boolean;
avatarUrl: string;
}>;
currentDriverId: string;
}
/**
* TeamDetailPageQuery - Server-side composition for team detail page
*/
export class TeamDetailPageQuery implements PageQuery<TeamDetailViewData, string> {
async execute(teamId: string): Promise<Result<TeamDetailViewData, PresentationError>> {
// Get session to determine current driver (optional for public view)
const sessionGateway = new SessionGateway();
const session = await sessionGateway.getSession();
const currentDriverId = session?.user?.primaryDriverId || '';
const service = new TeamService();
// Fetch team details
const teamResult = await service.getTeamDetails(teamId, currentDriverId);
if (teamResult.isErr()) {
return Result.err(mapToPresentationError(teamResult.getError()));
}
const teamData = teamResult.unwrap();
// Fetch team members
const membersResult = await service.getTeamMembers(teamId, currentDriverId, teamData.team.ownerId);
if (membersResult.isErr()) {
return Result.err(mapToPresentationError(membersResult.getError()));
}
const membersData = membersResult.unwrap();
// Transform to raw serializable DTO
const dto: TeamDetailPageDto = {
team: {
id: teamData.team.id,
name: teamData.team.name,
tag: teamData.team.tag,
description: teamData.team.description,
ownerId: teamData.team.ownerId,
leagues: teamData.team.leagues,
createdAt: teamData.team.createdAt,
specialization: (teamData.team as any).specialization,
region: (teamData.team as any).region,
languages: (teamData.team as any).languages,
category: teamData.team.category,
membership: teamData.membership ? {
role: teamData.membership.role,
joinedAt: teamData.membership.joinedAt,
isActive: teamData.membership.isActive,
} : null,
canManage: teamData.canManage,
},
memberships: membersData.map((member: TeamMemberViewModel) => ({
driverId: member.driverId,
driverName: member.driverName,
role: member.role,
joinedAt: member.joinedAt,
isActive: member.isActive,
avatarUrl: member.avatarUrl,
})),
currentDriverId,
};
const viewData = TeamDetailViewDataBuilder.build(dto);
return Result.ok(viewData);
}
static async execute(teamId: string): Promise<Result<TeamDetailViewData, PresentationError>> {
const query = new TeamDetailPageQuery();
return query.execute(teamId);
}
}