Files
gridpilot.gg/apps/website/app/sponsor/campaigns/page.tsx
2025-12-10 12:38:55 +01:00

278 lines
9.4 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import {
Megaphone,
Trophy,
Users,
Eye,
Calendar,
ExternalLink,
Plus,
ChevronRight,
Check,
Clock,
XCircle
} from 'lucide-react';
interface Sponsorship {
id: string;
leagueId: string;
leagueName: string;
tier: 'main' | 'secondary';
status: 'active' | 'pending' | 'expired';
startDate: Date;
endDate: Date;
price: number;
impressions: number;
drivers: number;
}
// Mock data - in production would come from repository
const MOCK_SPONSORSHIPS: Sponsorship[] = [
{
id: 'sp-1',
leagueId: 'league-1',
leagueName: 'GT3 Pro Championship',
tier: 'main',
status: 'active',
startDate: new Date('2025-01-01'),
endDate: new Date('2025-06-30'),
price: 1200,
impressions: 45200,
drivers: 32,
},
{
id: 'sp-2',
leagueId: 'league-2',
leagueName: 'Endurance Masters',
tier: 'main',
status: 'active',
startDate: new Date('2025-02-01'),
endDate: new Date('2025-07-31'),
price: 1000,
impressions: 38100,
drivers: 48,
},
{
id: 'sp-3',
leagueId: 'league-3',
leagueName: 'Formula Sim Series',
tier: 'secondary',
status: 'active',
startDate: new Date('2025-03-01'),
endDate: new Date('2025-08-31'),
price: 400,
impressions: 22800,
drivers: 24,
},
{
id: 'sp-4',
leagueId: 'league-4',
leagueName: 'Touring Car Cup',
tier: 'secondary',
status: 'pending',
startDate: new Date('2025-04-01'),
endDate: new Date('2025-09-30'),
price: 350,
impressions: 0,
drivers: 28,
},
];
function SponsorshipCard({ sponsorship }: { sponsorship: Sponsorship }) {
const router = useRouter();
const statusConfig = {
active: { icon: Check, color: 'text-performance-green', bg: 'bg-performance-green/10', label: 'Active' },
pending: { icon: Clock, color: 'text-warning-amber', bg: 'bg-warning-amber/10', label: 'Pending' },
expired: { icon: XCircle, color: 'text-gray-400', bg: 'bg-gray-400/10', label: 'Expired' },
};
const tierConfig = {
main: { color: 'text-primary-blue', bg: 'bg-primary-blue/10', border: 'border-primary-blue/30', label: 'Main Sponsor' },
secondary: { color: 'text-purple-400', bg: 'bg-purple-400/10', border: 'border-purple-400/30', label: 'Secondary' },
};
const status = statusConfig[sponsorship.status];
const tier = tierConfig[sponsorship.tier];
const StatusIcon = status.icon;
return (
<Card className="hover:border-charcoal-outline/80 transition-colors">
<div className="flex items-start justify-between mb-4">
<div className="flex items-center gap-3">
<div className={`px-2 py-1 rounded text-xs font-medium border ${tier.bg} ${tier.color} ${tier.border}`}>
{tier.label}
</div>
<div className={`flex items-center gap-1 px-2 py-1 rounded text-xs font-medium ${status.bg} ${status.color}`}>
<StatusIcon className="w-3 h-3" />
{status.label}
</div>
</div>
<Button
variant="secondary"
onClick={() => router.push(`/leagues/${sponsorship.leagueId}`)}
className="text-xs"
>
<ExternalLink className="w-3 h-3 mr-1" />
View League
</Button>
</div>
<h3 className="text-lg font-semibold text-white mb-2">{sponsorship.leagueName}</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-4">
<div className="bg-iron-gray/50 rounded-lg p-3">
<div className="flex items-center gap-1 text-gray-400 text-xs mb-1">
<Eye className="w-3 h-3" />
Impressions
</div>
<div className="text-white font-semibold">{sponsorship.impressions.toLocaleString()}</div>
</div>
<div className="bg-iron-gray/50 rounded-lg p-3">
<div className="flex items-center gap-1 text-gray-400 text-xs mb-1">
<Users className="w-3 h-3" />
Drivers
</div>
<div className="text-white font-semibold">{sponsorship.drivers}</div>
</div>
<div className="bg-iron-gray/50 rounded-lg p-3">
<div className="flex items-center gap-1 text-gray-400 text-xs mb-1">
<Calendar className="w-3 h-3" />
Period
</div>
<div className="text-white font-semibold text-xs">
{sponsorship.startDate.toLocaleDateString('en-US', { month: 'short', year: 'numeric' })} - {sponsorship.endDate.toLocaleDateString('en-US', { month: 'short', year: 'numeric' })}
</div>
</div>
<div className="bg-iron-gray/50 rounded-lg p-3">
<div className="flex items-center gap-1 text-gray-400 text-xs mb-1">
<Trophy className="w-3 h-3" />
Investment
</div>
<div className="text-white font-semibold">${sponsorship.price}</div>
</div>
</div>
<div className="flex items-center justify-between pt-3 border-t border-charcoal-outline/50">
<span className="text-xs text-gray-500">
{Math.ceil((sponsorship.endDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24))} days remaining
</span>
<Button
variant="secondary"
className="text-xs"
onClick={() => router.push(`/sponsor/campaigns/${sponsorship.id}`)}
>
View Details
<ChevronRight className="w-3 h-3 ml-1" />
</Button>
</div>
</Card>
);
}
export default function SponsorCampaignsPage() {
const router = useRouter();
const [filter, setFilter] = useState<'all' | 'active' | 'pending' | 'expired'>('all');
const filteredSponsorships = filter === 'all'
? MOCK_SPONSORSHIPS
: MOCK_SPONSORSHIPS.filter(s => s.status === filter);
const stats = {
total: MOCK_SPONSORSHIPS.length,
active: MOCK_SPONSORSHIPS.filter(s => s.status === 'active').length,
pending: MOCK_SPONSORSHIPS.filter(s => s.status === 'pending').length,
totalInvestment: MOCK_SPONSORSHIPS.reduce((sum, s) => sum + s.price, 0),
};
return (
<div className="max-w-6xl mx-auto py-8 px-4">
{/* Header */}
<div className="flex items-center justify-between mb-8">
<div>
<h1 className="text-2xl font-bold text-white flex items-center gap-3">
<Megaphone className="w-7 h-7 text-primary-blue" />
My Sponsorships
</h1>
<p className="text-gray-400 mt-1">Manage your league sponsorships</p>
</div>
<Button
variant="primary"
onClick={() => router.push('/leagues')}
>
<Plus className="w-4 h-4 mr-2" />
Find Leagues to Sponsor
</Button>
</div>
{/* Stats */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
<Card className="p-4">
<div className="text-2xl font-bold text-white">{stats.total}</div>
<div className="text-sm text-gray-400">Total Sponsorships</div>
</Card>
<Card className="p-4">
<div className="text-2xl font-bold text-performance-green">{stats.active}</div>
<div className="text-sm text-gray-400">Active</div>
</Card>
<Card className="p-4">
<div className="text-2xl font-bold text-warning-amber">{stats.pending}</div>
<div className="text-sm text-gray-400">Pending</div>
</Card>
<Card className="p-4">
<div className="text-2xl font-bold text-white">${stats.totalInvestment.toLocaleString()}</div>
<div className="text-sm text-gray-400">Total Investment</div>
</Card>
</div>
{/* Filters */}
<div className="flex items-center gap-2 mb-6">
{(['all', 'active', 'pending', 'expired'] as const).map((f) => (
<button
key={f}
onClick={() => setFilter(f)}
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
filter === f
? 'bg-primary-blue text-white'
: 'bg-iron-gray/50 text-gray-400 hover:bg-iron-gray'
}`}
>
{f.charAt(0).toUpperCase() + f.slice(1)}
</button>
))}
</div>
{/* Sponsorship List */}
{filteredSponsorships.length === 0 ? (
<Card className="text-center py-12">
<Megaphone className="w-12 h-12 text-gray-600 mx-auto mb-4" />
<h3 className="text-lg font-semibold text-white mb-2">No sponsorships found</h3>
<p className="text-gray-400 mb-6">Start sponsoring leagues to grow your brand visibility</p>
<Button variant="primary" onClick={() => router.push('/leagues')}>
Browse Leagues
</Button>
</Card>
) : (
<div className="space-y-4">
{filteredSponsorships.map((sponsorship) => (
<SponsorshipCard key={sponsorship.id} sponsorship={sponsorship} />
))}
</div>
)}
{/* Alpha Notice */}
<div className="mt-8 rounded-lg bg-warning-amber/10 border border-warning-amber/30 p-4">
<p className="text-xs text-gray-400">
<strong className="text-warning-amber">Alpha Note:</strong> Sponsorship data shown here is demonstration-only.
Real sponsorship management will be available when the system is fully implemented.
</p>
</div>
</div>
);
}