Spaces:
Build error
Build error
| 'use client'; | |
| import { TrendingUp, TrendingDown, Activity } from 'lucide-react'; | |
| interface RiskDistributionCardProps { | |
| lowRisk: number; | |
| mediumRisk: number; | |
| highRisk: number; | |
| criticalRisk: number; | |
| } | |
| export default function RiskDistributionCard({ | |
| lowRisk, | |
| mediumRisk, | |
| highRisk, | |
| criticalRisk | |
| }: RiskDistributionCardProps) { | |
| const total = lowRisk + mediumRisk + highRisk + criticalRisk; | |
| const data = [ | |
| { label: 'Low Risk', value: lowRisk, color: 'bg-emerald-400', percentage: (lowRisk / total * 100).toFixed(1) }, | |
| { label: 'Medium Risk', value: mediumRisk, color: 'bg-yellow-400', percentage: (mediumRisk / total * 100).toFixed(1) }, | |
| { label: 'High Risk', value: highRisk, color: 'bg-orange-400', percentage: (highRisk / total * 100).toFixed(1) }, | |
| { label: 'Critical', value: criticalRisk, color: 'bg-red-400', percentage: (criticalRisk / total * 100).toFixed(1) }, | |
| ]; | |
| // Create a simple scatter-like visualization | |
| const generatePoints = () => { | |
| const points: { x: number; y: number; risk: string; color: string }[] = []; | |
| // Generate clustered points for each risk level | |
| data.forEach((item, riskIndex) => { | |
| const count = Math.min(item.value, 30); // Cap at 30 points per category | |
| for (let i = 0; i < count; i++) { | |
| const baseX = 20 + (riskIndex * 20) + Math.random() * 15; | |
| const baseY = 20 + Math.random() * 60; | |
| points.push({ | |
| x: Math.min(95, Math.max(5, baseX)), | |
| y: Math.min(95, Math.max(5, baseY)), | |
| risk: item.label, | |
| color: item.color.replace('bg-', '') | |
| }); | |
| } | |
| }); | |
| return points; | |
| }; | |
| const points = generatePoints(); | |
| return ( | |
| <div className="card-teal rounded-3xl p-6 card-hover h-full"> | |
| {/* Header */} | |
| <div className="flex items-center justify-between mb-4"> | |
| <div className="flex items-center gap-3"> | |
| <div className="w-10 h-10 rounded-xl bg-white/20 flex items-center justify-center"> | |
| <Activity className="w-5 h-5" /> | |
| </div> | |
| <div> | |
| <h3 className="text-xl font-bold">RISK DISTRIBUTION</h3> | |
| <p className="text-xs text-white/60">Transaction Risk Mapping</p> | |
| </div> | |
| </div> | |
| <button className="text-white/60 hover:text-white transition-colors"> | |
| <svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"> | |
| <circle cx="11" cy="11" r="8" /> | |
| <path d="m21 21-4.35-4.35" /> | |
| </svg> | |
| </button> | |
| </div> | |
| {/* Scatter Plot Visualization */} | |
| <div className="relative h-40 mb-4 bg-white/10 rounded-2xl overflow-hidden"> | |
| {/* Grid lines */} | |
| <div className="absolute inset-0"> | |
| {[...Array(5)].map((_, i) => ( | |
| <div key={`h-${i}`} className="absolute w-full border-t border-white/10" style={{ top: `${i * 25}%` }} /> | |
| ))} | |
| {[...Array(5)].map((_, i) => ( | |
| <div key={`v-${i}`} className="absolute h-full border-l border-white/10" style={{ left: `${i * 25}%` }} /> | |
| ))} | |
| </div> | |
| {/* Points */} | |
| {points.map((point, i) => { | |
| const colorMap: Record<string, string> = { | |
| 'emerald-400': '#34d399', | |
| 'yellow-400': '#facc15', | |
| 'orange-400': '#fb923c', | |
| 'red-400': '#f87171' | |
| }; | |
| return ( | |
| <div | |
| key={i} | |
| className="absolute w-2 h-2 rounded-full animate-float" | |
| style={{ | |
| left: `${point.x}%`, | |
| top: `${point.y}%`, | |
| backgroundColor: colorMap[point.color] || '#fff', | |
| animationDelay: `${i * 0.1}s`, | |
| opacity: 0.8 | |
| }} | |
| /> | |
| ); | |
| })} | |
| </div> | |
| {/* Legend & Stats */} | |
| <div className="grid grid-cols-2 gap-2"> | |
| {data.map((item) => ( | |
| <div key={item.label} className="flex items-center gap-2 bg-white/10 rounded-xl p-2"> | |
| <div className={`w-3 h-3 rounded-full ${item.color}`} /> | |
| <div className="flex-1"> | |
| <p className="text-xs text-white/80">{item.label}</p> | |
| <div className="flex items-baseline gap-1"> | |
| <span className="text-sm font-bold">{item.value}</span> | |
| <span className="text-xs text-white/60">({item.percentage}%)</span> | |
| </div> | |
| </div> | |
| </div> | |
| ))} | |
| </div> | |
| {/* Trend indicator */} | |
| <div className="mt-4 flex items-center justify-between text-sm"> | |
| <span className="text-white/60">Risk Trend</span> | |
| <div className="flex items-center gap-1 text-emerald-300"> | |
| <TrendingDown className="w-4 h-4" /> | |
| <span>-2.3% this week</span> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |