# Start a Basic Chat

### Setting up the Mitter.io SDK

Before you consume any Mitter.io APIs, you need to setup the Mitter object. In your `index.js` file, add the following lines:

{% code title="index.js" %}

```javascript
import { Mitter } from '@mitter-io/web'

const mitter = Mitter.forWeb({
    applicationId: 'fb70ff76-ea33-4bb0-bd59-90853f103202', /* provide your application id here */
    mitterApiBaseUrl: '<mitter-api-url>', /* look below for the values */
    weaverUrl: '<distributor-url>' /* look below for values */
})

```

{% endcode %}

For the `<mitter-api-url>`, use the following value:

* If you're using the cloud hosted solution, you can omit the `mitterApiBaseUrl` key in the config or explicitly set it to `https://api.mitter.io`
* If you're running it as a docker container set it to `http://localhost:<port>` where the port is port forwarded by docker for `11902`. To find out which port it is, run the following command `docker port $(docker ps --filter expose=11901-11903/tcp --format "")`

For the `<distributor-url>`, use the following value:

* If you're using the cloud hosted solution, you can omit the `weaverUrl` key in the config or explicitly set it to `https://weaver.mitter.io`
* If you're running it as a docker container set it to `http://localhost:<port>` where the port is port forwarded by docker for `11903`. To find out which port it is, run the following command `docker port $(docker ps --filter expose=11901-11903/tcp --format "")`

Your application ID can be fetched from the Mitter.io Dashboard. Once you have this set up, you now need to pass in the user authorization. You can pick the correct user authorization for the user authorization map we had created earlier.

{% code title="index.js" %}

```javascript
const userAuth = {
    '@john': ' ... johns user token ...',
    '@amy': ' ... amys user token ...',
    '@candice': ' ... candices user token ... '
}

mitter.setUserAuthorization(userAuth[loggedUser])

```

{% endcode %}

We will also need to pass the `mitter` object we created to the `App` component so that it can fetch the user data and render it. At the end of this, your `index.js` file should look something like:

{% code title="index.js" %}

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { Mitter } from '@mitter-io/web'

const regex = /^\/user\/(@[a-zA-Z0-9-]+)/
const loggedUser = (new URL(document.location.href).pathname.match(regex)[1])

const userAuth = {
    '@john': ' ... johns user token ...',
    '@amy': ' ... amys user token ...',
    '@candice': ' ... candices user token ... '
}

const mitter = Mitter.forWeb({
    applicationId: 'fb70ff76-ea33-4bb0-bd59-90853f103202', /* provide your application id here */
    mitterApiBaseUrl: '<mitter-api-url>', /* look above for the values */
    weaverUrl: '<distributor-url>' /* look above for values */
})

mitter.setUserAuthorization(userAuth[loggedUser])

ReactDOM.render(
    <App
        mitter={mitter}
        loggedUser={loggedUser}
    />,
    document.getElementById('root')
);

registerServiceWorker();

```

{% endcode %}

### Getting the list of participated channels

We now want to get the list of channels for a user and then render them in our app. To do so, we'll have to make a couple of changes in our application. First, we'll have to move the channel messages object that we created to a variable that can be changed and propagated to the `ChannelComponent`. We'll move it to the state for the `App` component. Also, we'll pass on the Mitter object to the the `ChannelComponent` as we will need to send messages later on.

{% code title="App.js" %}

```javascript
class App extends Component {
    constructor() {
        super();

        this.state = {
            channelMessages: {}
        }
    }

     render() {
        return (
            <div className='App'>
                <h2 className='application-title'>
                  My Chat App

                  <div className='user-label'>
                      Welcome, <strong>{this.props.loggedUser}</strong>
                  </div>
              </h2>

              <ChannelComponent
                  mitter={this.props.mitter}
                  channelMessages={this.state.channelMessages}
                  selfUserId={this.props.loggedUser}
              />
          </div>
        );
    }
}

```

{% endcode %}

Do note that we have even modified the `render()` function to now pass the `channelMessages` prop from `App` via a state rather than the hard-coded variable. If you reload your application, you'll see a blank page. In your `App` component, we will now fetch a list of channels for the user. We will do this in the `componentDidMount()` method:

> **NOTE** Do note that for a messaging-based application, the architecture of this application is not a recommended one. Ideally, you should be using a state management system like `redux` or `flux`, but for the sake of simplicity we are not using this in the application so that we can focus on introducing Mitter.io concepts. There is also a package `mitter-redux` currently in alpha that builds atop redux and handles all intricacies of state management which should be used in production apps.

{% code title="App.js" %}

```javascript
class App extends Component {
    construtor() {
        super()

        this.state = {
            channelMessages: {}
        }

        this.setChannels = this.setChannels.bind(this)
    }

    setChannels(participatedChannels) {
        const activeChannels = {}

        Objects.forEach(participatedChannels, (participatedChannel) => {
            activeChannels[participatedChannel] = []

            this.setState((prevState) => {
                return Object.assign({}, prevState, {
                    activeChannels
                })
            })
        })
    }

    componentDidMount() {
        const mitter = this.props.mitter

        mitter.clients().channels().participatedChannels()
            .then(participatedChannels => this.setChannels(participatedChannels))
    }
}

```

{% endcode %}

In the code above, we are transforming a response we get from Mitter.io, of the form:

```
[
    {
        participantId: '...',
        channel: {
            channelId: 'channel-a'
        },
        participationStatus: 'Active'
    },
    {
        partipantId: '...',
        channel: {
            channelId: 'channel-b'
        },
        participationStatus: 'Active'
    }
]

```

to something of the form:

```
{
    'channel-a': [],
    'channel-b': []
}

```

Which is basically a map of channel IDs to an empty array of messages. We will be adding messages to this object as we get them from the Mitter.io pipeline.

Reload the page and you should see the channels listed for the current selected user.

![The chat window with the user's channels loaded from mitter.io](https://94728489-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LLZR00Qt6hZ5Vke2l2g%2F-LNEUrPfZZmO0w4u2Z7i%2F-LNEFHp7MfSsIoyGRH8e%2Fgetting-started-app-004.png?alt=media\&token=b66fed2a-4201-4f7f-9330-aa6b50a9abf0)

Change the url from `http://localhost:3000/user/@john` to `http://localhost:3000/user/@candice` and you should now see only one channel (`#roadtrip`) as opposed to two channels earlier.

![We are now loading the channels for each user from Mitter.io](https://94728489-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LLZR00Qt6hZ5Vke2l2g%2F-LNG8gQSc2I5rQOqy9cb%2F-LNGBSdd_7-vxkgDfGMw%2Fmitter-gs-vid-001.gif?alt=media\&token=532694cb-dcde-402a-9d83-caef71ad7a14)

### Listening to messages and populating them in a channel

Now, we will move on to setup the next phase of the project, where we listen to incoming events (in this case specifically, messages) and render them in our application. To listen to pipeline payloads (that's what Mitter calls events sent on different front-end mechanisms), you need to subscribe to them. So, add the following lines in the `componentDidMount()` function (also pay attention to the additional import `isNewMessagePayload` at the top of the file):

{% code title="App.js" %}

```javascript
import { Mitter, isNewMessagePayload } from '@mitter-io/core'

// your other code and imports

class App extends  React.Component {
    constructor() {
        // Previous code in constructor
        this.newMessage = this.newMessage.bind(this)
    }
    // other functions in the App

    newMessage(messagePayload) {
        // currently does nothing
    }

    comoponentDidMount() {
        mitter.subscribeToPayload(payload => {
            if (isNewMessagePayload(payload)) {
                this.newMessage(messagePayload)
            }
        })
    }
    
    // ... rest of the file
    
```

{% endcode %}

Adding this new message to our state is quite straightforward now. This is how the `newMessage` method should now look:

{% code title="App.js" %}

```javascript
    newMessage(messagePayload) {
        this.setState((prevState) => {
            const channelId = messagePayload.channelId.identifier // [1]

            if (
                prevState.channelMessages[channelId]
                    .find(x => x.messageId === messagePayload.message.messageId)
                        !== undefined
            ) {                                                   // [2]
                return prevState
            }


            return Object.assign({}, prevState, {                 // [3]
                channelMessages: Object.assign({}, prevState.channelMessages, {
                    [messagePayload.channelId.identifier]:
                        prevState.channelMessages[messagePayload.channelId.identifier]
                                 .concat(messagePayload.message)
                })
            })
        })
    }
    
```

{% endcode %}

A quick description of what's going on here (follow the numbered labels in the code):

1. We extract the channel ID from the payload. This is the channel that the message was sent in.
2. We are checking if the message already exists for the same ID in our `prevState`. While you may not encounter this frequently, Mitter.io might occasionally send duplicate messages on a payload. This usually happens when Mitter.io cannot confidently determine that a message delivery has occurred, but it might still have propagated. Also, the current implementation performs an entire iteration of the messages in a channel, which might not be very efficient. As an exercise to the reader, modify this to a store backed by a hashing algorithm.
3. We now `concat` this message on to the list of messages for the given channel.

> **NOTE** There are certain caveats with this approach, notably that you might get receive payloads for messages for which you do not have a channels object yet. This could happen if a user was added to a channel after the participated channels were fetched. While such a situation will not arise in our setup, production apps need to always be resilient to partial state and must reconstruct the state in whatever form they can from the available events.

This is pretty much it! However, these changes will not result in you seeing anything, because no messages are being sent. In the next section lets wire it up to send messages.

### Sending messages

To send messages, we'll have to wire up the `Send` button in our `ChannelComponent`. We'll add a few methods, namely `sendMessage()` and `updateTypedMessage` to `ChannelComponent`. Also, we'll set up the handlers on the input fields as we usually do for any React App. The input components will now look like this:

{% code title="ChannelComponent.js" %}

```javascript
<div className='message-input-box'>
    <input
      ref={(input) => { this.messageInput = input }}
      onChange={this.updateTypedMessage}
      value={this.state.typedMessage}
      className='message-input'
      type='text'
    />

    &nbsp;

    <input onClick={this.sendMessage} className='send-message'
          type='submit' value='Send' />
</div>

```

{% endcode %}

We'll modify our state to accommodate changes for the input field and also make the appropriate function binds so that we can use them as callbacks:

{% code title="ChannelComponent.js" %}

```javascript
constructor() {
    this.state = {
        activeChannel: null,
        typedMessage: ''
    }

    this.updateTypedMessage = this.updateTypedMessage.bind(this)
    this.sendMessage = this.sendMessage.bind(this)
}

```

{% endcode %}

And the functions to now send the messages:

{% code title="ChannelComponent.js" %}

```javascript
    sendMessage() {
        const mitter = this.props.mitter

        this.setState((prevState) => Object.assign({}, prevState, { // [1]
            typedMessage: ''
        }))

        this.messageInput.focus()                                   // [2]

        mitter.clients().messages()                                 // [3]
            .sendMessage(this.state.activeChannel, {
                senderId: mitter.me(),
                textPayload: this.state.typedMessage,
                timelineEvents: [
                    {
                        type: "mitter.mtet.SentTime",
                        eventTimeMs: new Date().getTime(),
                        subject: mitter.me()
                    }
                ]
            })
    }

    updateTypedMessage(evt) {
        const value = evt.target.value
        this.setState((prevState) => {
            return Object.assign({}, prevState, {
                typedMessage: value
            })
        })
    }
    
```

{% endcode %}

The `updateTypedMessage` is your standard message to store the state of an input field, and have a way to control it. Let us look into what we are doing in the `sendMessage` function. Pay attention to the numbered labels in the code:

1. &#x20;When we send a message, we would like to clear the input field so that the user can type their next message
2. We would also like to re-focus the `messageInput` field (this property is set in the ref callback of the `<input>` field)
3. We now use the message client to send a message. This message contains the basic minimum fields required to send a message. While the `senderId`, `textPayload` have been discussed before, `timelineEvents` are something new. Let's discuss them for a while.

A `TimelineEvent` is used to record events that occur for a given entity. Mitter.io supports timeline events for `Channels` and `Messages`. For example, this is what is used to store and transmit read/delivered receipts. You are free to use any type of timeline events and interpret them as you wish, with the exception that they may not start with `mitter.` or `io.mitter.`. Also, any message that is sent must have a `mitter.mtet.SentTime` timeline event attached to it. The server then attaches another timeline event recording the server receive time, synchronized to the servers clock.

Once you've done this, open up two browser windows and go to `http://localhost:3000/user/@john` and `http://localhost:3000/user/@candice`. Try exchanging a few messages between them and you'll notice that you have a working chat app!

![A basic working chat app with multiple users](https://94728489-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LLZR00Qt6hZ5Vke2l2g%2F-LNG8gQSc2I5rQOqy9cb%2F-LNG8n_xC3qu3QjkTDdw%2Fbasic-chat-2018-09-25_11.gif?alt=media\&token=7f2e092c-5a32-4eb9-a890-899a1bbd800d)

You might be wondering how your own messages got rendered. This is because every message to a channel is sent out to all participants of the channel and hence every user always gets an echo back of their own message. Do note that on slower networks there will be a significant delay in this occurring, so you might want to populate your message state when the user hits `Send` and then let the network call take its time.

Let's now add a slightly more complex behavior in our application. In the next section, we will explore ACLs and see how we can use them to implement selective deliveries.\ <br>
