{"version":3,"file":"use-can-show-volume-C3_XmLK7.cjs","names":["useOptionalAccountApi","useOptionalStore","canAccessRepSurfaces"],"sources":["../../../platform/volume-visibility/src/can-show-volume.ts","../../react/src/hooks/use-optional-account.ts","../../react/src/hooks/use-can-show-volume.ts"],"sourcesContent":["/**\n * The single policy deciding whether a viewer may see commissionable and\n * qualifying volume (CV/QV).\n *\n * Volume is a compensation-plan metric. Two independent things have to be true\n * before it reaches a screen: the merchant must not have hidden it, and the\n * viewer must be entitled to see it. Before this policy existed those questions\n * were answered by five different heuristics across nine render sites — and\n * four sites answered neither, which is how customers ended up seeing rep\n * figures (CURRENT-2159).\n *\n * This module is deliberately framework-agnostic: no React, no portal, no cart,\n * no generated API-client types. It takes two resolved booleans and returns\n * one. Each surface owns a thin adapter that translates its own state into\n * those booleans — checkout reads the cart's buyer-rep identity, portal and\n * shop read member-type permission — so the policy never learns what a cart or\n * a membership is, and a new surface adds an adapter rather than a sixth rule.\n */\n\n/** The two resolved facts the policy needs. */\nexport interface VolumeVisibilityInputs {\n  /**\n   * Whether the merchant has hidden volume from customer-facing surfaces.\n   *\n   * `undefined` means the flag was absent from the payload — an older backend,\n   * or a company that never set it. That reads as \"not hidden\", matching the\n   * server's own default, so an unset merchant never loses volume for reps.\n   */\n  companyHidesVolume: boolean | undefined;\n  /**\n   * Whether this viewer is entitled to see volume at all.\n   *\n   * `undefined` means entitlement is unknown — still loading, no session, or a\n   * surface that cannot resolve a viewer. That reads as \"not entitled\".\n   *\n   * The asymmetry with `companyHidesVolume` is deliberate. The company flag has\n   * a well-defined default; entitlement does not, and guessing \"entitled\" would\n   * show comp-plan figures to whoever happens to be looking. Volume is opt-in:\n   * when we cannot say who is asking, we do not answer.\n   */\n  viewerIsEntitled: boolean | undefined;\n}\n\n/**\n * Whether volume may be rendered.\n *\n * Callers must gate the *derivation* on this too, not only the markup. Several\n * surfaces compute volume locally — checkout multiplies a per-unit value by\n * quantity, the bundle builder sums group volumes, the portal transformer falls\n * back from one field name to another. Computing those from blanked server\n * values produces a visible `0` or `NaN`, which is a worse outcome than the\n * number itself.\n */\nexport function canShowVolume({\n  companyHidesVolume,\n  viewerIsEntitled,\n}: VolumeVisibilityInputs): boolean {\n  if (viewerIsEntitled !== true) return false;\n\n  return companyHidesVolume !== true;\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useOptionalAccountApi } from \"@fluid-app/portal-core/account-api-context\";\nimport type { AccountRep } from \"@fluid-app/portal-core/account-types\";\n\n/**\n * Shared cache key for the account query. Kept identical to the SDK's\n * `accountKeys.detail()` so `useAccount()` and this hook resolve from the same\n * cache entry rather than issuing a second request.\n */\nexport const ACCOUNT_QUERY_KEY = [\n  \"portalTenant\",\n  \"account\",\n  undefined,\n] as const;\nexport const ACCOUNT_STALE_TIME = 5 * 60 * 1000;\n\n/**\n * Account query that tolerates a missing `AccountApiProvider` — the same\n * situation `useOptionalStore()` handles for the store. Returns a disabled\n * query instead of throwing, so a widget rendered in the screen-builder palette\n * resolves to \"viewer unknown\" rather than crashing the palette.\n */\nexport function useOptionalAccount(): UseQueryResult<AccountRep> {\n  const api = useOptionalAccountApi();\n  return useQuery({\n    queryKey: ACCOUNT_QUERY_KEY,\n    // Only runs when enabled (api non-null), so the assertion is safe.\n    queryFn: async () => {\n      const response = await api!.fetchAccount();\n      return response.account;\n    },\n    enabled: api !== null,\n    staleTime: ACCOUNT_STALE_TIME,\n  });\n}\n","import { canShowVolume } from \"@fluid-app/volume-visibility/can-show-volume\";\nimport { canAccessRepSurfaces } from \"@fluid-app/portal-core/member-permissions\";\nimport { useOptionalAccount } from \"./use-optional-account\";\nimport { useOptionalStore } from \"./use-optional-store\";\n\n/**\n * Portal and shop's adapter for the shared CV/QV visibility policy.\n *\n * Entitlement is member-type permission, not a rep boolean: `canAccessRepSurfaces`\n * is the same helper the shell already uses to gate rep-only navigation, so the\n * member-type pricing epic (CURRENT-1368) extends this adapter rather than\n * unpicking the shared policy.\n *\n * Note it is the strict check, not `deniesRepSurfaces`. That sibling is\n * deliberately permissive while the account loads — right for navigation, where\n * briefly hiding a rep's own menu is the worse error. Here the worse error is\n * the opposite: showing comp-plan figures to someone who turns out not to be\n * entitled. An unresolved account reads as \"not entitled\".\n *\n * Both queries tolerate a missing provider, so a widget in the screen-builder\n * palette resolves to \"hide\" instead of crashing.\n */\nexport function useCanShowVolume(): boolean {\n  return useCanShowVolumeResolution().canShowVolume;\n}\n\n/**\n * The gate plus whether it is still settling.\n *\n * React components want the boolean: they re-render when the queries resolve,\n * so a first paint that hides volume corrects itself. Callers that answer once\n * and never revisit — the remote-widget capability host serves a product read\n * exactly once, with nothing to invalidate it — need to know the difference\n * between \"hidden\" and \"not known yet\", or they bake a boot-time answer into a\n * permanent response.\n *\n * `isResolving` is true only while a first fetch is genuinely in flight.\n * A query with no provider stays disabled and never settles, so waiting on it\n * would hang forever; that case is already \"viewer unknown\", which the policy\n * resolves to hide.\n */\nexport function useCanShowVolumeResolution(): {\n  canShowVolume: boolean;\n  isResolving: boolean;\n} {\n  const storeQuery = useOptionalStore();\n  const accountQuery = useOptionalAccount();\n\n  return {\n    canShowVolume: canShowVolume({\n      companyHidesVolume: storeQuery.data?.hide_volume_on_customer_surfaces,\n      viewerIsEntitled: accountQuery.data\n        ? canAccessRepSurfaces(accountQuery.data)\n        : undefined,\n    }),\n    isResolving: storeQuery.isLoading || accountQuery.isLoading,\n  };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAqDA,SAAgB,cAAc,EAC5B,oBACA,oBACkC;AAClC,KAAI,qBAAqB,KAAM,QAAO;AAEtC,QAAO,uBAAuB;;;;;;;;;AClDhC,MAAa,oBAAoB;CAC/B;CACA;CACA,KAAA;CACD;AACD,MAAa,qBAAqB,MAAS;;;;;;;AAQ3C,SAAgB,qBAAiD;CAC/D,MAAM,MAAMA,4BAAAA,uBAAuB;AACnC,SAAA,GAAA,sBAAA,UAAgB;EACd,UAAU;EAEV,SAAS,YAAY;AAEnB,WADiB,MAAM,IAAK,cAAc,EAC1B;;EAElB,SAAS,QAAQ;EACjB,WAAW;EACZ,CAAC;;;;;;;;;;;;;;;;;;;;;ACXJ,SAAgB,mBAA4B;AAC1C,QAAO,4BAA4B,CAAC;;;;;;;;;;;;;;;;;AAkBtC,SAAgB,6BAGd;CACA,MAAM,aAAaC,2BAAAA,kBAAkB;CACrC,MAAM,eAAe,oBAAoB;AAEzC,QAAO;EACL,eAAe,cAAc;GAC3B,oBAAoB,WAAW,MAAM;GACrC,kBAAkB,aAAa,OAC3BC,2BAAAA,qBAAqB,aAAa,KAAK,GACvC,KAAA;GACL,CAAC;EACF,aAAa,WAAW,aAAa,aAAa;EACnD"}