QuantumShield / frontend /components /TransactionChart.tsx
SantoshKumar1310's picture
Upload folder using huggingface_hub
49e53ae verified
'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>
)
}