# Handle incoming calls

In the previous section you added the ability to initiate a call. This section describes how to get notified of and handle incoming calls.

If you have not yet initiated a call, follow the steps in [Make an audio call](/docs/in-app-calling/getting-started/javascript/make-call).

## Listen for incoming calls

1. In the `call-container` of `index.html`, add the following HTML:

```html
<button id="answer" style="display: none">Answer</button>
<button id="hangup" style="display: none">Hang up</button>
```
2. Inside the `SinchClientWrapper` `#sinchClientListener` `onClientStarted` callback, add a listener for incoming calls:

```javascript
class SinchClientWrapper {
  // ...
  #sinchClientListener() {
    return {
      // ...
      onClientStarted: (sinchClient) => {
        console.log("Sinch - Start client succeded");
        const { callClient } = sinchClient;
        callClient.addListener({
          onIncomingCall: (client, call) => {
            this.ui.onIncomingCall(call);
            this.#callListeners(call);
          },
        });
      },
    };
  }
}
```
3. Inside the `UI` class, add functions to handle incoming calls and show/hide **Answer** and **Hang Up** buttons:

```javascript
class UI {
  // ...
  onIncomingCall(call) {
    console.log("Incoming call", call);
    this.audio.srcObject = call.incomingStream;
    this.onAnswer = this.#handleCall("answer", call, this.onAnswer);
    this.onHangup = this.#handleCall("hangup", call, this.onHangup);
  }

  onCallEstablished(call) {
    console.log("Call established", call);
    this.#hideElement("answer");
    this.#showElement("hangup");
  }

  onCallEnded(call) {
    console.log("Call ended", call);
    this.#hideElement("answer");
    this.#hideElement("hangup");
  }

  #handleCall(id, call, oldOnClickFunction) {
    const element = document.getElementById(id);
    element.removeEventListener("click", oldOnClickFunction);
    element.style = "display: block";
    const onClickFunction = () => call[id]();
    element.addEventListener("click", onClickFunction);
    return onClickFunction;
  }
  // ...
}
```
4. If you followed all the steps, the files should look like this:
`index.html`

```html
<html>
  <head>
    <script src="https://cdn.sinch.com/latest/sinch-rtc-min.js"></script>
  </head>
  <body>
    <div id="login-container">
      <input id="userid" placeholder="Enter user id" type="text" />
      <button id="login">Login</button>
    </div>
    <div id="call-container" style="display: none">
      <input id="callee" placeholder="Enter callee" type="text" />
      <button id="call">Call</button>
      <button id="answer" style="display: none">Answer</button>
      <button id="hangup" style="display: none">Hang up</button>
    </div>
    <script type="module" src="index.js"></script>
  </body>
</html>
```
`index.js`

```javascript
const APP_KEY = "enter-application-key";
const APP_SECRET = "enter-application-secret";
const ENVIRONMENT_HOST = "ocra.api.sinch.com";

class SinchClientWrapper {
  constructor(userId, ui) {
    this.userId = userId;
    this.ui = ui;

    const sinchClient = Sinch.getSinchClientBuilder()
      .applicationKey(APP_KEY)
      .userId(userId)
      .environmentHost(ENVIRONMENT_HOST)
      .build();

    sinchClient.addListener(this.#sinchClientListener());
    sinchClient.setSupportManagedPush();
    sinchClient.start();

    this.sinchClient = sinchClient;
  }

  async makeCall(callee) {
    const call = await this.sinchClient.callClient.callUser(callee);
    this.#callListeners(call);
    return call;
  }

  #callListeners(currentCall) {
    currentCall.addListener({
      onCallProgressing: (call) => {
        this.ui.onCallProgressing(call);
      },
      onCallEstablished: (call) => {
        this.ui.onCallEstablished(call);
      },
      onCallEnded: (call) => {
        this.ui.onCallEnded(call);
      },
    });
  }

  #sinchClientListener() {
    return {
      onClientStarted: (sinchClient) => {
        console.log("Sinch - Start client succeded");
        const { callClient } = sinchClient;
        callClient.addListener({
          onIncomingCall: (client, call) => {
            this.ui.onIncomingCall(call);
            this.#callListeners(call);
          },
        });
      },

      onClientFailed: (sinchClient, error) => {
        console.log("Sinch - Start client failed");
        console.error(error);
      },

      /**
       * The recommended way to implement this authentication scheme
       * is that the Application Secret should be kept securely on your
       * server-side backend, the signed token should be created and
       * signed on your server, then passed via a secure channel to
       * the application instance and Sinch client running on a device.
       */
      onCredentialsRequired: (sinchClient, clientRegistration) => {
        new JWT(APP_KEY, APP_SECRET, this.userId)
          .toJwt()
          .then(clientRegistration.register)
          .catch((error) => {
            clientRegistration.registerFailed();
            console.error(error);
          });
      },
    };
  }
}

class UI {
  constructor() {
    this.#handleLogin();
    this.audio = new Audio();
    this.audio.autoplay = true;
    console.log("UI started");
  }

  onIncomingCall(call) {
    console.log("Incoming call", call);
    this.audio.srcObject = call.incomingStream;
    this.onAnswer = this.#handleCall("answer", call, this.onAnswer);
    this.onHangup = this.#handleCall("hangup", call, this.onHangup);
  }

  onCallProgressing(call) {
    console.log("Call progressing", call);
  }

  onCallEstablished(call) {
    console.log("Call established", call);
    this.#hideElement("answer");
    this.#showElement("hangup");
  }

  onCallEnded(call) {
    console.log("Call ended", call);
    this.#hideElement("answer");
    this.#hideElement("hangup");
  }

  #handleCall(id, call, oldOnClickFunction) {
    const element = document.getElementById(id);
    element.removeEventListener("click", oldOnClickFunction);
    element.style = "display: block";
    const onClickFunction = () => call[id]();
    element.addEventListener("click", onClickFunction);
    return onClickFunction;
  }

  #hideElement(id) {
    const element = document.getElementById(id);
    element.style = "display: none";
  }

  #showElement(id) {
    const element = document.getElementById(id);
    element.style = "display: block";
  }

  #handleLogin() {
    document.getElementById("login").addEventListener("click", () => {
      const userId = document.getElementById("userid").value;
      this.#hideElement("login-container");
      this.sinchClientWrapper = new SinchClientWrapper(userId, this);
      this.#handleMakeCallClick();
      this.#showElement("call-container");
    });
  }

  #handleMakeCallClick() {
    document.getElementById("call").addEventListener("click", async () => {
      const callee = document.getElementById("callee").value;
      const call = await this.sinchClientWrapper.makeCall(callee);
      this.audio.srcObject = call.incomingStream;
      this.onHangup = this.#handleCall("hangup", call, this.onHangup);
    });
  }
}

new UI();
```
5. Open two tabs and log in as two different users. Enter the second user ID as the callee in the first tab and press **Call**. Click **Answer** and you should see `Call established` in the console and hear audio confirmation. Press **Hang Up** to end or decline a call.


## Next steps

Now that you've built a simple app to make and receive calls, learn more about the [JavaScript SDK](https://developers.sinch.com/docs/in-app-calling/js-cloud/).