import { useQuery } from "@tanstack/react-query"; import { api, ApiError } from "@/lib/api"; import type { ClaimDetail } from "@/types"; /** * Per-claim detail drawer query (SP4). * * Returns `{ data, isLoading, isError, error, refetch }`: * - `id === null` (drawer closed): the query is disabled and the hook * short-circuits to the empty drawer state `{ data: null, isLoading: * false, isError: false, error: null }`. `refetch` is a no-op since no * fetch is in flight. * - `id` is set: fetches `GET /api/claims/{id}` via `api.getClaimDetail`. * The response is cached for 30 s so j/k navigation across claims * reuses prior fetches within the drawer session (spec ยง3.4). * - On 404: `error` is the `ApiError(status=404)` thrown by the client. * We disable retries on 404 so the drawer can render the not-found * state immediately rather than masking it with three back-to-back * retries. */ export function useClaimDetail(id: string | null): { data: ClaimDetail | null; isLoading: boolean; isError: boolean; error: Error | null; refetch: () => void; } { const q = useQuery({ queryKey: ["claim-detail", id], queryFn: () => api.getClaimDetail(id as string), enabled: id !== null, staleTime: 30 * 1000, retry: (failureCount, error) => { if (error instanceof ApiError && error.status === 404) return false; return failureCount < 3; }, }); if (id === null) { return { data: null, isLoading: false, isError: false, error: null, refetch: () => {}, }; } return { data: q.data ?? null, isLoading: q.isLoading, isError: q.isError, // `q.error` is typed as `Error | null` (TanStack Query v5's default // TError is `Error`); at runtime the api layer throws `ApiError`, // which is a subclass of `Error`, so the cast is safe. error: q.error, // TanStack's refetch returns a Promise; the plan's signature wants // a plain `() => void` so consumers can fire-and-forget. refetch: () => { void q.refetch(); }, }; }