All files / src/services/api/products inventory.ts

100% Statements 6/6
75% Branches 3/4
100% Functions 3/3
100% Lines 6/6

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                                                                    5x       5x       14x         5x 24x         14x      
import { useQuery } from "react-query";
import { customInstance } from "@services/api";
import { QKEY_PRODUCT_INVENTORY } from "@constants/queryKeys";
import { EventVariantApiRow } from "@features/Events/EventDetail/inventory/inventory.types";
 
/**
 * An event's ticket types, for the Inventory tab.
 *
 * Deliberately not `useGetEventVariants` from ./events: that hook's query key is
 * the bare string "event-variants" with no product id, so two events share one
 * cache entry — navigating between events would show the previous one's tiers.
 * It has no callers today, so it is left alone rather than changed underneath
 * something else.
 *
 * The key here is `specific-product-inventory` + the product id, which is what
 * the rest of the app already invalidates when this resource moves: a refund
 * (`useRefund`) and a PayBuilder capacity edit (`Minibuilders/hooks.ts`) both
 * clear it, so the tab does not sit on stale counts after either.
 *
 * `sort=displayOrder` keeps the cards in the order the merchant arranged the
 * ticket types in PayBuilder.
 */
 
type EventVariantListResponse = {
  data: EventVariantApiRow[] | null;
  total: number;
};
 
/**
 * The tab draws every ticket type at once, so the read asks for all of them.
 * Left off, the endpoint applies its own `max` of 100 and truncates `data`
 * while `total` keeps the real count, which would drop tiers off the grid with
 * nothing on screen to say so.
 */
export const EVENT_INVENTORY_MAX = 500;
 
// customInstance is untyped here (it resolves to `any`), so the response shape
// is pinned on the wrapper's return type instead of a call-site generic.
export const getEventVariants = (
  merchantId: number,
  eventId: string | number,
): Promise<EventVariantListResponse> =>
  customInstance({
    url: `/merchants/${merchantId}/products/${eventId}/variants?sort=displayOrder&max=${EVENT_INVENTORY_MAX}`,
    method: "GET",
  });
 
export const useGetEventInventory = (merchantId: number, eventId?: string) =>
  useQuery<EventVariantListResponse>(
    // Product id second: `Minibuilders` invalidates by the
    // ["specific-product-inventory", productId] prefix with a numeric id, so
    // the shape and the type both have to match for that to reach this entry.
    [QKEY_PRODUCT_INVENTORY, eventId ? Number(eventId) : undefined, merchantId],
    () => getEventVariants(merchantId, eventId as string),
    { enabled: Boolean(merchantId && eventId) },
  );