# Expivi IFrame API specification

## Description

The Expivi iFrame API is a wrapper around the `window.postMessage(target: Window)` functionality,
as such it allows us to send message from an Expivi iFrame to the host page.
It also allows the host page to send message back to the Expivi iFrame.

This way we can achieve a tightly-knit application while still keeping a separation of concerns.

## Initialization

To initialize the Expivi iFrame Api you will need to instantiate it. This can be done as follows:

```js
const frameId = 'expivi-iframe-id';
const targetFrame = document.getElementById(frameId);
window.xpv.iFrameService = new ExpiviIFrameService(targetFrame.contentWindow);
```

This will ensure that your page begins listening to the Expivi iFrame.
Then, once the Expivi iFrame has initialized itself on our side, we will
fire off the "ready" event. You can listen to this via a promise, using the following code:

```js
window.xpv.iFrameService.isReady().then(() => {
    // the Expivi iFrame is now ready to receive messages.
});
```

## Interactions

### iFrame interactions using the querystring

Loading a certain "configurator state" can be done through the following
querystring parameters.

```js
// provided by Expivi
`${iframe-source}?preset-id=${some-preset-id}`

 // saved product id (made via saving a configuration)
`${iframe-source}?cpi=${some-configured-product-index}`
```
When both, a preset-id and a cpi have been provided, the cpi takes precedence.

Expivi allows you to hide certain agreed upon parts of the page. This works by
specifying the following querystring parameter:

```js
`${iframe-source}?hide-element={some-element-id}&hide-element={some-other-element-id}&hide-element=...`
```

Any element that has the `data-hideable-id` attribute can be hidden by using the attribute value. e.g.

```html
<div id="some-div-that-isnt-hideable">You can't hide me</div>
<div data-hideable-id="42">But you can hide me!</div>
<span data-hideable-id="20">And you can also hide me.</span>
```

### User logged in or out

Expivi can change its visuals when your user logs in and out to your system, to facilitate this
you will have to send an event whenever the user is logged in or out. This event can be caught be
Expivi once the ready event above has been fired by the iframe.

```js
window.xpv.iFrameService.userHasLoggedIn();
window.xpv.iFrameService.userHasLoggedOut();
```

>**Note**: The default user state for expivi is the logged out state. When a user is logged in
you should start of by calling the `userHasLoggedIn()` command. We do not remember state between
reloads, in order to stay compliant with privacy laws and browser specifics.

### Add To Cart

Expivi can send an event when our **'add to cart'** button has been pressed.
This event can be captured with a callback, that can be set as follows:

```js
const someHandlerFunction = (xpvEvent) => { /* does some work */ };
window.xpv.iFrameService.setEventListener('v1.add-to-cart', someHandlerFunction);
```

The xpvEvent in this case is the following object:

```js
{
    cpi: number;
    products: [
        {
            sku: string,
            thumbnail: string, // a base64 encoded image
        },
        // if you use a multi product viewer,
        // this array will contain more than one element
    ];
}
```

### Save Current Configured Product

Expivi can save a user their current configuration for later usage. This
action fires an event off to the parent frame, which can then handle this situation.

```js
const someHandlerFunction = (xpvEvent) => { /* does some work */ };
window.xpv.iFrameService.setEventListener('v1.save-current-config', someHandlerFunction);
```

The xpvEvent in this case looks like the following object:

```js
{
    cpi: number;
    thumbnail: string; // a base64 encoded image
}
```

### Before Image Upload

Expivi can send an event before opening an image upload. This event can be used to create a
modal to show the terms of service of uploaded images. The handler should return true or false
depending on if the user should be allowed to start uploading. You can capture this event like so:

```js
{
    const someHandlerFunction = () => allowedToUpload; // allowed to upload is a boolean
    window.xpv.iFrameService.setEventListener('v1.before-image-upload', someHandlerFunction);
}
```
