import React, { useState, useMemo } from 'react'; import { useMockStore } from '../data/mockStore'; import { Trophy, TrendingUp, DollarSign, Target, Calendar, Medal, ArrowUpRight, Crown } from 'lucide-react'; import { SpotlightCard } from '../components/SpotlightCard'; import AnimatedNumber from '../components/AnimatedNumber'; const LeaderboardPage = () => { const { users, salesHistory } = useMockStore(); const [timeframe, setTimeframe] = useState('month'); // 'week', 'month', 'custom' const [metric, setMetric] = useState('revenue'); // 'revenue', 'volume', 'winRate' // Filter agents const agents = useMemo(() => users.filter(u => u.role === 'FIELD_AGENT'), [users]); // Calculate metrics based on timeframe const leaderboardData = useMemo(() => { const now = new Date(); const startOfWeek = new Date(now.setDate(now.getDate() - now.getDay())); startOfWeek.setHours(0, 0, 0, 0); const startOfMonth = new Date(new Date().getFullYear(), new Date().getMonth(), 1); return agents.map(agent => { const agentTxals = salesHistory.filter(tx => { const txDate = new Date(tx.date); const isAgent = tx.agentId === agent.id; if (!isAgent) return false; if (timeframe === 'week') return txDate >= startOfWeek; if (timeframe === 'month') return txDate >= startOfMonth; return true; // All time / Custom }); // Calculate Metrics const revenue = agentTxals .filter(tx => tx.status === 'closed_won') .reduce((sum, tx) => sum + tx.amount, 0); const volume = agentTxals .filter(tx => tx.status === 'closed_won') .length; const won = agentTxals.filter(tx => tx.status === 'closed_won').length; const lost = agentTxals.filter(tx => tx.status === 'closed_lost').length; const totalDeals = won + lost; const winRate = totalDeals > 0 ? (won / totalDeals) * 100 : 0; return { ...agent, revenue, volume, winRate, totalDeals }; }).sort((a, b) => b[metric] - a[metric]); }, [agents, salesHistory, timeframe, metric]); const formatValue = (val, type) => { if (type === 'revenue') return `$${val.toLocaleString()}`; if (type === 'volume') return `${val} Deals`; if (type === 'winRate') return `${val.toFixed(1)}%`; return val; }; const TopPodium = ({ data }) => { if (data.length < 3) return null; const [first, second, third] = data; const PodiumStep = ({ agent, rank, height, color, glow }) => (
{/* Placeholder Avatar */} {agent.name.split(' ').map(n => n[0]).join('')}
{rank === 1 && }

{agent.name}

{metric === 'revenue' && } {metric === 'volume' && <> Deals} {metric === 'winRate' && <>%}

{/* The Step Block */}
{rank}
); return (
); }; return (
{/* Header */}

Sales Leaderboard

Real-time performance rankings for the sales team.

{/* Controls */}
{/* Timeframe */}
{['week', 'month'].map(t => ( ))}
{/* Metric */}
{[ { id: 'revenue', icon: DollarSign, label: 'Revenue' }, { id: 'volume', icon: Target, label: 'Volume' }, { id: 'winRate', icon: TrendingUp, label: 'Win Rate' } ].map(m => ( ))}
{/* Podium Section */}
{/* Background Glow */}
{/* Detailed List */}

Full Rankings

{leaderboardData.map((agent, index) => ( ))}
Rank Agent Revenue Volume Win Rate
{index + 1}
{agent.name.charAt(0)}
{agent.name}
{agent.email}
Deals %
igotsar.matyas | LynkedUpPro - Turns out roofing CRMs don't build themselves. Who knew?
); }; export default LeaderboardPage;