146 lines
5.0 KiB
TypeScript
146 lines
5.0 KiB
TypeScript
import React from 'react';
|
|
import { Trophy, Crown, Users } from 'lucide-react';
|
|
import type { TeamSummaryViewModel } from '@/lib/view-models/TeamSummaryViewModel';
|
|
import { getMediaUrl } from '@/lib/utilities/media';
|
|
import { Box } from './Box';
|
|
import { Stack } from './Stack';
|
|
import { Text } from './Text';
|
|
import { Icon } from './Icon';
|
|
import { Button } from './Button';
|
|
import { Image } from './Image';
|
|
import { Podium, PodiumItem } from './Podium';
|
|
|
|
interface TeamPodiumProps {
|
|
teams: TeamSummaryViewModel[];
|
|
onClick: (id: string) => void;
|
|
}
|
|
|
|
export function TeamPodium({ teams, onClick }: TeamPodiumProps) {
|
|
const top3 = teams.slice(0, 3) as [TeamSummaryViewModel, TeamSummaryViewModel, TeamSummaryViewModel];
|
|
if (teams.length < 3) return null;
|
|
|
|
// Display order: 2nd, 1st, 3rd
|
|
const podiumOrder: [TeamSummaryViewModel, TeamSummaryViewModel, TeamSummaryViewModel] = [
|
|
top3[1],
|
|
top3[0],
|
|
top3[2],
|
|
];
|
|
const podiumHeights = ['28', '36', '20'];
|
|
const podiumPositions = [2, 1, 3];
|
|
|
|
const getPositionColor = (position: number) => {
|
|
switch (position) {
|
|
case 1:
|
|
return 'text-yellow-400';
|
|
case 2:
|
|
return 'text-gray-300';
|
|
case 3:
|
|
return 'text-amber-600';
|
|
default:
|
|
return 'text-gray-500';
|
|
}
|
|
};
|
|
|
|
const getBgColor = (position: number) => {
|
|
switch (position) {
|
|
case 1:
|
|
return 'bg-gradient-to-br from-primary-blue/20 via-iron-gray/80 to-deep-graphite';
|
|
case 2:
|
|
return 'bg-iron-gray';
|
|
case 3:
|
|
return 'bg-gradient-to-br from-purple-600/20 via-iron-gray/80 to-deep-graphite';
|
|
default:
|
|
return 'bg-iron-gray/50';
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Podium title="Top 3 Teams">
|
|
{podiumOrder.map((team, index) => {
|
|
const position = podiumPositions[index] ?? 0;
|
|
|
|
return (
|
|
<PodiumItem
|
|
key={team.id}
|
|
position={position}
|
|
height={podiumHeights[index] || '20'}
|
|
bgColor={getBgColor(position)}
|
|
positionColor={getPositionColor(position)}
|
|
cardContent={
|
|
<Button
|
|
variant="ghost"
|
|
onClick={() => onClick(team.id)}
|
|
h="auto"
|
|
mb={4}
|
|
p={0}
|
|
className="transition-all"
|
|
>
|
|
<Box
|
|
bg={getBgColor(position)}
|
|
rounded="xl"
|
|
border={true}
|
|
borderColor="border-charcoal-outline"
|
|
p={4}
|
|
position="relative"
|
|
>
|
|
{/* Crown for 1st place */}
|
|
{position === 1 && (
|
|
<Box position="absolute" top="-4" left="1/2" translateX="-1/2">
|
|
<Box position="relative">
|
|
<Box animate="pulse">
|
|
<Icon icon={Crown} size={8} color="text-warning-amber" />
|
|
</Box>
|
|
<Box position="absolute" inset="0" bg="bg-yellow-400" bgOpacity={0.3} blur="md" rounded="full" />
|
|
</Box>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Team logo */}
|
|
<Box h="20" w="20" display="flex" center rounded="xl" bg="bg-deep-graphite" border={true} borderColor="border-charcoal-outline" overflow="hidden" mb={3}>
|
|
<Image
|
|
src={team.logoUrl || getMediaUrl('team-logo', team.id)}
|
|
alt={team.name}
|
|
width={80}
|
|
height={80}
|
|
objectFit="cover"
|
|
/>
|
|
</Box>
|
|
|
|
{/* Team name */}
|
|
<Text weight="bold" size="sm" color="text-white" align="center" block truncate maxWidth="28">
|
|
{team.name}
|
|
</Text>
|
|
|
|
{/* Category */}
|
|
{team.category && (
|
|
<Text size="xs" color="text-primary-blue" align="center" block mt={1}>
|
|
{team.category}
|
|
</Text>
|
|
)}
|
|
|
|
{/* Rating placeholder */}
|
|
<Text size="xl" weight="bold" color={getPositionColor(position)} align="center" block mt={1}>
|
|
—
|
|
</Text>
|
|
|
|
{/* Stats row */}
|
|
<Stack direction="row" align="center" justify="center" gap={3} mt={2}>
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Icon icon={Trophy} size={3} color="text-performance-green" />
|
|
<Text size="xs" color="text-gray-400">{team.totalWins}</Text>
|
|
</Stack>
|
|
<Stack direction="row" align="center" gap={1}>
|
|
<Icon icon={Users} size={3} color="text-primary-blue" />
|
|
<Text size="xs" color="text-gray-400">{team.memberCount}</Text>
|
|
</Stack>
|
|
</Stack>
|
|
</Box>
|
|
</Button>
|
|
}
|
|
/>
|
|
);
|
|
})}
|
|
</Podium>
|
|
);
|
|
}
|