198 lines
6.1 KiB
TypeScript
198 lines
6.1 KiB
TypeScript
'use client';
|
|
|
|
import { RatingBreakdown } from '@/ui/RatingBreakdown';
|
|
import { Breadcrumbs } from '@/ui/Breadcrumbs';
|
|
import { AchievementGrid } from '@/components/achievements/AchievementGrid';
|
|
import { CareerStats } from '@/ui/CareerStats';
|
|
import { FriendsPreview } from '@/components/social/FriendsPreview';
|
|
import { PerformanceOverview } from '@/ui/PerformanceOverview';
|
|
import { ProfileBio } from '@/ui/ProfileBio';
|
|
import { ProfileHero } from '@/components/drivers/ProfileHero';
|
|
import { ProfileTabs, type ProfileTab } from '@/ui/ProfileTabs';
|
|
import { RacingProfile } from '@/ui/RacingProfile';
|
|
import { TeamMembershipGrid } from '@/ui/TeamMembershipGrid';
|
|
import { Box } from '@/ui/Box';
|
|
import { Button } from '@/ui/Button';
|
|
import { Container } from '@/ui/Container';
|
|
import { LoadingSpinner } from '@/ui/LoadingSpinner';
|
|
import { Stack } from '@/ui/Stack';
|
|
import { Text } from '@/ui/Text';
|
|
import {
|
|
ArrowLeft,
|
|
} from 'lucide-react';
|
|
import React from 'react';
|
|
import type { DriverProfileViewData } from '../../../lib/types/view-data/DriverProfileViewData';
|
|
|
|
interface DriverProfileTemplateProps {
|
|
viewData: DriverProfileViewData;
|
|
isLoading?: boolean;
|
|
error?: string | null;
|
|
onBackClick: () => void;
|
|
onAddFriend: () => void;
|
|
friendRequestSent: boolean;
|
|
activeTab: ProfileTab;
|
|
onTabChange: (tab: ProfileTab) => void;
|
|
isSponsorMode?: boolean;
|
|
sponsorInsights?: React.ReactNode;
|
|
}
|
|
|
|
export function DriverProfileTemplate({
|
|
viewData,
|
|
isLoading = false,
|
|
error = null,
|
|
onBackClick,
|
|
onAddFriend,
|
|
friendRequestSent,
|
|
activeTab,
|
|
onTabChange,
|
|
isSponsorMode = false,
|
|
sponsorInsights = null,
|
|
}: DriverProfileTemplateProps) {
|
|
if (isLoading) {
|
|
return (
|
|
<Container size="lg" py={12}>
|
|
<Stack align="center" justify="center" gap={4}>
|
|
<LoadingSpinner size={10} />
|
|
<Text color="text-gray-400">Loading driver profile...</Text>
|
|
</Stack>
|
|
</Container>
|
|
);
|
|
}
|
|
|
|
if (error || !viewData?.currentDriver) {
|
|
return (
|
|
<Container size="md" py={12}>
|
|
<Stack align="center" gap={6}>
|
|
<Text color="text-warning-amber">{error || 'Driver not found'}</Text>
|
|
<Button variant="secondary" onClick={onBackClick}>
|
|
Back to Drivers
|
|
</Button>
|
|
</Stack>
|
|
</Container>
|
|
);
|
|
}
|
|
|
|
const { currentDriver, stats, teamMemberships, socialSummary, extendedProfile } = viewData;
|
|
|
|
return (
|
|
<Container size="lg" py={8}>
|
|
<Stack gap={6}>
|
|
{/* Back Navigation */}
|
|
<Box>
|
|
<Button
|
|
variant="secondary"
|
|
onClick={onBackClick}
|
|
icon={<ArrowLeft size={4} />}
|
|
>
|
|
Back to Drivers
|
|
</Button>
|
|
</Box>
|
|
|
|
{/* Breadcrumb */}
|
|
<Breadcrumbs
|
|
items={[
|
|
{ label: 'Home', href: '/' },
|
|
{ label: 'Drivers', href: '/drivers' },
|
|
{ label: currentDriver.name },
|
|
]}
|
|
/>
|
|
|
|
{/* Sponsor Insights Card */}
|
|
{isSponsorMode && sponsorInsights}
|
|
|
|
{/* Hero Header Section */}
|
|
<ProfileHero
|
|
driver={{
|
|
...currentDriver,
|
|
iracingId: currentDriver.iracingId || 0,
|
|
}}
|
|
stats={stats ? { rating: stats.rating || 0 } : null}
|
|
globalRank={currentDriver.globalRank || 0}
|
|
timezone={extendedProfile?.timezone || 'UTC'}
|
|
socialHandles={extendedProfile?.socialHandles || []}
|
|
onAddFriend={onAddFriend}
|
|
friendRequestSent={friendRequestSent}
|
|
/>
|
|
|
|
{/* Bio Section */}
|
|
{currentDriver.bio && <ProfileBio bio={currentDriver.bio} />}
|
|
|
|
{/* Team Memberships */}
|
|
{teamMemberships.length > 0 && (
|
|
<TeamMembershipGrid
|
|
memberships={teamMemberships.map((m) => ({
|
|
team: { id: m.teamId, name: m.teamName },
|
|
role: m.role,
|
|
joinedAt: new Date(m.joinedAt)
|
|
}))}
|
|
/>
|
|
)}
|
|
|
|
{/* Performance Overview */}
|
|
{stats && (
|
|
<PerformanceOverview
|
|
stats={{
|
|
wins: stats.wins,
|
|
podiums: stats.podiums,
|
|
totalRaces: stats.totalRaces,
|
|
consistency: stats.consistency,
|
|
dnfs: stats.dnfs,
|
|
bestFinish: stats.bestFinish || 0,
|
|
avgFinish: stats.avgFinish
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{/* Tab Navigation */}
|
|
<ProfileTabs activeTab={activeTab} onTabChange={onTabChange} />
|
|
|
|
{/* Tab Content */}
|
|
{activeTab === 'overview' && (
|
|
<Stack gap={6}>
|
|
<CareerStats stats={stats || { totalRaces: 0, wins: 0, podiums: 0, consistency: 0 }} />
|
|
|
|
{extendedProfile && (
|
|
<RacingProfile
|
|
racingStyle={extendedProfile.racingStyle}
|
|
favoriteTrack={extendedProfile.favoriteTrack}
|
|
favoriteCar={extendedProfile.favoriteCar}
|
|
availableHours={extendedProfile.availableHours}
|
|
lookingForTeam={extendedProfile.lookingForTeam}
|
|
openToRequests={extendedProfile.openToRequests}
|
|
/>
|
|
)}
|
|
|
|
{extendedProfile && extendedProfile.achievements.length > 0 && (
|
|
<AchievementGrid
|
|
achievements={extendedProfile.achievements.map((a) => ({
|
|
...a,
|
|
earnedAt: new Date(a.earnedAt)
|
|
}))}
|
|
/>
|
|
)}
|
|
|
|
{socialSummary.friends.length > 0 && (
|
|
<FriendsPreview friends={socialSummary.friends} />
|
|
)}
|
|
</Stack>
|
|
)}
|
|
|
|
{activeTab === 'stats' && !stats && (
|
|
<Stack align="center" py={12} gap={4}>
|
|
<Text color="text-gray-400">No statistics available yet</Text>
|
|
<Text size="sm" color="text-gray-500">This driver hasn't completed any races yet</Text>
|
|
</Stack>
|
|
)}
|
|
|
|
{activeTab === 'ratings' && (
|
|
<RatingBreakdown
|
|
skillRating={stats?.rating || 1450}
|
|
safetyRating={92} // Placeholder as not in viewData yet
|
|
sportsmanshipRating={4.8} // Placeholder as not in viewData yet
|
|
/>
|
|
)}
|
|
</Stack>
|
|
</Container>
|
|
);
|
|
}
|