How to create a real-time classroom chat in Next.js with Appwrite and Pink Design
Tags: javascript, nextjs, tutorial, opensource
Published: 2023-04-19 10:50:04


Regardless of the aspect of education you’re involved in, there’s no doubt that everyone’s busy. From deadlines for applications, assignments, and grades to campus events and program coordination — it’s a lot to manage. In response, many schools are choosing to offer live chat support. Using synchronous support channels allows schools to answer questions and quickly deliver information to their communities. 

This tutorial demonstrates how to use Appwrite’s [Pink Design ](https://pink.appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog)feature to create a real-time classroom chat with Next.js.

## GitHub
Check out the complete source code [here](https://github.com/Tundesamson26/realtime-classroom-chat).

Prerequisites

The following are required to follow along:

- Knowledge of JavaScript and React.js.
- A Docker Desktop installation; run the `docker -v` command to verify the installation. If not, install it from the [Get Docker documentation](https://docs.docker.com/get-docker/) site.
- An Appwrite instance running on our computer. Check out [this article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) to create a local Appwrite instance; we will use Appwrite’s robust database and Realtime service to manage our application.
- Experience with Next.js is advantageous but not required.

## Creating a Next.js project

To create a Next.js project, perform the following steps:

- Open a terminal and run this command line to scaffold a Next.js app:

```js
npx create-next-app classroom-chat
```
- Go to the project directory and start the development server on `localhost:3000` with this command:

```js
cd classroom-chat && npm run dev
```

## Getting started with Pink Design

[Pink Design](https://pink.appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) is an open-source system from [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) used to build consistent and reusable user interfaces. It enhances collaboration, development experience, and accessibility.

We can integrate Pink Design into a project via a content delivery network (CDN) or Node Package Manager (NPM). In this tutorial, we’ll use NPM.

To install Pink Design, open a terminal in the project directory and run the following command:

```js
npm install @appwrite.io/pink
```
To use Pink Design in our project, import it into your project’s JavaScript files like this:

```
import "@appwrite.io/pink";
```

## Installing dependencies
Installing unique-username-generator
This package helps generate a unique username from randomly selected nouns and adjectives. To install the unique-username-generator in our project, we run these terminal commands.

```js
npm install unique-username-generator --save
```
## Installing Appwrite
Appwrite is a development platform that provides a powerful API and management console for building backend servers for web and mobile applications. To install it, run the command below:

```js
npm install appwrite
```
## Setting up Appwrite
To get started, we need to log in to our [Appwrite cloud](https://appwrite.io/cloud?utm_source=hackmamba&utm_medium=hackmamba-blog) console, click the **Create project** button, input `realtime-chat` as the name, and then click **Create**.

![appwrite-create-console](https://paper-attachments.dropboxusercontent.com/s_D8D6E1F59290557695E8242287BECE485D4CF8205464B1EF48244B2372C092BC_1679318713929_image.png)

**Create a database, collection, and add attributes**

With our project created, we can set up our application database. First, navigate to the **Database** tab, click the **Create database** button, input `classroom-chat` as the name, and then click **Create**.

![appwrite-db](https://paper-attachments.dropboxusercontent.com/s_D8D6E1F59290557695E8242287BECE485D4CF8205464B1EF48244B2372C092BC_1679142675443_image.png)

Secondly, we need to create a collection for storing our products. To do this, click the **Create collection** button, input `chat_collection` as the name, and then click **Create**.

![appwrite-collection](https://paper-attachments.dropboxusercontent.com/s_D8D6E1F59290557695E8242287BECE485D4CF8205464B1EF48244B2372C092BC_1679143016358_image.png)

Thirdly, we need to create attributes to represent our database fields. To do this, we need to navigate to the **Attributes** tab and create attributes for each of the values shown below:

| Attribute key | Attribute type | Size | Required |
| ------------- | -------------- | ---- | -------- |
| username      | String         | 500  | YES      |
| messages      | String[]       | 500  | YES      |

![appwrite-attr](https://paper-attachments.dropboxusercontent.com/s_D8D6E1F59290557695E8242287BECE485D4CF8205464B1EF48244B2372C092BC_1679517342276_image.png)


Lastly, we need to update our database permission to manage them accordingly. Navigate to the **Settings** tab, scroll to the **Update Permissions** section, select `Any`, mark accordingly, and then click **Update**.

![appwrite-ssetting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k8jhkm2kmhu6keihzv1i.png)

## Building the chat interface

Our chat application will have one page: a mobile-sized chat app with a video, top menu, message, and input where the user will type. Create this chat application with the GitHub [gist](https://gist.github.com/Tundesamson26/80fed046b43ed46c25b675224ab659b3) below:

From the gist below, we have the `src/pages/index.js`.

{% embed https://gist.github.com/Tundesamson26/80fed046b43ed46c25b675224ab659b3 %}

In the `index.js`, we did the following:
- Imported required dependencies and components
- Added a video at the top of the chat app
- Implemented state variables that store (1) the **messages**, which contain a list of all messages sent and received, and (2) **usernames**, which is the array holding the user typing in the document
- **Top Menu**: This contains the application title and a section to show who is currently typing
- **Input**: This contains the text field to input messages and the **send** button

At this point, our application should look like so:

![chat-ui](https://paper-attachments.dropboxusercontent.com/s_D8D6E1F59290557695E8242287BECE485D4CF8205464B1EF48244B2372C092BC_1679310720282_image.png)

**Creating an anonymous user session**
Appwrite requires a user to sign in before reading or writing to a database to enable safety in the application. However, we can create an anonymous session that we'll use in this project. We'll do so in the `web-init.js` file.

```js
// Init your Web SDK
import { Client, Account, Databases } from "appwrite";
export const client = new Client();
client
  .setEndpoint("https://cloud.appwrite.io/v1")
  .setProject("641858468a39ef152488");
const account = new Account(client);
const database = new Databases(client);

export const createAnonymousSession = async () => {
  try {
    await account.createAnonymousSession();
  } catch (err) {
    console.log(err);
  }
};
```
**Generating random username**
Next, we need to generate a random username for each user typing the message input using our installed `unique-username-generator` package. First, import the dependency into the `src/pages/index.js` file.

```js
import { generateUsername } from "unique-username-generator";
```

Then write a conditional statement to check for the current “user” on the mount of our application using the React `useEffect()` Hook.

```js
useEffect(() => {
    if (!username) {
      const _username = localStorage.getItem("username") || generateUsername();
      localStorage.setItem("username", _username);
      setUsername(_username);
    }
}, [username]);
```

The code snippet above checks that the **username** does not already exist, and it should generate a username and store the **username** in `localStorage`.

**Creating database documents**
Next, we need to create a chat document that stores our list of users in the `username` attribute. In the `src/page/index.js` file, write a `createChatIfNotExist()` function to create the document if it does not exist. For simplicity, we'll keep the `id` as **general chat**.

```js
const createChatIfNotExist = async (e) => {
    console.log("Adding user", message);
    const promise = databases.createDocument(
      "6418bf5a278b4799614b",
      "6418bf6c38a6c826cc21",
      "general-chat",
      {
        username: username,
        messages:[...messages,message]
      }
    );
    promise.then(function (response) {
      console.log("runnner", response); // Success
  }, function (error) {
      console.log(error); // Failure
       databases.updateDocument(
        "6418bf5a278b4799614b",
        "6418bf6c38a6c826cc21",
        "general-chat",
        {
          username: username,
          messages:[...messages,message],
        }
      );
  });
  };
```
The `createChatIfNotExist` function above does the following:
- The `createDocument()` method creates a document using the collection ID and data fields to be stored. This collection ID is the same ID we copied from our **Permissions** page earlier.
- Uses the Appwrite `updateDocument()` method to update the `general-chat` document ID.

## Subscribing to updates on the document
When the user sends a message from the input field, the page sends a real-time request to listen to any events on the server side. This is broadcast to everyone as an event in real-time using the **subscribe** method.

```js
useEffect(() => {
    const _subscribe = client.subscribe(
      "databases.6418bf5a278b4799614b.collections.6418bf6c38a6c826cc21.documents",
      (response) => {
        console.log("iiiii",response);
        const { payload } = response;
        if (payload?.$id === "general-chat") {
          setMessages(payload.messages);
        }
      }
    );
    return () => {
      _subscribe();
    };
  }, []);
```
In the code snippet above, we did the following:
- Subscribed to a channel using Appwrite's subscribe method, which receives two parameters: the channel we subscribe to and a callback function. To learn more about the various channels we can subscribe to, check out [Appwrite's Realtime Channels](https://appwrite.io/docs/realtime#channels?utm_source=hackmamba&utm_medium=hackmamba-blog).

Our chat app should look like this by now:

![classroom-chat-realtime](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/empo92nz8g99am3kdtaw.png)

## Conclusion

This article discussed using Appwrite’s Pink Design and a real-time feature to subscribe to application events on a classroom chat application.

## Resources
- [Appwrite cloud](https://appwrite.io/cloud?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Appwrite Pink Design](https://pink.appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Unique-username-generator](https://www.npmjs.com/package/unique-username-generator?utm_source=hackmamba&utm_medium=hackmamba-blog)