Files
thrilltrack-explorer/src-old/components/admin/ErrorAnalytics.tsx

178 lines
7.4 KiB
TypeScript

import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';
import { AlertCircle, TrendingUp, Users, Zap, CheckCircle, XCircle } from 'lucide-react';
interface ErrorSummary {
error_type: string | null;
occurrence_count: number | null;
affected_users: number | null;
avg_duration_ms: number | null;
}
interface ApprovalMetric {
id: string;
success: boolean;
duration_ms: number | null;
created_at: string | null;
}
interface ErrorAnalyticsProps {
errorSummary: ErrorSummary[] | undefined;
approvalMetrics: ApprovalMetric[] | undefined;
}
export function ErrorAnalytics({ errorSummary, approvalMetrics }: ErrorAnalyticsProps) {
// Calculate error metrics
const totalErrors = errorSummary?.reduce((sum, item) => sum + (item.occurrence_count || 0), 0) || 0;
const totalAffectedUsers = errorSummary?.reduce((sum, item) => sum + (item.affected_users || 0), 0) || 0;
const avgErrorDuration = errorSummary?.length
? errorSummary.reduce((sum, item) => sum + (item.avg_duration_ms || 0), 0) / errorSummary.length
: 0;
const topErrors = errorSummary?.slice(0, 5) || [];
// Calculate approval metrics
const totalApprovals = approvalMetrics?.length || 0;
const failedApprovals = approvalMetrics?.filter(m => !m.success).length || 0;
const successRate = totalApprovals > 0 ? ((totalApprovals - failedApprovals) / totalApprovals) * 100 : 0;
const avgApprovalDuration = approvalMetrics?.length
? approvalMetrics.reduce((sum, m) => sum + (m.duration_ms || 0), 0) / approvalMetrics.length
: 0;
// Show message if no data available
if ((!errorSummary || errorSummary.length === 0) && (!approvalMetrics || approvalMetrics.length === 0)) {
return (
<Card>
<CardContent className="pt-6">
<p className="text-center text-muted-foreground">No analytics data available</p>
</CardContent>
</Card>
);
}
return (
<div className="space-y-6">
{/* Error Metrics */}
{errorSummary && errorSummary.length > 0 && (
<>
<div>
<h3 className="text-lg font-semibold mb-3">Error Metrics</h3>
<div className="grid gap-4 md:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Errors</CardTitle>
<AlertCircle className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{totalErrors}</div>
<p className="text-xs text-muted-foreground">Last 30 days</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Error Types</CardTitle>
<TrendingUp className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{errorSummary.length}</div>
<p className="text-xs text-muted-foreground">Unique error types</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Affected Users</CardTitle>
<Users className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{totalAffectedUsers}</div>
<p className="text-xs text-muted-foreground">Users impacted</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Avg Duration</CardTitle>
<Zap className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{Math.round(avgErrorDuration)}ms</div>
<p className="text-xs text-muted-foreground">Before error occurs</p>
</CardContent>
</Card>
</div>
</div>
<Card>
<CardHeader>
<CardTitle>Top 5 Errors</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={topErrors}>
<XAxis dataKey="error_type" />
<YAxis />
<Tooltip />
<Bar dataKey="occurrence_count" fill="hsl(var(--destructive))" />
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
</>
)}
{/* Approval Metrics */}
{approvalMetrics && approvalMetrics.length > 0 && (
<div>
<h3 className="text-lg font-semibold mb-3">Approval Metrics</h3>
<div className="grid gap-4 md:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Approvals</CardTitle>
<CheckCircle className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{totalApprovals}</div>
<p className="text-xs text-muted-foreground">Last 24 hours</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Failures</CardTitle>
<XCircle className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-destructive">{failedApprovals}</div>
<p className="text-xs text-muted-foreground">Failed approvals</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Success Rate</CardTitle>
<TrendingUp className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{successRate.toFixed(1)}%</div>
<p className="text-xs text-muted-foreground">Overall success rate</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Avg Duration</CardTitle>
<Zap className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{Math.round(avgApprovalDuration)}ms</div>
<p className="text-xs text-muted-foreground">Approval time</p>
</CardContent>
</Card>
</div>
</div>
)}
</div>
);
}