All files / src/hooks/queries useAdminNavBadges.ts

100% Statements 6/6
100% Branches 2/2
100% Functions 2/2
100% Lines 5/5

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46                                                  40x   22x             40x 40x 2x                  
import { useQuery } from "@tanstack/react-query";
import { adminRrmApi } from "../../lib/api/admin/rrm";
import { queryKeys } from "../../lib/query-keys";
import { STALE_2MIN } from "../../lib/stale-times";
 
export type AdminNavBadges = {
	rrmInbox?: number;
	rrmTasks?: number;
	rrmSignups?: number;
};
 
/**
 * Live counts for the admin sidebar.
 *
 * Deliberately does NOT poll. The sidebar renders on every admin page, so a
 * refetch interval here would poll the RRM funnel from screens that have
 * nothing to do with the campaign. It shares a cache key with
 * `useRrmFunnel`, so whenever a real RRM screen is open the badge is as fresh
 * as that screen; elsewhere it refreshes on navigation, which is enough to
 * notice a backlog without taxing every other page.
 *
 * Failure is silent by design — a sidebar that renders nothing because a
 * count could not be fetched would be a worse outcome than a missing badge.
 */
export function useAdminNavBadges(): AdminNavBadges {
	const { data } = useQuery({
		queryKey: queryKeys.admin.rrm.funnel(),
		queryFn: () => adminRrmApi.getFunnel(),
		staleTime: STALE_2MIN,
		retry: false,
	});
 
	// `request<T>` returns the { success, data, error } envelope, not the
	// payload — the count lives one level in.
	const funnel = data?.data;
	if (!funnel) return {};
	return {
		rrmInbox: funnel.unansweredCount,
		// Organic sign-ups nobody has replied to yet (3.1). Optional chaining
		// even though the contract makes `organic` required: this hook must
		// never throw the sidebar into an error state over one stale field
		// while the API deploys concurrently — a missing badge beats a broken page.
		rrmSignups: funnel.organic?.unrepliedCount,
	};
}