# Adding Realtime capabilities using socket

{% embed url="<https://www.youtube.com/watch?v=oIQI-KTO6mw>" %}
Add Realtime Capabilities
{% endembed %}

## Setting Up UI

1. Create a new UI file named `rt-message` within the `main-features` folder and set its path to `/`.
2. Add three buttons: Send Message, Leave Room, and Join Room.
3. Import `Space` and `Input` components, and wrap the buttons and input field within the `Space` component.
4. Add an input field and set the width of the input field to 300 for better usability.
5. Create a `div` with a height of 100 to display the last message.

### State Management

1. Initialize two states to manage the last message and the input value.
2. Incorporate these states within the UI, ensuring their proper rendering and functionality.

> Refer the code below:

{% code title="rt-message.tsx" %}

```tsx
import React, { useState } from "react"
import { Button, Input, Space } from "antd"

export default function Component(props: any) {
    const [msg, setMsg] = React.useState("")
    const [input, setInput] = React.useState("")

    return (
        <div>
            <div style={{ height: 100 }}>
                <p>Last Message:</p>
                <h1>{msg}</h1>
            </div>

            <Space>
                <Input
                    value={input}
                    onChange={(e) => setInput(e.target.value)}
                    style={{ width: 300 }}
                />

                <Button>Send Message</Button>

                <Button>Leave Room</Button>

                <Button>Join Room</Button>
            </Space>
        </div>
    )
}
```

{% endcode %}

## Backend Configuration

1. Create a backend function named `send-msg`.
2. Import `io` and emit a new message received from the frontend.

> Refer the snippet below.

{% code title="send-msg.server.tsx" %}

```tsx
import { createBackendFunction, io } from "@magicjs.dev/backend"

export default createBackendFunction(async function (msg: string) {
    io().emit('new-message', msg)

    return "Message from server"
})
```

{% endcode %}

* The function accepts a parameter `msg` of type string.
* Inside the function body:
  * It uses the `io` function to emit a message with the event name `'new-message'` and the provided `msg` parameter.

Configure the frontend to call this function upon clicking the Send Message button, passing the input value and resetting it afterward.

> Refer the snippet below.

```tsx
<Button onClick={() => sendMsgServer(input).then(() => {
    setMsg(input);
    setInput('');
})}>
    Send Message
</Button>
```

{% hint style="info" %}
Import the `sendMsgServer` from `"./send-msg.server".`
{% endhint %}

## Real-Time Messaging

1. Import `{ useSocket }` from `'@magicjs.dev/frontend'`;
2. Utilize the `useSocket()` hook to establish socket connection.
3. Implement a `useEffect()` hook to subscribe to incoming messages and update the state accordingly.
4. Ensure proper subscription management by unsubscribing within the hook.

> Refer the snippet below.

{% code title="In rt-message.tsx" %}

```tsx
const socket = useSocket();

React.useEffect(() => {
    const unsub = socket.subscribe("new-message", (msg) => {
        setMsg(msg)
    })
    return unsub
})
```

{% endcode %}

## Room Restriction

1. Modify the backend to emit messages only to a specific room, e.g., "secret-room".
2. Allow users to join and leave the room by invoking `socket.joinRoom()` and `socket.leaveRoom()` respectively in the frontend.

> Refer the snippets below.

{% code title="send-msg.server.tsx" %}

```typescript
import { createBackendFunction, io } from "@magicjs.dev/backend"

export default createBackendFunction(async function (msg: string) {
    io().to("secret-room").emit("new-message", msg)

    return "Message from server"
})
```

{% endcode %}

{% code title="In rt-message.tsx" %}

```tsx
<Button onClick={() => socket.leaveRoom("secret-room")}>
    Leave Room
</Button>

<Button onClick={() => socket.joinRoom("secret-room")}>
    Join Room
</Button>
```

{% endcode %}

<details>

<summary>Expand for Tailwind styled code.</summary>

{% code title="rt-message.tsx" lineNumbers="true" %}

```typescript
import React from 'react';
import sendMsgServer from "./send-message.server";
import { useSocket } from '@magicjs.dev/frontend';

export default function Test() {
  const [msg, setMsg] = React.useState("")
  const [input, setInput] = React.useState("")
  const socket = useSocket();

  React.useEffect(() => {
    const unsub = socket.subscribe("new-message", (msg) => {
      setMsg(msg)
    })
    return unsub
  })

  return (
    <div className='flex flex-col justify-center items-center min-h-screen'>
      <div>
        <div className='text-[40px] text-[#212121] mb-10'>Latest Message:</div>
        <div className='h-[80px]'>
          <h1 className='text-[56px] font-medium text-[#147E1D]'>{msg}</h1>
        </div>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          className='w-full border border-[#C1C1C1] rounded-[8px] mt-10'
        />
        <div className='flex flex-row gap-[33px] mt-10'>
          <button
            onClick={() => sendMsgServer(input).then(() => {
              setMsg(input);
              setInput('');
            })}
            className='text-[25px] text-[#151515] border border-[#BFBFBF] rounded-[10px] px-[62px] py-[15px] hover:opacity-70'
          >
            Send Message
          </button>
          <button
            onClick={() => socket.joinRoom("secret-room")}
            className='text-[25px] text-[#151515] border border-[#BFBFBF] rounded-[10px] px-[62px] py-[15px] hover:opacity-70'
          >
            Leave Room
          </button>
          <button
            onClick={() => socket.joinRoom("secret-room")}
            className='text-[25px] text-[#151515] border border-[#BFBFBF] rounded-[10px] px-[62px] py-[15px] hover:opacity-70'
          >
            Join Room
          </button>
        </div>
      </div>
    </div>
  )
}
```

{% endcode %}

</details>

## Testing

1. Open two browsers with the same page.
2. Test sending messages within the room, ensuring they are received in real-time only by members of the room.

<figure><img src="https://629398272-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrhfVeNvXQhNiRfJxJ9pq%2Fuploads%2FzKynW8rFJTVnSM2cBRhu%2FSocket%201%20(1).gif?alt=media&#x26;token=d554688d-16de-434c-9fb8-726946bf029d" alt=""><figcaption><p>Output in 2 browsers.</p></figcaption></figure>

:tada: Congratulations! You have successfully implemented real-time messaging capabilities using MagicJS's socket feature.
