wip
This commit is contained in:
@@ -3,27 +3,6 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import Card from '@/components/ui/Card';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Breadcrumbs from '@/components/layout/Breadcrumbs';
|
||||
import {
|
||||
getRaceRepository,
|
||||
getLeagueRepository,
|
||||
getProtestRepository,
|
||||
getDriverRepository,
|
||||
getPenaltyRepository,
|
||||
getLeagueMembershipRepository,
|
||||
getReviewProtestUseCase,
|
||||
getApplyPenaltyUseCase,
|
||||
} from '@/lib/di-container';
|
||||
import { useEffectiveDriverId } from '@/lib/currentDriver';
|
||||
import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles';
|
||||
import type { Race } from '@gridpilot/racing/domain/entities/Race';
|
||||
import type { League } from '@gridpilot/racing/domain/entities/League';
|
||||
import type { Protest } from '@gridpilot/racing/domain/entities/Protest';
|
||||
import type { Penalty, PenaltyType } from '@gridpilot/racing/domain/entities/Penalty';
|
||||
import type { DriverDTO } from '@gridpilot/racing/application/dto/DriverDTO';
|
||||
import { EntityMappers } from '@gridpilot/racing/application/mappers/EntityMappers';
|
||||
import {
|
||||
AlertTriangle,
|
||||
Clock,
|
||||
@@ -40,6 +19,22 @@ import {
|
||||
Users,
|
||||
Trophy,
|
||||
} from 'lucide-react';
|
||||
import Card from '@/components/ui/Card';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Breadcrumbs from '@/components/layout/Breadcrumbs';
|
||||
import {
|
||||
getGetRaceProtestsUseCase,
|
||||
getGetRacePenaltiesUseCase,
|
||||
getRaceRepository,
|
||||
getLeagueRepository,
|
||||
getLeagueMembershipRepository,
|
||||
} from '@/lib/di-container';
|
||||
import { useEffectiveDriverId } from '@/lib/currentDriver';
|
||||
import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles';
|
||||
import type { RaceProtestViewModel } from '@gridpilot/racing/application/presenters/IRaceProtestsPresenter';
|
||||
import type { RacePenaltyViewModel } from '@gridpilot/racing/application/presenters/IRacePenaltiesPresenter';
|
||||
import type { League } from '@gridpilot/racing/domain/entities/League';
|
||||
import type { Race } from '@gridpilot/racing/domain/entities/Race';
|
||||
|
||||
export default function RaceStewardingPage() {
|
||||
const params = useParams();
|
||||
@@ -49,9 +44,8 @@ export default function RaceStewardingPage() {
|
||||
|
||||
const [race, setRace] = useState<Race | null>(null);
|
||||
const [league, setLeague] = useState<League | null>(null);
|
||||
const [protests, setProtests] = useState<Protest[]>([]);
|
||||
const [penalties, setPenalties] = useState<Penalty[]>([]);
|
||||
const [driversById, setDriversById] = useState<Record<string, DriverDTO>>({});
|
||||
const [protests, setProtests] = useState<RaceProtestViewModel[]>([]);
|
||||
const [penalties, setPenalties] = useState<RacePenaltyViewModel[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState<'pending' | 'resolved' | 'penalties'>('pending');
|
||||
@@ -62,12 +56,10 @@ export default function RaceStewardingPage() {
|
||||
try {
|
||||
const raceRepo = getRaceRepository();
|
||||
const leagueRepo = getLeagueRepository();
|
||||
const protestRepo = getProtestRepository();
|
||||
const penaltyRepo = getPenaltyRepository();
|
||||
const driverRepo = getDriverRepository();
|
||||
const membershipRepo = getLeagueMembershipRepository();
|
||||
const protestsUseCase = getGetRaceProtestsUseCase();
|
||||
const penaltiesUseCase = getGetRacePenaltiesUseCase();
|
||||
|
||||
// Get race
|
||||
const raceData = await raceRepo.findById(raceId);
|
||||
if (!raceData) {
|
||||
setLoading(false);
|
||||
@@ -75,48 +67,24 @@ export default function RaceStewardingPage() {
|
||||
}
|
||||
setRace(raceData);
|
||||
|
||||
// Get league
|
||||
const leagueData = await leagueRepo.findById(raceData.leagueId);
|
||||
setLeague(leagueData);
|
||||
|
||||
// Check admin status
|
||||
if (leagueData) {
|
||||
const membership = await membershipRepo.getMembership(leagueData.id, currentDriverId);
|
||||
const membership = await membershipRepo.getMembership(
|
||||
leagueData.id,
|
||||
currentDriverId,
|
||||
);
|
||||
setIsAdmin(membership ? isLeagueAdminOrHigherRole(membership.role) : false);
|
||||
}
|
||||
|
||||
// Get protests for this race
|
||||
const raceProtests = await protestRepo.findByRaceId(raceId);
|
||||
setProtests(raceProtests);
|
||||
await protestsUseCase.execute(raceId);
|
||||
const protestsViewModel = protestsUseCase.presenter.getViewModel();
|
||||
setProtests(protestsViewModel.protests);
|
||||
|
||||
// Get penalties for this race
|
||||
const racePenalties = await penaltyRepo.findByRaceId(raceId);
|
||||
setPenalties(racePenalties);
|
||||
|
||||
// Collect driver IDs
|
||||
const driverIds = new Set<string>();
|
||||
raceProtests.forEach((p) => {
|
||||
driverIds.add(p.protestingDriverId);
|
||||
driverIds.add(p.accusedDriverId);
|
||||
});
|
||||
racePenalties.forEach((p) => {
|
||||
driverIds.add(p.driverId);
|
||||
});
|
||||
|
||||
// Load driver info
|
||||
const driverEntities = await Promise.all(
|
||||
Array.from(driverIds).map((id) => driverRepo.findById(id))
|
||||
);
|
||||
const byId: Record<string, DriverDTO> = {};
|
||||
driverEntities.forEach((driver) => {
|
||||
if (driver) {
|
||||
const dto = EntityMappers.toDriverDTO(driver);
|
||||
if (dto) {
|
||||
byId[dto.id] = dto;
|
||||
}
|
||||
}
|
||||
});
|
||||
setDriversById(byId);
|
||||
await penaltiesUseCase.execute(raceId);
|
||||
const penaltiesViewModel = penaltiesUseCase.presenter.getViewModel();
|
||||
setPenalties(penaltiesViewModel.penalties);
|
||||
} catch (err) {
|
||||
console.error('Failed to load data:', err);
|
||||
} finally {
|
||||
@@ -128,10 +96,13 @@ export default function RaceStewardingPage() {
|
||||
}, [raceId, currentDriverId]);
|
||||
|
||||
const pendingProtests = protests.filter(
|
||||
(p) => p.status === 'pending' || p.status === 'under_review'
|
||||
(p) => p.status === 'pending' || p.status === 'under_review',
|
||||
);
|
||||
const resolvedProtests = protests.filter(
|
||||
(p) => p.status === 'upheld' || p.status === 'dismissed' || p.status === 'withdrawn'
|
||||
(p) =>
|
||||
p.status === 'upheld' ||
|
||||
p.status === 'dismissed' ||
|
||||
p.status === 'withdrawn',
|
||||
);
|
||||
|
||||
const getStatusBadge = (status: string) => {
|
||||
@@ -166,8 +137,9 @@ export default function RaceStewardingPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (date: Date) => {
|
||||
return new Date(date).toLocaleDateString('en-US', {
|
||||
const formatDate = (date: Date | string) => {
|
||||
const d = typeof date === 'string' ? new Date(date) : date;
|
||||
return d.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
|
||||
Reference in New Issue
Block a user