import { useState, useEffect } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { AlertTriangle, CheckCircle, RefreshCw, Loader2 } from 'lucide-react'; import { supabase } from '@/lib/supabaseClient'; import { format } from 'date-fns'; import { logger } from '@/lib/logger'; interface DuplicateStats { date: string | null; total_attempts: number | null; duplicates_prevented: number | null; prevention_rate: number | null; health_status: 'healthy' | 'warning' | 'critical'; } interface RecentDuplicate { id: string; user_id: string; channel: string; idempotency_key: string | null; created_at: string; profiles?: { username: string; display_name: string | null; }; } export function NotificationDebugPanel() { const [stats, setStats] = useState([]); const [recentDuplicates, setRecentDuplicates] = useState([]); const [isLoading, setIsLoading] = useState(true); useEffect(() => { loadData(); }, []); const loadData = async () => { setIsLoading(true); try { // Load health dashboard const { data: healthData, error: healthError } = await supabase .from('notification_health_dashboard') .select('*') .limit(7); if (healthError) throw healthError; if (healthData) { setStats(healthData.map(stat => ({ ...stat, health_status: stat.health_status as 'healthy' | 'warning' | 'critical' }))); } // Load recent prevented duplicates const { data: duplicates, error: duplicatesError } = await supabase .from('notification_logs') .select(` id, user_id, channel, idempotency_key, created_at `) .eq('is_duplicate', true) .order('created_at', { ascending: false }) .limit(10); if (duplicatesError) throw duplicatesError; if (duplicates) { // Fetch profiles separately const userIds = [...new Set(duplicates.map(d => d.user_id))]; const { data: profiles } = await supabase .from('profiles') .select('user_id, username, display_name') .in('user_id', userIds); const profileMap = new Map(profiles?.map(p => [p.user_id, p]) || []); setRecentDuplicates(duplicates.map(dup => ({ ...dup, profiles: profileMap.get(dup.user_id) }))); } } catch (error) { logger.error('Failed to load notification debug data', { error }); } finally { setIsLoading(false); } }; const getHealthBadge = (status: string) => { switch (status) { case 'healthy': return ( Healthy ); case 'warning': return ( Warning ); case 'critical': return ( Critical ); default: return Unknown; } }; if (isLoading) { return (
); } return (
Notification Health Dashboard Monitor duplicate prevention and notification system health
{stats.length === 0 ? ( No notification statistics available yet ) : ( Date Total Attempts Duplicates Prevented Prevention Rate Status {stats.map((stat) => ( {stat.date ? format(new Date(stat.date), 'MMM d, yyyy') : 'N/A'} {stat.total_attempts ?? 0} {stat.duplicates_prevented ?? 0} {stat.prevention_rate !== null ? stat.prevention_rate.toFixed(1) : 'N/A'}% {getHealthBadge(stat.health_status)} ))}
)}
Recent Prevented Duplicates Notifications that were blocked due to duplication {recentDuplicates.length === 0 ? ( No recent duplicates detected ) : (
{recentDuplicates.map((dup) => (
{dup.profiles?.display_name || dup.profiles?.username || 'Unknown User'}
Channel: {dup.channel} • Key: {dup.idempotency_key?.substring(0, 12)}...
{format(new Date(dup.created_at), 'PPp')}
))}
)}
); }