error and load state
This commit is contained in:
@@ -1,28 +1,39 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { RaceDetailTemplate } from '@/templates/RaceDetailTemplate';
|
||||
import {
|
||||
useRaceDetail,
|
||||
useRegisterForRace,
|
||||
useWithdrawFromRace,
|
||||
useCancelRace,
|
||||
useCompleteRace,
|
||||
useReopenRace
|
||||
import {
|
||||
useRegisterForRace,
|
||||
useWithdrawFromRace,
|
||||
useCancelRace,
|
||||
useCompleteRace,
|
||||
useReopenRace
|
||||
} from '@/hooks/useRaceService';
|
||||
import { useLeagueMembership } from '@/hooks/useLeagueMembershipService';
|
||||
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
|
||||
import { LeagueMembershipUtility } from '@/lib/utilities/LeagueMembershipUtility';
|
||||
|
||||
// Shared state components
|
||||
import { useDataFetching } from '@/components/shared/hooks/useDataFetching';
|
||||
import { StateContainer } from '@/components/shared/state/StateContainer';
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
import { Flag } from 'lucide-react';
|
||||
|
||||
export function RaceDetailInteractive() {
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const raceId = params.id as string;
|
||||
const currentDriverId = useEffectiveDriverId();
|
||||
const { raceService } = useServices();
|
||||
|
||||
// Fetch data
|
||||
const { data: viewModel, isLoading, error } = useRaceDetail(raceId, currentDriverId);
|
||||
// Fetch data using new hook
|
||||
const { data: viewModel, isLoading, error, retry } = useDataFetching({
|
||||
queryKey: ['raceDetail', raceId, currentDriverId],
|
||||
queryFn: () => raceService.getRaceDetail(raceId, currentDriverId),
|
||||
});
|
||||
|
||||
// Fetch membership
|
||||
const { data: membership } = useLeagueMembership(viewModel?.league?.id || '', currentDriverId);
|
||||
|
||||
// UI State
|
||||
@@ -37,7 +48,7 @@ export function RaceDetailInteractive() {
|
||||
const reopenMutation = useReopenRace();
|
||||
|
||||
// Determine if user is owner/admin
|
||||
const isOwnerOrAdmin = membership
|
||||
const isOwnerOrAdmin = membership
|
||||
? LeagueMembershipUtility.isOwnerOrAdmin(viewModel?.league?.id || '', currentDriverId)
|
||||
: false;
|
||||
|
||||
@@ -184,34 +195,53 @@ export function RaceDetailInteractive() {
|
||||
} : undefined;
|
||||
|
||||
return (
|
||||
<RaceDetailTemplate
|
||||
viewModel={templateViewModel}
|
||||
<StateContainer
|
||||
data={viewModel}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
onBack={handleBack}
|
||||
onRegister={handleRegister}
|
||||
onWithdraw={handleWithdraw}
|
||||
onCancel={handleCancel}
|
||||
onReopen={handleReopen}
|
||||
onEndRace={handleEndRace}
|
||||
onFileProtest={handleFileProtest}
|
||||
onResultsClick={handleResultsClick}
|
||||
onStewardingClick={handleStewardingClick}
|
||||
onLeagueClick={handleLeagueClick}
|
||||
onDriverClick={handleDriverClick}
|
||||
currentDriverId={currentDriverId}
|
||||
isOwnerOrAdmin={isOwnerOrAdmin}
|
||||
showProtestModal={showProtestModal}
|
||||
setShowProtestModal={setShowProtestModal}
|
||||
showEndRaceModal={showEndRaceModal}
|
||||
setShowEndRaceModal={setShowEndRaceModal}
|
||||
mutationLoading={{
|
||||
register: registerMutation.isPending,
|
||||
withdraw: withdrawMutation.isPending,
|
||||
cancel: cancelMutation.isPending,
|
||||
reopen: reopenMutation.isPending,
|
||||
complete: completeMutation.isPending,
|
||||
retry={retry}
|
||||
config={{
|
||||
loading: { variant: 'skeleton', message: 'Loading race details...' },
|
||||
error: { variant: 'full-screen' },
|
||||
empty: {
|
||||
icon: Flag,
|
||||
title: 'Race not found',
|
||||
description: 'The race may have been cancelled or deleted',
|
||||
action: { label: 'Back to Races', onClick: handleBack }
|
||||
}
|
||||
}}
|
||||
/>
|
||||
>
|
||||
{(raceData) => (
|
||||
<RaceDetailTemplate
|
||||
viewModel={templateViewModel}
|
||||
isLoading={false}
|
||||
error={null}
|
||||
onBack={handleBack}
|
||||
onRegister={handleRegister}
|
||||
onWithdraw={handleWithdraw}
|
||||
onCancel={handleCancel}
|
||||
onReopen={handleReopen}
|
||||
onEndRace={handleEndRace}
|
||||
onFileProtest={handleFileProtest}
|
||||
onResultsClick={handleResultsClick}
|
||||
onStewardingClick={handleStewardingClick}
|
||||
onLeagueClick={handleLeagueClick}
|
||||
onDriverClick={handleDriverClick}
|
||||
currentDriverId={currentDriverId}
|
||||
isOwnerOrAdmin={isOwnerOrAdmin}
|
||||
showProtestModal={showProtestModal}
|
||||
setShowProtestModal={setShowProtestModal}
|
||||
showEndRaceModal={showEndRaceModal}
|
||||
setShowEndRaceModal={setShowEndRaceModal}
|
||||
mutationLoading={{
|
||||
register: registerMutation.isPending,
|
||||
withdraw: withdrawMutation.isPending,
|
||||
cancel: cancelMutation.isPending,
|
||||
reopen: reopenMutation.isPending,
|
||||
complete: completeMutation.isPending,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</StateContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,20 +3,36 @@
|
||||
import { useState } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { RaceResultsTemplate } from '@/templates/RaceResultsTemplate';
|
||||
import { useRaceResultsDetail, useRaceWithSOF } from '@/hooks/useRaceService';
|
||||
import { useLeagueMembership } from '@/hooks/useLeagueMembershipService';
|
||||
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
|
||||
import { LeagueRoleUtility } from '@/lib/utilities/LeagueRoleUtility';
|
||||
|
||||
// Shared state components
|
||||
import { useDataFetching } from '@/components/shared/hooks/useDataFetching';
|
||||
import { StateContainer } from '@/components/shared/state/StateContainer';
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
import { Trophy } from 'lucide-react';
|
||||
|
||||
export function RaceResultsInteractive() {
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const raceId = params.id as string;
|
||||
const currentDriverId = useEffectiveDriverId();
|
||||
const { raceResultsService, raceService } = useServices();
|
||||
|
||||
// Fetch data
|
||||
const { data: raceData, isLoading, error } = useRaceResultsDetail(raceId, currentDriverId);
|
||||
const { data: sofData } = useRaceWithSOF(raceId);
|
||||
// Fetch data using new hook
|
||||
const { data: raceData, isLoading, error, retry } = useDataFetching({
|
||||
queryKey: ['raceResultsDetail', raceId, currentDriverId],
|
||||
queryFn: () => raceResultsService.getResultsDetail(raceId, currentDriverId),
|
||||
});
|
||||
|
||||
// Fetch SOF data
|
||||
const { data: sofData } = useDataFetching({
|
||||
queryKey: ['raceWithSOF', raceId],
|
||||
queryFn: () => raceResultsService.getWithSOF(raceId),
|
||||
});
|
||||
|
||||
// Fetch membership
|
||||
const { data: membership } = useLeagueMembership(raceData?.league?.id || '', currentDriverId);
|
||||
|
||||
// UI State
|
||||
@@ -83,28 +99,47 @@ export function RaceResultsInteractive() {
|
||||
};
|
||||
|
||||
return (
|
||||
<RaceResultsTemplate
|
||||
raceTrack={raceData?.race?.track}
|
||||
raceScheduledAt={raceData?.race?.scheduledAt}
|
||||
totalDrivers={raceData?.stats.totalDrivers}
|
||||
leagueName={raceData?.league?.name}
|
||||
raceSOF={raceSOF}
|
||||
results={results}
|
||||
penalties={penalties}
|
||||
pointsSystem={raceData?.pointsSystem ?? {}}
|
||||
fastestLapTime={raceData?.fastestLapTime ?? 0}
|
||||
currentDriverId={currentDriverId}
|
||||
isAdmin={isAdmin}
|
||||
<StateContainer
|
||||
data={raceData}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
onBack={handleBack}
|
||||
onImportResults={handleImportResults}
|
||||
onPenaltyClick={handlePenaltyClick}
|
||||
importing={importing}
|
||||
importSuccess={importSuccess}
|
||||
importError={importError}
|
||||
showImportForm={showImportForm}
|
||||
setShowImportForm={setShowImportForm}
|
||||
/>
|
||||
retry={retry}
|
||||
config={{
|
||||
loading: { variant: 'skeleton', message: 'Loading race results...' },
|
||||
error: { variant: 'full-screen' },
|
||||
empty: {
|
||||
icon: Trophy,
|
||||
title: 'No results available',
|
||||
description: 'Race results will appear here once the race is completed',
|
||||
action: { label: 'Back to Race', onClick: handleBack }
|
||||
}
|
||||
}}
|
||||
>
|
||||
{(raceResultsData) => (
|
||||
<RaceResultsTemplate
|
||||
raceTrack={raceResultsData?.race?.track}
|
||||
raceScheduledAt={raceResultsData?.race?.scheduledAt}
|
||||
totalDrivers={raceResultsData?.stats.totalDrivers}
|
||||
leagueName={raceResultsData?.league?.name}
|
||||
raceSOF={raceSOF}
|
||||
results={results}
|
||||
penalties={penalties}
|
||||
pointsSystem={raceResultsData?.pointsSystem ?? {}}
|
||||
fastestLapTime={raceResultsData?.fastestLapTime ?? 0}
|
||||
currentDriverId={currentDriverId}
|
||||
isAdmin={isAdmin}
|
||||
isLoading={false}
|
||||
error={null}
|
||||
onBack={handleBack}
|
||||
onImportResults={handleImportResults}
|
||||
onPenaltyClick={handlePenaltyClick}
|
||||
importing={importing}
|
||||
importSuccess={importSuccess}
|
||||
importError={importError}
|
||||
showImportForm={showImportForm}
|
||||
setShowImportForm={setShowImportForm}
|
||||
/>
|
||||
)}
|
||||
</StateContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,30 @@
|
||||
import { useState } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { RaceStewardingTemplate, StewardingTab } from '@/templates/RaceStewardingTemplate';
|
||||
import { useRaceStewardingData } from '@/hooks/useRaceStewardingService';
|
||||
import { useLeagueMembership } from '@/hooks/useLeagueMembershipService';
|
||||
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
|
||||
import { LeagueRoleUtility } from '@/lib/utilities/LeagueRoleUtility';
|
||||
|
||||
// Shared state components
|
||||
import { useDataFetching } from '@/components/shared/hooks/useDataFetching';
|
||||
import { StateContainer } from '@/components/shared/state/StateContainer';
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
import { Gavel } from 'lucide-react';
|
||||
|
||||
export function RaceStewardingInteractive() {
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const raceId = params.id as string;
|
||||
const currentDriverId = useEffectiveDriverId();
|
||||
const { raceStewardingService } = useServices();
|
||||
|
||||
// Fetch data
|
||||
const { data: stewardingData, isLoading, error } = useRaceStewardingData(raceId, currentDriverId);
|
||||
// Fetch data using new hook
|
||||
const { data: stewardingData, isLoading, error, retry } = useDataFetching({
|
||||
queryKey: ['raceStewardingData', raceId, currentDriverId],
|
||||
queryFn: () => raceStewardingService.getRaceStewardingData(raceId, currentDriverId),
|
||||
});
|
||||
|
||||
// Fetch membership
|
||||
const { data: membership } = useLeagueMembership(stewardingData?.league?.id || '', currentDriverId);
|
||||
|
||||
// UI State
|
||||
@@ -47,15 +58,34 @@ export function RaceStewardingInteractive() {
|
||||
} : undefined;
|
||||
|
||||
return (
|
||||
<RaceStewardingTemplate
|
||||
stewardingData={templateData}
|
||||
<StateContainer
|
||||
data={stewardingData}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
onBack={handleBack}
|
||||
onReviewProtest={handleReviewProtest}
|
||||
isAdmin={isAdmin}
|
||||
activeTab={activeTab}
|
||||
setActiveTab={setActiveTab}
|
||||
/>
|
||||
retry={retry}
|
||||
config={{
|
||||
loading: { variant: 'skeleton', message: 'Loading stewarding data...' },
|
||||
error: { variant: 'full-screen' },
|
||||
empty: {
|
||||
icon: Gavel,
|
||||
title: 'No stewarding data',
|
||||
description: 'No protests or penalties for this race',
|
||||
action: { label: 'Back to Race', onClick: handleBack }
|
||||
}
|
||||
}}
|
||||
>
|
||||
{(stewardingData) => (
|
||||
<RaceStewardingTemplate
|
||||
stewardingData={templateData}
|
||||
isLoading={false}
|
||||
error={null}
|
||||
onBack={handleBack}
|
||||
onReviewProtest={handleReviewProtest}
|
||||
isAdmin={isAdmin}
|
||||
activeTab={activeTab}
|
||||
setActiveTab={setActiveTab}
|
||||
/>
|
||||
)}
|
||||
</StateContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user