2026-04-20 13:26:58 +02:00
|
|
|
import { Link } from 'react-router';
|
|
|
|
|
import { Bell } from 'lucide-react';
|
|
|
|
|
import { useUnreadCount } from '../api/queries/alerts';
|
|
|
|
|
import { useSelectedEnv } from '../api/queries/alertMeta';
|
|
|
|
|
import css from './NotificationBell.module.css';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Global notification bell shown in the layout header. Links to the alerts
|
|
|
|
|
* inbox and renders a badge with the unread-alert count for the currently
|
|
|
|
|
* selected environment.
|
|
|
|
|
*
|
2026-04-20 13:30:07 +02:00
|
|
|
* Polling pause when the tab is hidden is handled by `useUnreadCount`'s
|
|
|
|
|
* `refetchIntervalInBackground: false`; no separate visibility subscription
|
|
|
|
|
* is needed. If per-severity coloring (spec §13) is re-introduced, the
|
|
|
|
|
* backend `UnreadCountResponse` must grow a `bySeverity` map.
|
2026-04-20 13:26:58 +02:00
|
|
|
*/
|
|
|
|
|
export function NotificationBell() {
|
|
|
|
|
const env = useSelectedEnv();
|
|
|
|
|
const { data } = useUnreadCount();
|
|
|
|
|
|
|
|
|
|
const count = data?.count ?? 0;
|
|
|
|
|
|
|
|
|
|
if (!env) return null;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Link
|
|
|
|
|
to="/alerts/inbox"
|
|
|
|
|
role="button"
|
|
|
|
|
aria-label={`Notifications (${count} unread)`}
|
|
|
|
|
className={css.bell}
|
|
|
|
|
>
|
|
|
|
|
<Bell size={16} />
|
|
|
|
|
{count > 0 && (
|
|
|
|
|
<span className={css.badge} aria-hidden>
|
|
|
|
|
{count > 99 ? '99+' : count}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</Link>
|
|
|
|
|
);
|
|
|
|
|
}
|