DEV Community

Cover image for How to create a real-time classroom chat in Next.js with Appwrite and Pink Design
Odewole Babatunde Samson for Hackmamba

Posted on • Updated on

How to create a real-time classroom chat in Next.js with Appwrite and Pink Design

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 feature to create a real-time classroom chat with Next.js.

GitHub

Check out the complete source code here.

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 site.
  • An Appwrite instance running on our computer. Check out this article 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:
npx create-next-app classroom-chat
Enter fullscreen mode Exit fullscreen mode
  • Go to the project directory and start the development server on localhost:3000 with this command:
cd classroom-chat && npm run dev
Enter fullscreen mode Exit fullscreen mode

Getting started with Pink Design

Pink Design is an open-source system from Appwrite 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:

npm install @appwrite.io/pink
Enter fullscreen mode Exit fullscreen mode

To use Pink Design in our project, import it into your project’s JavaScript files like this:

import "@appwrite.io/pink";
Enter fullscreen mode Exit fullscreen mode

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.

npm install unique-username-generator --save
Enter fullscreen mode Exit fullscreen mode

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:

npm install appwrite
Enter fullscreen mode Exit fullscreen mode

Setting up Appwrite

To get started, we need to log in to our Appwrite cloud console, click the Create project button, input realtime-chat as the name, and then click Create.

appwrite-create-console

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

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

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

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

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 below:

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

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

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.

// 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);
  }
};
Enter fullscreen mode Exit fullscreen mode

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.

import { generateUsername } from "unique-username-generator";
Enter fullscreen mode Exit fullscreen mode

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

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

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.

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],
        }
      );
  });
  };
Enter fullscreen mode Exit fullscreen mode

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.

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();
    };
  }, []);
Enter fullscreen mode Exit fullscreen mode

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.

Our chat app should look like this by now:

classroom-chat-realtime

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

Top comments (0)