Spaces:
Build error
Build error
| 'use client' | |
| import { useMemo } from 'react' | |
| import { | |
| LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, | |
| ResponsiveContainer, Area, AreaChart, ReferenceLine, Scatter, ComposedChart | |
| } from 'recharts' | |
| import { TrendingUp } from 'lucide-react' | |
| interface Transaction { | |
| id: number | |
| amount: number | |
| prediction: string | |
| final_score: number | |
| } | |
| interface TransactionChartProps { | |
| transactions: Transaction[] | |
| } | |
| export default function TransactionChart({ transactions }: TransactionChartProps) { | |
| const chartData = useMemo(() => { | |
| if (transactions.length === 0) return [] | |
| // Create rolling average for smoother visualization | |
| const windowSize = Math.max(3, Math.floor(transactions.length / 50)) | |
| return transactions.map((t, i) => { | |
| const start = Math.max(0, i - windowSize + 1) | |
| const window = transactions.slice(start, i + 1) | |
| const avgAmount = window.reduce((sum, tx) => sum + tx.amount, 0) / window.length | |
| return { | |
| index: i, | |
| amount: t.amount, | |
| smoothAmount: avgAmount, | |
| score: t.final_score, | |
| isFraud: t.prediction === 'Fraud', | |
| id: t.id | |
| } | |
| }) | |
| }, [transactions]) | |
| const CustomTooltip = ({ active, payload, label }: any) => { | |
| if (active && payload && payload.length) { | |
| const data = payload[0].payload | |
| return ( | |
| <div className="glass rounded-lg p-3 border border-dark-600"> | |
| <p className="text-sm text-dark-300">Transaction #{data.id}</p> | |
| <p className="text-lg font-semibold">${data.amount.toFixed(2)}</p> | |
| <p className="text-sm"> | |
| Risk Score: <span className={data.score > 0.5 ? 'text-red-400' : 'text-green-400'}> | |
| {(data.score * 100).toFixed(1)}% | |
| </span> | |
| </p> | |
| {data.isFraud && ( | |
| <p className="text-red-400 text-sm font-medium mt-1">⚠️ Fraud Detected</p> | |
| )} | |
| </div> | |
| ) | |
| } | |
| return null | |
| } | |
| if (transactions.length === 0) { | |
| return ( | |
| <div className="glass rounded-xl p-6 h-80 flex flex-col items-center justify-center"> | |
| <TrendingUp className="w-12 h-12 text-dark-500 mb-4" /> | |
| <p className="text-dark-400 text-center"> | |
| Start processing transactions to see the flow chart | |
| </p> | |
| </div> | |
| ) | |
| } | |
| return ( | |
| <div className="glass rounded-xl p-6"> | |
| <h3 className="text-lg font-semibold mb-4 flex items-center gap-2"> | |
| <TrendingUp className="w-5 h-5 text-primary-500" /> | |
| Transaction Flow Analysis | |
| <span className="text-sm font-normal text-dark-400 ml-2"> | |
| ({transactions.length.toLocaleString()} transactions) | |
| </span> | |
| </h3> | |
| <div className="h-64"> | |
| <ResponsiveContainer width="100%" height="100%"> | |
| <ComposedChart data={chartData}> | |
| <defs> | |
| <linearGradient id="amountGradient" x1="0" y1="0" x2="0" y2="1"> | |
| <stop offset="5%" stopColor="#00d4a0" stopOpacity={0.3} /> | |
| <stop offset="95%" stopColor="#00d4a0" stopOpacity={0} /> | |
| </linearGradient> | |
| </defs> | |
| <CartesianGrid strokeDasharray="3 3" stroke="#333" /> | |
| <XAxis | |
| dataKey="index" | |
| stroke="#666" | |
| tick={{ fill: '#888', fontSize: 11 }} | |
| tickFormatter={(value) => `#${value}`} | |
| /> | |
| <YAxis | |
| stroke="#666" | |
| tick={{ fill: '#888', fontSize: 11 }} | |
| tickFormatter={(value) => `$${value}`} | |
| /> | |
| <Tooltip content={<CustomTooltip />} /> | |
| {/* Smooth area chart */} | |
| <Area | |
| type="monotone" | |
| dataKey="smoothAmount" | |
| stroke="#00d4a0" | |
| strokeWidth={2} | |
| fill="url(#amountGradient)" | |
| /> | |
| {/* Fraud markers */} | |
| <Scatter | |
| dataKey="amount" | |
| fill="#ff4444" | |
| shape={(props: any) => { | |
| if (!props.payload.isFraud) return <circle r={0} /> | |
| return ( | |
| <circle | |
| cx={props.cx} | |
| cy={props.cy} | |
| r={6} | |
| fill="#ff4444" | |
| stroke="#fff" | |
| strokeWidth={2} | |
| /> | |
| ) | |
| }} | |
| /> | |
| </ComposedChart> | |
| </ResponsiveContainer> | |
| </div> | |
| {/* Legend */} | |
| <div className="flex items-center gap-6 mt-4 justify-center"> | |
| <div className="flex items-center gap-2"> | |
| <div className="w-4 h-1 bg-primary-500 rounded" /> | |
| <span className="text-sm text-dark-300">Transaction Flow</span> | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| <div className="w-3 h-3 bg-red-500 rounded-full" /> | |
| <span className="text-sm text-dark-300">Fraud Alert</span> | |
| </div> | |
| </div> | |
| </div> | |
| ) | |
| } | |