website refactor
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
'use client';
|
||||
|
||||
import { useDriverProfile } from "@/lib/hooks/driver";
|
||||
import { useDriverProfile } from "@/hooks/driver/useDriverProfile";
|
||||
import { useMemo } from 'react';
|
||||
import Card from '../ui/Card';
|
||||
import RankBadge from './RankBadge';
|
||||
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 { RankBadge } from '@/ui/RankBadge';
|
||||
|
||||
interface ProfileStatsProps {
|
||||
driverId?: string;
|
||||
@@ -17,15 +22,12 @@ interface ProfileStatsProps {
|
||||
};
|
||||
}
|
||||
|
||||
export default function ProfileStats({ driverId, stats }: ProfileStatsProps) {
|
||||
export function ProfileStats({ driverId, stats }: ProfileStatsProps) {
|
||||
const { data: profileData } = useDriverProfile(driverId ?? '');
|
||||
|
||||
const driverStats = profileData?.stats ?? null;
|
||||
const totalDrivers = profileData?.currentDriver?.totalDrivers ?? 0;
|
||||
|
||||
// League rank widget needs a dedicated API contract; keep it disabled until provided.
|
||||
// (Leaving UI block out avoids `never` typing issues.)
|
||||
|
||||
const defaultStats = useMemo(() => {
|
||||
if (stats) {
|
||||
return stats;
|
||||
@@ -78,132 +80,102 @@ export default function ProfileStats({ driverId, stats }: ProfileStatsProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<Stack gap={6}>
|
||||
{driverStats && (
|
||||
<Card>
|
||||
<h3 className="text-xl font-semibold text-white mb-6">Rankings Dashboard</h3>
|
||||
<Heading level={2} mb={6}>Rankings Dashboard</Heading>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="p-4 rounded-lg bg-deep-graphite border border-charcoal-outline">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<Stack gap={4}>
|
||||
<Box p={4} rounded="lg" bg="bg-deep-graphite" border borderColor="border-charcoal-outline">
|
||||
<Box display="flex" alignItems="center" justifyContent="between" mb={3}>
|
||||
<Box display="flex" alignItems="center" gap={3}>
|
||||
<RankBadge rank={driverStats.overallRank ?? 0} size="lg" />
|
||||
<div>
|
||||
<div className="text-white font-medium text-lg">Overall Ranking</div>
|
||||
<div className="text-sm text-gray-400">
|
||||
<Box>
|
||||
<Text color="text-white" weight="medium" size="lg" block>Overall Ranking</Text>
|
||||
<Text size="sm" color="text-gray-400" block>
|
||||
{driverStats.overallRank ?? 0} of {totalDrivers} drivers
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div
|
||||
className={`text-sm font-medium ${getPercentileColor(driverStats.percentile ?? 0)}`}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box textAlign="right">
|
||||
<Text
|
||||
size="sm"
|
||||
weight="medium"
|
||||
color={getPercentileColor(driverStats.percentile ?? 0)}
|
||||
block
|
||||
>
|
||||
{getPercentileLabel(driverStats.percentile ?? 0)}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">Global Percentile</div>
|
||||
</div>
|
||||
</div>
|
||||
</Text>
|
||||
<Text size="xs" color="text-gray-500" block>Global Percentile</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 pt-3 border-t border-charcoal-outline">
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold text-primary-blue">
|
||||
<Box display="grid" gridCols={3} gap={4} pt={3} borderTop borderColor="border-charcoal-outline">
|
||||
<Box textAlign="center">
|
||||
<Text size="2xl" weight="bold" color="text-primary-blue" block>
|
||||
{driverStats.rating ?? 0}
|
||||
</div>
|
||||
<div className="text-xs text-gray-400">Rating</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-lg font-bold text-green-400">
|
||||
</Text>
|
||||
<Text size="xs" color="text-gray-400" block>Rating</Text>
|
||||
</Box>
|
||||
<Box textAlign="center">
|
||||
<Text size="lg" weight="bold" color="text-green-400" block>
|
||||
{getTrendIndicator(5)} {winRate}%
|
||||
</div>
|
||||
<div className="text-xs text-gray-400">Win Rate</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-lg font-bold text-warning-amber">
|
||||
</Text>
|
||||
<Text size="xs" color="text-gray-400" block>Win Rate</Text>
|
||||
</Box>
|
||||
<Box textAlign="center">
|
||||
<Text size="lg" weight="bold" color="text-warning-amber" block>
|
||||
{getTrendIndicator(2)} {podiumRate}%
|
||||
</div>
|
||||
<div className="text-xs text-gray-400">Podium Rate</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Primary-league ranking removed until we have a dedicated API + view model for league ranks. */}
|
||||
</div>
|
||||
</Text>
|
||||
<Text size="xs" color="text-gray-400" block>Podium Rate</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{defaultStats ? (
|
||||
<>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{[
|
||||
{
|
||||
label: 'Total Races',
|
||||
value: defaultStats.totalRaces,
|
||||
color: 'text-primary-blue',
|
||||
},
|
||||
{ label: 'Wins', value: defaultStats.wins, color: 'text-green-400' },
|
||||
{
|
||||
label: 'Podiums',
|
||||
value: defaultStats.podiums,
|
||||
color: 'text-warning-amber',
|
||||
},
|
||||
{ label: 'DNFs', value: defaultStats.dnfs, color: 'text-red-400' },
|
||||
{
|
||||
label: 'Avg Finish',
|
||||
value: defaultStats.avgFinish.toFixed(1),
|
||||
color: 'text-white',
|
||||
},
|
||||
{
|
||||
label: 'Completion',
|
||||
value: `${defaultStats.completionRate.toFixed(1)}%`,
|
||||
color: 'text-green-400',
|
||||
},
|
||||
{ label: 'Win Rate', value: `${winRate}%`, color: 'text-primary-blue' },
|
||||
{
|
||||
label: 'Podium Rate',
|
||||
value: `${podiumRate}%`,
|
||||
color: 'text-warning-amber',
|
||||
},
|
||||
].map((stat, index) => (
|
||||
<Card key={index} className="text-center">
|
||||
<div className="text-sm text-gray-400 mb-1">{stat.label}</div>
|
||||
<div className={`text-2xl font-bold ${stat.color}`}>{stat.value}</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
<Box display="grid" responsiveGridCols={{ base: 2, md: 4 }} gap={4}>
|
||||
<StatCard label="Total Races" value={defaultStats.totalRaces} variant="blue" />
|
||||
<StatCard label="Wins" value={defaultStats.wins} variant="green" />
|
||||
<StatCard label="Podiums" value={defaultStats.podiums} variant="orange" />
|
||||
<StatCard label="DNFs" value={defaultStats.dnfs} variant="blue" />
|
||||
<StatCard label="Avg Finish" value={defaultStats.avgFinish.toFixed(1)} variant="blue" />
|
||||
<StatCard label="Completion" value={`${defaultStats.completionRate.toFixed(1)}%`} variant="green" />
|
||||
<StatCard label="Win Rate" value={`${winRate}%`} variant="blue" />
|
||||
<StatCard label="Podium Rate" value={`${podiumRate}%`} variant="orange" />
|
||||
</Box>
|
||||
) : (
|
||||
<Card>
|
||||
<h3 className="text-lg font-semibold text-white mb-2">Career Statistics</h3>
|
||||
<p className="text-sm text-gray-400">
|
||||
<Heading level={3} mb={2}>Career Statistics</Heading>
|
||||
<Text size="sm" color="text-gray-400" block>
|
||||
No statistics available yet. Compete in races to start building your record.
|
||||
</p>
|
||||
</Text>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<Card className="bg-charcoal-200/50 border-primary-blue/30">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className="text-2xl">📊</div>
|
||||
<h3 className="text-lg font-semibold text-white">Performance by Car Class</h3>
|
||||
</div>
|
||||
<p className="text-gray-400 text-sm">
|
||||
<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}>Performance by Car Class</Heading>
|
||||
</Box>
|
||||
<Text color="text-gray-400" size="sm" block>
|
||||
Detailed per-car and per-class performance breakdowns will be available in a future
|
||||
version once more race history data is tracked.
|
||||
</p>
|
||||
</Text>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-charcoal-200/50 border-primary-blue/30">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className="text-2xl">📈</div>
|
||||
<h3 className="text-lg font-semibold text-white">Coming Soon</h3>
|
||||
</div>
|
||||
<p className="text-gray-400 text-sm">
|
||||
<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>
|
||||
Performance trends, track-specific stats, head-to-head comparisons vs friends, and
|
||||
league member comparisons will be available in production.
|
||||
</p>
|
||||
</Text>
|
||||
</Card>
|
||||
</div>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user