import { useQuery } from "@tanstack/react-query"; import { api, ApiError } from "@/lib/api"; import type { Ack } from "@/types"; /** * UI-facing ack detail shape returned by `GET /api/acks/{id}`. * * Extends the base `Ack` shape with the `raw_999_text` field that * `api.getAck` populates on top of the canonical row. The download * button inside `AckDrawer` reads this string to hand the user the * regenerated X12 file. */ export interface AckDetail extends Ack { /** * Full regenerated 999 X12 text. The backend re-emits the parsed * transaction set so a user can grab the original file from the * drawer without a second round-trip to `/api/acks/{id}/raw`. */ raw_999_text?: string; /** * Raw JSON envelope captured by the parser (the same dict the * parser wrote into `raw_json`). Optional so older rows without * it still typecheck. */ rawJson?: unknown; } /** * Per-ack detail drawer query (AckDrawer · SP21 Phase 5 Task 5.2). * * Twin of `useProviderDetail` and `useClaimDetail` — same return * shape, same retry semantics, no in-memory fallback (the spec §5.2 * calls out that ACKs are backend-only; `useAcks` has no sample-data * path so there's nothing to fall back on). * * Returns `{ data, isLoading, isError, error, refetch }`: * - `ackId === 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. * - `ackId` is set: fetches `GET /api/acks/{id}` via `api.getAck`. * Cached 60 s — the underlying ack rows don't change after * parse-time. * - 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. * * The drawer accepts `ackId: string | null` (the URL keeps the id as * a string for clean deep-link round-tripping) and does the * `Number()` coercion here, matching how `useProviderDetail` * (`string`) and `useRemitDetail` (`string`) already work. */ export function useAckDetail(ackId: string | null): { data: AckDetail | null; isLoading: boolean; isError: boolean; error: Error | null; refetch: () => void; } { const q = useQuery({ queryKey: ["ack-detail", ackId], queryFn: () => api.getAck(Number(ackId)), enabled: ackId !== null, staleTime: 60 * 1000, retry: (failureCount, error) => { if (error instanceof ApiError && error.status === 404) return false; return failureCount < 3; }, }); if (ackId === 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(); }, }; }