'use client'; import React, { useState, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import Card from '@/components/ui/Card'; import Button from '@/components/ui/Button'; import { Eye, TrendingUp, Users, Star, Target, DollarSign, Calendar, Trophy, Zap, ExternalLink, MessageCircle, Activity, Shield, Check, Loader2, } from 'lucide-react'; // ============================================================================ // TYPES // ============================================================================ export type EntityType = 'league' | 'race' | 'driver' | 'team'; export interface SponsorMetric { icon: React.ElementType; label: string; value: string | number; color?: string; trend?: { value: number; isPositive: boolean; }; } export interface SponsorshipSlot { tier: 'main' | 'secondary'; available: boolean; price: number; currency?: string; benefits: string[]; } 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; } // ============================================================================ // HELPER FUNCTIONS // ============================================================================ function getTierStyles(tier: SponsorInsightsProps['tier']) { switch (tier) { case 'premium': return { badge: 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30', gradient: 'from-yellow-500/10 via-transparent to-transparent', }; case 'standard': return { badge: 'bg-blue-500/20 text-blue-400 border-blue-500/30', gradient: 'from-blue-500/10 via-transparent to-transparent', }; default: return { badge: 'bg-gray-500/20 text-gray-400 border-gray-500/30', gradient: 'from-gray-500/10 via-transparent to-transparent', }; } } function getEntityLabel(type: EntityType): string { switch (type) { case 'league': return 'League'; case 'race': return 'Race'; case 'driver': return 'Driver'; case 'team': return 'Team'; } } function getEntityIcon(type: EntityType) { switch (type) { case 'league': return Trophy; case 'race': return Zap; case 'driver': return Users; case 'team': return Users; } } function getSponsorshipTagline(type: EntityType): string { if (type === 'league') { return 'Reach engaged sim racers by sponsoring a season in this league.'; } return `Reach engaged sim racers by sponsoring this ${getEntityLabel(type).toLowerCase()}`; } // ============================================================================ // COMPONENT // ============================================================================ export default function SponsorInsightsCard({ entityType, entityId, entityName, tier, metrics, slots, additionalStats, trustScore, discordMembers, monthlyActivity, ctaLabel, ctaHref, currentSponsorId, onSponsorshipRequested, }: SponsorInsightsProps) { const router = useRouter(); 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 use case setApplyingTier(slotTier); setError(null); try { const applyUseCase = getApplyForSponsorshipUseCase(); const slot = slotTier === 'main' ? mainSlot : secondarySlots[0]; const slotPrice = slot?.price ?? 0; await applyUseCase.execute({ 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.`, }); // 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; 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'}

); } // ============================================================================ // HELPER HOOK: useSponsorMode // ============================================================================ export function useSponsorMode(): boolean { const [isSponsor, setIsSponsor] = React.useState(false); React.useEffect(() => { if (typeof document !== 'undefined') { const cookies = document.cookie.split(';'); const demoModeCookie = cookies.find(c => c.trim().startsWith('gridpilot_demo_mode=')); if (demoModeCookie) { const value = demoModeCookie.split('=')[1]?.trim(); setIsSponsor(value === 'sponsor'); } } }, []); return isSponsor; } // ============================================================================ // COMMON METRIC BUILDERS // ============================================================================ export const MetricBuilders = { views: (value: number, label = 'Views'): SponsorMetric => ({ icon: Eye, label, value, color: 'text-primary-blue', }), engagement: (value: number | string): SponsorMetric => ({ icon: TrendingUp, label: 'Engagement', value: typeof value === 'number' ? `${value}%` : value, color: 'text-performance-green', }), reach: (value: number): SponsorMetric => ({ icon: Users, label: 'Est. Reach', value, color: 'text-purple-400', }), rating: (value: number | string, label = 'Rating'): SponsorMetric => ({ icon: Star, label, value, color: 'text-warning-amber', }), races: (value: number): SponsorMetric => ({ icon: Calendar, label: 'Races', value, color: 'text-neon-aqua', }), members: (value: number): SponsorMetric => ({ icon: Users, label: 'Members', value, color: 'text-purple-400', }), impressions: (value: number): SponsorMetric => ({ icon: Eye, label: 'Impressions', value, color: 'text-primary-blue', }), sof: (value: number | string): SponsorMetric => ({ icon: Zap, label: 'Avg SOF', value, color: 'text-warning-amber', }), }; // ============================================================================ // SLOT TEMPLATES // ============================================================================ export const SlotTemplates = { league: (mainAvailable: boolean, secondaryAvailable: number, mainPrice: number, secondaryPrice: number): SponsorshipSlot[] => [ { tier: 'main', available: mainAvailable, price: mainPrice, benefits: ['Hood placement', 'League banner', 'Prominent logo'], }, { tier: 'secondary', available: secondaryAvailable > 0, price: secondaryPrice, benefits: ['Side logo placement', 'League page listing'], }, { tier: 'secondary', available: secondaryAvailable > 1, price: secondaryPrice, benefits: ['Side logo placement', 'League page listing'], }, ], race: (mainAvailable: boolean, mainPrice: number): SponsorshipSlot[] => [ { tier: 'main', available: mainAvailable, price: mainPrice, benefits: ['Race title sponsor', 'Stream overlay', 'Results banner'], }, ], driver: (available: boolean, price: number): SponsorshipSlot[] => [ { tier: 'main', available, price, benefits: ['Suit logo', 'Helmet branding', 'Social mentions'], }, ], team: (mainAvailable: boolean, secondaryAvailable: boolean, mainPrice: number, secondaryPrice: number): SponsorshipSlot[] => [ { tier: 'main', available: mainAvailable, price: mainPrice, benefits: ['Team name suffix', 'Car livery', 'All driver suits'], }, { tier: 'secondary', available: secondaryAvailable, price: secondaryPrice, benefits: ['Team page logo', 'Minor livery placement'], }, ], };