website refactor
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { SponsorActivityItem } from '@/ui/SponsorActivityItem';
|
||||
import { SponsorActivityItem } from '@/components/sponsors/SponsorActivityItem';
|
||||
|
||||
interface ActivityItemProps {
|
||||
activity: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { AvailableLeagueCard as UiAvailableLeagueCard } from '@/ui/AvailableLeagueCard';
|
||||
import { AvailableLeagueCard as UiAvailableLeagueCard } from '@/components/leagues/AvailableLeagueCard';
|
||||
|
||||
interface AvailableLeague {
|
||||
id: string;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Heading } from '@/ui/Heading';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { Badge } from '@/ui/Badge';
|
||||
import { SponsorshipRequestItem } from '@/ui/SponsorshipRequestItem';
|
||||
import { SponsorshipRequestItem } from '@/components/sponsors/SponsorshipRequestItem';
|
||||
|
||||
export interface PendingRequestDTO {
|
||||
id: string;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Trophy, Users, Car, Flag, Megaphone, LucideIcon } from 'lucide-react';
|
||||
import { RenewalItem } from '@/ui/RenewalItem';
|
||||
import { RenewalItem } from '@/components/sponsors/RenewalItem';
|
||||
|
||||
interface RenewalAlertProps {
|
||||
renewal: {
|
||||
|
||||
57
apps/website/components/sponsors/RenewalItem.tsx
Normal file
57
apps/website/components/sponsors/RenewalItem.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
|
||||
import { LucideIcon } from 'lucide-react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Button } from '@/ui/Button';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
|
||||
interface RenewalItemProps {
|
||||
name: string;
|
||||
renewDateLabel: string;
|
||||
priceLabel: string;
|
||||
icon: LucideIcon;
|
||||
onRenew?: () => void;
|
||||
}
|
||||
|
||||
export function RenewalItem({
|
||||
name,
|
||||
renewDateLabel,
|
||||
priceLabel,
|
||||
icon,
|
||||
onRenew,
|
||||
}: RenewalItemProps) {
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
align="center"
|
||||
justify="between"
|
||||
p={3}
|
||||
rounded="lg"
|
||||
bg="bg-warning-amber/10"
|
||||
border
|
||||
borderColor="border-warning-amber/30"
|
||||
>
|
||||
<Stack direction="row" align="center" gap={3}>
|
||||
<Icon icon={icon} size={4} color="rgb(245, 158, 11)" />
|
||||
<Box>
|
||||
<Text size="sm" color="text-white" block>{name}</Text>
|
||||
<Text size="xs" color="text-gray-400">Renews {renewDateLabel}</Text>
|
||||
</Box>
|
||||
</Stack>
|
||||
<Box textAlign="right">
|
||||
<Text size="sm" weight="semibold" color="text-white" block>{priceLabel}</Text>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
mt={1}
|
||||
onClick={onRenew}
|
||||
style={{ minHeight: 0, padding: '0.25rem 0.5rem', fontSize: '0.75rem' }}
|
||||
>
|
||||
Renew
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
36
apps/website/components/sponsors/SponsorActivityItem.tsx
Normal file
36
apps/website/components/sponsors/SponsorActivityItem.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
|
||||
interface SponsorActivityItemProps {
|
||||
message: string;
|
||||
time: string;
|
||||
typeColor: string;
|
||||
formattedImpressions?: string | null;
|
||||
}
|
||||
|
||||
export function SponsorActivityItem({
|
||||
message,
|
||||
time,
|
||||
typeColor,
|
||||
formattedImpressions,
|
||||
}: SponsorActivityItemProps) {
|
||||
return (
|
||||
<Stack direction="row" align="start" gap={3} py={3} borderBottom={true} borderColor="border-charcoal-outline/50">
|
||||
<Box width="2" height="2" rounded="full" mt={2} className={typeColor} flexShrink={0} />
|
||||
<Box flexGrow={1} minWidth="0">
|
||||
<Text size="sm" color="text-white" block truncate>{message}</Text>
|
||||
<Stack direction="row" align="center" gap={2} mt={1}>
|
||||
<Text size="xs" color="text-gray-500">{time}</Text>
|
||||
{formattedImpressions && (
|
||||
<>
|
||||
<Text size="xs" color="text-gray-600">•</Text>
|
||||
<Text size="xs" color="text-gray-400">{formattedImpressions} views</Text>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { Box } from '@/ui/Box';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Surface } from '@/ui/Surface';
|
||||
import { SponsorLogo } from '@/ui/SponsorLogo';
|
||||
import { SponsorLogo } from '@/components/sponsors/SponsorLogo';
|
||||
|
||||
interface SponsorBrandingPreviewProps {
|
||||
name: string;
|
||||
|
||||
@@ -30,9 +30,9 @@ import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { SponsorMetricCard } from '@/ui/SponsorMetricCard';
|
||||
import { SponsorSlotCard } from '@/ui/SponsorSlotCard';
|
||||
import { SponsorshipTierBadge } from '@/ui/SponsorshipTierBadge';
|
||||
import { SponsorMetricCard } from '@/components/sponsors/SponsorMetricCard';
|
||||
import { SponsorSlotCard } from '@/components/sponsors/SponsorSlotCard';
|
||||
import { SponsorshipTierBadge } from '@/components/sponsors/SponsorshipTierBadge';
|
||||
import { InfoBox } from '@/ui/InfoBox';
|
||||
import { SponsorMetric, SponsorshipSlot } from './SponsorInsightsCardTypes';
|
||||
import { getTierStyles, getEntityLabel, getSponsorshipTagline } from './SponsorInsightsCardHelpers';
|
||||
|
||||
53
apps/website/components/sponsors/SponsorLogo.tsx
Normal file
53
apps/website/components/sponsors/SponsorLogo.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Image } from '@/ui/Image';
|
||||
import { Building2 } from 'lucide-react';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
|
||||
export interface SponsorLogoProps {
|
||||
sponsorId?: string;
|
||||
src?: string;
|
||||
alt: string;
|
||||
size?: number;
|
||||
className?: string;
|
||||
border?: boolean;
|
||||
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
||||
}
|
||||
|
||||
export function SponsorLogo({
|
||||
sponsorId,
|
||||
src,
|
||||
alt,
|
||||
size = 48,
|
||||
className = '',
|
||||
border = true,
|
||||
rounded = 'md',
|
||||
}: SponsorLogoProps) {
|
||||
const logoSrc = src || (sponsorId ? `/media/sponsors/${sponsorId}/logo` : undefined);
|
||||
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
rounded={rounded}
|
||||
overflow="hidden"
|
||||
bg="bg-charcoal-outline/10"
|
||||
border={border}
|
||||
borderColor="border-charcoal-outline/50"
|
||||
className={className}
|
||||
style={{ width: size, height: size, flexShrink: 0 }}
|
||||
>
|
||||
{logoSrc ? (
|
||||
<Image
|
||||
src={logoSrc}
|
||||
alt={alt}
|
||||
className="w-full h-full object-contain p-1"
|
||||
fallbackSrc="/default-sponsor-logo.png"
|
||||
/>
|
||||
) : (
|
||||
<Icon icon={Building2} size={size > 32 ? 5 : 4} color="text-gray-500" />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
49
apps/website/components/sponsors/SponsorMetricCard.tsx
Normal file
49
apps/website/components/sponsors/SponsorMetricCard.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { LucideIcon } from 'lucide-react';
|
||||
|
||||
interface SponsorMetricCardProps {
|
||||
label: string;
|
||||
value: string | number;
|
||||
icon: LucideIcon;
|
||||
color?: string;
|
||||
trend?: {
|
||||
value: number;
|
||||
isPositive: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export function SponsorMetricCard({
|
||||
label,
|
||||
value,
|
||||
icon,
|
||||
color = 'text-primary-blue',
|
||||
trend,
|
||||
}: SponsorMetricCardProps) {
|
||||
return (
|
||||
<Box
|
||||
bg="bg-iron-gray/50"
|
||||
rounded="lg"
|
||||
p={3}
|
||||
border={true}
|
||||
borderColor="border-charcoal-outline"
|
||||
>
|
||||
<Box display="flex" alignItems="center" gap={1.5} className={color} mb={1}>
|
||||
<Icon icon={icon} size={4} />
|
||||
<Text size="xs" weight="medium">{label}</Text>
|
||||
</Box>
|
||||
<Box display="flex" alignItems="baseline" gap={2}>
|
||||
<Text size="xl" weight="bold" color="text-white">
|
||||
{typeof value === 'number' ? value.toLocaleString() : value}
|
||||
</Text>
|
||||
{trend && (
|
||||
<Text size="xs" color={trend.isPositive ? 'text-performance-green' : 'text-red-400'}>
|
||||
{trend.isPositive ? '+' : ''}{trend.value}%
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
45
apps/website/components/sponsors/SponsorSlotCard.tsx
Normal file
45
apps/website/components/sponsors/SponsorSlotCard.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Text } from '@/ui/Text';
|
||||
|
||||
interface SponsorSlotCardProps {
|
||||
title: string;
|
||||
status: string;
|
||||
statusColor: string;
|
||||
benefits: string;
|
||||
price?: string;
|
||||
action?: ReactNode;
|
||||
available: boolean;
|
||||
variant: 'main' | 'secondary';
|
||||
}
|
||||
|
||||
export function SponsorSlotCard({
|
||||
title,
|
||||
status,
|
||||
statusColor,
|
||||
benefits,
|
||||
price,
|
||||
action,
|
||||
available,
|
||||
variant,
|
||||
}: SponsorSlotCardProps) {
|
||||
const bgClass = available
|
||||
? (variant === 'main' ? 'bg-performance-green/10 border-performance-green/30' : 'bg-purple-500/10 border-purple-500/30')
|
||||
: 'bg-iron-gray/30 border-charcoal-outline';
|
||||
|
||||
return (
|
||||
<Box p={3} rounded="lg" border={true} className={bgClass}>
|
||||
<Box display="flex" alignItems="center" justifyContent="between" mb={1}>
|
||||
<Text size="sm" weight="medium" color="text-white">{title}</Text>
|
||||
<Text size="xs" className={statusColor}>{status}</Text>
|
||||
</Box>
|
||||
<Text size="xs" color="text-gray-400" block mb={2}>{benefits}</Text>
|
||||
{available && price && (
|
||||
<Box display="flex" alignItems="center" justifyContent="between">
|
||||
<Text size="lg" weight="bold" color="text-white">{price}</Text>
|
||||
{action}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { Trophy, Star } from 'lucide-react';
|
||||
import { SponsorTierCard as UiSponsorTierCard } from '@/ui/SponsorTierCard';
|
||||
|
||||
import { CheckCircle2, LucideIcon } from 'lucide-react';
|
||||
import { Badge } from '@/ui/Badge';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Surface } from '@/ui/Surface';
|
||||
import { Text } from '@/ui/Text';
|
||||
|
||||
interface SponsorTierCardProps {
|
||||
type: 'main' | 'secondary';
|
||||
@@ -13,6 +18,8 @@ interface SponsorTierCardProps {
|
||||
benefits: string[];
|
||||
isSelected: boolean;
|
||||
onClick: () => void;
|
||||
icon: LucideIcon;
|
||||
iconColor: string;
|
||||
}
|
||||
|
||||
export function SponsorTierCard({
|
||||
@@ -24,23 +31,69 @@ export function SponsorTierCard({
|
||||
benefits,
|
||||
isSelected,
|
||||
onClick,
|
||||
icon,
|
||||
iconColor,
|
||||
}: SponsorTierCardProps) {
|
||||
const isMain = type === 'main';
|
||||
const TierIcon = isMain ? Trophy : Star;
|
||||
const iconColor = isMain ? 'text-yellow-400' : 'text-purple-400';
|
||||
|
||||
return (
|
||||
<UiSponsorTierCard
|
||||
type={type}
|
||||
available={available}
|
||||
availableCount={availableCount}
|
||||
totalCount={totalCount}
|
||||
price={price}
|
||||
benefits={benefits}
|
||||
isSelected={isSelected}
|
||||
onClick={onClick}
|
||||
icon={TierIcon}
|
||||
iconColor={iconColor}
|
||||
/>
|
||||
<Surface
|
||||
variant="muted"
|
||||
rounded="xl"
|
||||
border={true}
|
||||
padding={5}
|
||||
className={`transition-all duration-200 ${available ? 'cursor-pointer' : 'opacity-60 cursor-default'} ${isSelected ? 'border-primary-blue ring-2 ring-primary-blue/20' : 'border-charcoal-outline'}`}
|
||||
onClick={available ? onClick : undefined}
|
||||
position="relative"
|
||||
>
|
||||
<Stack direction="row" align="start" justify="between" mb={4}>
|
||||
<Box>
|
||||
<Stack direction="row" align="center" gap={2} mb={1}>
|
||||
<Icon icon={icon} size={5} className={iconColor} />
|
||||
<Heading level={3}>{isMain ? 'Main Sponsor' : 'Secondary Sponsor'}</Heading>
|
||||
</Stack>
|
||||
<Text size="sm" color="text-gray-400">
|
||||
{isMain ? 'Primary branding position' : 'Supporting branding position'}
|
||||
</Text>
|
||||
</Box>
|
||||
<Badge variant={available ? 'success' : 'default'}>
|
||||
{isMain
|
||||
? (available ? 'Available' : 'Filled')
|
||||
: (available ? `${availableCount}/${totalCount} Available` : 'Full')
|
||||
}
|
||||
</Badge>
|
||||
</Stack>
|
||||
|
||||
<Box mb={4}>
|
||||
<Text size="3xl" weight="bold" color="text-white">
|
||||
${price}
|
||||
<Text size="sm" weight="normal" color="text-gray-500">/season</Text>
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Stack gap={2} mb={4}>
|
||||
{benefits.map((benefit, i) => (
|
||||
<Stack key={i} direction="row" align="center" gap={2}>
|
||||
<Icon icon={CheckCircle2} size={4} color="text-performance-green" />
|
||||
<Text size="sm" color="text-gray-300">{benefit}</Text>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
|
||||
{isSelected && available && (
|
||||
<Box position="absolute" top="4" right="4">
|
||||
<Box
|
||||
width="4"
|
||||
height="4"
|
||||
rounded="full"
|
||||
bg="bg-primary-blue"
|
||||
display="flex"
|
||||
center
|
||||
>
|
||||
<Icon icon={CheckCircle2} size={3} color="text-white" />
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { LucideIcon } from 'lucide-react';
|
||||
import { SponsorshipCategoryCard as UiSponsorshipCategoryCard } from '@/ui/SponsorshipCategoryCard';
|
||||
import { Link } from '@/ui/Link';
|
||||
import { Card } from '@/ui/Card';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
|
||||
interface SponsorshipCategoryCardProps {
|
||||
icon: LucideIcon;
|
||||
@@ -21,13 +25,31 @@ export function SponsorshipCategoryCard({
|
||||
href
|
||||
}: SponsorshipCategoryCardProps) {
|
||||
return (
|
||||
<UiSponsorshipCategoryCard
|
||||
icon={icon}
|
||||
title={title}
|
||||
count={count}
|
||||
impressions={impressions}
|
||||
color={color}
|
||||
href={href}
|
||||
/>
|
||||
<Link href={href} variant="ghost" block>
|
||||
<Card p={4} className="hover:border-charcoal-outline/60 transition-all cursor-pointer">
|
||||
<Stack direction="row" align="center" justify="between">
|
||||
<Stack direction="row" align="center" gap={3}>
|
||||
<Box
|
||||
width="10"
|
||||
height="10"
|
||||
rounded="lg"
|
||||
bg="bg-charcoal-outline"
|
||||
display="flex"
|
||||
center
|
||||
>
|
||||
<Icon icon={icon} size={5} className={color} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text weight="medium" color="text-white" block>{title}</Text>
|
||||
<Text size="sm" color="text-gray-500">{count} active</Text>
|
||||
</Box>
|
||||
</Stack>
|
||||
<Box textAlign="right">
|
||||
<Text weight="semibold" color="text-white" block>{impressions.toLocaleString()}</Text>
|
||||
<Text size="xs" color="text-gray-500">impressions</Text>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
166
apps/website/components/sponsors/SponsorshipRequestItem.tsx
Normal file
166
apps/website/components/sponsors/SponsorshipRequestItem.tsx
Normal file
@@ -0,0 +1,166 @@
|
||||
|
||||
|
||||
import { Building, Check, Clock, DollarSign, MessageCircle, X } from 'lucide-react';
|
||||
import React from 'react';
|
||||
import { Badge } from '@/ui/Badge';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Button } from '@/ui/Button';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { Image } from '@/ui/Image';
|
||||
import { Text } from '@/ui/Text';
|
||||
|
||||
interface SponsorshipRequestItemProps {
|
||||
sponsorName: string;
|
||||
sponsorLogo?: string;
|
||||
tier: string;
|
||||
formattedAmount: string;
|
||||
netAmount: number;
|
||||
createdAt: Date;
|
||||
message?: string;
|
||||
isProcessing: boolean;
|
||||
isRejecting: boolean;
|
||||
rejectReason: string;
|
||||
onAccept: () => void;
|
||||
onRejectClick: () => void;
|
||||
onRejectConfirm: () => void;
|
||||
onRejectCancel: () => void;
|
||||
onRejectReasonChange: (reason: string) => void;
|
||||
}
|
||||
|
||||
export function SponsorshipRequestItem({
|
||||
sponsorName,
|
||||
sponsorLogo,
|
||||
tier,
|
||||
formattedAmount,
|
||||
netAmount,
|
||||
createdAt,
|
||||
message,
|
||||
isProcessing,
|
||||
isRejecting,
|
||||
rejectReason,
|
||||
onAccept,
|
||||
onRejectClick,
|
||||
onRejectConfirm,
|
||||
onRejectCancel,
|
||||
onRejectReasonChange,
|
||||
}: SponsorshipRequestItemProps) {
|
||||
return (
|
||||
<Box rounded="lg" border borderColor="border-charcoal-outline" bg="bg-deep-graphite/70" p={4}>
|
||||
{/* Reject Modal */}
|
||||
{isRejecting && (
|
||||
<Box mb={4} p={4} rounded="lg" bg="bg-iron-gray/50" border borderColor="border-red-500/30">
|
||||
<Heading level={4} mb={2}>
|
||||
Reject sponsorship from {sponsorName}?
|
||||
</Heading>
|
||||
<Box
|
||||
as="textarea"
|
||||
value={rejectReason}
|
||||
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => onRejectReasonChange(e.target.value)}
|
||||
placeholder="Optional: Provide a reason for rejection..."
|
||||
rows={2}
|
||||
p={3}
|
||||
py={2}
|
||||
bg="bg-iron-gray/80"
|
||||
color="text-white"
|
||||
border
|
||||
borderColor="border-charcoal-outline"
|
||||
rounded="lg"
|
||||
fullWidth
|
||||
style={{ resize: 'none' }}
|
||||
className="text-sm placeholder:text-gray-500 focus:ring-2 focus:ring-red-500 mb-3"
|
||||
/>
|
||||
<Box display="flex" gap={2}>
|
||||
<Button variant="secondary" onClick={onRejectCancel} size="sm">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={onRejectConfirm}
|
||||
disabled={isProcessing}
|
||||
size="sm"
|
||||
>
|
||||
{isProcessing ? 'Rejecting...' : 'Confirm Reject'}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Box display="flex" alignItems="start" justifyContent="between" gap={4}>
|
||||
<Box display="flex" alignItems="start" gap={3} flexGrow={1}>
|
||||
{/* Sponsor Logo */}
|
||||
<Box display="flex" h="12" w="12" alignItems="center" justifyContent="center" rounded="lg" bg="bg-iron-gray/50" flexShrink={0}>
|
||||
{sponsorLogo ? (
|
||||
<Image src={sponsorLogo} alt={sponsorName} width={32} height={32} objectFit="contain" />
|
||||
) : (
|
||||
<Icon icon={Building} size={6} color="rgb(156, 163, 175)" />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box flexGrow={1} minWidth="0">
|
||||
<Box display="flex" alignItems="center" gap={2} mb={1}>
|
||||
<Heading level={4} truncate>
|
||||
{sponsorName}
|
||||
</Heading>
|
||||
<Badge variant={tier === 'main' ? 'primary' : 'default'}>
|
||||
{tier === 'main' ? 'Main Sponsor' : 'Secondary'}
|
||||
</Badge>
|
||||
</Box>
|
||||
|
||||
{/* Offer Details */}
|
||||
<Box display="flex" flexWrap="wrap" gap={3} mb={2}>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<Icon icon={DollarSign} size={3} color="rgb(16, 185, 129)" />
|
||||
<Text weight="semibold" color="text-performance-green" size="xs">{formattedAmount}</Text>
|
||||
</Box>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<Text color="text-gray-500" size="xs">Net: ${(netAmount / 100).toFixed(2)}</Text>
|
||||
</Box>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<Icon icon={Clock} size={3} color="rgb(156, 163, 175)" />
|
||||
<Text color="text-gray-500" size="xs">
|
||||
{createdAt.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
})}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Message */}
|
||||
{message && (
|
||||
<Box display="flex" alignItems="start" gap={1.5} p={2} bg="bg-iron-gray/30" rounded>
|
||||
<Icon icon={MessageCircle} size={3} color="rgb(156, 163, 175)" flexShrink={0} mt={0.5} />
|
||||
<Text size="xs" color="text-gray-400" lineClamp={2}>{message}</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Actions */}
|
||||
{!isRejecting && (
|
||||
<Box display="flex" gap={2} flexShrink={0}>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={onAccept}
|
||||
disabled={isProcessing}
|
||||
size="sm"
|
||||
icon={<Icon icon={Check} size={3} />}
|
||||
>
|
||||
{isProcessing ? 'Accepting...' : 'Accept'}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={onRejectClick}
|
||||
disabled={isProcessing}
|
||||
size="sm"
|
||||
icon={<Icon icon={X} size={3} />}
|
||||
>
|
||||
Reject
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
26
apps/website/components/sponsors/SponsorshipTierBadge.tsx
Normal file
26
apps/website/components/sponsors/SponsorshipTierBadge.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
|
||||
import { Badge } from '@/ui/Badge';
|
||||
|
||||
interface SponsorshipTierBadgeProps {
|
||||
tier: 'premium' | 'standard' | 'starter';
|
||||
entityLabel: string;
|
||||
}
|
||||
|
||||
export function SponsorshipTierBadge({ tier, entityLabel }: SponsorshipTierBadgeProps) {
|
||||
const tierStyles = {
|
||||
premium: 'bg-yellow-400/10 border-yellow-400/30 text-yellow-400',
|
||||
standard: 'bg-purple-400/10 border-purple-400/30 text-purple-400',
|
||||
starter: 'bg-primary-blue/10 border-primary-blue/30 text-primary-blue',
|
||||
};
|
||||
|
||||
return (
|
||||
<Badge
|
||||
bg={tierStyles[tier].split(' ')[0]}
|
||||
borderColor={tierStyles[tier].split(' ')[1]}
|
||||
color={tierStyles[tier].split(' ')[2]}
|
||||
>
|
||||
{tier.charAt(0).toUpperCase() + tier.slice(1)} {entityLabel}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user