# Operator Integration Instructions

{% hint style="info" %}
Please note that the code snippets displayed in this article are intended to be used for assessment and testing purposes only. Prior to going liv&#x65;**,** please reach out to <integrations@imgarena.com>.
{% endhint %}

## Integration Library

The Front Row Seat integration library is distributed with an ES module build and a UMD build, the examples below use the UMD syntax for clarity and to show the simplest implementation. When using via an `import` statement the ES module build be used.

The ES module build is intended for use in modern browsers\* which support Javascript syntax and features released after 2016. These features allow web browsers to deliver better performance with smaller Javascript bundle sizes, causing users to experience faster page loads and response rates from the UI. This is the recommended approach due to its performance benefits.

The UMD build is intended for use in legacy browsers that do not support modern Javascript features referenced above. The build contains [polyfills](https://en.wikipedia.org/wiki/Polyfill_\(programming\)) which allow these legacy browsers to make use of the Front Row Seat integration library, but this comes at a cost of a larger bundle size which will result in slower initial page load times.

\* Most popular "modern web browsers" are: Chrome, Safari, Microsoft Edge and Firefox. All of which are available on both mobile and desktop.

The package is distributed using npm, where both ES module and UMD builds are available: <https://www.npmjs.com/package/@img-arena/front-row-seat>

The UMD build is available on unpkg: <https://unpkg.com/@img-arena/front-row-seat/dist/index.umd.js>

For more information on how to use unpkg please see their docs: <https://unpkg.com/>

## Usage

All that is needed to integrate an IMG Arena Event Centre into your website is:

1. Add a containing HTML DOM element for where the Event Centre should appear
2. Include the integration library script
3. Initialise the integration library

The code below shows an example of integrating a Golf Event Centre with placeholder values.

```markup
<!-- define where the Event Centre should appear in the page -->
<div id="img-arena-event-centre"></div>

<!-- load the integration library -->
<script src="https://unpkg.com/@img-arena/front-row-seat/dist/index.umd.js"></script>
<!-- initialise your Event Centre -->
<script type="text/javascript">
  // frontRowSeat is exposed on the window scope by loading the integration library
  const { MessageTopics } = frontRowSeat.eventCentreUtils;
  const eventCentreInstance = frontRowSeat.eventCentre({
    operator: '[OPERATOR-NAME]',
    sport: 'golf',
    version: 'latest',
    eventId: '275',
    targetModule: 'full',
    language: 'en',
    targetElementSelector: '#img-arena-event-centre'
  });

  // subscribe to selection updates from the host sportsbook
  eventCentreInstance.on(MessageTopics.SELECTION_UPDATE, messageData => {
    // operate on received messageData
  });
  
  // send context update to the event-centre
  const data = {
          view: "group-detail-hole",
          roundNo: "1",
          groupNo: "123",
          holeNo: "1"
  }
  eventCentreInstance.emit(MessageTopics.CONTEXT_UPDATE, data);
</script>
```

### Target Element

There may be occasions where it is preferable to pass in an element node instead of a string for the target destination of the event centre.

The `targetElementSelector` property can be either a string for the selection of a DOM element, or an element node itself.

```javascript
const targetElement = document.querySelector('#img-arena-event-centre');
const eventCentreInstance = frontRowSeat.eventCentre({
  operator: "[OPERATOR-NAME]",
  sport: "golf",
  version: "latest",
  eventId: "493",
  language: "en",
  targetModule: "full",
  targetElementSelector: targetElement
});
```

### Initialisation

To handle the synchronising of Event Centre with your site there are two methods exposed on the return value from the `eventCentre` initialiser: `on` and `emit`. Both these methods follow the pub/sub pattern for asynchronous message exchange. The `on` method is for receiving messages from the Event Centre, whereas the `emit` method is for sending messages to the Event Centre.

#### Modularisation for Golf Stokeplay:

The Event centre supports being initialised in seven different modular configurations, Provide the required module to the library:Initialisation value

| Module name         | Description                                      | Notes                                                               |
| ------------------- | ------------------------------------------------ | ------------------------------------------------------------------- |
| `full`              | All Event Centre                                 |                                                                     |
| `leaderboard`       | Leaderboard Only (no global navigation)          |                                                                     |
| `leaderboarddetail` | Leaderboard & Team/Player (no global navigation) |                                                                     |
| `course`            | Course & Hole Only (no global navigation)        |                                                                     |
| `hole`              | Hole Only (No navigation back to Course)         | holeNo must be passed in initialContext, see below for more details |
| `groupdetail`       | Groups List & Group Detail                       |                                                                     |
| `groups`            | Group Only                                       |                                                                     |
| `minileaderboard`   | Mini Leaderboard with 7 top players              | No global navigation                                                |

**Modularisation for** **Golf Match Play (covers Ryder Cup)**

| Module name   | Description                                     |
| ------------- | ----------------------------------------------- |
| `full`        | All Event Centre                                |
| `matchlist`   | Match list Only (no navigation to match detail) |
| `matchdetail` | Match detail Only (no navigation to match list) |

To target one of the above pass the initialisation value to the `targetModule` field when initialising the event centre, for example to initialise an Event Centre with only the Leaderboard module:

```javascript
const { EventCentreModules } = frontRowSeat.eventCentreUtils;
const eventCentreInstance = frontRowSeat.eventCentre({
  operator: '[OPERATOR-NAME]',
  sport: 'golf',
  version: 'latest',
  eventId: '275',
  language: 'en',
  targetModule: 'leaderboard',
  targetElementSelector: '#img-arena-event-centre'
});
```

#### Theming

The theme of the event centre can be configured by passing in a value for the `theme` parameter, this is how operators can add their brand colours and typography; the IMG Arena integrations team manage this process.

```javascript
const eventCentreInstance = frontRowSeat.eventCentre({
  operator: "img",
  sport: "golf",
  targetModule: "full",
  eventId: "275",
  version: "latest",
  targetElementSelector: "#img-arena-event-centre",
  language: "en",
  theme: "dark"
});
```

#### Backend Environment

The backend environment used by the event centre can be changed by setting a value to the `env` initialisation parameter. Defining this field is optional, if it is omitted the default value is "prod", see below for each environment's data source.

| Environment | Data Source    |
| ----------- | -------------- |
| prod        | DDE Production |
| sims        | DDE Simulation |

```javascript
const eventCentreInstance = frontRowSeat.eventCentre({
  operator: "bet365",
  sport: "golf",
  targetModule: "full",
  eventId: "251",
  version: "latest",
  targetElementSelector: "#img-arena-event-centre",
  language: "en",
  env: "sims"
});
```

#### Options

Some additional options can be specified in the `options` field.

| Option name            | Description                                                                    | default   | example     |
| ---------------------- | ------------------------------------------------------------------------------ | --------- | ----------- |
| `videoPlaybackEnabled` | Enables viewing broadcasts when they are available                             | false     | true        |
| `userId`               | Used for google analytics tracking                                             | undefined | "123e4567"  |
| `units`                | Used for operators wishing to use metric units, rather than imperial           | undefined | "metric"    |
| `holeNavOnly`          | Used for operators wishing to have only hole nav on `course-live-streams` view | false     | true        |
| `oddsFormat`           | Used to specify odds format ('fractional', 'decimal', 'moneyline')             | undefined | "moneyline" |

## Fractional Odds Example:

```
const eventCentreInstance = frontRowSeat.eventCentre({
  operator: "img",
  sport: "golf",
  targetModule: "full",
  eventId: "251",
  version: "5.x",
  targetElementSelector: "#img-arena-event-centre",
  language: "en",
  options: {
    userId: "unique-not-PII-id",
    videoPlaybackEnabled: true,
    oddsFormat: "fractional",
  },
});
```

Deep Linking

The Event Centre also supports being initialised with a specific UI state. This is achieved by passing in a "Context Update" message object, detailed below, when initialising the Event Centre. These can include specific tournaments, rounds, players etc.

| View                    | Required initial context fields | Optional initial context fields |
| ----------------------- | ------------------------------- | ------------------------------- |
| leaderboard             | view                            |                                 |
| player-detail-hole      | view, teamNo                    | *roundNo*, *holeNo*             |
| player-detail-scorecard | view, teamNo                    | *roundNo*                       |
| player-detail-shots     | view, teamNo                    | *roundNo*                       |
| playoff-detail-hole     | view, groupId                   | *roundNo*, *holeNo°*            |
| playoff-detail-shots    | view, groupId                   | *roundNo*, *holeNo*°            |
| groups                  | view                            |                                 |
| GroupDetail             | view, groupNo, roundNo          | *holeNo*                        |
| group-detail-hole       | view, groupId                   | *roundNo*, *holeNo*             |
| group-detail-scorecard  | view, groupId                   | *roundNo*, *holeNo*             |
| group-detail-shots      | view, groupId                   | *roundNo*, *holeNo*             |
| course                  | view                            |                                 |
| course-live-streams     | view, holeNo                    |                                 |
| course-detail-hole      | view, holeNo                    |                                 |
| course-detail-scorecard | view, holeNo                    | *courseId*                      |
| course-detail-shots     | view, holeNo                    | *courseId*                      |

#### Golf Match Play (covers Ryder Cup) Views

| View                        | Fields                    | Optional Fields |
| --------------------------- | ------------------------- | --------------- |
| match-play-list             | tournament, view          |                 |
| match-play-detail-hole      | tournament, view, matchNo | holeNo          |
| match-play-detail-scorecard | tournament, view, matchNo | holeNo          |
| match-play-detail-shots     | tournament, view, matchNo | holeNo          |
| match-play-streaming        | tournament, view          |                 |
| match-play-streaming-hole   | tournament, view, holeNo  |                 |

**° For playoff views the holeNo field MUST take it's value from the holeOrder field from DDE feeds**

The following are examples of these message objects and their corresponding UI states:

{% tabs %}
{% tab title="Full Event Centre" %}
**Full Event Centre with Event ID 207**

```javascript
const eventCentreInstance = frontRowSeat.eventCentre({
  operator: '[OPERATOR-NAME]',
  sport: 'golf',
  eventId: '275',
  targetModule: 'full',
  version: 'latest',
  language: 'en',
  targetElementSelector: '#img-arena-event-centre',
});
```

{% endtab %}

{% tab title="Group Detail Page" %}
**A Group Detail Page, with Event Id 207, Round Number 1, Group Number 19. Hole Number is optional.**

```javascript
const eventCentreInstance = frontRowSeat.eventCentre({
  operator: '[OPERATOR-NAME]',
  sport: 'golf',
  eventId: '275',
  targetModule: 'full',
  version: 'latest',
  language: 'en',
  targetElementSelector: '#img-arena-event-centre',
  initialContext: {
    view: 'group-detail-hole',
    roundNo: '4',
    groupId: '75737',
    holeNo: '9'
  }
});
```

{% endtab %}

{% tab title="Hole View" %}
**Hole view for Hole 12. Very useful for directing a user to a specific hole which has Par 3 streaming.**

```javascript
const { EventCentreModules } = frontRowSeat.eventCentreUtils;
const eventCentreInstance = frontRowSeat.eventCentre({
  operator: '[OPERATOR-NAME]',
  sport: 'golf',
  eventId: '275',
  targetModule: 'full',
  version: 'latest',
  language: 'en',
  targetElementSelector: '#img-arena-event-centre',
  initialContext: {
    view: 'course-detail-hole',
    holeNo: '12'
  }
  targetElementSelector: '#img-arena-event-centre'
});
```

{% endtab %}
{% endtabs %}

### Subscribing

```javascript
.on(MESSAGE_TOPIC_NAME, (messageData) => {
  // operate on received messageData, see below for returned fields for each topic
})
```

The `on` method is available on the return value from the `eventCentre` initialiser, it is used to subscribe to messages emitted from the Event Centre. The supported message topics are exposed on the `eventCentreUtils` namespace, `eventCentreUtils.MessageTopics`, and are detailed below. The callback receives a single value which is an object containing the respective fields to the message topic subscribed to.

### Emitting

```javascript
// See below the fields to include on object passed for each topic
.emit(MESSAGE_TOPIC_NAME, messageData)
```

{% embed url="<https://codepen.io/Waqas-Jadoon/pen/MYgGabG>" %}

In console, type: `ec.emit('context-update', { view: 'groups'})`

The `emit` method is available on the return value from the `eventCentre` initialiser, it is used to send message to the Event Centre. Only supported message topics will be passed to the Event Centre.

**Emitting context updates to synchronize the event centre**

The event centre emits context updates whenever the webpage navigates to a new route. These context updates can be used to keep track of what users are doing in the event centre. For example, these events can be used to display appropriate markets when a user navigates to a certain player, hole or group.

The other scenario is that a user is navigating on your webpage, and you would like to synchronize the event centre to display similar contextual data. In this case it is possible to emit context updates to the event centre. These updates will allow you to control what page/view the event centre is displaying.

*Note: These updates will not re-create the event centre therefore it is not possible to change things like the tournamentId or the theme.*

The list of possible views and their required fields that can passed into the CONTEXT\_UPDATE topic is covered above in the Golf Views section.

*Note: The values that are passed for `initialContext` when creating the `eventCentreInstance` can also be used as data for context updates.*

See below a few examples:

**Navigate to groups list**

```
eventCentreInstance.emit(
  frontRowSeat.eventCentreUtils.MessageTopics.CONTEXT_UPDATE,
  { view: "groups" }
);
```

**Navigate to a player**

```
eventCentreInstance.emit(
  frontRowSeat.eventCentreUtils.MessageTopics.CONTEXT_UPDATE,
  {
    view: "player-detail-hole",
    teamNo: "4", // replace with desired teamNo
  }
);
```

**Navigate to a group's shots view**

```
eventCentreInstance.emit(
  frontRowSeat.eventCentreUtils.MessageTopics.CONTEXT_UPDATE,
  {
    view: "group-detail-shots",
    groupId: "464838", // replace with desired groupId
  }
);
```

### Languages

Please see the [Language Translations Available](https://app.gitbook.com/@img-arena/s/golf-operator-integration-instructions/~/drafts/-MfI8I8m2aIW0qcWJMH1/languages-available) page to the left.

### Message Topics

All the tables below detail the data fields present in the message data objects that are **sent and received** for each message topic.

### Handshake Failed `MessageTopics.HANDSHAKE_FAILED`

Dedicated topic to signify the handshake between Event Centre and your site failed to complete. This topic is emitted by the integration library, it **should only be subscribed to, not emitted**.

| Field     |  Type  | Description                         | Required |
| --------- | :----: | ----------------------------------- | :------: |
| timestamp | number | unix timestamp from time of failure |     ✅    |

### Context Update `MessageTopics.CONTEXT_UPDATE`

Topic for covering general UI state updates, for example navigation changes or the user selecting a player in the UI.

| Field        |       Type       | Description                                       | Required |
| ------------ | :--------------: | ------------------------------------------------- | :------: |
| view         |      string      | The name of the active view                       |     ✅    |
| tournamentId | number or string | Identifier for the tournament                     |     ✅    |
| roundNo      | number or string | The round the user is currently viewing data from |     -    |
| holeNo       | number or string | The hole the user is currently viewing data from  |     -    |
| playerNo     | number or string | The player's ID                                   |     -    |
| groupNo      | number or string | The group's ID                                    |     -    |

**From iframe to parent message. List of possible events:**

| View         | Component   | Action        | Sending parameters                                        |
| ------------ | ----------- | ------------- | --------------------------------------------------------- |
| Leaderboard  | Leaderboard | onLoad        | <p>view</p><p>tournamentId</p><p>roundNo</p>              |
| Group List   | GroupList   | onLoad        | view                                                      |
|              |             | onRoundChange | tournamentId                                              |
|              |             |               | roundNo                                                   |
| Course       | Course      | onLoad        | <p>view</p><p>tournamentId</p><p>roundNo</p>              |
|              |             | onRoundChange | <p>view</p><p>tournamentId</p><p>roundNo</p><p>holeNo</p> |
| All Bets     | AllBets     | onLoad        | <p>view</p><p>tournamentId</p><p>roundNo</p>              |
| Group Detail | GroupDetail | onLoad        | view                                                      |
|              |             | onTeamChange  | tournamentId                                              |
|              |             | onHoleChange  | roundNo                                                   |
|              |             |               | holeNo                                                    |
|              |             |               | groupNo                                                   |
|              |             |               | playerNo                                                  |
| Hole         | Hole        | onLoad        | view                                                      |
|              |             | onGroupChange | tournamentId                                              |
|              |             | onTeamChange  | roundNo                                                   |
|              |             | onHoleChange  | <p>holeNo</p><p>groupNo</p><p>playerNo</p>                |
| Player       | Team        | onLoad        | view                                                      |
|              |             | onRoundChange | tournamentId                                              |
|              |             | onHoleChange  | <p>roundNo</p><p>holeNo</p><p>playerNo</p>                |

### Selection Updates `MessageTopics.SELECTION_UPDATE`

Dedicated topic for handling user selection updates. The `selected` field within the message data handles both selecting and deselecting updates.

| Field    |       Type       | Description                                            | Required |
| -------- | :--------------: | ------------------------------------------------------ | :------: |
| marketId | number or string | supplied by Mustard                                    |     ✅    |
| betId    | number or string | supplied by Mustard                                    |     ✅    |
| selected |      boolean     | whether or not the UI state should display as selected |     ✅    |

On all views client app uses the same component **Bet**, so we need to send message in the one place. Message is sent after selecting or unselecting bet. Sending payload:

```javascript
{
 betId,
 marketId,
 selected
}
```

**`MessageTopics.VIDEO_PLAYBACK_AUTH_REQUEST`**

Dedicated topic when the user has requested video playback. You must listen for this event and respond to using `VIDEO_PLAYBACK_AUTH_RESPONSE` as described below.

**`MessageTopics.VIDEO_PLAYBACK_AUTH_RESPONSE`**

Topic to provide authorisation for video playback.

| Field      |  Type  | Description                               | Required |
| ---------- | :----: | ----------------------------------------- | :------: |
| operatorId | string | as supplied by ALC                        |     ✅    |
| auth       | string | generated by your backend                 |     ✅    |
| timestamp  | number | timestamp in milliseconds since epoch     |     ✅    |
| error      |  Error | error message should auth not be possible |     -    |
