import { useState, useEffect } from 'react'; import { Brain, TrendingUp, AlertTriangle, Zap, Target, CheckCircle, BarChart3, RefreshCw, Loader2 } from 'lucide-react'; import api from '../lib/api'; import { PageHeader, MetricCard, EmptyState, CardSkeleton } from '../components/ui/LinearPrimitives'; interface Prediction { batchId: string; accuracy: string; predictedAt: string; } interface Anomaly { id: string; entityType: string; entityId: string; anomalyType: string; severity: string; description: string; isResolved: boolean; detectedAt: string; } interface InsightsDashboardData { predictions: { count: number; avgAccuracy: string; recentAccuracy: Prediction[]; }; anomalies: { unresolved: number; recent: Anomaly[]; }; performance: { topBatches: { batchId: string; costPerGram: string; totalCost: number; yieldGrams: number; }[]; }; } export default function InsightsDashboard() { const [dashboard, setDashboard] = useState(null); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); useEffect(() => { loadData(); }, []); const loadData = async () => { try { const res = await api.get('/api/insights/dashboard'); setDashboard(res.data); } catch (error) { console.error('Failed to load insights:', error); } finally { setLoading(false); } }; const handleRefresh = async () => { setRefreshing(true); await loadData(); setRefreshing(false); }; const resolveAnomaly = async (id: string) => { try { await api.post(`/api/insights/anomalies/${id}/resolve`); loadData(); } catch (error) { console.error('Failed to resolve anomaly:', error); } }; if (loading) { return (
{Array.from({ length: 3 }).map((_, i) => )}
); } const anomalyCount = dashboard?.anomalies.unresolved || 0; return (
} /> {/* Quick Stats */}
0 ? 'border-warning/30 bg-warning-muted' : 'border-success/30 bg-success-muted'} `}>
0 ? 'text-warning' : 'text-success'} size={16} /> Active Anomalies
0 ? 'text-warning' : 'text-success'}`}> {anomalyCount}

{anomalyCount === 0 ? 'All systems normal' : 'Requires attention'}

{/* Anomalies Section */}

Detected Anomalies

{dashboard?.anomalies.recent.map(anomaly => (
{anomaly.isResolved ? : }
{anomaly.description} {anomaly.severity}
{anomaly.entityType} · {anomaly.anomalyType.replace('_', ' ')} ·{' '} {new Date(anomaly.detectedAt).toLocaleString()}
{!anomaly.isResolved && ( )}
))} {(!dashboard?.anomalies.recent || dashboard.anomalies.recent.length === 0) && (

No anomalies detected

)}
{/* Top Performing Batches */}

Best Cost Efficiency

{dashboard?.performance.topBatches.map((batch, idx) => ( ))} {(!dashboard?.performance.topBatches || dashboard.performance.topBatches.length === 0) && ( )}
Batch Cost/Gram Total Cost Yield
{idx + 1} {batch.batchId.substring(0, 8)}...
${batch.costPerGram}/g ${batch.totalCost.toLocaleString()} {batch.yieldGrams?.toLocaleString() || 'N/A'}g
No batch performance data available
{/* Recent Predictions */}

Recent Predictions

{dashboard?.predictions.recentAccuracy.map(pred => (
Batch {pred.batchId.substring(0, 8)}

{new Date(pred.predictedAt).toLocaleString()}

= 80 ? 'text-success' : parseFloat(pred.accuracy) >= 60 ? 'text-warning' : 'text-destructive'} `}> {pred.accuracy}
))} {(!dashboard?.predictions.recentAccuracy || dashboard.predictions.recentAccuracy.length === 0) && (

No predictions with verified accuracy yet

)}
); }