Build a Real Time Leaderboard in Nuxt.js and Pink Design
Tags: webdev, javascript, cloud, appwrite
Published: 2023-05-16 10:27:06

In modern software development, real-time updates are vital, especially for applications that rely on up-to-date information for users. In such scenarios, changes made to the app's database are immediately reflected in the user interface, eliminating the need for manual refreshing or waiting for server responses.

Appwrite is a popular backend-as-a-service platform that simplifies database management, user authentication, account management, and storage. Its real-time functionality is especially vital for chat apps, analytics, live scoreboards, or more complex features like live streaming and collaborative editing.

This blog post illustrates how to use Appwrite's real-time feature to create a racing leaderboard in Nuxt.js. You will style your leaderboard using Appwrite's [Pink Design](https://pink.appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) system, giving it a cohesive and visually appealing look.

The **source code** for this project is available below:
[Real-Time Racing Leaderboard | GitHub](https://github.com/dpkreativ/nuxt-racing-leaderboard)

_Jump ahead:_

- [Prerequisites](#prerequisites)
- [Setting Up a Nuxt Project](#setting-up-a-nuxt-project)
- [Setting Up an Appwrite Database](#setting-up-an-appwrite-database)
- [Implementing Real Time Updates with Appwrite](#implementing-real-time-updates-with-appwrite)
- [Conclusion](#conclusion)

## Prerequisites

To create a real-time leaderboard in Nuxt.js, it is essential to meet the following requirements:

- Have a solid understanding of JavaScript, Vue.js, CSS, and styling.
- Verify that Node.js is installed on your personal computer (PC) by running `node -v` in your terminal. If not, download and install it from the [official website](https://nodejs.org/en/download/).
- Verify that Yarn is installed on your PC by running `yarn -v` in your terminal. If not, install it by running `npm install --location=global yarn` in your terminal.
- Set up a remote Appwrite instance with [Appwrite Cloud](https://cloud.appwrite.io/login?utm_source=hackmamba&utm_medium=hackmamba-blog).

_or_

- Verify that Docker Desktop is installed on your PC by running `docker -v` in your terminal, or follow [this guide](https://docs.docker.com/desktop/) to install it. Then set up a local Appwrite instance on your PC by following [this blog post](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba).
- You can also set up your remote instance on [Digital Ocean](https://docs.digitalocean.com/products/marketplace/catalog/appwrite/) or [Gitpod](https://www.gitpod.io/guides/appwrite-and-gitpod).

## Setting Up a Nuxt Project

You can create a new Nuxt.js project by navigating to your preferred repo in your terminal and running the command below:
```bash
npx nuxi init <project name>
```

However, to speed up the development process, bootstrap your project with [this starter template](https://github.com/dpkreativ/racing-leaderboard-starter/generate) on GitHub. It comes with [Nuxt 3](https://nuxt.com/), Appwrite's [Pink Design](https://pink.appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog), and [Appwrite's Nuxt module](https://nuxt.com/modules/appwrite). It also contains some helper functions in the `utils` folder.

![Generate repository from starter repo](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913528643_Untitled-min.png)

Clone your generated repo to your preferred local directory, and run `yarn` to install the dependencies listed in `package.json`.

> **Note:** If you encounter any errors while installing dependencies, it is most likely because you need to add your Appwrite details—endpoint, project ID, database ID, and collection ID—to a `.env` file. Don't worry about it for now. [Set up your Appwrite Database](#setting-up-an-appwrite-database) first, then add the necessary details to your `.env` file and rerun `yarn` in your terminal.

![Install your dependencies](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913560521_Untitled+1-min.png)

## Setting Up an Appwrite Database

If you have an Appwrite Cloud account, click [here](https://cloud.appwrite.io/login?utm_source=hackmamba&utm_medium=hackmamba-blog) to open it in your browser and create a new project.

![Create project on Appwrite](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913587492_Untitled+2-min.png)

In your Appwrite project, click on **Databases**, and then click on **Create Database** to create a new database.

![Create database in Appwrite project](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913599996_Untitled+3-min.png)

In your newly created database, create a collection.

![Create a database collection](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913617318_Untitled+4-min.png)

In the **Settings** tab of your new collection, scroll down to **Update Permissions** and set **Any** to **Read**.

![Update read and write permissions](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913633951_Untitled+5-min.png)

This ensures that anybody can view the data on your database. If you want your users to create, update, or delete documents in the database, check the necessary boxes.
In your collection, click on the **Attributes** tab and create some attributes for each document in your collection.

![Create attributes for your collection's documents](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913648706_Untitled+6-min.png)

You will create four attributes:

- `car` - String
- `carNumber` - Integer
- `driver` - String
- `duration` - Integer (in seconds)

![Attributes](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913664874_Untitled+7-min.png)

Seed the database with some data by clicking on the **Documents** tab and clicking **Create document**.

![Collection of Documents in Leaderboard database](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913678114_Untitled+8-min.png)

## Implementing Real Time Updates with Appwrite

### Setting up environment variables

In your code editor, create a `.env` in your project's root directory or rename `.env.example` to `.env`. It should contain the text below:

```env
APPWRITE_ENDPOINT=
APPWRITE_PROJECT_ID=
APPWRITE_DATABASE_ID=
APPWRITE_COLLECTION_ID=
```

Follow this guide to update your `.env` file with the correct data from your Appwrite database:

- If you created your database with Appwrite Cloud, your `APPWRITE_ENDPOINT` is `https://cloud.appwrite.io/v1`. If you're running a local instance, use `http://localhost/80` as your endpoint. If you hosted on Digital Ocean or Gitpod, use the provided endpoint for your chosen platform.
- Store your project's ID in `APPWRITE_PROJECT_ID`, your database ID in `APPWRITE_DATABASE_ID`, and your collection ID in `APPWRITE_COLLECTION_ID`.

In your project's root directory, update `nuxt.config.ts` with the code below:

```jsx
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      database: process.env.APPWRITE_DATABASE_ID,
      collection: process.env.APPWRITE_COLLECTION_ID,
    },
  },
  modules: ['nuxt-appwrite'],
  appwrite: {
    endpoint: process.env.APPWRITE_ENDPOINT,
    project: process.env.APPWRITE_PROJECT_ID,
  },
});
```

Here, you set up Nuxt.js' runtime config to read the data from your `.env` file and set up `nuxt-appwrite` module with the correct endpoint and project ID.

### Getting Data From Appwrite's Database

Open `app.vue` and update the `<script>` tag with the code below:

```jsx
<script setup>
import '@appwrite.io/pink';
import '@appwrite.io/pink-icons';

const config = useRuntimeConfig();

const { account, client, database } = useAppwrite();

// Create an anonymous session if it doesn't already exist
if (account.getSession === null) {
  await account.createAnonymousSession();
}

// Get initial data from the database
const { documents } = await database.listDocuments(
  config.database,
  config.collection
);

// Add racing data to state
const { value: racingData } = useState('racingData', () => sortData(documents));
</script>
```

Here you did the following:

- Set up runtime config to access data from your `.env` file
- Imported `account`, `client`, and `database` from Appwrite's Nuxt.js module
- Created an anonymous Appwrite session so any user can access your database
- Got the initial data from your leaderboard database and destructured it to get the `documents` key; this contains an array of all the documents in your database
- Sorted your array of documents by duration using a helper function (`sortData`) and added the sorted array to Nuxt.js' state with `racingData` as its variable name

Still in your `app.vue`, update `<RacingLeaderboard>` in your `<template>` tag:

```xml
<template>
  <NuxtLayout>
    <RacingLeaderboard :data="racingData" />
  </NuxtLayout>
</template>
```

If you run the project with `yarn dev` and open `localhost:3000` in your terminal, you will see the UI below:

![Racing leaderboard UI](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913698490_Untitled+9-min.png)

### Subscribing to Real Time Updates

In the `app.vue` `<script>` tag, add the code below:

```jsx
<script>
// ...previous code, do not delete; just add the one below

// Subscribe to real-time updates from the database
onMounted(() => {
  try {
    client.subscribe(
      `databases.${config.database}.collections.${config.collection}.documents`,
      (res) => updateState(racingData, res.payload)
    );
  } catch (error) {
    console.log(error);
  }
});
<script/>
```

Here you did the following:

- Set up `onMounted()` to ensure that the `client.subscribe()` method only works when the project is loaded on the browser; this is because it requires the `window` method, which is only available on the browser
- Your `client.subscribe()` method takes in the exact location of your documents as its channel and updates your state with a helper function when there are any changes to the documents in your database

Here's a preview of how it will work.

![Real-time updates in Appwrite](https://paper-attachments.dropboxusercontent.com/s_6DE1294194673DC40A51BBD0CA09AD4B606B742A10609854076A6E417520F712_1679913709081_ezgif.com-optimize.gif)

Notice that you don't need to refresh the browser to see updates to your database.

## Conclusion

This blog post demonstrated Appwrite's real-time functionality in a racing leaderboard. The post covered how to set up a Nuxt.js project with Appwrite's Pink Design, set up an Appwrite database, implement real-time updates with Appwrite, and subscribe to real-time updates. Following these steps, developers can add real-time functionality to their applications and create dynamic and engaging user experiences.

## Resources

- [Get Started with Nuxt](https://nuxt.com/docs/getting-started/installation)
- [Pink Design](https://pink.appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Array.prototype.findIndex() - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)
- [Hrdtr/nuxt-appwrite: Easily connect Appwrite to Nuxt](https://github.com/Hrdtr/nuxt-appwrite)