import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { History, CheckCircle, XCircle, Loader2, Trash2, RefreshCw, ChevronDown, ChevronUp } from 'lucide-react'; import { api } from '../api/client'; import { parseUTCDate, formatTimeOnly, formatDateTime, type TimeFormat } from '../utils/date'; import type { NotificationLogEntry } from '../api/client'; import { Button } from './Button'; import { useToast } from '../contexts/ToastContext'; const EVENT_LABELS: Record = { print_start: 'Print Started', print_complete: 'Print Complete', print_failed: 'Print Failed', print_stopped: 'Print Stopped', print_progress: 'Progress', printer_offline: 'Printer Offline', printer_error: 'Printer Error', filament_low: 'Low Filament', maintenance_due: 'Maintenance Due', test: 'Test', }; const EVENT_COLORS: Record = { print_start: 'text-blue-400', print_complete: 'text-bambu-green', print_failed: 'text-red-400', print_stopped: 'text-orange-400', print_progress: 'text-yellow-400', printer_offline: 'text-gray-400', printer_error: 'text-rose-400', filament_low: 'text-cyan-400', maintenance_due: 'text-purple-400', test: 'text-bambu-gray', }; interface NotificationLogViewerProps { onClose: () => void; } export function NotificationLogViewer({ onClose }: NotificationLogViewerProps) { const queryClient = useQueryClient(); const { showToast } = useToast(); const [days, setDays] = useState(7); const [expandedId, setExpandedId] = useState(null); const [showFailedOnly, setShowFailedOnly] = useState(false); const { data: settings } = useQuery({ queryKey: ['settings'], queryFn: api.getSettings, }); const timeFormat: TimeFormat = settings?.time_format || 'system'; const { data: logs, isLoading, refetch, isRefetching } = useQuery({ queryKey: ['notification-logs', days, showFailedOnly], queryFn: () => api.getNotificationLogs({ days, limit: 100, success: showFailedOnly ? false : undefined, }), }); const { data: stats } = useQuery({ queryKey: ['notification-log-stats', days], queryFn: () => api.getNotificationLogStats(days), }); const clearMutation = useMutation({ mutationFn: () => api.clearNotificationLogs(30), onSuccess: (data) => { showToast(data.message, 'success'); queryClient.invalidateQueries({ queryKey: ['notification-logs'] }); queryClient.invalidateQueries({ queryKey: ['notification-log-stats'] }); }, onError: (error: Error) => { showToast(`Failed to clear logs: ${error.message}`, 'error'); }, }); const formatDate = (dateStr: string) => { const date = parseUTCDate(dateStr); if (!date) return ''; const now = new Date(); const diff = now.getTime() - date.getTime(); if (diff < 60000) return 'Just now'; if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`; if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`; return date.toLocaleDateString() + ' ' + formatTimeOnly(date, timeFormat); }; return (
{/* Header */}

Notification Log

{/* Stats Bar */} {stats && (
Last {days} days: {stats.total} notifications {stats.success_count} sent {stats.failure_count > 0 && ( {stats.failure_count} failed )}
)} {/* Filters */}
{/* Log List */}
{isLoading ? (
) : logs && logs.length > 0 ? (
{logs.map((log) => ( setExpandedId(expandedId === log.id ? null : log.id)} formatDate={formatDate} formatFullDate={(dateStr) => formatDateTime(dateStr, timeFormat)} /> ))}
) : (

{showFailedOnly ? 'No failed notifications' : 'No notifications logged'}

)}
); } function LogEntry({ log, isExpanded, onToggle, formatDate, formatFullDate, }: { log: NotificationLogEntry; isExpanded: boolean; onToggle: () => void; formatDate: (date: string) => string; formatFullDate: (date: string) => string; }) { return (
{isExpanded && (

Title

{log.title}

Message

{log.message}

{!log.success && log.error_message && (

Error

{log.error_message}

)}
Provider: {log.provider_type} Time: {formatFullDate(log.created_at)}
)}
); }