All files / src/pages/AcquirerPortal/LegalDocuments/api usePublishedDocumentByType.ts

100% Statements 11/11
92.85% Branches 13/14
100% Functions 5/5
100% Lines 11/11

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73                                      63x         166x   166x       13x     12x           166x 48x     166x     9x                                         166x     166x    
import { useQuery } from "react-query";
import { customInstance } from "@services/api";
import { LEGAL_DOC_KEYS } from "./keys";
import type { LegalDocument, DocumentVersion } from "../types";
 
/**
 * Resolves the currently-published document of a given `typeName`
 * (e.g. "merchant_agreement") readable by an account:
 *   list -> match the type's PUBLISHED row -> read that version's content.
 *
 * `accountID` is the caller's OWN account (the current portal account), not the
 * acquirer's: an acquirer gets its own documents; a merchant/provider gets its
 * parent acquirer's documents read-only — published only, no drafts, no editor
 * PII — with the hierarchy resolved by the backend. The public endpoint only
 * serves privacy_policy / terms_of_service, so agreement prose must come from
 * these authenticated routes. Callers without read access simply get no content
 * (retry disabled), so consumers render nothing / fall back to the legacy
 * hardcoded terms.
 */
export const usePublishedDocumentByType = (
  accountID?: number | string | null,
  type?: string,
  options?: { enabled?: boolean },
) => {
  const baseEnabled = (options?.enabled ?? true) && !!accountID && !!type;
 
  const listQuery = useQuery<LegalDocument[]>(
    [LEGAL_DOC_KEYS.list, accountID],
    () =>
      // Endpoint returns a { total, data } envelope; unwrap to the array.
      customInstance({
        url: `/merchants/${accountID}/legal-documents`,
        method: "GET",
      }).then((res) => res?.data ?? []),
    { enabled: baseEnabled, retry: false, refetchOnWindowFocus: false },
  );
 
  // The type's published row — never the draft (drafts are pinned on top of
  // the list, and a draft's version id 404s on the read-gated version read).
  const versionID = listQuery.data?.find(
    (doc) => doc.typeName === type && !doc.isDraft,
  )?.versionID;
 
  const versionQuery = useQuery<DocumentVersion>(
    [LEGAL_DOC_KEYS.version, accountID, versionID],
    () =>
      customInstance({
        url: `/merchants/${accountID}/legal-documents/versions/${versionID}`,
        method: "GET",
      }),
    {
      enabled: baseEnabled && !!versionID,
      retry: false,
      refetchOnWindowFocus: false,
    },
  );
 
  // Whether we are still DETERMINING if there is a published document to show.
  // This is a two-step fetch (list -> version), so we cannot rely on the
  // version query's own `isLoading`: while the list is still loading the
  // version query is DISABLED, which react-query v3 reports as `idle`
  // (`isLoading:false`, `data:undefined`) — indistinguishable from "nothing
  // published". Consumers must show a loading state while this is true so the
  // hardcoded fallback agreement does not flash before the published one
  // resolves. (Only the query window; the feature-flag async window is surfaced
  // separately via `useGetFeatureFlagValues().isFeatureFlagLoading`.)
  const isResolving =
    baseEnabled &&
    (listQuery.isLoading || (!!versionID && versionQuery.isLoading));
 
  return { ...versionQuery, isResolving };
};