/** * Notifications Settings Page * Configure notification preferences and view notification history */ import { useState } from 'react'; import { ActionIcon, Alert, Badge, Button, Card, Container, Divider, Group, Loader, Menu, Paper, ScrollArea, Stack, Switch, Text, ThemeIcon, Title, Tooltip, } from '@mantine/core'; import { notifications as mantineNotifications } from '@mantine/notifications'; import { IconBell, IconBellOff, IconAlertCircle, IconCheck, IconTrash, IconDots, IconRefresh, IconMail, IconBrandSlack, IconBrandDiscord, IconAlertTriangle, IconInfoCircle, } from '@tabler/icons-react'; import { GetServerSidePropsContext } from 'next'; import { UnraidLayout } from '~/components/Unraid/Layout'; import { getServerAuthSession } from '~/server/auth'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { api } from '~/utils/api'; import type { Notification, NotificationImportance } from '~/lib/unraid/types'; function getImportanceColor(importance: NotificationImportance): string { switch (importance) { case 'ALERT': return 'red'; case 'WARNING': return 'yellow'; case 'NORMAL': return 'blue'; default: return 'gray'; } } function getImportanceIcon(importance: NotificationImportance) { switch (importance) { case 'ALERT': return ; case 'WARNING': return ; case 'NORMAL': return ; default: return ; } } function formatDate(timestamp: number): string { return new Date(timestamp * 1000).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', }); } function NotificationItem({ notification, onMarkRead, onDelete, }: { notification: Notification; onMarkRead: () => void; onDelete: () => void; }) { return ( {getImportanceIcon(notification.importance)} {notification.subject} {!notification.read && ( New )} {notification.description} {notification.type} {formatDate(notification.timestamp)} {!notification.read && ( } onClick={onMarkRead} > Mark as Read )} } onClick={onDelete} > Delete ); } export default function NotificationsSettingsPage() { const [filter, setFilter] = useState<'all' | 'unread'>('all'); const { data: notificationsList, isLoading, error, refetch, } = api.unraid.notifications.useQuery(); const markRead = api.unraid.markNotificationRead.useMutation({ onSuccess: () => { mantineNotifications.show({ title: 'Marked as Read', message: 'Notification marked as read', color: 'green', icon: , }); refetch(); }, }); const deleteNotification = api.unraid.deleteNotification.useMutation({ onSuccess: () => { mantineNotifications.show({ title: 'Deleted', message: 'Notification deleted', color: 'green', icon: , }); refetch(); }, }); const markAllRead = api.unraid.markAllNotificationsRead.useMutation({ onSuccess: () => { mantineNotifications.show({ title: 'All Read', message: 'All notifications marked as read', color: 'green', icon: , }); refetch(); }, }); const filteredNotifications = notificationsList?.filter((n) => filter === 'all' ? true : !n.read ); const unreadCount = notificationsList?.filter((n) => !n.read).length || 0; const alertCount = notificationsList?.filter((n) => n.importance === 'ALERT').length || 0; const warningCount = notificationsList?.filter((n) => n.importance === 'WARNING').length || 0; if (isLoading) { return ( Loading notifications... ); } if (error) { return ( } title="Error" color="red"> {error.message} ); } return ( {/* Header */} Notifications {unreadCount} unread notification{unreadCount !== 1 ? 's' : ''} {unreadCount > 0 && ( } onClick={() => markAllRead.mutate()} loading={markAllRead.isLoading} > Mark All Read )} } onClick={() => refetch()} > Refresh {/* Stats */} Unread {unreadCount} Alerts {alertCount} Warnings {warningCount} Total {notificationsList?.length || 0} {/* Notification Settings (placeholder) */} Notification Channels Email Notifications Send notifications via email Slack Notifications Send notifications to Slack Discord Notifications Send notifications to Discord {/* Filter */} setFilter('all')} size="sm" > All ({notificationsList?.length || 0}) setFilter('unread')} size="sm" color="blue" > Unread ({unreadCount}) {/* Notifications List */} {filteredNotifications?.map((notification) => ( markRead.mutate({ id: notification.id })} onDelete={() => deleteNotification.mutate({ id: notification.id })} /> ))} {filteredNotifications?.length === 0 && ( {filter === 'unread' ? 'No unread notifications' : 'No notifications'} )} ); } export const getServerSideProps = async (context: GetServerSidePropsContext) => { const session = await getServerAuthSession(context); const translations = await getServerSideTranslations( ['common'], context.locale, context.req, context.res ); const result = checkForSessionOrAskForLogin( context, session, () => session?.user != undefined ); if (result) { return result; } return { props: { ...translations, }, }; };