Files
gridpilot.gg/apps/website/app/drivers/[id]/page.tsx
2025-12-31 15:39:28 +01:00

1004 lines
40 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { useRouter, useParams } from 'next/navigation';
import SponsorInsightsCard, { useSponsorMode, MetricBuilders, SlotTemplates } from '@/components/sponsors/SponsorInsightsCard';
import {
User,
Trophy,
Star,
Calendar,
Users,
Flag,
Award,
TrendingUp,
UserPlus,
ExternalLink,
Target,
Zap,
Clock,
Medal,
Crown,
ChevronRight,
Globe,
Twitter,
Youtube,
Twitch,
MessageCircle,
ArrowLeft,
BarChart3,
Shield,
Percent,
Activity,
} from 'lucide-react';
import Button from '@/components/ui/Button';
import Card from '@/components/ui/Card';
import Breadcrumbs from '@/components/layout/Breadcrumbs';
import { useServices } from '@/lib/services/ServiceProvider';
import { DriverProfileViewModel } from '@/lib/view-models/DriverProfileViewModel';
import { mediaConfig } from '@/lib/config/mediaConfig';
// ============================================================================
// TYPES
// ============================================================================
type ProfileTab = 'overview' | 'stats';
interface Team {
id: string;
name: string;
}
interface SocialHandle {
platform: 'twitter' | 'youtube' | 'twitch' | 'discord';
handle: string;
url: string;
}
interface Achievement {
id: string;
title: string;
description: string;
icon: 'trophy' | 'medal' | 'star' | 'crown' | 'target' | 'zap';
rarity: 'common' | 'rare' | 'epic' | 'legendary';
earnedAt: Date;
}
interface DriverExtendedProfile {
socialHandles: SocialHandle[];
achievements: Achievement[];
racingStyle: string;
favoriteTrack: string;
favoriteCar: string;
timezone: string;
availableHours: string;
lookingForTeam: boolean;
openToRequests: boolean;
}
interface TeamMembershipInfo {
team: Team;
role: string;
joinedAt: Date;
}
// ============================================================================
// DEMO DATA
// ============================================================================
// ============================================================================
// HELPERS
// ============================================================================
function getCountryFlag(countryCode: string): string {
const code = countryCode.toUpperCase();
if (code.length === 2) {
const codePoints = [...code].map(char => 127397 + char.charCodeAt(0));
return String.fromCodePoint(...codePoints);
}
return '🏁';
}
function getRarityColor(rarity: Achievement['rarity']) {
switch (rarity) {
case 'common':
return 'text-gray-400 bg-gray-400/10 border-gray-400/30';
case 'rare':
return 'text-primary-blue bg-primary-blue/10 border-primary-blue/30';
case 'epic':
return 'text-purple-400 bg-purple-400/10 border-purple-400/30';
case 'legendary':
return 'text-yellow-400 bg-yellow-400/10 border-yellow-400/30';
}
}
function getAchievementIcon(icon: Achievement['icon']) {
switch (icon) {
case 'trophy':
return Trophy;
case 'medal':
return Medal;
case 'star':
return Star;
case 'crown':
return Crown;
case 'target':
return Target;
case 'zap':
return Zap;
}
}
function getSocialIcon(platform: SocialHandle['platform']) {
switch (platform) {
case 'twitter':
return Twitter;
case 'youtube':
return Youtube;
case 'twitch':
return Twitch;
case 'discord':
return MessageCircle;
}
}
function getSocialColor(platform: SocialHandle['platform']) {
switch (platform) {
case 'twitter':
return 'hover:text-sky-400 hover:bg-sky-400/10';
case 'youtube':
return 'hover:text-red-500 hover:bg-red-500/10';
case 'twitch':
return 'hover:text-purple-400 hover:bg-purple-400/10';
case 'discord':
return 'hover:text-indigo-400 hover:bg-indigo-400/10';
}
}
// ============================================================================
// STAT DIAGRAM COMPONENTS
// ============================================================================
interface CircularProgressProps {
value: number;
max: number;
label: string;
color: string;
size?: number;
}
function CircularProgress({ value, max, label, color, size = 80 }: CircularProgressProps) {
const percentage = Math.min((value / max) * 100, 100);
const strokeWidth = 6;
const radius = (size - strokeWidth) / 2;
const circumference = radius * 2 * Math.PI;
const strokeDashoffset = circumference - (percentage / 100) * circumference;
return (
<div className="flex flex-col items-center">
<div className="relative" style={{ width: size, height: size }}>
<svg className="transform -rotate-90" width={size} height={size}>
<circle
cx={size / 2}
cy={size / 2}
r={radius}
stroke="currentColor"
strokeWidth={strokeWidth}
fill="transparent"
className="text-charcoal-outline"
/>
<circle
cx={size / 2}
cy={size / 2}
r={radius}
stroke="currentColor"
strokeWidth={strokeWidth}
fill="transparent"
strokeDasharray={circumference}
strokeDashoffset={strokeDashoffset}
strokeLinecap="round"
className={color}
style={{ transition: 'stroke-dashoffset 0.5s ease-in-out' }}
/>
</svg>
<div className="absolute inset-0 flex items-center justify-center">
<span className="text-lg font-bold text-white">{percentage.toFixed(0)}%</span>
</div>
</div>
<span className="text-xs text-gray-400 mt-2">{label}</span>
</div>
);
}
interface BarChartProps {
data: { label: string; value: number; color: string }[];
maxValue: number;
}
function HorizontalBarChart({ data, maxValue }: BarChartProps) {
return (
<div className="space-y-3">
{data.map((item) => (
<div key={item.label}>
<div className="flex justify-between text-sm mb-1">
<span className="text-gray-400">{item.label}</span>
<span className="text-white font-medium">{item.value}</span>
</div>
<div className="h-2 bg-charcoal-outline rounded-full overflow-hidden">
<div
className={`h-full rounded-full ${item.color} transition-all duration-500 ease-out`}
style={{ width: `${Math.min((item.value / maxValue) * 100, 100)}%` }}
/>
</div>
</div>
))}
</div>
);
}
// ============================================================================
// MAIN PAGE
// ============================================================================
export default function DriverDetailPage() {
const router = useRouter();
const params = useParams();
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<ProfileTab>('overview');
const [allTeamMemberships, setAllTeamMemberships] = useState<TeamMembershipInfo[]>([]);
const [friendRequestSent, setFriendRequestSent] = useState(false);
const search =
typeof window !== 'undefined'
? new URLSearchParams(window.location.search)
: undefined;
const from = search?.get('from') ?? undefined;
const leagueId = search?.get('leagueId') ?? undefined;
const raceId = search?.get('raceId') ?? undefined;
let backLink: string | null = null;
if (from === 'league-standings' && leagueId) {
backLink = `/leagues/${leagueId}/standings`;
} else if (from === 'league' && leagueId) {
backLink = `/leagues/${leagueId}`;
} else if (from === 'league-members' && leagueId) {
backLink = `/leagues/${leagueId}`;
} else if (from === 'league-race' && raceId) {
backLink = `/races/${raceId}`;
} else {
backLink = null;
}
const isSponsorMode = useSponsorMode();
useEffect(() => {
loadDriver();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [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
const allTeams = await teamService.getAllTeams();
const memberships: TeamMembershipInfo[] = [];
for (const team of allTeams) {
const teamMembers = await teamService.getTeamMembers(team.id, driverId, ''); // ownerId not available in summary
const membership = teamMembers.find(member => member.driverId === driverId);
if (membership) {
memberships.push({
team: {
id: team.id,
name: team.name,
} as Team,
role: membership.role,
joinedAt: new Date(membership.joinedAt),
});
}
}
setAllTeamMemberships(memberships);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load driver');
} finally {
setLoading(false);
}
};
const handleAddFriend = () => {
setFriendRequestSent(true);
};
if (loading) {
return (
<div className="max-w-6xl mx-auto px-4">
<div className="flex items-center justify-center min-h-[400px]">
<div className="flex flex-col items-center gap-4">
<div className="w-10 h-10 border-2 border-primary-blue border-t-transparent rounded-full animate-spin" />
<p className="text-gray-400">Loading driver profile...</p>
</div>
</div>
</div>
);
}
if (error || !driverProfile?.currentDriver) {
return (
<div className="max-w-4xl mx-auto px-4">
<Card className="text-center py-12">
<User className="w-16 h-16 text-gray-600 mx-auto mb-4" />
<div className="text-warning-amber mb-4">{error || 'Driver not found'}</div>
<Button variant="secondary" onClick={() => router.push('/drivers')}>
Back to Drivers
</Button>
</Card>
</div>
);
}
const extendedProfile: DriverExtendedProfile = driverProfile.extendedProfile ? {
socialHandles: driverProfile.extendedProfile.socialHandles,
achievements: driverProfile.extendedProfile.achievements.map((achievement) => ({
id: achievement.id,
title: achievement.title,
description: achievement.description,
icon: achievement.icon,
rarity: achievement.rarity,
earnedAt: new Date(achievement.earnedAt),
})),
racingStyle: driverProfile.extendedProfile.racingStyle,
favoriteTrack: driverProfile.extendedProfile.favoriteTrack,
favoriteCar: driverProfile.extendedProfile.favoriteCar,
timezone: driverProfile.extendedProfile.timezone,
availableHours: driverProfile.extendedProfile.availableHours,
lookingForTeam: driverProfile.extendedProfile.lookingForTeam,
openToRequests: driverProfile.extendedProfile.openToRequests,
} : {
socialHandles: [],
achievements: [],
racingStyle: 'Unknown',
favoriteTrack: 'Unknown',
favoriteCar: 'Unknown',
timezone: 'UTC',
availableHours: 'Flexible',
lookingForTeam: false,
openToRequests: false,
};
const stats = driverProfile?.stats || null;
const globalRank = driverProfile?.currentDriver?.globalRank || 1;
const driver = driverProfile.currentDriver;
// Build sponsor insights for driver
const friendsCount = driverProfile?.socialSummary?.friends?.length ?? 0;
const driverMetrics = [
MetricBuilders.rating(stats?.rating ?? 0, 'Driver Rating'),
MetricBuilders.views((friendsCount * 8) + 50),
MetricBuilders.engagement(stats?.consistency ?? 75),
MetricBuilders.reach((friendsCount * 12) + 100),
];
return (
<div className="max-w-6xl mx-auto px-4 pb-12 space-y-6">
{/* Back Navigation */}
{backLink ? (
<Link
href={backLink}
className="inline-flex items-center gap-2 text-sm text-gray-400 hover:text-white transition-colors mb-4"
>
<ArrowLeft className="w-4 h-4" />
Back to league
</Link>
) : (
<Button
variant="secondary"
onClick={() => router.push('/drivers')}
className="flex items-center gap-2 mb-4"
>
<ArrowLeft className="w-4 h-4" />
Back to Drivers
</Button>
)}
{/* Breadcrumb */}
<Breadcrumbs
items={[
{ label: 'Home', href: '/' },
{ label: 'Drivers', href: '/drivers' },
{ label: driver.name },
]}
/>
{/* Sponsor Insights Card - Consistent placement at top */}
{isSponsorMode && driver && (
<SponsorInsightsCard
entityType="driver"
entityId={driver.id}
entityName={driver.name}
tier="standard"
metrics={driverMetrics}
slots={SlotTemplates.driver(true, 200)}
trustScore={88}
monthlyActivity={stats?.consistency ?? 75}
/>
)}
{/* Hero Header Section */}
<div className="relative rounded-2xl overflow-hidden bg-gradient-to-br from-iron-gray/80 via-iron-gray/60 to-deep-graphite border border-charcoal-outline">
{/* Background Pattern */}
<div className="absolute inset-0 opacity-5">
<div
className="absolute inset-0"
style={{
backgroundImage: `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`,
}}
/>
</div>
<div className="relative p-6 md:p-8">
<div className="flex flex-col md:flex-row md:items-start gap-6">
{/* Avatar */}
<div className="relative">
<div className="w-28 h-28 md:w-36 md:h-36 rounded-2xl bg-gradient-to-br from-primary-blue to-purple-600 p-1 shadow-xl shadow-primary-blue/20">
<div className="w-full h-full rounded-xl overflow-hidden bg-iron-gray">
<Image
src={driver.avatarUrl || mediaConfig.avatars.defaultFallback}
alt={driver.name}
width={144}
height={144}
className="w-full h-full object-cover"
/>
</div>
</div>
</div>
{/* Driver Info */}
<div className="flex-1 min-w-0">
<div className="flex flex-wrap items-center gap-3 mb-2">
<h1 className="text-3xl md:text-4xl font-bold text-white">{driver.name}</h1>
<span className="text-4xl" aria-label={`Country: ${driver.country}`}>
{getCountryFlag(driver.country)}
</span>
</div>
{/* Rating and Rank */}
<div className="flex flex-wrap items-center gap-4 mb-4">
{stats && (
<>
<div className="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-primary-blue/10 border border-primary-blue/30">
<Star className="w-4 h-4 text-primary-blue" />
<span className="font-mono font-bold text-primary-blue">{stats.rating}</span>
<span className="text-xs text-gray-400">Rating</span>
</div>
<div className="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-yellow-400/10 border border-yellow-400/30">
<Trophy className="w-4 h-4 text-yellow-400" />
<span className="font-mono font-bold text-yellow-400">#{globalRank}</span>
<span className="text-xs text-gray-400">Global</span>
</div>
</>
)}
</div>
{/* Meta info */}
<div className="flex flex-wrap items-center gap-4 text-sm text-gray-400">
<span className="flex items-center gap-1.5">
<Globe className="w-4 h-4" />
iRacing: {driver.iracingId}
</span>
<span className="flex items-center gap-1.5">
<Calendar className="w-4 h-4" />
Joined{' '}
{new Date(driver.joinedAt).toLocaleDateString('en-US', {
month: 'short',
year: 'numeric',
})}
</span>
<span className="flex items-center gap-1.5">
<Clock className="w-4 h-4" />
{extendedProfile.timezone}
</span>
</div>
</div>
{/* Action Buttons */}
<div className="flex flex-col gap-2">
<Button
variant="primary"
onClick={handleAddFriend}
disabled={friendRequestSent}
className="flex items-center gap-2"
>
<UserPlus className="w-4 h-4" />
{friendRequestSent ? 'Request Sent' : 'Add Friend'}
</Button>
</div>
</div>
{/* Social Handles */}
{extendedProfile.socialHandles.length > 0 && (
<div className="mt-6 pt-6 border-t border-charcoal-outline/50">
<div className="flex flex-wrap items-center gap-2">
<span className="text-sm text-gray-500 mr-2">Connect:</span>
{extendedProfile.socialHandles.map((social: SocialHandle) => {
const Icon = getSocialIcon(social.platform);
return (
<a
key={social.platform}
href={social.url}
target="_blank"
rel="noopener noreferrer"
className={`flex items-center gap-2 px-3 py-1.5 rounded-lg bg-iron-gray/50 border border-charcoal-outline text-gray-400 transition-all ${getSocialColor(social.platform)}`}
>
<Icon className="w-4 h-4" />
<span className="text-sm">{social.handle}</span>
<ExternalLink className="w-3 h-3 opacity-50" />
</a>
);
})}
</div>
</div>
)}
</div>
</div>
{/* Bio Section */}
{driver.bio && (
<Card>
<h2 className="text-lg font-semibold text-white mb-3 flex items-center gap-2">
<User className="w-5 h-5 text-primary-blue" />
About
</h2>
<p className="text-gray-300 leading-relaxed">{driver.bio}</p>
</Card>
)}
{/* Team Memberships */}
{allTeamMemberships.length > 0 && (
<Card>
<h2 className="text-lg font-semibold text-white mb-4 flex items-center gap-2">
<Shield className="w-5 h-5 text-purple-400" />
Team Memberships
<span className="text-sm text-gray-500 font-normal">({allTeamMemberships.length})</span>
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{allTeamMemberships.map((membership) => (
<Link
key={membership.team.id}
href={`/teams/${membership.team.id}`}
className="flex items-center gap-4 p-4 rounded-xl bg-iron-gray/30 border border-charcoal-outline hover:border-purple-400/30 hover:bg-iron-gray/50 transition-all group"
>
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-purple-600/20 border border-purple-600/30">
<Users className="w-6 h-6 text-purple-400" />
</div>
<div className="flex-1 min-w-0">
<p className="text-white font-semibold truncate group-hover:text-purple-400 transition-colors">
{membership.team.name}
</p>
<div className="flex items-center gap-2 text-xs text-gray-400">
<span className="px-2 py-0.5 rounded-full bg-purple-600/20 text-purple-400 capitalize">
{membership.role}
</span>
<span>
Since {membership.joinedAt.toLocaleDateString('en-US', { month: 'short', year: 'numeric' })}
</span>
</div>
</div>
<ChevronRight className="w-4 h-4 text-gray-500 group-hover:text-purple-400 transition-colors" />
</Link>
))}
</div>
</Card>
)}
{/* Performance Overview with Diagrams */}
{stats && (
<Card>
<h2 className="text-lg font-semibold text-white mb-6 flex items-center gap-2">
<Activity className="w-5 h-5 text-neon-aqua" />
Performance Overview
</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{/* Circular Progress Charts */}
<div className="flex flex-col items-center">
<div className="flex gap-6 mb-4">
<CircularProgress
value={stats.wins}
max={stats.totalRaces}
label="Win Rate"
color="text-performance-green"
/>
<CircularProgress
value={stats.podiums}
max={stats.totalRaces}
label="Podium Rate"
color="text-warning-amber"
/>
</div>
<div className="flex gap-6">
<CircularProgress
value={stats.consistency ?? 0}
max={100}
label="Consistency"
color="text-primary-blue"
/>
<CircularProgress
value={stats.totalRaces - stats.dnfs}
max={stats.totalRaces}
label="Finish Rate"
color="text-neon-aqua"
/>
</div>
</div>
{/* Bar chart and key metrics */}
<div className="md:col-span-2">
<h3 className="text-sm font-medium text-gray-400 mb-4 flex items-center gap-2">
<BarChart3 className="w-4 h-4" />
Results Breakdown
</h3>
<HorizontalBarChart
data={[
{ label: 'Wins', value: stats.wins, color: 'bg-performance-green' },
{ label: 'Podiums (2nd-3rd)', value: stats.podiums - stats.wins, color: 'bg-warning-amber' },
{ label: 'DNFs', value: stats.dnfs, color: 'bg-red-500' },
]}
maxValue={stats.totalRaces}
/>
<div className="mt-6 grid grid-cols-2 gap-4">
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline">
<div className="flex items-center gap-2 mb-2">
<TrendingUp className="w-4 h-4 text-performance-green" />
<span className="text-xs text-gray-500 uppercase">Best Finish</span>
</div>
<p className="text-2xl font-bold text-performance-green">P{stats.bestFinish}</p>
</div>
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline">
<div className="flex items-center gap-2 mb-2">
<Target className="w-4 h-4 text-primary-blue" />
<span className="text-xs text-gray-500 uppercase">Avg Finish</span>
</div>
<p className="text-2xl font-bold text-primary-blue">
P{(stats.avgFinish ?? 0).toFixed(1)}
</p>
</div>
</div>
</div>
</div>
</Card>
)}
{/* Tab Navigation */}
<div className="flex items-center gap-1 p-1 rounded-xl bg-iron-gray/50 border border-charcoal-outline w-fit">
<button
type="button"
onClick={() => setActiveTab('overview')}
className={`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-all ${
activeTab === 'overview'
? 'bg-primary-blue text-white'
: 'text-gray-400 hover:text-white hover:bg-iron-gray'
}`}
>
<User className="w-4 h-4" />
Overview
</button>
<button
type="button"
onClick={() => setActiveTab('stats')}
className={`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-all ${
activeTab === 'stats'
? 'bg-primary-blue text-white'
: 'text-gray-400 hover:text-white hover:bg-iron-gray'
}`}
>
<BarChart3 className="w-4 h-4" />
Detailed Stats
</button>
</div>
{/* Tab Content */}
{activeTab === 'overview' && (
<>
{/* Stats and Profile Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Career Stats */}
<Card className="lg:col-span-2">
<h2 className="text-lg font-semibold text-white mb-4 flex items-center gap-2">
<TrendingUp className="w-5 h-5 text-performance-green" />
Career Statistics
</h2>
{stats ? (
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline text-center">
<div className="text-3xl font-bold text-white mb-1">{stats.totalRaces}</div>
<div className="text-xs text-gray-500 uppercase tracking-wider">Races</div>
</div>
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline text-center">
<div className="text-3xl font-bold text-performance-green mb-1">{stats.wins}</div>
<div className="text-xs text-gray-500 uppercase tracking-wider">Wins</div>
</div>
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline text-center">
<div className="text-3xl font-bold text-warning-amber mb-1">{stats.podiums}</div>
<div className="text-xs text-gray-500 uppercase tracking-wider">Podiums</div>
</div>
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline text-center">
<div className="text-3xl font-bold text-primary-blue mb-1">{stats.consistency}%</div>
<div className="text-xs text-gray-500 uppercase tracking-wider">Consistency</div>
</div>
</div>
) : (
<p className="text-gray-400 text-sm">No race statistics available yet.</p>
)}
</Card>
{/* Racing Preferences */}
<Card>
<h2 className="text-lg font-semibold text-white mb-4 flex items-center gap-2">
<Flag className="w-5 h-5 text-neon-aqua" />
Racing Profile
</h2>
<div className="space-y-4">
<div>
<span className="text-xs text-gray-500 uppercase tracking-wider">Racing Style</span>
<p className="text-white font-medium">{extendedProfile.racingStyle}</p>
</div>
<div>
<span className="text-xs text-gray-500 uppercase tracking-wider">Favorite Track</span>
<p className="text-white font-medium">{extendedProfile.favoriteTrack}</p>
</div>
<div>
<span className="text-xs text-gray-500 uppercase tracking-wider">Favorite Car</span>
<p className="text-white font-medium">{extendedProfile.favoriteCar}</p>
</div>
<div>
<span className="text-xs text-gray-500 uppercase tracking-wider">Available</span>
<p className="text-white font-medium">{extendedProfile.availableHours}</p>
</div>
{/* Status badges */}
<div className="pt-4 border-t border-charcoal-outline/50 space-y-2">
{extendedProfile.lookingForTeam && (
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-performance-green/10 border border-performance-green/30">
<Users className="w-4 h-4 text-performance-green" />
<span className="text-sm text-performance-green font-medium">Looking for Team</span>
</div>
)}
{extendedProfile.openToRequests && (
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-primary-blue/10 border border-primary-blue/30">
<UserPlus className="w-4 h-4 text-primary-blue" />
<span className="text-sm text-primary-blue font-medium">Open to Friend Requests</span>
</div>
)}
</div>
</div>
</Card>
</div>
{/* Achievements */}
<Card>
<h2 className="text-lg font-semibold text-white mb-4 flex items-center gap-2">
<Award className="w-5 h-5 text-yellow-400" />
Achievements
<span className="ml-auto text-sm text-gray-500">{extendedProfile.achievements.length} earned</span>
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{extendedProfile.achievements.map((achievement: Achievement) => {
const Icon = getAchievementIcon(achievement.icon);
const rarityClasses = getRarityColor(achievement.rarity);
return (
<div
key={achievement.id}
className={`p-4 rounded-xl border ${rarityClasses} transition-all hover:scale-105`}
>
<div className="flex items-start gap-3">
<div className={`flex h-10 w-10 items-center justify-center rounded-lg ${rarityClasses.split(' ')[1]}`}>
<Icon className={`w-5 h-5 ${rarityClasses.split(' ')[0]}`} />
</div>
<div className="flex-1 min-w-0">
<p className="text-white font-semibold text-sm">{achievement.title}</p>
<p className="text-gray-400 text-xs mt-0.5">{achievement.description}</p>
<p className="text-gray-500 text-xs mt-1">
{achievement.earnedAt.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</p>
</div>
</div>
</div>
);
})}
</div>
</Card>
{/* Friends Preview */}
{driverProfile.socialSummary.friends.length > 0 && (
<Card>
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-semibold text-white flex items-center gap-2">
<Users className="w-5 h-5 text-purple-400" />
Friends
<span className="text-sm text-gray-500 font-normal">({driverProfile.socialSummary.friends.length})</span>
</h2>
</div>
<div className="flex flex-wrap gap-3">
{driverProfile.socialSummary.friends.slice(0, 8).map((friend) => (
<Link
key={friend.id}
href={`/drivers/${friend.id}`}
className="flex items-center gap-2 px-3 py-2 rounded-lg bg-iron-gray/50 border border-charcoal-outline hover:border-purple-400/30 hover:bg-iron-gray transition-all"
>
<div className="w-8 h-8 rounded-full overflow-hidden bg-gradient-to-br from-primary-blue to-purple-600">
<Image
src={friend.avatarUrl || mediaConfig.avatars.defaultFallback}
alt={friend.name}
width={32}
height={32}
className="w-full h-full object-cover"
/>
</div>
<span className="text-sm text-white">{friend.name}</span>
<span className="text-lg">{getCountryFlag(friend.country)}</span>
</Link>
))}
{driverProfile.socialSummary.friends.length > 8 && (
<div className="flex items-center px-3 py-2 text-sm text-gray-400">+{driverProfile.socialSummary.friends.length - 8} more</div>
)}
</div>
</Card>
)}
</>
)}
{activeTab === 'stats' && stats && (
<div className="space-y-6">
{/* Detailed Performance Metrics */}
<Card>
<h2 className="text-lg font-semibold text-white mb-6 flex items-center gap-2">
<BarChart3 className="w-5 h-5 text-primary-blue" />
Detailed Performance Metrics
</h2>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* Performance Bars */}
<div>
<h3 className="text-sm font-medium text-gray-400 mb-4">Results Breakdown</h3>
<HorizontalBarChart
data={[
{ label: 'Wins', value: stats.wins, color: 'bg-performance-green' },
{ label: 'Podiums (2nd-3rd)', value: stats.podiums - stats.wins, color: 'bg-warning-amber' },
{ label: 'DNFs', value: stats.dnfs, color: 'bg-red-500' },
]}
maxValue={stats.totalRaces}
/>
</div>
{/* Key Metrics */}
<div className="grid grid-cols-2 gap-4">
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline">
<div className="flex items-center gap-2 mb-2">
<Percent className="w-4 h-4 text-performance-green" />
<span className="text-xs text-gray-500 uppercase">Win Rate</span>
</div>
<p className="text-2xl font-bold text-performance-green">
{((stats.wins / stats.totalRaces) * 100).toFixed(1)}%
</p>
</div>
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline">
<div className="flex items-center gap-2 mb-2">
<Percent className="w-4 h-4 text-warning-amber" />
<span className="text-xs text-gray-500 uppercase">Podium Rate</span>
</div>
<p className="text-2xl font-bold text-warning-amber">
{((stats.podiums / stats.totalRaces) * 100).toFixed(1)}%
</p>
</div>
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline">
<div className="flex items-center gap-2 mb-2">
<Activity className="w-4 h-4 text-primary-blue" />
<span className="text-xs text-gray-500 uppercase">Consistency</span>
</div>
<p className="text-2xl font-bold text-primary-blue">{stats.consistency}%</p>
</div>
<div className="p-4 rounded-xl bg-deep-graphite border border-charcoal-outline">
<div className="flex items-center gap-2 mb-2">
<Zap className="w-4 h-4 text-neon-aqua" />
<span className="text-xs text-gray-500 uppercase">Finish Rate</span>
</div>
<p className="text-2xl font-bold text-neon-aqua">
{(((stats.totalRaces - stats.dnfs) / stats.totalRaces) * 100).toFixed(1)}%
</p>
</div>
</div>
</div>
</Card>
{/* Position Statistics */}
<Card>
<h2 className="text-lg font-semibold text-white mb-6 flex items-center gap-2">
<Flag className="w-5 h-5 text-red-400" />
Position Statistics
</h2>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="p-4 rounded-xl bg-gradient-to-br from-performance-green/20 to-performance-green/5 border border-performance-green/30 text-center">
<div className="text-4xl font-bold text-performance-green mb-1">P{stats.bestFinish}</div>
<div className="text-xs text-gray-400 uppercase">Best Finish</div>
</div>
<div className="p-4 rounded-xl bg-gradient-to-br from-primary-blue/20 to-primary-blue/5 border border-primary-blue/30 text-center">
<div className="text-4xl font-bold text-primary-blue mb-1">
P{(stats.avgFinish ?? 0).toFixed(1)}
</div>
<div className="text-xs text-gray-400 uppercase">Avg Finish</div>
</div>
<div className="p-4 rounded-xl bg-gradient-to-br from-warning-amber/20 to-warning-amber/5 border border-warning-amber/30 text-center">
<div className="text-4xl font-bold text-warning-amber mb-1">P{stats.worstFinish}</div>
<div className="text-xs text-gray-400 uppercase">Worst Finish</div>
</div>
<div className="p-4 rounded-xl bg-gradient-to-br from-red-500/20 to-red-500/5 border border-red-500/30 text-center">
<div className="text-4xl font-bold text-red-400 mb-1">{stats.dnfs}</div>
<div className="text-xs text-gray-400 uppercase">DNFs</div>
</div>
</div>
</Card>
{/* Global Rankings */}
<Card>
<h2 className="text-lg font-semibold text-white mb-6 flex items-center gap-2">
<Trophy className="w-5 h-5 text-yellow-400" />
Global Rankings
</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="p-6 rounded-xl bg-gradient-to-br from-yellow-400/20 to-yellow-600/5 border border-yellow-400/30 text-center">
<Trophy className="w-8 h-8 text-yellow-400 mx-auto mb-3" />
<div className="text-3xl font-bold text-yellow-400 mb-1">#{globalRank}</div>
<div className="text-sm text-gray-400">Global Rank</div>
</div>
<div className="p-6 rounded-xl bg-gradient-to-br from-primary-blue/20 to-primary-blue/5 border border-primary-blue/30 text-center">
<Star className="w-8 h-8 text-primary-blue mx-auto mb-3" />
<div className="text-3xl font-bold text-primary-blue mb-1">{stats.rating}</div>
<div className="text-sm text-gray-400">Rating</div>
</div>
<div className="p-6 rounded-xl bg-gradient-to-br from-purple-400/20 to-purple-600/5 border border-purple-400/30 text-center">
<TrendingUp className="w-8 h-8 text-purple-400 mx-auto mb-3" />
<div className="text-3xl font-bold text-purple-400 mb-1">Top {stats.percentile}%</div>
<div className="text-sm text-gray-400">Percentile</div>
</div>
</div>
</Card>
</div>
)}
{activeTab === 'stats' && !stats && (
<Card className="text-center py-12">
<BarChart3 className="w-16 h-16 text-gray-600 mx-auto mb-4" />
<p className="text-gray-400 mb-2">No statistics available yet</p>
<p className="text-sm text-gray-500">This driver hasn&apos;t completed any races yet</p>
</Card>
)}
</div>
);
}