diff --git a/src/pages/LeaderboardPage.jsx b/src/pages/LeaderboardPage.jsx index 3bf8dd9..3352f38 100644 --- a/src/pages/LeaderboardPage.jsx +++ b/src/pages/LeaderboardPage.jsx @@ -1,4 +1,5 @@ import React, { useState, useMemo } from 'react'; +import { motion } from 'framer-motion'; import { useMockStore } from '../data/mockStore'; import { Trophy, TrendingUp, DollarSign, Target, Crown, ShieldOff, @@ -16,10 +17,12 @@ const rankBadge = (i) => 'text-zinc-500'; // ── Podium (shared) ────────────────────────────────────────────────────────── -const TopPodium = ({ data, metricKey, formatVal, accentColor = 'border-yellow-400' }) => { +const TopPodium = ({ data, metricKey, numberFormat = {}, accentColor = 'border-yellow-400' }) => { if (data.length < 3) return null; const [first, second, third] = data; - const Step = ({ agent, rank, height, color, glow }) => ( + // Bars grow from a shared baseline at a constant speed, so the shortest (bronze) + // finishes first, then silver, and the tallest (gold) lands last. + const Step = ({ agent, rank, heightPx, color, glow }) => (
@@ -33,20 +36,27 @@ const TopPodium = ({ data, metricKey, formatVal, accentColor = 'border-yellow-40

{agent.name}

- {formatVal(agent[metricKey])} +

-
+
{rank}
-
+
); return ( -
- - - + // Fixed min-height reserves the full podium space so the shared baseline + // never shifts while the bars animate — they grow upward from the floor. +
+ + +
); }; @@ -137,13 +147,6 @@ const LeaderboardPage = () => { }).sort((a, b) => b[metric] - a[metric]); }, [agents, salesHistory, timeframe, metric]); - const formatSales = (val, m) => { - if (m === 'revenue') return `$${val.toLocaleString('en-US')}`; - if (m === 'volume') return `${val} Deals`; - if (m === 'winRate') return `${val.toFixed(1)}%`; - return val; - }; - // ── Canvasser leaderboard data ─────────────────────────────────────────── // Single source of truth: canvasserHistory records, filtered by date window. // verified = records with status 'verified' OR 'converted' (converted is also verified) @@ -170,11 +173,6 @@ const LeaderboardPage = () => { }).sort((a, b) => b[cvMetric] - a[cvMetric]); }, [agents, canvasserHistory, cvTimeframe, cvMetric]); - const formatCv = (val, m) => { - if (m === 'convRate') return `${val.toFixed(1)}%`; - return `${val}`; - }; - // ── Permission guard ───────────────────────────────────────────────────── if (!can('leaderboard', 'view')) { return ( @@ -259,7 +257,11 @@ const LeaderboardPage = () => { formatSales(v, metric)} + numberFormat={{ + revenue: { prefix: '$', useLocaleString: true }, + volume: { suffix: ' Deals' }, + winRate: { suffix: '%', decimals: 1 }, + }[metric]} accentColor="border-yellow-400" />
@@ -350,7 +352,11 @@ const LeaderboardPage = () => { formatCv(v, cvMetric)} + numberFormat={{ + verified: {}, + total: {}, + convRate: { suffix: '%', decimals: 1 }, + }[cvMetric]} accentColor="border-emerald-400" />