Files
gridpilot.gg/apps/website/components/drivers/DriverProfile.tsx
2026-01-15 19:55:46 +01:00

178 lines
6.0 KiB
TypeScript

'use client';
import type { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { Card } from '@/ui/Card';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/Stack';
import { StatCard } from '@/ui/StatCard';
import { ProfileHeader } from '@/components/drivers/ProfileHeader';
import { ProfileStats } from './ProfileStats';
import { CareerHighlights } from '@/ui/CareerHighlights';
import { DriverRankings } from '@/components/drivers/DriverRankings';
import { PerformanceMetrics } from '@/ui/PerformanceMetrics';
import { useDriverProfile } from "@/hooks/driver/useDriverProfile";
interface DriverProfileProps {
driver: DriverViewModel;
isOwnProfile?: boolean;
onEditClick?: () => void;
}
interface DriverTeamViewModel {
team: {
name: string;
tag: string;
};
}
export function DriverProfile({ driver, isOwnProfile = false, onEditClick }: DriverProfileProps) {
const { data: profileData } = useDriverProfile(driver.id);
// Extract team data from profile
const teamData: DriverTeamViewModel | null = (() => {
if (!profileData?.teamMemberships || profileData.teamMemberships.length === 0) {
return null;
}
const currentTeam = profileData.teamMemberships.find((m: { isCurrent: boolean }) => m.isCurrent) || profileData.teamMemberships[0];
if (!currentTeam) {
return null;
}
return {
team: {
name: currentTeam.teamName,
tag: currentTeam.teamTag ?? ''
}
};
})();
const driverStats = profileData?.stats ?? null;
const globalRank = driverStats?.overallRank ?? null;
const totalDrivers = 1000; // Placeholder
const performanceStats = driverStats ? {
winRate: driverStats.totalRaces > 0 ? (driverStats.wins / driverStats.totalRaces) * 100 : 0,
podiumRate: driverStats.totalRaces > 0 ? (driverStats.podiums / driverStats.totalRaces) * 100 : 0,
dnfRate: driverStats.totalRaces > 0 ? (driverStats.dnfs / driverStats.totalRaces) * 100 : 0,
avgFinish: driverStats.avgFinish ?? 0,
consistency: driverStats.consistency ?? 0,
bestFinish: driverStats.bestFinish ?? 0,
worstFinish: driverStats.worstFinish ?? 0,
} : null;
const rankings = driverStats ? [
{
type: 'overall' as const,
name: 'Overall Ranking',
rank: globalRank ?? driverStats.overallRank ?? 0,
totalDrivers,
percentile: driverStats.percentile ?? 0,
rating: driverStats.rating ?? 0,
},
] : [];
return (
<Stack gap={6}>
<Card>
<ProfileHeader
driver={driver}
rating={driverStats?.rating ?? null}
rank={driverStats?.overallRank ?? null}
isOwnProfile={isOwnProfile}
onEditClick={onEditClick ?? (() => {})}
teamName={teamData?.team.name ?? null}
teamTag={teamData?.team.tag ?? null}
/>
</Card>
{driver.bio && (
<Card>
<Heading level={3} mb={4}>About</Heading>
<Text color="text-gray-300" leading="relaxed" block>{driver.bio}</Text>
</Card>
)}
{driverStats && (
<Box display="grid" responsiveGridCols={{ base: 1, lg: 3 }} gap={6}>
<Box responsiveColSpan={{ lg: 2 }}>
<Stack gap={6}>
<Card>
<Heading level={3} mb={4}>Career Statistics</Heading>
<Box display="grid" gridCols={2} gap={4}>
<StatCard
label="Rating"
value={driverStats.rating ?? 0}
variant="blue"
/>
<StatCard label="Total Races" value={driverStats.totalRaces} variant="blue" />
<StatCard label="Wins" value={driverStats.wins} variant="green" />
<StatCard label="Podiums" value={driverStats.podiums} variant="orange" />
</Box>
</Card>
{performanceStats && <PerformanceMetrics stats={performanceStats} />}
</Stack>
</Box>
<DriverRankings rankings={rankings} />
</Box>
)}
{!driverStats && (
<Box display="grid" responsiveGridCols={{ base: 1, lg: 3 }} gap={6}>
<Card responsiveColSpan={{ lg: 3 }}>
<Heading level={3} mb={4}>Career Statistics</Heading>
<Text color="text-gray-400" size="sm" block>
No statistics available yet. Compete in races to start building your record.
</Text>
</Card>
</Box>
)}
<Card>
<Heading level={3} mb={4}>Performance by Class</Heading>
{driverStats && (
<ProfileStats
stats={{
totalRaces: driverStats.totalRaces,
wins: driverStats.wins,
podiums: driverStats.podiums,
dnfs: driverStats.dnfs,
avgFinish: driverStats.avgFinish ?? 0,
completionRate:
driverStats.totalRaces > 0
? ((driverStats.totalRaces - driverStats.dnfs) / driverStats.totalRaces) * 100
: 0,
}}
/>
)}
</Card>
<CareerHighlights />
<Card bg="bg-charcoal-200/50" borderColor="border-primary-blue/30">
<Box display="flex" alignItems="center" gap={3} mb={3}>
<Text size="2xl">🔒</Text>
<Heading level={3}>Private Information</Heading>
</Box>
<Text color="text-gray-400" size="sm" block>
Detailed race history, settings, and preferences are only visible to the driver.
</Text>
</Card>
<Card bg="bg-charcoal-200/50" borderColor="border-primary-blue/30">
<Box display="flex" alignItems="center" gap={3} mb={3}>
<Text size="2xl">📊</Text>
<Heading level={3}>Coming Soon</Heading>
</Box>
<Text color="text-gray-400" size="sm" block>
Per-car statistics, per-track performance, and head-to-head comparisons will be available in production.
</Text>
</Card>
</Stack>
);
}