website refactor
This commit is contained in:
@@ -1,189 +1,122 @@
|
||||
'use client';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
import React from 'react';
|
||||
import {
|
||||
Trophy,
|
||||
Users,
|
||||
Search,
|
||||
Crown,
|
||||
} from 'lucide-react';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Input from '@/components/ui/Input';
|
||||
import Card from '@/components/ui/Card';
|
||||
import Heading from '@/components/ui/Heading';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Container } from '@/ui/Container';
|
||||
import { Grid } from '@/ui/Grid';
|
||||
import { GridItem } from '@/ui/GridItem';
|
||||
import { Surface } from '@/ui/Surface';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { FeaturedDriverCard } from '@/components/drivers/FeaturedDriverCard';
|
||||
import { SkillDistribution } from '@/components/drivers/SkillDistribution';
|
||||
import { CategoryDistribution } from '@/components/drivers/CategoryDistribution';
|
||||
import { LeaderboardPreview } from '@/components/drivers/LeaderboardPreview';
|
||||
import { RecentActivity } from '@/components/drivers/RecentActivity';
|
||||
import { useDriverSearch } from '@/lib/hooks/useDriverSearch';
|
||||
import type { DriverLeaderboardViewModel } from '@/lib/view-models/DriverLeaderboardViewModel';
|
||||
import { DriversHero } from '@/components/drivers/DriversHero';
|
||||
import { DriversSearch } from '@/components/drivers/DriversSearch';
|
||||
import { EmptyState } from '@/components/shared/state/EmptyState';
|
||||
import type { DriversViewData } from '@/lib/types/view-data/DriversViewData';
|
||||
|
||||
interface DriversTemplateProps {
|
||||
data: DriverLeaderboardViewModel | null;
|
||||
viewData: DriversViewData | null;
|
||||
searchQuery: string;
|
||||
onSearchChange: (query: string) => void;
|
||||
filteredDrivers: DriversViewData['drivers'];
|
||||
onDriverClick: (id: string) => void;
|
||||
onViewLeaderboard: () => void;
|
||||
}
|
||||
|
||||
export function DriversTemplate({ data }: DriversTemplateProps) {
|
||||
const drivers = data?.drivers || [];
|
||||
const totalRaces = data?.totalRaces || 0;
|
||||
const totalWins = data?.totalWins || 0;
|
||||
const activeCount = data?.activeCount || 0;
|
||||
const isLoading = false;
|
||||
|
||||
const router = useRouter();
|
||||
const { searchQuery, setSearchQuery, filteredDrivers } = useDriverSearch(drivers);
|
||||
|
||||
const handleDriverClick = (driverId: string) => {
|
||||
router.push(`/drivers/${driverId}`);
|
||||
};
|
||||
export function DriversTemplate({
|
||||
viewData,
|
||||
searchQuery,
|
||||
onSearchChange,
|
||||
filteredDrivers,
|
||||
onDriverClick,
|
||||
onViewLeaderboard
|
||||
}: DriversTemplateProps) {
|
||||
const drivers = viewData?.drivers || [];
|
||||
const totalRaces = viewData?.totalRaces || 0;
|
||||
const totalWins = viewData?.totalWins || 0;
|
||||
const activeCount = viewData?.activeCount || 0;
|
||||
|
||||
// Featured drivers (top 4)
|
||||
const featuredDrivers = filteredDrivers.slice(0, 4);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="max-w-7xl 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 drivers...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto px-4 pb-12">
|
||||
{/* Hero Section */}
|
||||
<div className="relative mb-10 py-10 px-8 rounded-2xl bg-gradient-to-br from-primary-blue/20 via-iron-gray/80 to-deep-graphite border border-primary-blue/30 overflow-hidden">
|
||||
{/* Background decoration */}
|
||||
<div className="absolute top-0 right-0 w-96 h-96 bg-primary-blue/10 rounded-full blur-3xl" />
|
||||
<div className="absolute bottom-0 left-0 w-64 h-64 bg-yellow-400/5 rounded-full blur-3xl" />
|
||||
<div className="absolute top-1/2 right-1/4 w-48 h-48 bg-performance-green/5 rounded-full blur-2xl" />
|
||||
<Container size="lg" py={8}>
|
||||
<Stack gap={10}>
|
||||
{/* Hero Section */}
|
||||
<DriversHero
|
||||
driverCount={drivers.length}
|
||||
activeCount={activeCount}
|
||||
totalWins={totalWins}
|
||||
totalRaces={totalRaces}
|
||||
onViewLeaderboard={onViewLeaderboard}
|
||||
/>
|
||||
|
||||
<div className="relative z-10 flex flex-col lg:flex-row lg:items-center lg:justify-between gap-8">
|
||||
<div className="max-w-2xl">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-gradient-to-br from-primary-blue/20 to-primary-blue/5 border border-primary-blue/20">
|
||||
<Users className="w-6 h-6 text-primary-blue" />
|
||||
</div>
|
||||
<Heading level={1} className="text-3xl lg:text-4xl">
|
||||
Drivers
|
||||
</Heading>
|
||||
</div>
|
||||
<p className="text-gray-400 text-lg leading-relaxed mb-6">
|
||||
Meet the racers who make every lap count. From rookies to champions, track their journey and see who's dominating the grid.
|
||||
</p>
|
||||
{/* Search */}
|
||||
<DriversSearch query={searchQuery} onChange={onSearchChange} />
|
||||
|
||||
{/* Quick Stats */}
|
||||
<div className="flex flex-wrap gap-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 rounded-full bg-primary-blue" />
|
||||
<span className="text-sm text-gray-400">
|
||||
<span className="text-white font-semibold">{drivers.length}</span> drivers
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 rounded-full bg-performance-green animate-pulse" />
|
||||
<span className="text-sm text-gray-400">
|
||||
<span className="text-white font-semibold">{activeCount}</span> active
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 rounded-full bg-yellow-400" />
|
||||
<span className="text-sm text-gray-400">
|
||||
<span className="text-white font-semibold">{totalWins.toLocaleString()}</span> total wins
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 rounded-full bg-neon-aqua" />
|
||||
<span className="text-sm text-gray-400">
|
||||
<span className="text-white font-semibold">{totalRaces.toLocaleString()}</span> races
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Featured Drivers */}
|
||||
{!searchQuery && (
|
||||
<Box>
|
||||
<Stack direction="row" align="center" gap={3} mb={4}>
|
||||
<Surface variant="muted" rounded="xl" padding={2}>
|
||||
<Icon icon={Crown} size={6} color="#f59e0b" />
|
||||
</Surface>
|
||||
<Box>
|
||||
<Heading level={2}>Featured Drivers</Heading>
|
||||
<Text size="xs" color="text-gray-500">Top performers on the grid</Text>
|
||||
</Box>
|
||||
</Stack>
|
||||
|
||||
{/* CTA */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => router.push('/leaderboards/drivers')}
|
||||
className="flex items-center gap-2 px-6 py-3"
|
||||
>
|
||||
<Trophy className="w-5 h-5" />
|
||||
View Leaderboard
|
||||
</Button>
|
||||
<p className="text-xs text-gray-500 text-center">See full driver rankings</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Grid cols={4} gap={4}>
|
||||
{featuredDrivers.map((driver, index) => (
|
||||
<GridItem key={driver.id} colSpan={12} mdSpan={6} lgSpan={3}>
|
||||
<FeaturedDriverCard
|
||||
driver={driver}
|
||||
position={index + 1}
|
||||
onClick={() => onDriverClick(driver.id)}
|
||||
/>
|
||||
</GridItem>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Search */}
|
||||
<div className="mb-8">
|
||||
<div className="relative max-w-md">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-500" />
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Search drivers by name or nationality..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pl-11"
|
||||
{/* Active Drivers */}
|
||||
{!searchQuery && <RecentActivity drivers={drivers} onDriverClick={onDriverClick} />}
|
||||
|
||||
{/* Skill Distribution */}
|
||||
{!searchQuery && <SkillDistribution drivers={drivers} />}
|
||||
|
||||
{/* Category Distribution */}
|
||||
{!searchQuery && <CategoryDistribution drivers={drivers} />}
|
||||
|
||||
{/* Leaderboard Preview */}
|
||||
<LeaderboardPreview drivers={filteredDrivers} onDriverClick={onDriverClick} />
|
||||
|
||||
{/* Empty State */}
|
||||
{filteredDrivers.length === 0 && (
|
||||
<EmptyState
|
||||
icon={Search}
|
||||
title="No drivers found"
|
||||
description={`No drivers found matching "${searchQuery}"`}
|
||||
action={{
|
||||
label: 'Clear search',
|
||||
onClick: () => onSearchChange(''),
|
||||
variant: 'secondary'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Featured Drivers */}
|
||||
{!searchQuery && (
|
||||
<div className="mb-10">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-yellow-400/10 border border-yellow-400/20">
|
||||
<Crown className="w-5 h-5 text-yellow-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-white">Featured Drivers</h2>
|
||||
<p className="text-xs text-gray-500">Top performers on the grid</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{featuredDrivers.map((driver, index) => (
|
||||
<FeaturedDriverCard
|
||||
key={driver.id}
|
||||
driver={driver}
|
||||
position={index + 1}
|
||||
onClick={() => handleDriverClick(driver.id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Active Drivers */}
|
||||
{!searchQuery && <RecentActivity drivers={drivers} onDriverClick={handleDriverClick} />}
|
||||
|
||||
{/* Skill Distribution */}
|
||||
{!searchQuery && <SkillDistribution drivers={drivers} />}
|
||||
|
||||
{/* Category Distribution */}
|
||||
{!searchQuery && <CategoryDistribution drivers={drivers} />}
|
||||
|
||||
{/* Leaderboard Preview */}
|
||||
<LeaderboardPreview drivers={filteredDrivers} onDriverClick={handleDriverClick} />
|
||||
|
||||
{/* Empty State */}
|
||||
{filteredDrivers.length === 0 && (
|
||||
<Card className="text-center py-12">
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<Search className="w-10 h-10 text-gray-600" />
|
||||
<p className="text-gray-400">No drivers found matching "{searchQuery}"</p>
|
||||
<Button variant="secondary" onClick={() => setSearchQuery('')}>
|
||||
Clear search
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Stack>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user