314 lines
9.9 KiB
TypeScript
314 lines
9.9 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import Image from 'next/image';
|
|
import DriverCard from '@/components/drivers/DriverCard';
|
|
import RankBadge from '@/components/drivers/RankBadge';
|
|
import Input from '@/components/ui/Input';
|
|
import Card from '@/components/ui/Card';
|
|
import { getDriverAvatarUrl } from '@/lib/racingLegacyFacade';
|
|
|
|
// Mock data (fictional demo drivers only)
|
|
const MOCK_DRIVERS = [
|
|
{
|
|
id: 'driver-1',
|
|
name: 'Alex Vermeer',
|
|
rating: 3245,
|
|
skillLevel: 'pro' as const,
|
|
nationality: 'Netherlands',
|
|
racesCompleted: 156,
|
|
wins: 45,
|
|
podiums: 89,
|
|
isActive: true,
|
|
rank: 1,
|
|
},
|
|
{
|
|
id: 'driver-2',
|
|
name: 'Liam Hartmann',
|
|
rating: 3198,
|
|
skillLevel: 'pro' as const,
|
|
nationality: 'United Kingdom',
|
|
racesCompleted: 234,
|
|
wins: 78,
|
|
podiums: 145,
|
|
isActive: true,
|
|
rank: 2,
|
|
},
|
|
{
|
|
id: 'driver-3',
|
|
name: 'Michael Schmidt',
|
|
rating: 2912,
|
|
skillLevel: 'advanced' as const,
|
|
nationality: 'Germany',
|
|
racesCompleted: 145,
|
|
wins: 34,
|
|
podiums: 67,
|
|
isActive: true,
|
|
rank: 3,
|
|
},
|
|
{
|
|
id: 'driver-4',
|
|
name: 'Emma Thompson',
|
|
rating: 2789,
|
|
skillLevel: 'advanced' as const,
|
|
nationality: 'Australia',
|
|
racesCompleted: 112,
|
|
wins: 23,
|
|
podiums: 56,
|
|
isActive: true,
|
|
rank: 5,
|
|
},
|
|
{
|
|
id: 'driver-5',
|
|
name: 'Sarah Chen',
|
|
rating: 2456,
|
|
skillLevel: 'advanced' as const,
|
|
nationality: 'Singapore',
|
|
racesCompleted: 89,
|
|
wins: 12,
|
|
podiums: 34,
|
|
isActive: true,
|
|
rank: 8,
|
|
},
|
|
{
|
|
id: 'driver-6',
|
|
name: 'Isabella Rossi',
|
|
rating: 2145,
|
|
skillLevel: 'intermediate' as const,
|
|
nationality: 'Italy',
|
|
racesCompleted: 67,
|
|
wins: 8,
|
|
podiums: 23,
|
|
isActive: true,
|
|
rank: 12,
|
|
},
|
|
{
|
|
id: 'driver-7',
|
|
name: 'Carlos Rodriguez',
|
|
rating: 1876,
|
|
skillLevel: 'intermediate' as const,
|
|
nationality: 'Spain',
|
|
racesCompleted: 45,
|
|
wins: 3,
|
|
podiums: 12,
|
|
isActive: false,
|
|
rank: 18,
|
|
},
|
|
{
|
|
id: 'driver-8',
|
|
name: 'Yuki Tanaka',
|
|
rating: 1234,
|
|
skillLevel: 'beginner' as const,
|
|
nationality: 'Japan',
|
|
racesCompleted: 12,
|
|
wins: 0,
|
|
podiums: 2,
|
|
isActive: true,
|
|
rank: 45,
|
|
},
|
|
];
|
|
|
|
export default function DriversPage() {
|
|
const router = useRouter();
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
const [selectedSkill, setSelectedSkill] = useState('all');
|
|
const [selectedNationality, setSelectedNationality] = useState('all');
|
|
const [activeOnly, setActiveOnly] = useState(false);
|
|
const [sortBy, setSortBy] = useState<'rank' | 'rating' | 'wins' | 'podiums'>('rank');
|
|
|
|
const nationalities = Array.from(
|
|
new Set(MOCK_DRIVERS.map((d) => d.nationality).filter(Boolean))
|
|
).sort();
|
|
|
|
const filteredDrivers = MOCK_DRIVERS.filter((driver) => {
|
|
const matchesSearch = driver.name
|
|
.toLowerCase()
|
|
.includes(searchQuery.toLowerCase());
|
|
const matchesSkill =
|
|
selectedSkill === 'all' || driver.skillLevel === selectedSkill;
|
|
const matchesNationality =
|
|
selectedNationality === 'all' || driver.nationality === selectedNationality;
|
|
const matchesActive = !activeOnly || driver.isActive;
|
|
|
|
return matchesSearch && matchesSkill && matchesNationality && matchesActive;
|
|
});
|
|
|
|
const sortedDrivers = [...filteredDrivers].sort((a, b) => {
|
|
switch (sortBy) {
|
|
case 'rank':
|
|
return a.rank - b.rank;
|
|
case 'rating':
|
|
return b.rating - a.rating;
|
|
case 'wins':
|
|
return b.wins - a.wins;
|
|
case 'podiums':
|
|
return b.podiums - a.podiums;
|
|
default:
|
|
return 0;
|
|
}
|
|
});
|
|
|
|
const handleDriverClick = (driverId: string) => {
|
|
router.push(`/drivers/${driverId}`);
|
|
};
|
|
|
|
return (
|
|
<div className="max-w-6xl mx-auto">
|
|
<div className="mb-8">
|
|
<h1 className="text-3xl font-bold text-white mb-2">Drivers</h1>
|
|
<p className="text-gray-400">
|
|
Browse driver profiles and stats
|
|
</p>
|
|
</div>
|
|
|
|
<Card className="mb-8">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4 mb-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-400 mb-2">
|
|
Search Drivers
|
|
</label>
|
|
<Input
|
|
type="text"
|
|
placeholder="Search by name..."
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-400 mb-2">
|
|
Skill Level
|
|
</label>
|
|
<select
|
|
className="w-full px-3 py-3 bg-iron-gray border-0 rounded-md text-white ring-1 ring-inset ring-charcoal-outline focus:ring-2 focus:ring-primary-blue transition-all duration-150 text-sm"
|
|
value={selectedSkill}
|
|
onChange={(e) => setSelectedSkill(e.target.value)}
|
|
>
|
|
<option value="all">All Levels</option>
|
|
<option value="beginner">Beginner</option>
|
|
<option value="intermediate">Intermediate</option>
|
|
<option value="advanced">Advanced</option>
|
|
<option value="pro">Pro</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-400 mb-2">
|
|
Nationality
|
|
</label>
|
|
<select
|
|
className="w-full px-3 py-3 bg-iron-gray border-0 rounded-md text-white ring-1 ring-inset ring-charcoal-outline focus:ring-2 focus:ring-primary-blue transition-all duration-150 text-sm"
|
|
value={selectedNationality}
|
|
onChange={(e) => setSelectedNationality(e.target.value)}
|
|
>
|
|
<option value="all">All Countries</option>
|
|
{nationalities.map((nat) => (
|
|
<option key={nat} value={nat}>
|
|
{nat}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-400 mb-2">
|
|
Status
|
|
</label>
|
|
<label className="flex items-center pt-3">
|
|
<input
|
|
type="checkbox"
|
|
className="w-4 h-4 text-primary-blue bg-iron-gray border-charcoal-outline rounded focus:ring-primary-blue focus:ring-2"
|
|
checked={activeOnly}
|
|
onChange={(e) => setActiveOnly(e.target.checked)}
|
|
/>
|
|
<span className="ml-2 text-sm text-gray-400">Active only</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-400 mb-2">
|
|
Sort By
|
|
</label>
|
|
<select
|
|
className="w-full px-3 py-3 bg-iron-gray border-0 rounded-md text-white ring-1 ring-inset ring-charcoal-outline focus:ring-2 focus:ring-primary-blue transition-all duration-150 text-sm"
|
|
value={sortBy}
|
|
onChange={(e) => setSortBy(e.target.value as any)}
|
|
>
|
|
<option value="rank">Overall Rank</option>
|
|
<option value="rating">Rating</option>
|
|
<option value="wins">Wins</option>
|
|
<option value="podiums">Podiums</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
|
|
<div className="mb-4 flex items-center justify-between">
|
|
<p className="text-sm text-gray-400">
|
|
{sortedDrivers.length} {sortedDrivers.length === 1 ? 'driver' : 'drivers'} found
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
{sortedDrivers.map((driver, index) => (
|
|
<Card
|
|
key={driver.id}
|
|
className="hover:border-charcoal-outline/60 transition-colors cursor-pointer"
|
|
onClick={() => handleDriverClick(driver.id)}
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-4 flex-1">
|
|
<RankBadge rank={driver.rank} size="lg" />
|
|
|
|
<div className="w-16 h-16 rounded-full bg-primary-blue/20 overflow-hidden flex items-center justify-center">
|
|
<Image
|
|
src={getDriverAvatarUrl(driver.id)}
|
|
alt={driver.name}
|
|
width={64}
|
|
height={64}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex-1">
|
|
<h3 className="text-xl font-semibold text-white mb-1">{driver.name}</h3>
|
|
<p className="text-sm text-gray-400">
|
|
{driver.nationality} • {driver.racesCompleted} races
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-8 text-center">
|
|
<div>
|
|
<div className="text-2xl font-bold text-primary-blue">{driver.rating}</div>
|
|
<div className="text-xs text-gray-400">Rating</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-2xl font-bold text-green-400">{driver.wins}</div>
|
|
<div className="text-xs text-gray-400">Wins</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-2xl font-bold text-warning-amber">{driver.podiums}</div>
|
|
<div className="text-xs text-gray-400">Podiums</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-sm text-gray-400">
|
|
{((driver.wins / driver.racesCompleted) * 100).toFixed(0)}%
|
|
</div>
|
|
<div className="text-xs text-gray-500">Win Rate</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
{sortedDrivers.length === 0 && (
|
|
<div className="text-center py-12">
|
|
<p className="text-gray-400">No drivers found matching your filters.</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
} |