fix(ui/alerts): remove dead usePageVisible subscription; align alerts test mock with DTO
NotificationBell used a usePageVisible() subscription that re-rendered on
every visibilitychange without consuming the value. TanStack Query's
refetchIntervalInBackground:false already pauses polling; the extra
subscription was speculative generality. Dropped the import + call + JSDoc
reference; usePageVisible hook + test retained as a reusable primitive.
Also: alerts.test.tsx 'returns the server payload unmodified' asserted a
pre-plan {total, bySeverity} shape, but UnreadCountResponse is actually
{count}. Fixed mock + assertion to {count: 3}.
This commit is contained in:
@@ -60,14 +60,11 @@ describe('useUnreadCount', () => {
|
||||
|
||||
it('returns the server payload unmodified', async () => {
|
||||
(apiClient.GET as any).mockResolvedValue({
|
||||
data: { total: 3, bySeverity: { CRITICAL: 1, WARNING: 2, INFO: 0 } },
|
||||
data: { count: 3 },
|
||||
error: null,
|
||||
});
|
||||
const { result } = renderHook(() => useUnreadCount(), { wrapper });
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true));
|
||||
expect(result.current.data).toEqual({
|
||||
total: 3,
|
||||
bySeverity: { CRITICAL: 1, WARNING: 2, INFO: 0 },
|
||||
});
|
||||
expect(result.current.data).toEqual({ count: 3 });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Link } from 'react-router';
|
||||
import { Bell } from 'lucide-react';
|
||||
import { useUnreadCount } from '../api/queries/alerts';
|
||||
import { useSelectedEnv } from '../api/queries/alertMeta';
|
||||
import { usePageVisible } from '../hooks/usePageVisible';
|
||||
import css from './NotificationBell.module.css';
|
||||
|
||||
/**
|
||||
@@ -10,23 +9,13 @@ import css from './NotificationBell.module.css';
|
||||
* inbox and renders a badge with the unread-alert count for the currently
|
||||
* selected environment.
|
||||
*
|
||||
* Polling is driven by `useUnreadCount` (30s interval, paused in background
|
||||
* via TanStack Query's `refetchIntervalInBackground: false`). The
|
||||
* `usePageVisible` hook is retained as a defense-in-depth signal so future
|
||||
* UI behavior (e.g. animations, live-region updates) can key off visibility
|
||||
* without re-wiring the polling logic.
|
||||
*
|
||||
* TODO (spec §13): per-severity badge coloring — the backend
|
||||
* `UnreadCountResponse` currently exposes only a scalar `count` field. To
|
||||
* colour the badge by max unread severity (CRITICAL → error, WARNING →
|
||||
* amber, INFO → muted) the DTO must grow a `bySeverity` map; deferred to a
|
||||
* future task. Until then the badge uses a single `var(--error)` tint.
|
||||
* 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.
|
||||
*/
|
||||
export function NotificationBell() {
|
||||
const env = useSelectedEnv();
|
||||
// Subscribe to visibility so the component re-renders on tab focus, even
|
||||
// though the polling pause itself is handled inside useUnreadCount.
|
||||
usePageVisible();
|
||||
const { data } = useUnreadCount();
|
||||
|
||||
const count = data?.count ?? 0;
|
||||
|
||||
Reference in New Issue
Block a user