error and load state

This commit is contained in:
2026-01-06 11:05:16 +01:00
parent 4a1bfa57a3
commit 6aad7897db
29 changed files with 5172 additions and 1462 deletions

View File

@@ -1,14 +1,23 @@
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { DriversTemplate } from '@/templates/DriversTemplate';
import { useDriverLeaderboard } from '@/hooks/useDriverService';
import { DriverLeaderboardItemViewModel } from '@/lib/view-models/DriverLeaderboardItemViewModel';
// Shared state components
import { useDataFetching } from '@/components/shared/hooks/useDataFetching';
import { StateContainer } from '@/components/shared/state/StateContainer';
import { useServices } from '@/lib/services/ServiceProvider';
import { Users } from 'lucide-react';
export function DriversInteractive() {
const router = useRouter();
const { data: viewModel, isLoading: loading } = useDriverLeaderboard();
const { driverService } = useServices();
const { data: viewModel, isLoading: loading, error, retry } = useDataFetching({
queryKey: ['driverLeaderboard'],
queryFn: () => driverService.getDriverLeaderboard(),
});
const drivers = viewModel?.drivers || [];
const totalRaces = viewModel?.totalRaces || 0;
@@ -16,17 +25,35 @@ export function DriversInteractive() {
const activeCount = viewModel?.activeCount || 0;
// Transform data for template
const driverViewModels = drivers.map((driver, index) =>
const driverViewModels = drivers.map((driver, index) =>
new DriverLeaderboardItemViewModel(driver, index + 1)
);
return (
<DriversTemplate
drivers={driverViewModels}
totalRaces={totalRaces}
totalWins={totalWins}
activeCount={activeCount}
<StateContainer
data={viewModel}
isLoading={loading}
/>
error={error}
retry={retry}
config={{
loading: { variant: 'skeleton', message: 'Loading driver leaderboard...' },
error: { variant: 'inline' },
empty: {
icon: Users,
title: 'No drivers found',
description: 'There are no drivers in the system yet',
}
}}
>
{(leaderboardData) => (
<DriversTemplate
drivers={driverViewModels}
totalRaces={totalRaces}
totalWins={totalWins}
activeCount={activeCount}
isLoading={false}
/>
)}
</StateContainer>
);
}
}

View File

@@ -1,12 +1,16 @@
'use client';
import { useState, useEffect } from 'react';
import { useState } from 'react';
import { useParams, useRouter } from 'next/navigation';
import { DriverProfileTemplate } from '@/templates/DriverProfileTemplate';
import { useServices } from '@/lib/services/ServiceProvider';
import { DriverProfileViewModel } from '@/lib/view-models/DriverProfileViewModel';
import SponsorInsightsCard, { useSponsorMode, MetricBuilders, SlotTemplates } from '@/components/sponsors/SponsorInsightsCard';
// Shared state components
import { useDataFetching } from '@/components/shared/hooks/useDataFetching';
import { StateContainer } from '@/components/shared/state/StateContainer';
import { Car } from 'lucide-react';
interface Team {
id: string;
name: string;
@@ -24,34 +28,23 @@ export function DriverProfileInteractive() {
const driverId = params.id as string;
const { driverService, teamService } = useServices();
const [driverProfile, setDriverProfile] = useState<DriverProfileViewModel | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [activeTab, setActiveTab] = useState<'overview' | 'stats'>('overview');
const [allTeamMemberships, setAllTeamMemberships] = useState<TeamMembershipInfo[]>([]);
const [friendRequestSent, setFriendRequestSent] = useState(false);
const isSponsorMode = useSponsorMode();
useEffect(() => {
loadDriver();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [driverId]);
// Fetch driver profile
const { data: driverProfile, isLoading, error, retry } = useDataFetching({
queryKey: ['driverProfile', driverId],
queryFn: () => driverService.getDriverProfile(driverId),
});
const loadDriver = async () => {
try {
// Get driver profile
const profileViewModel = await driverService.getDriverProfile(driverId);
if (!profileViewModel.currentDriver) {
setError('Driver not found');
setLoading(false);
return;
}
setDriverProfile(profileViewModel);
// Load team memberships - get all teams and check memberships
// Fetch team memberships
const { data: allTeamMemberships } = useDataFetching({
queryKey: ['driverTeamMemberships', driverId],
queryFn: async () => {
if (!driverProfile?.currentDriver) return [];
const allTeams = await teamService.getAllTeams();
const memberships: TeamMembershipInfo[] = [];
@@ -69,13 +62,10 @@ export function DriverProfileInteractive() {
});
}
}
setAllTeamMemberships(memberships);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load driver');
} finally {
setLoading(false);
}
};
return memberships;
},
enabled: !!driverProfile?.currentDriver,
});
const handleAddFriend = () => {
setFriendRequestSent(true);
@@ -110,23 +100,38 @@ export function DriverProfileInteractive() {
/>
) : null;
if (!driverProfile) {
return null;
}
return (
<DriverProfileTemplate
driverProfile={driverProfile}
allTeamMemberships={allTeamMemberships}
isLoading={loading}
<StateContainer
data={driverProfile}
isLoading={isLoading}
error={error}
onBackClick={handleBackClick}
onAddFriend={handleAddFriend}
friendRequestSent={friendRequestSent}
activeTab={activeTab}
setActiveTab={setActiveTab}
isSponsorMode={isSponsorMode}
sponsorInsights={sponsorInsights}
/>
retry={retry}
config={{
loading: { variant: 'skeleton', message: 'Loading driver profile...' },
error: { variant: 'full-screen' },
empty: {
icon: Car,
title: 'Driver not found',
description: 'The driver profile may not exist or you may not have access',
action: { label: 'Back to Drivers', onClick: handleBackClick }
}
}}
>
{(profileData) => (
<DriverProfileTemplate
driverProfile={profileData}
allTeamMemberships={allTeamMemberships || []}
isLoading={false}
error={null}
onBackClick={handleBackClick}
onAddFriend={handleAddFriend}
friendRequestSent={friendRequestSent}
activeTab={activeTab}
setActiveTab={setActiveTab}
isSponsorMode={isSponsorMode}
sponsorInsights={sponsorInsights}
/>
)}
</StateContainer>
);
}
}