# Komo React Native SDK

Embed Komo content in your React Native applications.

## Installation

```sh
npm install @komo-tech/react-native-widgets
```

NOTE: This package has a peer dependency on [react-native-webview](https://github.com/react-native-webview/react-native-webview), and recommends the latest major version, `13.x`.

## Basic Usage

- The quickest way to get started with embedding Komo content in react native is by using the [`KomoCardWidget`](#komocardwidget-props) component.
- This component combines metadata fetching, card cover display, and modal handling for the card content (i.e. experience).
- The only required prop is `embedMetaUrl`. To find this in the Komo portal:
  - Navigate to the settings of the card to be embedded.
  - Select the `Embed` tab and click on `React Native code` in the right sidebar.
  - Copy the `Card embed meta URL` and use it as the value of the `embedMetaUrl` prop.

```js
import { KomoCardWidget } from '@komo-tech/react-native-widgets';

// ...

<KomoCardWidget
  embedMetaUrl={KomoCardNativeEmbedUrl}
  containerStyle={{ maxWidth: '80%' }}
/>;
```

### Prefilling form details

- You can pass information through to the Komo experience that will be pre-filled in any forms that the user may encounter.
- Pass a plain `Record<string,string>` object of keys and values through to the `formPrefillValues` prop on [`KomoCardWidget`](#komocardwidget-props) or [`ExperienceModal`](#experiencemodal-props).
- The object keys must match the Unique ID of the form field or contact property from the Komo Platform that you want to prefill.

```js
<KomoCardWidget
  embedMetaUrl={KomoCardNativeEmbedUrl}
  containerStyle={{ maxWidth: '80%' }}
  formPrefillValues={{
    email: 'email@domain.com',
    first_name: 'Person',
    last_name: 'Doe',
  }}
/>
```

## Advanced usage

### Metadata fetching

- The first step to using embedded Komo content involves fetching the card metadata.
- Use the [`useFetchCardMetadata`](#usefetchcardmetadata-hook) hook and the `Native embed URL` copied from the platform to fetch the [CardEmbedMetadata](#cardembedmetadata).
- The [CardEmbedMetadata](#cardembedmetadata) has the information required to render the cover image (`imageUrl`) and the URL (`embedUrl`) that the [ExperienceModal](#experiencemodal-props) needs to render the embedded experience.
- Note: you can use your own data-fetching patterns if you require more advanced data fetching handling. So long as it produces a [CardEmbedMetadata](#cardembedmetadata), you can pass that to the other components that you want to use.

```js
import { useFetchCardMetadata } from '@komo-tech/react-native-widgets';

// ... rest of your component

const { data, isLoading, isError } = useFetchCardMetadata({
  embedMetaUrl: KomoCardNativeEmbedUrl,
});

// ... use the data.
```

### Render a Card Cover

- The [`CardCover`](#cardcover-props) component is used to display the cover image of a Komo card.
- It handles loading states, error states, and button display.
- The component requires an `onClick` handler and `isLoading` state.
- The `imageUrl` and `imageAspectRatio` props are typically obtained from the [CardEmbedMetadata](#cardembedmetadata).

```js
import { CardCover } from '@komo-tech/react-native-widgets';

// ... rest of your component

<CardCover
  imageUrl={metadata?.imageUrl}
  imageAspectRatio={metadata?.imageAspectRatio}
  isLoading={isLoading}
  isError={isError}
  onClick={() => doSomethingOnCoverClicked()}
  metaButtonStyle={metadata?.buttonStyle}
  containerStyle={{ borderRadius: 8 }}
/>;
```

### Using the Experience Modal

- The [`ExperienceModal`](#experiencemodal-props) component is used to display the full Komo experience in a modal overlay.
- It handles loading states, error states, and communication with the embedded experience.
- The component requires an `isOpen` state and `onClose` handler.
- A valid `embedUrl` prop is required for the experience modal to function, and this is typically obtained from the [CardEmbedMetadata](#cardembedmetadata).
- If you have forced OAuth enabled, you also need to pass through the `embedAuthUrl` from [CardEmbedMetadata](#cardembedmetadata).

```js
import { ExperienceModal } from '@komo-tech/react-native-widgets';

// ... rest of your component

<ExperienceModal
  isOpen={isModalOpen}
  onClose={() => setIsModalOpen(false)}
  embedUrl={metadata?.embedUrl}
  embedAuthUrl={metadata?.embedAuthUrl}
  loadingTimeoutMs={15000} // Optional: customize loading timeout
  appId="my-app" // Optional: identify where the content is embedded
/>;
```

### Experience Modal example without Card Cover

- You can use whichever components you want to build your desired experience.
- For example, you can trigger the [`ExperienceModal`](#experiencemodal-props) without rendering our CardCover.

```js
// ... rest of your component
const { data, isLoading } = useFetchCardMetadata({
  isEnabled,
  embedMetaUrl: EmbedMetaUrlFromKomoPortal,
});
const [modalOpen, setModalOpen] = useState(false);

// other code, e.g. some element that calls setModalOpen(true) after isLoading returns false

<ExperienceModal
  isOpen={modalOpen}
  onClose={() => {
    setModalOpen(false);
  }}
  embedUrl={data?.embedUrl}
/>;
```

### Listening for events from the embedded experience

- You can listen for events from the embedded experience by using the `onWindowMessage` or `onKomoEvent` props on the [`ExperienceModal`](#experiencemodal-props) or [`KomoCardWidget`](#komocardwidget-props).
- The `onWindowMessage` prop exposes any `window.postMessage` events from the embedded experience.
- The `onKomoEvent` prop exposes any [User Interaction Events](https://developers.komo.tech/user-interaction-events) from the embedded experience.
  - Note: User Interaction Events will also appear in the `onWindowMessage` callback. `onKomoEvent` is a more convenient way to listen for Komo User Interaction Events from the embedded experience.

```js
<ExperienceModal
  isOpen={modalOpen}
  onClose={() => {
    setModalOpen(false);
  }}
  embedUrl={data?.embedUrl}
  onKomoEvent={(event) => {
    console.log('Komo event received:', event);
  }}
  onWindowMessage={(event) => {
    console.log('Window message received:', event);
  }}
/>
```

### Extension Data

- The [`ExperienceModal`](#experiencemodal-props) and [`KomoCardWidget`](#komocardwidget-props) components allow you to set [extension data](https://developers.komo.tech/user-interaction-events/extension-data) on the user interaction events.
- The `extensionDataValues` prop is a plain `Record<string, string | number | boolean | object>` object.
- Make sure PII is not passed in as extension data, as it is passed directly to your tag manager integrations.

```js
<KomoCardWidget
  embedMetaUrl={KomoCardNativeEmbedUrl}
  extensionDataValues={{
    custom_unique_id: 'ABC123',
    custom_object: {
      some_id: 'ABC123',
      some_measure: 123456
    }
  }}
/>
```

### Auth0 Session Transfer

- The [`KomoCardWidget`](#komocardwidget-props) component supports Auth0 authentication through the `authPassthroughParams` prop.
- The [`ExperienceModal`](#experiencemodal-props) component supports Auth0 authentication through the `embedAuthUrl` and `authPassthroughParams` props.
  - The `embedAuthUrl` is typically obtained from [CardEmbedMetadata](#cardembedmetadata).
- Pre-requisites:
  - Auth0 SSO must be configured on the Komo Hub, and "Force Embed Auth" must be enabled under Embed SDK settings on the hub.  
  - Pass a fresh session transfer token to the `authPassthroughParams` prop, e.g. `session_transfer_token: 'ABC123'`.
- With this setup, the user will be redirected to Auth0 to authenticate when the experience modal is opened, before being redirected back to the embedded experience.
- The session transfer token must be obtained immediately before opening the experience modal, since it has a short 60 second lifespan.

```js
<KomoCardWidget
    embedMetaUrl={KomoCardNativeEmbedUrl}
    authPassthroughParams={new URLSearchParams({
        session_transfer_token: 'ABC123'
    })}
/>
// or if using the ExperienceModal directly
<ExperienceModal
    isOpen={isModalOpen}
    onClose={() => setIsModalOpen(false)}
    embedUrl={metadata?.embedUrl}
    embedAuthUrl={metadata?.embedAuthUrl}
    authPassthroughParams={new URLSearchParams({
        session_transfer_token: 'ABC123'
    })}
/>
```

#### Error handling

- If the `session_transfer_token` passed to Auth0 is used, invalid, or expired, then the users will end up being shown the ExperienceModal `errorDisplay`, which includes a built-in retry button.
- If you don't provide an `errorDisplay` override, the retry function will just attempt to reload the experience with the current parameters and will most likely fail again.
- We recommend that you provide a custom `errorDisplay` so that you can handle `session_transfer_token` regeneration before trying to load the content again.

## Metadata model

### CardEmbedMetadata

| Property           | Type         | Description                                                   |
| ------------------ | ------------ | ------------------------------------------------------------- |
| `title`            | string?      | The title of the card                                         |
| `imageUrl`         | string?      | URL of the card's cover image                                 |
| `imageHeight`      | number?      | Height of the cover image in pixels                           |
| `imageWidth`       | number?      | Width of the cover image in pixels                            |
| `imageAspectRatio` | number?      | Aspect ratio of the cover image                               |
| `embedUrl`         | string?      | URL for the embedded experience                               |
| `embedAuthUrl`          | string?      | URL used to OAuth the user before showing the embedded experience |
| `buttonStyle`      | ButtonStyle? | Styling for the card's button                                 |

### ButtonStyle

| Property          | Type    | Description                    |
| ----------------- | ------- | ------------------------------ |
| `text`            | string? | Text to display on the button  |
| `backgroundColor` | string? | Background color of the button |
| `color`           | string? | Text color of the button       |

## Hooks

### useFetchCardMetadata

A hook for fetching card metadata from the Komo platform.

#### Options

| Property       | Type             | Required | Description                                                                   |
| -------------- | ---------------- | -------- | ----------------------------------------------------------------------------- |
| `embedMetaUrl` | string           | Yes      | The URL of the embed metadata for the card, copied from the Komo Portal       |
| `isEnabled`    | boolean          | No       | Whether the embed metadata query is enabled. Defaults to true                 |
| `onError`      | (e: any) => void | No       | Callback for when an error occurs during querying the embed metadata endpoint |

#### Result

| Property       | Type                | Description                                |
| -------------- | ------------------- | ------------------------------------------ |
| `data`         | CardEmbedMetadata?  | The embed metadata for the card            |
| `isLoading`    | boolean             | Whether the embed metadata is loading      |
| `isError`      | boolean             | Whether the embed metadata query failed    |
| `isSuccess`    | boolean             | Whether the embed metadata query succeeded |
| `refetchAsync` | () => Promise<void> | Function to refetch the embed metadata     |

## Components

### CardCover Props

| Property                  | Type                   | Required | Description                                                |
| ------------------------- | ---------------------- | -------- | ---------------------------------------------------------- |
| `onClick`                 | () => void             | Yes      | The callback for when the cover is clicked                 |
| `isLoading`               | boolean                | Yes      | Whether the cover is loading                               |
| `isError`                 | boolean?               | No       | Whether the cover is in an error state                     |
| `loader`                  | ReactNode?             | No       | Override the default skeleton loader                       |
| `errorDisplay`            | ReactNode?             | No       | Override the default error display                         |
| `metaButtonStyle`         | ButtonStyle?           | No       | The button style returned from the embed metadata endpoint |
| `overrideButtonStyle`     | StyleProp<ViewStyle>?  | No       | Override the button style                                  |
| `overrideButtonTextStyle` | StyleProp<TextStyle>?  | No       | Override the button text style                             |
| `containerStyle`          | StyleProp<ViewStyle>?  | No       | Override the container style                               |
| `coverImageStyle`         | StyleProp<ImageStyle>? | No       | Override the cover image style                             |
| `hideCoverButton`         | boolean?               | No       | Whether to hide the cover button                           |
| `imageUrl`                | string?                | No       | The url of the cover image                                 |
| `imageAspectRatio`        | number?                | No       | The aspect ratio of the cover image                        |

### ExperienceModal Props

| Property            | Type                                                | Required | Description                                                                                                                                                                      |
| ------------------- | --------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isOpen`            | boolean                                             | Yes      | Whether the modal is open                                                                                                                                                        |
| `onClose`           | () => void                                          | Yes      | Callback for when close is requested                                                                                                                                             |
| `embedUrl`          | string                                              | Yes      | The URL of the embedded card experience                                                                                                                                          |
| `modalHeader`       | ReactNode                                           | No       | Override the default modal header                                                                                                                                                |
| `shareClickUrl`     | string                                              | No       | Override the url that redirects a user when clicking on a share link                                                                                                             |
| `appId`             | string                                              | No       | An identifier for the embedded Komo content                                                                                                                                      |
| `formPrefillValues` | Record<string, string>                              | No       | Prefill values for the form within the experience                                                                                                                                |
| `loadingIndicator`  | ReactNode                                           | No       | Override the default loading indicator                                                                                                                                           |
| `modalProps`        | ModalProps                                          | No       | Override the default modal props                                                                                                                                                 |
| `loadingTimeoutMs`  | number                                              | No       | Timeout in milliseconds before showing error state. Defaults to 15000ms                                                                                                          |
| `errorDisplay`      | ({ onRetry }: { onRetry: () => void }) => ReactNode | No       | Override the default error display                                                                                                                                               |
| `onFileDownload`    | WebViewProps['onFileDownload']                      | No       | Callback for when a file download is requested. Only applies to iOS. See react-native-webview docs for more details                                                              |
| `onKomoEvent`       | (eventData: KomoEvent) => void                      | No       | Callback for when a komo-event is raised in the embedded experience                                                                                                              |
| `onWindowMessage`   | (eventData: any) => void                            | No       | Callback for when a window message is raised in the embedded experience. Note that komo-events are also window messages, so this callback will be called for komo-events as well |
| `extensionDataValues` | Record<string, string \| number \| boolean \| object> | No       | Extension data to be included with user interaction events. Avoid including PII as this data is passed directly to tag manager integrations.                                    |
| `embedAuthUrl`            | string                                              | No       | The URL of the authorization endpoint. If provided, the experience modal will first load the auth URL, then redirect to the embed URL. Typically obtained from CardEmbedMetadata                                            |
| `authPassthroughParams` | URLSearchParams                                   | No       | Passthrough parameters to add to the auth URL as query parameters. For example, an Auth0 session transfer token can be added to the auth URL.                                |
| `webViewProps`      | WebViewProps                                        | No       | Additional props for the react-native-webview component. Only applies if the platform is not web.                                                                                |
| `iframeProps`       | IframeProps                                         | No       | Additional props for the iframe component. Only applies if the platform is web.                                                                                                  |

### KomoCardWidget Props

| Property            | Type                           | Required | Description                                                                                                                                                                      |
| ------------------- | ------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `embedMetaUrl`      | string                         | Yes      | The URL of the embed metadata for the card, copied from the Komo Portal                                                                                                          |
| `appId`             | string                         | No       | An identifier for the embedded Komo content                                                                                                                                      |
| `containerStyle`    | StyleProp<ViewStyle>           | No       | Override the container style                                                                                                                                                     |
| `coverImageStyle`   | StyleProp<ImageStyle>          | No       | Override the cover image style                                                                                                                                                   |
| `buttonStyle`       | StyleProp<ViewStyle>           | No       | Override the button style                                                                                                                                                        |
| `buttonTextStyle`   | StyleProp<TextStyle>           | No       | Override the button text style                                                                                                                                                   |
| `coverLoader`       | ReactNode                      | No       | Override the default loader for the cover                                                                                                                                        |
| `coverErrorDisplay` | ReactNode                      | No       | Override the default error display for the cover                                                                                                                                 |
| `hideCoverButton`   | boolean                        | No       | Whether to hide the cover button. Defaults to false                                                                                                                              |
| `modalHeader`       | ReactNode                      | No       | Override the default modal header                                                                                                                                                |
| `onError`           | (e: any) => void               | No       | Callback for when an error occurs during querying the embed metadata endpoint                                                                                                    |
| `onModalClose`      | () => void                     | No       | Callback for when the modal is closed                                                                                                                                            |
| `onModalOpen`       | () => void                     | No       | Callback for when the modal is opened                                                                                                                                            |
| `shareClickUrl`     | string                         | No       | Override the url that redirects a user when clicking on a share link                                                                                                             |
| `formPrefillValues` | Record<string, string>         | No       | Prefill values for the form within the experience                                                                                                                                |
| `onFileDownload`    | WebViewProps['onFileDownload'] | No       | Callback for when a file download is requested. Only applies to iOS. See react-native-webview docs for more details                                                              |
| `onKomoEvent`       | (eventData: KomoEvent) => void | No       | Callback for when a komo-event is raised in the embedded experience                                                                                                              |
| `onWindowMessage`   | (eventData: any) => void       | No       | Callback for when a window message is raised in the embedded experience. Note that komo-events are also window messages, so this callback will be called for komo-events as well |
| `extensionDataValues` | Record<string, string \| number \| boolean \| object> | No       | Extension data to be included with user interaction events. Avoid including PII as this data is passed directly to tag manager integrations.                                    |
| `authPassthroughParams` | URLSearchParams              | No       | Passthrough parameters to add to the auth URL as query parameters. For example, an Auth0 session transfer token can be added to the auth URL.                                |
| `loadingTimeoutMs`  | number                        | No       | Timeout in milliseconds before showing error state in the modal. Defaults to 15000ms                                                                                                          |
| `modalErrorDisplay` | ({ onRetry }: { onRetry: () => void }) => ReactNode | No       | Override the default error display for the modal                                                                                                                                 |
| `webViewProps`      | WebViewProps                   | No       | Additional props for the react-native-webview component. Only applies if the platform is not web.                                                                                |
| `iframeProps`       | IframeProps                    | No       | Additional props for the iframe component. Only applies if the platform is web.                                                                                                  |

## Other models

### KomoEvent

| Property    | Type   | Description                             |
| ----------- | ------ | --------------------------------------- |
| `eventName` | string | The name of the Komo event              |
| `eventData` | any    | The data associated with the Komo event |
| `extensionData` | Record<string, string \| number \| boolean \| object> | The extension data raised along with the event |

