import React from 'react';
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
Area,
AreaChart,
Cell,
PieChart,
Pie,
} from 'recharts';
import { TrendingUp, Award, Target, Zap } from 'lucide-react';
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
import { Badge } from '@/components/ui/Badge';
import { useEpisodeRewards, useCurrentEpisode } from '@/hooks/useEpisode';
import { formatReward } from '@/utils/helpers';
interface RewardChartProps {
className?: string;
}
const COLORS = [
'#10a37f',
'#6366f1',
'#f59e0b',
'#ef4444',
'#8b5cf6',
'#06b6d4',
'#ec4899',
'#84cc16',
];
const CustomTooltip: React.FC<{
active?: boolean;
payload?: Array<{ value: number; name: string; color: string }>;
label?: string;
}> = ({ active, payload, label }) => {
if (!active || !payload || payload.length === 0) return null;
return (
Step {label}
{payload.map((entry, i) => (
{entry.name}:
= 0 ? 'text-green-400' : 'text-red-400'}
>
{formatReward(entry.value)}
))}
);
};
export const RewardChart: React.FC = ({ className }) => {
const { data: episode } = useCurrentEpisode();
const { data: rewards, isLoading } = useEpisodeRewards(episode?.id);
const chartData = React.useMemo(() => {
if (!rewards || rewards.length === 0) return [];
return rewards.map((r, i) => ({
step: i + 1,
total: r.total,
cumulative: r.cumulative,
...r.components.reduce(
(acc, c) => ({ ...acc, [c.name]: c.value }),
{} as Record
),
}));
}, [rewards]);
const componentNames = React.useMemo(() => {
if (!rewards || rewards.length === 0) return [];
const names = new Set();
rewards.forEach((r) => r.components.forEach((c) => names.add(c.name)));
return Array.from(names);
}, [rewards]);
const latestReward = rewards?.[rewards.length - 1];
const componentBreakdown = latestReward?.components ?? [];
const pieData = componentBreakdown.map((c, i) => ({
name: c.name,
value: Math.abs(c.value),
fill: COLORS[i % COLORS.length],
originalValue: c.value,
}));
const stats = React.useMemo(() => {
if (!rewards || rewards.length === 0) {
return { total: 0, avg: 0, max: 0, min: 0 };
}
const totals = rewards.map((r) => r.total);
return {
total: rewards[rewards.length - 1]?.cumulative ?? 0,
avg: totals.reduce((a, b) => a + b, 0) / totals.length,
max: Math.max(...totals),
min: Math.min(...totals),
};
}, [rewards]);
return (
}
action={
latestReward && (
= 0 ? 'success' : 'error'}
size="sm"
>
{formatReward(latestReward.total)}
)
}
/>
{/* Stats Grid */}
Total
= 0 ? 'text-green-400' : 'text-red-400'
}`}
>
{formatReward(stats.total)}
Avg
{formatReward(stats.avg)}
Max
{formatReward(stats.max)}
Min
{formatReward(stats.min)}
{/* Cumulative Reward Chart */}
{isLoading ? (
) : chartData.length === 0 ? (
) : (
<>
{/* Component Breakdown Bar Chart */}
{componentNames.length > 0 && (
Reward Components
} />
{componentNames.map((name, i) => (
))}
)}
{/* Pie Chart for Latest Breakdown */}
{pieData.length > 0 && (
{pieData.map((entry, i) => (
|
))}
{componentBreakdown.map((c, i) => (
{c.name}
= 0 ? 'text-green-400' : 'text-red-400'
}
>
{formatReward(c.value)}
))}
)}
>
)}
);
};
export default RewardChart;