import { useQuery } from "@tanstack/react-query"; import { useSyncExternalStore } from "react"; import { api, ApiError } from "@/lib/api"; import { useAppStore } from "@/store"; import type { Provider } from "@/types"; /** * Per-provider detail drawer query (SP21 Task 2.2). * * Twin of `useClaimDetail` — same return shape, same retry semantics, * same demo-mode fallback story. Returns `{ data, isLoading, isError, * error, refetch }`: * - `npi === 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. * - `npi` is set AND a backend is configured: fetches * `GET /api/config/providers/{npi}` via `api.getProvider`. Cached * 60 s — provider directory rows change infrequently, but we still * want the drawer to refresh when a user reopens it across a long * 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. * - `!api.isConfigured` (demo mode): no fetch is issued. The hook * reads from the in-memory zustand store (`useAppStore.providers`). * An unknown NPI surfaces as `isError: true` so the drawer's * error branch handles it instead of spinning on a missing fetch. */ export function useProviderDetail(npi: string | null): { data: Provider | null; isLoading: boolean; isError: boolean; error: Error | null; refetch: () => void; } { const fallback = useSyncExternalStore( (cb) => useAppStore.subscribe(cb), () => useAppStore.getState().providers, () => useAppStore.getState().providers ); const q = useQuery({ queryKey: ["provider-detail", npi], queryFn: () => api.getProvider(npi as string), enabled: npi !== null && api.isConfigured, staleTime: 60 * 1000, retry: (failureCount, error) => { if (error instanceof ApiError && error.status === 404) return false; return failureCount < 3; }, }); if (!api.isConfigured) { const provider = npi === null ? null : fallback.find((p) => p.npi === npi) ?? null; return { data: provider, isLoading: false, isError: provider === null && npi !== null, error: provider === null && npi !== null ? new ApiError(404, "Provider not found") : null, refetch: () => {}, }; } if (npi === 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(); }, }; }