import { useQuery, useQueryClient, skipToken } from '@tanstack/react-query'; import { useCallback } from 'react'; import { apiClient } from '@/api/client'; import type { NetworkUsage } from '@/api/types'; export const networkUsageQueryKey = (networkId: string | undefined) => ['network-usage', networkId] as const; export function useNetworkUsage(networkId: string | undefined) { return useQuery({ queryKey: networkUsageQueryKey(networkId), queryFn: networkId ? () => apiClient.getNetworkUsage(networkId) : skipToken, // Refetch whenever a consumer mounts (billing settings, compose indicator) // so users land on fresh quota state without listener wiring. refetchOnMount: 'always', refetchOnWindowFocus: true, refetchInterval: 10000, }); } /** * Returns a callback that invalidates the usage query for a network. * Callers: own-send success path, inbound-particle listener. */ export function useInvalidateNetworkUsage() { const qc = useQueryClient(); return useCallback( (networkId: string) => qc.invalidateQueries({ queryKey: networkUsageQueryKey(networkId) }), [qc], ); } /** * Optimistic bump of the cached `used` count. The worker-written truth is * reconciled on the next invalidation/refetch. */ export function useBumpNetworkUsage() { const qc = useQueryClient(); return useCallback( (networkId: string) => { qc.setQueryData(networkUsageQueryKey(networkId), (prev) => prev ? { ...prev, used: prev.used + 1 } : prev, ); }, [qc], ); } /** * True iff the network is on the free plan and has exhausted today's quota. */ export function isUsageExhausted(usage: NetworkUsage | undefined): boolean { if (!usage) return false; if (usage.limit == null) return false; return usage.used >= usage.limit; }