Files
gridpilot.gg/apps/website/templates/DriverProfileTemplate.tsx
2026-01-15 17:12:24 +01:00

198 lines
6.1 KiB
TypeScript

'use client';
import { RatingBreakdown } from '@/ui/RatingBreakdown';
import { Breadcrumbs } from '@/ui/Breadcrumbs';
import { AchievementGrid } from '@/ui/AchievementGrid';
import { CareerStats } from '@/ui/CareerStats';
import { FriendsPreview } from '@/ui/FriendsPreview';
import { PerformanceOverview } from '@/ui/PerformanceOverview';
import { ProfileBio } from '@/ui/ProfileBio';
import { ProfileHero } from '@/ui/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&apos;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>
);
}