Appearance
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-sdkCatalogLink
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
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
bootstrapToken | string | Yes | — | Short-lived token returned by your backend |
widgetUrl | string | Yes | — | Hosted catalog URL. Use https://catalog.iimmpact.com for production or https://dev-catalog.iimmpact.com for development |
allowedOrigins | string[] | No | Origin derived from widgetUrl | Usually omit; advanced override for accepted iframe message origins |
defaultOpen | boolean | No | false | Open the modal automatically on mount |
iframeTitle | string | No | Catalog checkout | Accessible iframe title |
modalLabel | string | No | Catalog checkout dialog | ARIA label for the modal dialog |
className | string | No | — | Class applied to the trigger wrapper |
children | ReactNode | (controller) => ReactNode | No | Default button | Static 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.
| Status | Meaning |
|---|---|
idle | Not opened yet |
loading | open() was called and the iframe is mounting |
ready | Iframe loaded and token delivery has started/completed |
open | Reserved for active hosted UI state |
closed | User exited or checkout completed |
error | Hosted 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:
useCatalogLinkCATALOG_SDK_MESSAGE_PREFIXCATALOG_SDK_MESSAGESCatalogSdkPaymentRequiredMessageandCatalogSdkPaymentRequiredPayloadtypescreateRequestIdgetOriginisAllowedOriginisCatalogSdkBootstrapMessageisCatalogSdkHostMessageparseAllowedOrigins
