'use client'; import Button from '@/ui/Button'; import Card from '@/ui/Card'; import { useInject } from '@/lib/di/hooks/useInject'; import { SPONSOR_SERVICE_TOKEN } from '@/lib/di/tokens'; import { Activity, Check, Loader2, MessageCircle, Shield, Target } from 'lucide-react'; import { useRouter } from 'next/navigation'; import React, { useCallback, useState } from 'react'; import { SponsorMetric, SponsorshipSlot } from './SponsorInsightsCardTypes'; import { getTierStyles, getEntityLabel, getEntityIcon, getSponsorshipTagline } from './SponsorInsightsCardHelpers'; // ============================================================================ // TYPES // ============================================================================ export type EntityType = 'league' | 'race' | 'driver' | 'team'; export interface SponsorInsightsProps { // Entity info entityType: EntityType; entityId: string; entityName: string; // Tier classification tier: 'premium' | 'standard' | 'starter'; // Key metrics (shown in grid) metrics: SponsorMetric[]; // Sponsorship availability slots: SponsorshipSlot[]; // Optional: additional stats section additionalStats?: { label: string; items: Array<{ label: string; value: string | number }>; }; // Optional: trust indicators trustScore?: number; discordMembers?: number; monthlyActivity?: number; // CTA customization ctaLabel?: string; ctaHref?: string; // Optional: current sponsor ID (if logged in as sponsor) currentSponsorId?: string; // Optional: callback when sponsorship request is submitted onSponsorshipRequested?: (tier: 'main' | 'secondary') => void; } // ============================================================================ // COMPONENT // ============================================================================ export default function SponsorInsightsCard({ entityType, entityId, entityName, tier, metrics, slots, additionalStats, trustScore, discordMembers, monthlyActivity, ctaLabel, ctaHref, currentSponsorId, onSponsorshipRequested, }: SponsorInsightsProps) { // TODO components should not fetch any data const router = useRouter(); const sponsorshipService = useInject(SPONSOR_SERVICE_TOKEN); const tierStyles = getTierStyles(tier); const EntityIcon = getEntityIcon(entityType); // State for sponsorship application const [applyingTier, setApplyingTier] = useState<'main' | 'secondary' | null>(null); const [appliedTiers, setAppliedTiers] = useState>(new Set()); const [error, setError] = useState(null); const mainSlot = slots.find(s => s.tier === 'main'); const secondarySlots = slots.filter(s => s.tier === 'secondary'); const availableSecondary = secondarySlots.filter(s => s.available).length; // Map EntityType to SponsorableEntityType const getSponsorableEntityType = useCallback((type: EntityType): 'driver' | 'team' | 'race' | 'season' => { switch (type) { case 'league': return 'season'; // Leagues are sponsored via their seasons case 'race': return 'race'; case 'driver': return 'driver'; case 'team': return 'team'; } }, []); const handleSponsorClick = useCallback(async (slotTier: 'main' | 'secondary') => { // If no sponsor ID, redirect to sponsor signup/login if (!currentSponsorId) { const href = ctaHref || `/sponsor/${entityType}s/${entityId}?tier=${slotTier}`; router.push(href); return; } // If already applied for this tier, show details page if (appliedTiers.has(slotTier)) { router.push(`/sponsor/dashboard`); return; } // Apply for sponsorship using service setApplyingTier(slotTier); setError(null); try { const slot = slotTier === 'main' ? mainSlot : secondarySlots[0]; const slotPrice = slot?.price ?? 0; // Note: The sponsorship service would need a method to submit sponsorship requests // For now, we'll use a placeholder since the exact API may not be available const request = { sponsorId: currentSponsorId, entityType: getSponsorableEntityType(entityType), entityId, tier: slotTier, offeredAmount: slotPrice * 100, // Convert to cents currency: (slot?.currency as 'USD' | 'EUR' | 'GBP') ?? 'USD', message: `Interested in sponsoring ${entityName} as ${slotTier} sponsor.`, }; // This would be: await sponsorshipService.submitSponsorshipRequest(request); // For now, we'll log it as a placeholder console.log('Sponsorship request:', request); // Mark as applied setAppliedTiers(prev => new Set([...prev, slotTier])); // Call callback if provided onSponsorshipRequested?.(slotTier); } catch (err) { console.error('Failed to apply for sponsorship:', err); setError(err instanceof Error ? err.message : 'Failed to submit sponsorship request'); } finally { setApplyingTier(null); } }, [currentSponsorId, ctaHref, entityType, entityId, entityName, router, mainSlot, secondarySlots, appliedTiers, getSponsorableEntityType, onSponsorshipRequested]); return ( {/* Header */}

Sponsorship Opportunity

{getSponsorshipTagline(entityType)}

{tier.charAt(0).toUpperCase() + tier.slice(1)} {getEntityLabel(entityType)}
{/* Key Metrics Grid */}
{metrics.slice(0, 4).map((metric, index) => { const Icon = metric.icon as React.ComponentType<{ className?: string }>; return (
{metric.label}
{typeof metric.value === 'number' ? metric.value.toLocaleString() : metric.value}
{metric.trend && ( {metric.trend.isPositive ? '+' : ''}{metric.trend.value}% )}
); })}
{/* Trust & Activity Indicators */} {(trustScore !== undefined || discordMembers !== undefined || monthlyActivity !== undefined) && (
{trustScore !== undefined && (
Trust Score: {trustScore}/100
)} {discordMembers !== undefined && (
Discord: {discordMembers.toLocaleString()}
)} {monthlyActivity !== undefined && (
Monthly Activity: {monthlyActivity}%
)}
)} {/* Sponsorship Slots */}
{/* Main Sponsor Slot */} {mainSlot && (
Main Sponsor Slot {mainSlot.available ? 'Available' : 'Taken'}

{mainSlot.benefits.join(' • ')}

{mainSlot.available && (
${mainSlot.price.toLocaleString()}/season
)}
)} {/* Secondary Slots */} {secondarySlots.length > 0 && (
0 ? 'bg-purple-500/10 border-purple-500/30' : 'bg-iron-gray/30 border-charcoal-outline' }`}>
Secondary Slots 0 ? 'text-purple-400' : 'text-gray-500'}`}> {availableSecondary}/{secondarySlots.length} Available

{secondarySlots[0]?.benefits.join(' • ') || 'Logo placement on page'}

{availableSecondary > 0 && (
${secondarySlots[0]?.price.toLocaleString()}/season
)}
)}
{/* Additional Stats */} {additionalStats && (

{additionalStats.label}

{additionalStats.items.map((item, index) => (
{item.label}: {typeof item.value === 'number' ? item.value.toLocaleString() : item.value}
))}
)} {/* Error Message */} {error && (

{error}

)} {/* Footer */}

10% platform fee applies • Logos burned on all liveries • Sponsorships are attached to seasons, so you can change partners from season to season {appliedTiers.size > 0 && ' • Application pending review'}

); }