Spaces:
Running
Running
File size: 3,684 Bytes
f568a4f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | import { useEffect, useState } from 'react';
import { Card } from '@/components/ui/card';
import { PieChart, Pie, Cell, ResponsiveContainer, Legend, Tooltip } from 'recharts';
import { supabase } from '@/integrations/supabase/client';
type SignalCount = {
name: string;
value: number;
color: string;
};
const COLORS = {
LONG: '#00FF88',
SHORT: '#FF6B35',
HOLD: '#888888',
};
export const SignalDistributionChart = () => {
const [data, setData] = useState<SignalCount[]>([]);
const [loading, setLoading] = useState(true);
const [totalSignals, setTotalSignals] = useState(0);
useEffect(() => {
fetchData();
const interval = setInterval(fetchData, 30000); // Refresh every 30s
return () => clearInterval(interval);
}, []);
const fetchData = async () => {
try {
const { data: signals, error } = await supabase
.from('trading_signals')
.select('signal_type')
.gte('timestamp', new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString());
if (error) throw error;
const counts: Record<string, number> = {
LONG: 0,
SHORT: 0,
HOLD: 0,
};
(signals || []).forEach((signal) => {
counts[signal.signal_type]++;
});
const total = Object.values(counts).reduce((sum, val) => sum + val, 0);
setTotalSignals(total);
const chartData = Object.entries(counts)
.filter(([_, value]) => value > 0)
.map(([name, value]) => ({
name,
value,
color: COLORS[name as keyof typeof COLORS],
}));
setData(chartData);
} catch (error) {
console.error('Error fetching signal distribution:', error);
} finally {
setLoading(false);
}
};
if (loading) {
return (
<Card className="p-6">
<h3 className="text-lg font-semibold mb-4">Signal Distribution</h3>
<p className="text-muted-foreground">Loading data...</p>
</Card>
);
}
return (
<Card className="p-6">
<h3 className="text-lg font-semibold mb-4">📊 Signal Distribution (24h)</h3>
<p className="text-sm text-muted-foreground mb-4">
Breakdown of LONG, SHORT, and HOLD signals
</p>
{data.length > 0 ? (
<>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={data}
cx="50%"
cy="50%"
labelLine={false}
label={({ name, percent }) => `${name}: ${(percent * 100).toFixed(0)}%`}
outerRadius={80}
fill="#8884d8"
dataKey="value"
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--background))',
border: '1px solid hsl(var(--border))',
borderRadius: '8px',
}}
/>
<Legend />
</PieChart>
</ResponsiveContainer>
<div className="text-center mt-4">
<p className="text-sm text-muted-foreground">
Total Signals: <strong>{totalSignals}</strong>
</p>
</div>
</>
) : (
<p className="text-center text-sm text-muted-foreground mt-4">
No signals yet. Start the field on /aureon to begin tracking.
</p>
)}
</Card>
);
};
|