refactor page to use services

This commit is contained in:
2025-12-18 15:58:09 +01:00
parent f54fa5de5b
commit fc386db06a
45 changed files with 2254 additions and 1292 deletions

View File

@@ -8,13 +8,10 @@ import Button from '@/components/ui/Button';
import Card from '@/components/ui/Card';
import Heading from '@/components/ui/Heading';
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
import { apiClient } from '@/lib/apiClient';
import { getMembership, isOwnerOrAdmin } from '@/lib/leagueMembership';
import type {
RaceDetailEntryViewModel,
RaceDetailUserResultViewModel,
RaceDetailViewModel,
} from '@core/racing/application/presenters/IRaceDetailPresenter';
import { ServiceFactory } from '@/lib/services/ServiceFactory';
import { LeagueMembershipService } from '@/lib/services/leagues/LeagueMembershipService';
import { LeagueMembershipUtility } from '@/lib/utilities/LeagueMembershipUtility';
import type { RaceDetailViewModel } from '@/lib/view-models/RaceDetailViewModel';
import {
AlertTriangle,
ArrowLeft,
@@ -60,15 +57,15 @@ export default function RaceDetailPage() {
setLoading(true);
setError(null);
try {
const vm = await apiClient.races.getDetail(raceId, currentDriverId);
if (!vm) {
throw new Error('Race detail not available');
}
const serviceFactory = new ServiceFactory(process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001');
const raceService = serviceFactory.createRaceService();
const vm = await raceService.getRaceDetail(raceId, currentDriverId);
setViewModel(vm);
// Fetch league membership for admin controls
if (vm.league) {
const leagueMembership = getMembership(vm.league.id, currentDriverId);
await LeagueMembershipService.fetchLeagueMemberships(vm.league.id);
const leagueMembership = LeagueMembershipService.getMembership(vm.league.id, currentDriverId);
setMembership(leagueMembership);
}
@@ -126,7 +123,9 @@ export default function RaceDetailPage() {
setCancelling(true);
try {
await apiClient.races.cancel(race.id);
const serviceFactory = new ServiceFactory(process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001');
const raceService = serviceFactory.createRaceService();
await raceService.cancelRace(race.id);
await loadRaceData();
} catch (err) {
alert(err instanceof Error ? err.message : 'Failed to cancel race');
@@ -148,10 +147,9 @@ export default function RaceDetailPage() {
setRegistering(true);
try {
await apiClient.races.register(race.id, {
leagueId: league.id,
driverId: currentDriverId,
});
const serviceFactory = new ServiceFactory(process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001');
const raceService = serviceFactory.createRaceService();
await raceService.registerForRace(race.id, league.id, currentDriverId);
await loadRaceData();
} catch (err) {
alert(err instanceof Error ? err.message : 'Failed to register for race');
@@ -173,9 +171,9 @@ export default function RaceDetailPage() {
setRegistering(true);
try {
await apiClient.races.withdraw(race.id, {
driverId: currentDriverId,
});
const serviceFactory = new ServiceFactory(process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001');
const raceService = serviceFactory.createRaceService();
await raceService.withdrawFromRace(race.id, currentDriverId);
await loadRaceData();
} catch (err) {
alert(err instanceof Error ? err.message : 'Failed to withdraw from race');
@@ -894,7 +892,7 @@ export default function RaceDetailPage() {
<Scale className="w-4 h-4" />
Stewarding
</Button>
{membership && isOwnerOrAdmin(viewModel.league?.id || '', currentDriverId) && (
{LeagueMembershipUtility.isOwnerOrAdmin(viewModel.league?.id || '', currentDriverId) && (
<>
<Button
variant="outline"
@@ -917,7 +915,7 @@ export default function RaceDetailPage() {
</>
)}
{race.status === 'running' && membership && isOwnerOrAdmin(viewModel.league?.id || '', currentDriverId) && (
{race.status === 'running' && LeagueMembershipUtility.isOwnerOrAdmin(viewModel.league?.id || '', currentDriverId) && (
<Button
variant="primary"
className="w-full flex items-center justify-center gap-2"
@@ -975,7 +973,9 @@ export default function RaceDetailPage() {
raceName={race.track}
onConfirm={async () => {
try {
await apiClient.races.complete(race.id);
const serviceFactory = new ServiceFactory(process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001');
const raceService = serviceFactory.createRaceService();
await raceService.completeRace(race.id);
await loadRaceData();
setShowEndRaceModal(false);
} catch (err) {