'use client'; import { useState } from 'react'; import { AuthGuard } from '@/components/AuthGuard'; import { DashboardLayout } from '@/components/DashboardLayout'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { notificationsApi, NotificationConfig, NotificationConfigCreate, NotificationConfigUpdate } from '@/lib/api'; import { NotificationWizard } from '@/components/NotificationWizard'; import { Plus, Edit2, Trash2, Bell, Send, CheckCircle, XCircle, Loader2 } from 'lucide-react'; const CHANNEL_DISPLAY: Record = { telegram: { icon: '🤖', label: 'Telegram', color: 'bg-blue-100 text-blue-800' }, discord: { icon: '💬', label: 'Discord', color: 'bg-indigo-100 text-indigo-800' }, slack: { icon: '💼', label: 'Slack', color: 'bg-yellow-100 text-yellow-800' }, email: { icon: '📧', label: 'Email', color: 'bg-green-100 text-green-800' }, webhook: { icon: '🔗', label: 'Webhook', color: 'bg-purple-100 text-purple-800' }, custom: { icon: '⚙️', label: 'Custom', color: 'bg-gray-100 text-gray-800' }, }; export default function NotificationsPage() { const [showWizard, setShowWizard] = useState(false); const [editingConfig, setEditingConfig] = useState(null); const [testingId, setTestingId] = useState(null); const [testResults, setTestResults] = useState>({}); const queryClient = useQueryClient(); const { data: notifications, isLoading } = useQuery({ queryKey: ['notifications'], queryFn: notificationsApi.list, }); const createMutation = useMutation({ mutationFn: (data: NotificationConfigCreate) => notificationsApi.create(data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications'] }); setShowWizard(false); setEditingConfig(null); }, }); const updateMutation = useMutation({ mutationFn: ({ id, data }: { id: number; data: NotificationConfigUpdate }) => notificationsApi.update(id, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications'] }); setShowWizard(false); setEditingConfig(null); }, }); const deleteMutation = useMutation({ mutationFn: notificationsApi.delete, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications'] }); }, }); const toggleMutation = useMutation({ mutationFn: ({ id, is_enabled }: { id: number; is_enabled: boolean }) => notificationsApi.update(id, { is_enabled }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications'] }); }, }); const handleWizardComplete = (config: { name: string; channel: string; apprise_url: string; notify_on_errors: boolean; notify_on_success: boolean; }) => { if (editingConfig) { updateMutation.mutate({ id: editingConfig.id, data: config }); } else { createMutation.mutate(config); } }; const handleEdit = (config: NotificationConfig) => { setEditingConfig(config); setShowWizard(true); }; const handleDelete = async (id: number) => { if (!confirm('Delete this notification channel?')) return; try { await deleteMutation.mutateAsync(id); } catch { alert('Failed to delete notification channel'); } }; const handleTest = async (config: NotificationConfig) => { if (!config.apprise_url) return; setTestingId(config.id); try { const result = await notificationsApi.test(config.apprise_url); setTestResults((prev) => ({ ...prev, [config.id]: result })); } catch { setTestResults((prev) => ({ ...prev, [config.id]: { success: false, message: 'Test request failed' }, })); } finally { setTestingId(null); setTimeout(() => { setTestResults((prev) => { const next = { ...prev }; delete next[config.id]; return next; }); }, 5000); } }; const handleOpenWizard = () => { setEditingConfig(null); setShowWizard(true); }; const handleCancelWizard = () => { setShowWizard(false); setEditingConfig(null); }; if (showWizard) { return (
); } return (
{/* Header */}

Notification Channels

Get alerts when emails are processed or errors occur.

{/* Content */} {isLoading ? (
) : notifications && notifications.length > 0 ? (
{notifications.map((config) => { const channel = CHANNEL_DISPLAY[config.channel] ?? CHANNEL_DISPLAY.custom; const testResult = testResults[config.id]; const isTesting = testingId === config.id; return (
{channel.icon}

{config.name}

{channel.label}
{config.notify_on_errors && ( On Errors )} {config.notify_on_success && ( On Success )} {!config.notify_on_errors && !config.notify_on_success && ( No triggers set )}
{testResult && (
{testResult.success ? ( ) : ( )} {testResult.message}
)}
); })}
) : (

No notification channels yet

Add a channel to receive alerts when emails are processed or errors occur.

)} {/* Info box */}

About Notifications

Notifications are powered by{' '} Apprise , which supports 80+ notification services including Telegram, Discord, Slack, email, and many more. Each channel can be configured independently with different triggers.

); }