refactor page to use services
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import {
|
||||
@@ -9,144 +10,24 @@ import {
|
||||
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';
|
||||
// Dashboard service imports
|
||||
import { ServiceFactory } from '@/lib/services/ServiceFactory';
|
||||
import { DashboardOverviewViewModel } from '@/lib/view-models/DashboardOverviewViewModel';
|
||||
|
||||
// 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 {
|
||||
@@ -197,29 +78,56 @@ function getGreeting(): string {
|
||||
return 'Good evening';
|
||||
}
|
||||
|
||||
interface FeedItem {
|
||||
id: string;
|
||||
type: string;
|
||||
headline: string;
|
||||
body: string | null;
|
||||
timestamp: Date;
|
||||
ctaHref?: string;
|
||||
ctaLabel?: string;
|
||||
}
|
||||
import { DashboardFeedItemSummaryViewModel } from '@/lib/view-models/DashboardOverviewViewModel';
|
||||
|
||||
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 [dashboardData, setDashboardData] = useState<DashboardOverviewViewModel | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const { totalRaces, wins, podiums, rating, globalRank, consistency } = currentDriver;
|
||||
useEffect(() => {
|
||||
const fetchDashboardData = async () => {
|
||||
try {
|
||||
const serviceFactory = new ServiceFactory(process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001');
|
||||
const dashboardService = serviceFactory.createDashboardService();
|
||||
const data = await dashboardService.getDashboardOverview();
|
||||
setDashboardData(data);
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch dashboard data:', err);
|
||||
setError('Failed to load dashboard data');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchDashboardData();
|
||||
}, []);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<main className="min-h-screen bg-deep-graphite flex items-center justify-center">
|
||||
<div className="text-white">Loading dashboard...</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !dashboardData) {
|
||||
return (
|
||||
<main className="min-h-screen bg-deep-graphite flex items-center justify-center">
|
||||
<div className="text-red-400">{error || 'Failed to load dashboard'}</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
const currentDriver = dashboardData.currentDriver;
|
||||
const nextRace = dashboardData.nextRace;
|
||||
const upcomingRaces = dashboardData.upcomingRaces;
|
||||
const leagueStandingsSummaries = dashboardData.leagueStandings;
|
||||
const feedSummary = { items: dashboardData.feedItems };
|
||||
const friends = dashboardData.friends;
|
||||
const activeLeaguesCount = dashboardData.activeLeaguesCount;
|
||||
|
||||
const { totalRaces, wins, podiums, rating, globalRank, consistency } = currentDriver;
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-deep-graphite">
|
||||
@@ -581,7 +489,7 @@ export default function DashboardPage() {
|
||||
}
|
||||
|
||||
// Feed Item Row Component
|
||||
function FeedItemRow({ item }: { item: FeedItem }) {
|
||||
function FeedItemRow({ item }: { item: DashboardFeedItemSummaryViewModel }) {
|
||||
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' };
|
||||
|
||||
Reference in New Issue
Block a user