website refactor
This commit is contained in:
163
apps/website/components/sponsors/AvailableLeagueCard.tsx
Normal file
163
apps/website/components/sponsors/AvailableLeagueCard.tsx
Normal file
@@ -0,0 +1,163 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { Star, Clock, CheckCircle2, ChevronRight } from 'lucide-react';
|
||||
import { Card } from '@/ui/Card';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Badge } from '@/ui/Badge';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { Surface } from '@/ui/Surface';
|
||||
import { Button } from '@/ui/Button';
|
||||
import { Link } from '@/ui/Link';
|
||||
|
||||
interface AvailableLeague {
|
||||
id: string;
|
||||
name: string;
|
||||
game: string;
|
||||
drivers: number;
|
||||
avgViewsPerRace: number;
|
||||
mainSponsorSlot: { available: boolean; price: number };
|
||||
secondarySlots: { available: number; total: number; price: number };
|
||||
rating: number;
|
||||
tier: 'premium' | 'standard' | 'starter';
|
||||
nextRace?: string;
|
||||
seasonStatus: 'active' | 'upcoming' | 'completed';
|
||||
description: string;
|
||||
formattedAvgViews: string;
|
||||
formattedCpm: string;
|
||||
}
|
||||
|
||||
interface AvailableLeagueCardProps {
|
||||
league: AvailableLeague;
|
||||
}
|
||||
|
||||
export function AvailableLeagueCard({ league }: AvailableLeagueCardProps) {
|
||||
const tierConfig = {
|
||||
premium: { icon: '⭐', label: 'Premium' },
|
||||
standard: { icon: '🏆', label: 'Standard' },
|
||||
starter: { icon: '🚀', label: 'Starter' },
|
||||
};
|
||||
|
||||
const statusConfig = {
|
||||
active: { color: '#10b981', label: 'Active Season' },
|
||||
upcoming: { color: '#f59e0b', label: 'Starting Soon' },
|
||||
completed: { color: '#9ca3af', label: 'Season Ended' },
|
||||
};
|
||||
|
||||
const config = tierConfig[league.tier];
|
||||
const status = statusConfig[league.seasonStatus];
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Stack gap={4}>
|
||||
{/* Header */}
|
||||
<Stack direction="row" align="start" justify="between">
|
||||
<Box style={{ flex: 1 }}>
|
||||
<Stack direction="row" align="center" gap={2} mb={1} wrap>
|
||||
<Badge variant="primary">{config.icon} {config.label}</Badge>
|
||||
<Surface variant="muted" rounded="full" padding={1} style={{ backgroundColor: `${status.color}1A`, paddingLeft: '0.5rem', paddingRight: '0.5rem' }}>
|
||||
<Text size="xs" weight="medium" style={{ color: status.color }}>{status.label}</Text>
|
||||
</Surface>
|
||||
</Stack>
|
||||
<Heading level={3}>{league.name}</Heading>
|
||||
<Text size="sm" color="text-gray-500" block mt={1}>{league.game}</Text>
|
||||
</Box>
|
||||
<Surface variant="muted" rounded="lg" padding={1} style={{ backgroundColor: 'rgba(38, 38, 38, 0.5)', paddingLeft: '0.5rem', paddingRight: '0.5rem' }}>
|
||||
<Stack direction="row" align="center" gap={1}>
|
||||
<Icon icon={Star} size={3.5} color="#facc15" />
|
||||
<Text size="sm" weight="medium" color="text-white">{league.rating}</Text>
|
||||
</Stack>
|
||||
</Surface>
|
||||
</Stack>
|
||||
|
||||
{/* Description */}
|
||||
<Text size="sm" color="text-gray-400" block truncate>{league.description}</Text>
|
||||
|
||||
{/* Stats Grid */}
|
||||
<Box style={{ display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: '0.5rem' }}>
|
||||
<StatItem label="Drivers" value={league.drivers} />
|
||||
<StatItem label="Avg Views" value={league.formattedAvgViews} />
|
||||
<StatItem label="CPM" value={league.formattedCpm} color="#10b981" />
|
||||
</Box>
|
||||
|
||||
{/* Next Race */}
|
||||
{league.nextRace && (
|
||||
<Stack direction="row" align="center" gap={2}>
|
||||
<Icon icon={Clock} size={4} color="#9ca3af" />
|
||||
<Text size="sm" color="text-gray-400">Next:</Text>
|
||||
<Text size="sm" color="text-white">{league.nextRace}</Text>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{/* Sponsorship Slots */}
|
||||
<Stack gap={2}>
|
||||
<SlotRow
|
||||
label="Main Sponsor"
|
||||
available={league.mainSponsorSlot.available}
|
||||
price={`$${league.mainSponsorSlot.price}/season`}
|
||||
/>
|
||||
<SlotRow
|
||||
label="Secondary Slots"
|
||||
available={league.secondarySlots.available > 0}
|
||||
price={`${league.secondarySlots.available}/${league.secondarySlots.total} @ $${league.secondarySlots.price}`}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
{/* Actions */}
|
||||
<Stack direction="row" gap={2}>
|
||||
<Box style={{ flex: 1 }}>
|
||||
<Link href={`/sponsor/leagues/${league.id}`}>
|
||||
<Button variant="secondary" fullWidth size="sm">
|
||||
View Details
|
||||
</Button>
|
||||
</Link>
|
||||
</Box>
|
||||
{(league.mainSponsorSlot.available || league.secondarySlots.available > 0) && (
|
||||
<Box style={{ flex: 1 }}>
|
||||
<Link href={`/sponsor/leagues/${league.id}?action=sponsor`}>
|
||||
<Button variant="primary" fullWidth size="sm">
|
||||
Sponsor
|
||||
</Button>
|
||||
</Link>
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function StatItem({ label, value, color = 'white' }: { label: string, value: string | number, color?: string }) {
|
||||
return (
|
||||
<Box p={2} style={{ backgroundColor: 'rgba(38, 38, 38, 0.5)', borderRadius: '0.5rem', textAlign: 'center' }}>
|
||||
<Text weight="bold" color="text-white" style={{ color: color !== 'white' ? color : undefined }}>{value}</Text>
|
||||
<Text size="xs" color="text-gray-500" block mt={1}>{label}</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function SlotRow({ label, available, price }: { label: string, available: boolean, price: string }) {
|
||||
return (
|
||||
<Surface variant="muted" rounded="lg" padding={2} style={{ backgroundColor: 'rgba(38, 38, 38, 0.3)' }}>
|
||||
<Stack direction="row" align="center" justify="between">
|
||||
<Stack direction="row" align="center" gap={2}>
|
||||
<Box style={{ width: '0.625rem', height: '0.625rem', borderRadius: '9999px', backgroundColor: available ? '#10b981' : '#ef4444' }} />
|
||||
<Text size="sm" color="text-gray-300">{label}</Text>
|
||||
</Stack>
|
||||
<Box>
|
||||
{available ? (
|
||||
<Text size="sm" weight="semibold" color="text-white">{price}</Text>
|
||||
) : (
|
||||
<Stack direction="row" align="center" gap={1}>
|
||||
<Icon icon={CheckCircle2} size={3} color="#737373" />
|
||||
<Text size="sm" color="text-gray-500">Filled</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</Box>
|
||||
</Stack>
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user