'use client'; import Image from 'next/image'; import Link from 'next/link'; import { Calendar, Trophy, Users, Star, Clock, Flag, TrendingUp, ChevronRight, Zap, Target, Award, Activity, Play, Bell, Medal, Crown, Heart, MessageCircle, UserPlus, } from 'lucide-react'; import Card from '@/components/ui/Card'; import Button from '@/components/ui/Button'; // TODO: Re-enable API integration once backend is ready // import type { // DashboardOverviewViewModel, // DashboardFeedItemSummaryViewModel, // } from '@core/racing/application/presenters/IDashboardOverviewPresenter'; // Mock data for prototype const MOCK_CURRENT_DRIVER = { id: 'driver-1', name: 'Max Verstappen', avatarUrl: 'https://api.dicebear.com/7.x/avataaars/svg?seed=MaxV', country: 'NL', totalRaces: 142, wins: 28, podiums: 67, rating: 2847, globalRank: 15, consistency: 94, }; const MOCK_NEXT_RACE = { id: 'race-1', track: 'Spa-Francorchamps', car: 'Porsche 911 GT3 R', scheduledAt: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000), // 2 days from now isMyLeague: true, leagueName: 'GT3 Masters Series', }; const MOCK_UPCOMING_RACES = [ { id: 'race-1', track: 'Spa-Francorchamps', car: 'Porsche 911 GT3 R', scheduledAt: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000), isMyLeague: true, }, { id: 'race-2', track: 'Nürburgring GP', car: 'BMW M4 GT3', scheduledAt: new Date(Date.now() + 5 * 24 * 60 * 60 * 1000), isMyLeague: true, }, { id: 'race-3', track: 'Monza', car: 'Ferrari 296 GT3', scheduledAt: new Date(Date.now() + 8 * 24 * 60 * 60 * 1000), isMyLeague: false, }, { id: 'race-4', track: 'Silverstone', car: 'Aston Martin Vantage GT3', scheduledAt: new Date(Date.now() + 12 * 24 * 60 * 60 * 1000), isMyLeague: true, }, ]; const MOCK_LEAGUE_STANDINGS = [ { leagueId: 'league-1', leagueName: 'GT3 Masters Series', position: 2, points: 186, totalDrivers: 24, }, { leagueId: 'league-2', leagueName: 'Endurance Pro League', position: 5, points: 142, totalDrivers: 32, }, { leagueId: 'league-3', leagueName: 'F1 Weekend Warriors', position: 1, points: 225, totalDrivers: 18, }, ]; const MOCK_FEED_ITEMS = [ { id: 'feed-1', type: 'win', headline: 'You won the race at Spa-Francorchamps!', body: 'Great driving! You finished P1 with a 3.2s gap to second place.', timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000), ctaHref: '/races/race-prev-1', ctaLabel: 'View Results', }, { id: 'feed-2', type: 'friend_join', headline: 'Lewis Hamilton joined GT3 Masters Series', body: null, timestamp: new Date(Date.now() - 8 * 60 * 60 * 1000), ctaHref: '/leagues/league-1', ctaLabel: 'View League', }, { id: 'feed-3', type: 'podium', headline: 'Charles Leclerc finished P2 at Monza', body: 'Your friend had a great race!', timestamp: new Date(Date.now() - 24 * 60 * 60 * 1000), ctaHref: '/drivers/driver-2', ctaLabel: 'View Profile', }, ]; const MOCK_FRIENDS = [ { id: 'friend-1', name: 'Lewis Hamilton', avatarUrl: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Lewis', country: 'GB' }, { id: 'friend-2', name: 'Charles Leclerc', avatarUrl: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Charles', country: 'MC' }, { id: 'friend-3', name: 'Lando Norris', avatarUrl: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Lando', country: 'GB' }, { id: 'friend-4', name: 'Oscar Piastri', avatarUrl: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Oscar', country: 'AU' }, ]; // Helper functions 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 timeUntil(date: Date): string { const now = new Date(); const diffMs = date.getTime() - now.getTime(); if (diffMs < 0) return 'Started'; const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffDays = Math.floor(diffHours / 24); if (diffDays > 0) { return `${diffDays}d ${diffHours % 24}h`; } if (diffHours > 0) { const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60)); return `${diffHours}h ${diffMinutes}m`; } const diffMinutes = Math.floor(diffMs / (1000 * 60)); return `${diffMinutes}m`; } function timeAgo(timestamp: Date | string): string { const time = typeof timestamp === 'string' ? new Date(timestamp) : timestamp; const diffMs = Date.now() - time.getTime(); const diffMinutes = Math.floor(diffMs / 60000); if (diffMinutes < 1) return 'Just now'; if (diffMinutes < 60) return `${diffMinutes}m ago`; const diffHours = Math.floor(diffMinutes / 60); if (diffHours < 24) return `${diffHours}h ago`; const diffDays = Math.floor(diffHours / 24); return `${diffDays}d ago`; } function getGreeting(): string { const hour = new Date().getHours(); if (hour < 12) return 'Good morning'; if (hour < 18) return 'Good afternoon'; return 'Good evening'; } interface FeedItem { id: string; type: string; headline: string; body: string | null; timestamp: Date; ctaHref?: string; ctaLabel?: string; } export default function DashboardPage() { // TODO: Re-enable API integration once backend is ready // Currently using mock data for prototype const currentDriver = MOCK_CURRENT_DRIVER; const nextRace = MOCK_NEXT_RACE; const upcomingRaces = MOCK_UPCOMING_RACES; const leagueStandingsSummaries = MOCK_LEAGUE_STANDINGS; const feedSummary = { items: MOCK_FEED_ITEMS }; const friends = MOCK_FRIENDS; const activeLeaguesCount = 3; const { totalRaces, wins, podiums, rating, globalRank, consistency } = currentDriver; return (
{/* Hero Section */}
{/* Background Pattern */}
{/* Welcome Message */}
{currentDriver.name}

{getGreeting()},

{currentDriver.name} {getCountryFlag(currentDriver.country)}

{rating}
#{globalRank}
{totalRaces} races completed
{/* Quick Actions */}
{/* Quick Stats Row */}

{wins}

Wins

{podiums}

Podiums

{consistency}%

Consistency

{activeLeaguesCount}

Active Leagues

{/* Main Content */}
{/* Left Column - Main Content */}
{/* Next Race Card */} {nextRace && (
Next Race
{nextRace.isMyLeague && ( Your League )}

{nextRace.track}

{nextRace.car}

{nextRace.scheduledAt.toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric', })} {nextRace.scheduledAt.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', })}

Starts in

{timeUntil(nextRace.scheduledAt)}

)} {/* League Standings Preview */} {leagueStandingsSummaries.length > 0 && (

Your Championship Standings

View all
{leagueStandingsSummaries.map(({ leagueId, leagueName, position, points, totalDrivers }) => (
{position > 0 ? `P${position}` : '-'}

{leagueName}

{points} points • {totalDrivers} drivers

{position <= 3 && position > 0 && ( )}
))}
)} {/* Activity Feed */}

Recent Activity

{feedSummary.items.length > 0 ? (
{feedSummary.items.slice(0, 5).map((item) => ( ))}
) : (

No activity yet

Join leagues and add friends to see activity here

)}
{/* Right Column - Sidebar */}
{/* Upcoming Races */}

Upcoming Races

View all
{upcomingRaces.length > 0 ? (
{upcomingRaces.slice(0, 5).map((race) => { const isMyRace = race.isMyLeague; return (

{race.track}

{isMyRace && ( )}

{race.car}

{race.scheduledAt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} {timeUntil(race.scheduledAt)}
); })}
) : (

No upcoming races

)}
{/* Friends */}

Friends

{friends.length} friends
{friends.length > 0 ? (
{friends.slice(0, 6).map((friend) => (
{friend.name}

{friend.name}

{getCountryFlag(friend.country)}

))} {friends.length > 6 && ( +{friends.length - 6} more )}
) : (

No friends yet

)}
); } // Feed Item Row Component function FeedItemRow({ item }: { item: FeedItem }) { const getActivityIcon = (type: string) => { if (type.includes('win')) return { icon: Trophy, color: 'text-yellow-400 bg-yellow-400/10' }; if (type.includes('podium')) return { icon: Medal, color: 'text-warning-amber bg-warning-amber/10' }; if (type.includes('join')) return { icon: UserPlus, color: 'text-performance-green bg-performance-green/10' }; if (type.includes('friend')) return { icon: Heart, color: 'text-pink-400 bg-pink-400/10' }; if (type.includes('league')) return { icon: Flag, color: 'text-primary-blue bg-primary-blue/10' }; if (type.includes('race')) return { icon: Play, color: 'text-red-400 bg-red-400/10' }; return { icon: Activity, color: 'text-gray-400 bg-gray-400/10' }; }; const { icon: Icon, color } = getActivityIcon(item.type); return (

{item.headline}

{item.body && (

{item.body}

)}

{timeAgo(item.timestamp)}

{item.ctaHref && ( )}
); }