173 lines
6.8 KiB
TypeScript
173 lines
6.8 KiB
TypeScript
'use client';
|
|
|
|
import React from 'react';
|
|
import { Star, Trophy, Globe, Calendar, Clock, UserPlus, ExternalLink, LucideIcon } from 'lucide-react';
|
|
import { Box } from '@/ui/Box';
|
|
import { Stack } from '@/ui/Stack';
|
|
import { Text } from '@/ui/Text';
|
|
import { Heading } from '@/ui/Heading';
|
|
import { Image } from '@/ui/Image';
|
|
import { Button } from '@/ui/Button';
|
|
import { Link } from '@/ui/Link';
|
|
import { Surface } from '@/ui/Surface';
|
|
import { mediaConfig } from '@/lib/config/mediaConfig';
|
|
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
|
|
|
|
interface ProfileHeroProps {
|
|
driver: {
|
|
name: string;
|
|
avatarUrl?: string;
|
|
country: string;
|
|
iracingId: number;
|
|
joinedAt: string | Date;
|
|
};
|
|
stats: {
|
|
rating: number;
|
|
} | null;
|
|
globalRank: number;
|
|
timezone: string;
|
|
socialHandles: {
|
|
platform: string;
|
|
handle: string;
|
|
url: string;
|
|
}[];
|
|
onAddFriend: () => void;
|
|
friendRequestSent: boolean;
|
|
}
|
|
|
|
function getSocialIcon(platform: string) {
|
|
const { Twitter, Youtube, Twitch, MessageCircle } = require('lucide-react');
|
|
switch (platform) {
|
|
case 'twitter': return Twitter;
|
|
case 'youtube': return Youtube;
|
|
case 'twitch': return Twitch;
|
|
case 'discord': return MessageCircle;
|
|
default: return Globe;
|
|
}
|
|
}
|
|
|
|
export function ProfileHero({
|
|
driver,
|
|
stats,
|
|
globalRank,
|
|
timezone,
|
|
socialHandles,
|
|
onAddFriend,
|
|
friendRequestSent,
|
|
}: ProfileHeroProps) {
|
|
return (
|
|
<Surface variant="muted" rounded="2xl" border padding={6} style={{ background: 'linear-gradient(to bottom right, rgba(38, 38, 38, 0.8), rgba(38, 38, 38, 0.6), #0f1115)', borderColor: '#262626' }}>
|
|
<Stack direction="row" align="start" gap={6} wrap>
|
|
{/* Avatar */}
|
|
<Box style={{ position: 'relative' }}>
|
|
<Box style={{ width: '7rem', height: '7rem', borderRadius: '1rem', background: 'linear-gradient(to bottom right, #3b82f6, #9333ea)', padding: '0.25rem', boxShadow: '0 20px 25px -5px rgba(59, 130, 246, 0.2)' }}>
|
|
<Box style={{ width: '100%', height: '100%', borderRadius: '0.75rem', overflow: 'hidden', backgroundColor: '#262626' }}>
|
|
<Image
|
|
src={driver.avatarUrl || mediaConfig.avatars.defaultFallback}
|
|
alt={driver.name}
|
|
width={144}
|
|
height={144}
|
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* Driver Info */}
|
|
<Box style={{ flex: 1, minWidth: 0 }}>
|
|
<Stack direction="row" align="center" gap={3} wrap mb={2}>
|
|
<Heading level={1}>{driver.name}</Heading>
|
|
<Text size="4xl" aria-label={`Country: ${driver.country}`}>
|
|
{CountryFlagDisplay.fromCountryCode(driver.country).toString()}
|
|
</Text>
|
|
</Stack>
|
|
|
|
{/* Rating and Rank */}
|
|
<Stack direction="row" align="center" gap={4} wrap mb={4}>
|
|
{stats && (
|
|
<>
|
|
<Surface variant="muted" rounded="lg" padding={1} style={{ backgroundColor: 'rgba(59, 130, 246, 0.1)', border: '1px solid rgba(59, 130, 246, 0.3)', paddingLeft: '0.75rem', paddingRight: '0.75rem' }}>
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Star style={{ width: '1rem', height: '1rem', color: '#3b82f6' }} />
|
|
<Text font="mono" weight="bold" color="text-primary-blue">{stats.rating}</Text>
|
|
<Text size="xs" color="text-gray-400">Rating</Text>
|
|
</Stack>
|
|
</Surface>
|
|
<Surface variant="muted" rounded="lg" padding={1} style={{ backgroundColor: 'rgba(250, 204, 21, 0.1)', border: '1px solid rgba(250, 204, 21, 0.3)', paddingLeft: '0.75rem', paddingRight: '0.75rem' }}>
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Trophy style={{ width: '1rem', height: '1rem', color: '#facc15' }} />
|
|
<Text font="mono" weight="bold" style={{ color: '#facc15' }}>#{globalRank}</Text>
|
|
<Text size="xs" color="text-gray-400">Global</Text>
|
|
</Stack>
|
|
</Surface>
|
|
</>
|
|
)}
|
|
</Stack>
|
|
|
|
{/* Meta info */}
|
|
<Stack direction="row" align="center" gap={4} wrap style={{ fontSize: '0.875rem', color: '#9ca3af' }}>
|
|
<Stack direction="row" align="center" gap={1.5}>
|
|
<Globe style={{ width: '1rem', height: '1rem' }} />
|
|
<Text size="sm">iRacing: {driver.iracingId}</Text>
|
|
</Stack>
|
|
<Stack direction="row" align="center" gap={1.5}>
|
|
<Calendar style={{ width: '1rem', height: '1rem' }} />
|
|
<Text size="sm">
|
|
Joined{' '}
|
|
{new Date(driver.joinedAt).toLocaleDateString('en-US', {
|
|
month: 'short',
|
|
year: 'numeric',
|
|
})}
|
|
</Text>
|
|
</Stack>
|
|
<Stack direction="row" align="center" gap={1.5}>
|
|
<Clock style={{ width: '1rem', height: '1rem' }} />
|
|
<Text size="sm">{timezone}</Text>
|
|
</Stack>
|
|
</Stack>
|
|
</Box>
|
|
|
|
{/* Action Buttons */}
|
|
<Box>
|
|
<Button
|
|
variant="primary"
|
|
onClick={onAddFriend}
|
|
disabled={friendRequestSent}
|
|
icon={<UserPlus style={{ width: '1rem', height: '1rem' }} />}
|
|
>
|
|
{friendRequestSent ? 'Request Sent' : 'Add Friend'}
|
|
</Button>
|
|
</Box>
|
|
</Stack>
|
|
|
|
{/* Social Handles */}
|
|
{socialHandles.length > 0 && (
|
|
<Box mt={6} pt={6} style={{ borderTop: '1px solid rgba(38, 38, 38, 0.5)' }}>
|
|
<Stack direction="row" align="center" gap={2} wrap>
|
|
<Text size="sm" color="text-gray-500" style={{ marginRight: '0.5rem' }}>Connect:</Text>
|
|
{socialHandles.map((social) => {
|
|
const Icon = getSocialIcon(social.platform);
|
|
return (
|
|
<Box key={social.platform}>
|
|
<Link
|
|
href={social.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
variant="ghost"
|
|
>
|
|
<Surface variant="muted" rounded="lg" padding={1} style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', paddingLeft: '0.75rem', paddingRight: '0.75rem', backgroundColor: 'rgba(38, 38, 38, 0.5)', border: '1px solid #262626', color: '#9ca3af' }}>
|
|
<Icon style={{ width: '1rem', height: '1rem' }} />
|
|
<Text size="sm">{social.handle}</Text>
|
|
<ExternalLink style={{ width: '0.75rem', height: '0.75rem', opacity: 0.5 }} />
|
|
</Surface>
|
|
</Link>
|
|
</Box>
|
|
);
|
|
})}
|
|
</Stack>
|
|
</Box>
|
|
)}
|
|
</Surface>
|
|
);
|
|
}
|