website refactor
This commit is contained in:
144
apps/website/components/sponsors/SponsorContractCard.tsx
Normal file
144
apps/website/components/sponsors/SponsorContractCard.tsx
Normal file
@@ -0,0 +1,144 @@
|
||||
'use client';
|
||||
|
||||
import React from '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 { Icon } from '@/ui/Icon';
|
||||
import { Button } from '@/ui/Button';
|
||||
import {
|
||||
Trophy,
|
||||
Users,
|
||||
Car,
|
||||
Flag,
|
||||
Megaphone,
|
||||
ChevronRight,
|
||||
ExternalLink,
|
||||
Calendar,
|
||||
BarChart3
|
||||
} from 'lucide-react';
|
||||
import { SponsorStatusChip, SponsorStatus } from './SponsorStatusChip';
|
||||
|
||||
export type SponsorshipType = 'league' | 'team' | 'driver' | 'race' | 'platform';
|
||||
|
||||
interface SponsorContractCardProps {
|
||||
id: string;
|
||||
type: SponsorshipType;
|
||||
status: string; // Accept raw status string
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
tier: string;
|
||||
investment: string;
|
||||
impressions: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
onViewDetails?: (id: string) => void;
|
||||
}
|
||||
|
||||
const TYPE_CONFIG = {
|
||||
league: { icon: Trophy, color: 'text-primary-blue', bgColor: 'bg-primary-blue/10', label: 'League' },
|
||||
team: { icon: Users, color: 'text-purple-400', bgColor: 'bg-purple-400/10', label: 'Team' },
|
||||
driver: { icon: Car, color: 'text-performance-green', bgColor: 'bg-performance-green/10', label: 'Driver' },
|
||||
race: { icon: Flag, color: 'text-warning-amber', bgColor: 'bg-warning-amber/10', label: 'Race' },
|
||||
platform: { icon: Megaphone, color: 'text-racing-red', bgColor: 'bg-racing-red/10', label: 'Platform' },
|
||||
};
|
||||
|
||||
function mapStatus(status: string): SponsorStatus {
|
||||
if (status === 'pending_approval' || status === 'pending') return 'pending';
|
||||
if (status === 'rejected' || status === 'declined') return 'declined';
|
||||
if (status === 'expired') return 'expired';
|
||||
if (status === 'approved') return 'approved';
|
||||
if (status === 'active') return 'active';
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
/**
|
||||
* SponsorContractCard
|
||||
*
|
||||
* Semantic component for displaying a sponsorship contract/campaign.
|
||||
* Provides a high-density overview of the sponsorship status and performance.
|
||||
*/
|
||||
export function SponsorContractCard({
|
||||
id,
|
||||
type,
|
||||
status,
|
||||
title,
|
||||
subtitle,
|
||||
tier,
|
||||
investment,
|
||||
impressions,
|
||||
startDate,
|
||||
endDate,
|
||||
onViewDetails
|
||||
}: SponsorContractCardProps) {
|
||||
const typeConfig = TYPE_CONFIG[type];
|
||||
const mappedStatus = mapStatus(status);
|
||||
|
||||
return (
|
||||
<Card p={5} hoverBorderColor="border-primary-blue/30">
|
||||
<Stack direction="row" align="start" justify="between" mb={4}>
|
||||
<Stack direction="row" align="center" gap={3}>
|
||||
<Box w="10" h="10" rounded="lg" bg={typeConfig.bgColor as string} display="flex" alignItems="center" justifyContent="center">
|
||||
<Icon icon={typeConfig.icon} size={5} color={typeConfig.color as string} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text size="xs" weight="bold" uppercase letterSpacing="wider" color={typeConfig.color as string}>
|
||||
{typeConfig.label} • {tier}
|
||||
</Text>
|
||||
<Heading level={4} fontSize="lg" weight="bold" color="text-white">
|
||||
{title}
|
||||
</Heading>
|
||||
{subtitle && <Text size="xs" color="text-gray-500">{subtitle}</Text>}
|
||||
</Box>
|
||||
</Stack>
|
||||
<SponsorStatusChip status={mappedStatus} />
|
||||
</Stack>
|
||||
|
||||
<Box display="grid" gridCols={3} gap={4} mb={4} p={3} rounded="lg" bg="bg-iron-gray/20">
|
||||
<Box>
|
||||
<Text size="xs" color="text-gray-500" block mb={1}>Impressions</Text>
|
||||
<Stack direction="row" align="center" gap={1}>
|
||||
<Icon icon={BarChart3} size={3} color="text-gray-400" />
|
||||
<Text weight="bold" color="text-white">{impressions}</Text>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text size="xs" color="text-gray-500" block mb={1}>Investment</Text>
|
||||
<Text weight="bold" color="text-white">{investment}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text size="xs" color="text-gray-500" block mb={1}>Term</Text>
|
||||
<Stack direction="row" align="center" gap={1}>
|
||||
<Icon icon={Calendar} size={3} color="text-gray-400" />
|
||||
<Text weight="bold" color="text-white">{endDate || 'N/A'}</Text>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Stack direction="row" align="center" justify="between" pt={4} borderTop borderColor="border-charcoal-outline/30">
|
||||
<Text size="xs" color="text-gray-500">
|
||||
{startDate ? `Started ${startDate}` : 'Contract pending'}
|
||||
</Text>
|
||||
<Stack direction="row" gap={2}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
icon={<Icon icon={ExternalLink} size={3} />}
|
||||
onClick={() => onViewDetails?.(id)}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
icon={<Icon icon={ChevronRight} size={3} />}
|
||||
>
|
||||
Details
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user