import { useQuery } from "@tanstack/react-query"; import { api, ApiError } from "@/lib/api"; import type { Remittance } from "@/types"; /** * UI-facing remittance detail shape returned by `GET /api/remittances/{id}`. * * The backend mapper (`cyclone.store.to_ui_remittance_with_adjustments`) * returns the standard `Remittance` fields plus the labeled `adjustments` * array. We extend the base type locally with the additional 835-derived * fields the backend emits — `payerClaimControlNumber` and `totalCharge` * (which aren't part of the v1 `Remittance` interface but ARE part of the * backend's `/api/remittances/{id}` payload). All newly-added fields are * optional so the component degrades gracefully when the backend hasn't * populated them (e.g. earlier rows without those columns populated). * * `payer` and `payee` blocks are also optional — the current detail * endpoint does not surface these yet, but the PartiesGrid renders them * when present so a future backend version lights up the cards without a * frontend change. */ export interface RemitDetail extends Remittance { payerClaimControlNumber?: string; totalCharge?: number; paymentMethod?: string | null; paymentDate?: string | null; payer?: { name?: string | null; id?: string | null; address?: { line1?: string; line2?: string | null; city?: string; state?: string; zip?: string; } | null; } | null; payee?: { name?: string | null; npi?: string | null; address?: { line1?: string; line2?: string | null; city?: string; state?: string; zip?: string; } | null; } | null; } /** * Per-remittance detail drawer query (RemitDrawer). * * Mirror of `useClaimDetail` — same return shape, same retry semantics. * Returns `{ data, isLoading, isError, error, refetch }`: * - `id === null` (drawer closed): the query is disabled and the hook * short-circuits to the empty drawer state so a closed drawer doesn't * burn a network request or a TanStack cache slot. * - `id` is set: fetches `GET /api/remittances/{id}` via * `api.getRemittance`. Cached 30 s so j/k navigation across remits * reuses prior fetches within the drawer session. * - On 404: the hook's retry predicate short-circuits (no retries) so * the drawer's not-found state appears immediately rather than being * masked by three back-to-back retry attempts. */ export function useRemitDetail(id: string | null): { data: RemitDetail | null; isLoading: boolean; isError: boolean; error: Error | null; refetch: () => void; } { const q = useQuery({ queryKey: ["remit-detail", id], queryFn: () => api.getRemittance(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, error: q.error, refetch: () => { void q.refetch(); }, }; }