Skip to content

React SDK

The @iimmpact-sdn-bhd/catalog-sdk package exposes a React component and a headless hook for opening the hosted catalog checkout.

Installation

bash
npm install @iimmpact-sdn-bhd/catalog-sdk

Use CatalogLink for the standard modal iframe integration.

tsx
import { CatalogLink } from "@iimmpact-sdn-bhd/catalog-sdk";

<CatalogLink
  bootstrapToken={bootstrapTokenFromBackend}
  widgetUrl="https://catalog.iimmpact.com"
  onSuccess={(result) => {
    console.log(result.orderId);
  }}
  onExit={({ reason }) => {
    console.log(reason);
  }}
  onError={(error) => {
    console.error(error.message);
  }}
>
  {({ open, status }) => (
    <button disabled={status === "loading"} onClick={open} type="button">
      Open catalog
    </button>
  )}
</CatalogLink>

Props

PropTypeRequiredDefaultDescription
bootstrapTokenstringYesShort-lived token returned by your backend
widgetUrlstringYesHosted catalog URL. Use https://catalog.iimmpact.com for production or https://dev-catalog.iimmpact.com for development
allowedOriginsstring[]NoOrigin derived from widgetUrlUsually omit; advanced override for accepted iframe message origins
defaultOpenbooleanNofalseOpen the modal automatically on mount
iframeTitlestringNoCatalog checkoutAccessible iframe title
modalLabelstringNoCatalog checkout dialogARIA label for the modal dialog
classNamestringNoClass applied to the trigger wrapper
childrenReactNode | (controller) => ReactNodeNoDefault buttonStatic trigger content or render prop

Callbacks

onReady()

Called when the iframe is loaded and the wrapper has delivered the bootstrap token.

onSuccess(payload)

Called when the hosted catalog flow has created an order and is ready to hand off payment to the client app.

The hosted UI currently emits this handoff as iimmpact.catalog.paymentRequired; CatalogLink maps it to onSuccess for client integrations.

typescript
interface CatalogSdkSuccessPayload {
  orderId: string;
  status: "pending_payment";
  totalAmount: string;
  items: Array<{
    product_code: string;
    account_number: string;
    amount: string;
    quantity: number;
    extras?: Record<string, unknown>;
  }>;
}

onExit(event)

Called when the user or hosted UI closes the flow before success.

typescript
interface CatalogSdkExitEvent {
  reason?: string;
}

The close button provided by CatalogLink sends reason: "client_closed".

Payment Responsibility

onSuccess gives the client app the payment handoff payload:

typescript
interface CatalogSdkSuccessPayload {
  orderId: string;
  status: "pending_payment";
  totalAmount: string;
  items: Array<{
    product_code: string;
    account_number: string;
    amount: string;
    quantity: number;
    extras?: Record<string, unknown>;
  }>;
}

Use totalAmount to collect payment in your own app. Use items to show the selected products, accounts, and extras. Use orderId as the IIMMPACT order reference when your backend confirms payment after your payment flow succeeds.

Do not treat onSuccess as final settlement by itself. It means the catalog/order step succeeded and the client app should now handle payment.

After your backend confirms payment, the order moves to processing while IIMMPACT fulfills the underlying transactions asynchronously. Track the final result through order status, transaction history, or configured Catalog SDK Webhooks.

onEvent(event)

Optional lifecycle or analytics events from the hosted UI.

typescript
interface CatalogSdkEvent {
  name: string;
  payload?: Record<string, unknown>;
}

onError(error)

Called when the hosted catalog reports an error.

typescript
interface CatalogSdkError {
  message: string;
  code?: string;
}

Status Values

The render-prop controller exposes status so your button or UI can react to the iframe lifecycle.

StatusMeaning
idleNot opened yet
loadingopen() was called and the iframe is mounting
readyIframe loaded and token delivery has started/completed
openReserved for active hosted UI state
closedUser exited or checkout completed
errorHosted UI reported an error

Headless Hook

Use useCatalogLink when you need to render your own modal, drawer, or layout.

tsx
import { useCatalogLink } from "@iimmpact-sdn-bhd/catalog-sdk";

function CustomCatalogModal({ bootstrapToken }: { bootstrapToken: string }) {
  const controller = useCatalogLink({
    bootstrapToken,
    widgetUrl: "https://catalog.iimmpact.com",
    onSuccess: (payload) => console.log(payload.orderId),
  });

  return (
    <>
      <button onClick={controller.open} type="button">
        Open catalog
      </button>

      {controller.isOpen ? (
        <iframe
          allow="payment *; clipboard-write"
          onLoad={(event) => controller.handleIframeLoad(event.currentTarget)}
          sandbox="allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
          src="https://catalog.iimmpact.com"
          title="Catalog checkout"
        />
      ) : null}
    </>
  );
}

The hook returns:

typescript
interface CatalogLinkController {
  status: "idle" | "loading" | "ready" | "open" | "closed" | "error";
  requestId: string;
  isOpen: boolean;
  open: () => void;
  close: (reason?: string) => void;
  handleMessage: (event: MessageEvent<unknown>) => void;
  handleIframeLoad: (iframe: HTMLIFrameElement | null) => void;
}

Iframe Behavior

The default CatalogLink iframe uses:

text
sandbox="allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
allow="payment *; clipboard-write"

The default modal is mobile-first: min(430px, 100vw) wide and min(860px, 100vh) tall.

Exported Utilities

Most integrations only need CatalogLink. Advanced integrations can also import:

  • useCatalogLink
  • CATALOG_SDK_MESSAGE_PREFIX
  • CATALOG_SDK_MESSAGES
  • CatalogSdkPaymentRequiredMessage and CatalogSdkPaymentRequiredPayload types
  • createRequestId
  • getOrigin
  • isAllowedOrigin
  • isCatalogSdkBootstrapMessage
  • isCatalogSdkHostMessage
  • parseAllowedOrigins

IIMMPACT API Documentation