Enhancing user experience with real-time health data insights in Nuxt.js
Tags: appwrite, nuxt, webdev, javascript
Published: 2023-03-17 08:16:16

Real-time data processing involves almost instantaneous feedback after program execution. This type of processing is critically important in the health field to track and monitor items such as user dosage or patient test results to decide on a patient's health status.

In this article, we will demonstrate the use of [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) to build application in Nuxt.js that allows tracking and enhancing user experience by leveraging on Appwrite's [real-time](https://appwrite.io/docs/realtime?utm_source=hackmamba&utm_medium=hackmamba-blog) feature. Appwrite is a self-hosted backend-as-a-service platform that provides developers with all the core APIs required to build any application


## GitHub

Check out the complete source code [here](https://github.com/MoeRayo/realtime-data-insight).


## Prerequisites

Understanding this article requires the following:

- Installation of Node.js
- Basic knowledge of JavaScript and Vue.js
- Docker [installation](https://www.docker.com/get-started/)
- An Appwrite instance; check out this [article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) on how to set up an instance locally or via one-click install on [DigitalOcean](https://marketplace.digitalocean.com/apps/appwrite) or [Gitpod](https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod)
- Installation of the [Appwrite CLI](https://appwrite.io/docs/command-line?utm_source=hackmamba&utm_medium=hackmamba-blog)

## Creating a Nuxt project

Use `npx create-nuxt-app <project-name>` to create a new Nuxt.js project. 
Scaffolding the Nuxt.js project provides a list of options, from which we will pick the one that best suits our preferences.

We can start our Nuxt3 application by running the following command:

```javascript
cd <project name>
npm run dev
```
Nuxt.js will, in turn, start a hot-reloading development environment that is accessible by default at `http://localhost:3000`.


## Creating an Appwrite project

To create a new project, we will start the Appwrite instance on our machine and navigate to the specified hostname and port `http://localhost:80`. Next, we must log into our account or create an [account](https://appwrite.io/docs?utm_source=hackmamba&utm_medium=hackmamba-blog) if we don't have one.

![Appwrite signup page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/97m7c00o9ng7zd00psuo.png)

Learn more about setting up Appwrite [here](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba-blog). On the console, click on the **Create Project** button.

![Appwrite project creation page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jklzk0yicuvlvnc86ish.png)

The project dashboard becomes visible on the console after the project creation. We can access the inner page from the Settings tab at the bottom of the page.

![Appwrite project setting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hqw46xwq57ebaozdwy9g.png)

The inner page allows us to copy the **Project ID** and **API Endpoint** for our Nuxt application.


### Adding Appwrite Web SDK to Nuxt.js
We will then proceed to create an `init.js` file in our Nuxt.js application's root directory to initialize the Appwrite Web SDK by adding the code block below:


```javascript
import { Client, Account, functions } from "appwrite";
export const client = new Client();
export const account = new Account(client);
client
    .setEndpoint('http://localhost/v1') // API Endpoint
    .setProject('***') // project ID
;

export const insightFunction = () => {
  const functions = new Functions(client)
  return functions.createExecution('***') // Function ID
}
```
## Creating an Appwrite function

Among Appwrite's supported runtimes for creating a serverless function is Node.js. Appwrite's serverless function gives room to build on and customize Appwrite server functionality by adding and executing our custom code.

### Integrating Appwrite function in Nuxt.js
We will start by logging onto Appwrite's server using the Appwrite command-line interface (CLI), like so:

```javascript
appwrite login
```
Running the command above requires us to use our Appwrite credentials in the terminal.

After logging into the application, we will initialize and link the Nuxt.js application with the previously created Appwrite project. To do this, we will run the command below:
```javascript
appwrite init project
```
Running the command above will display a list of options from which we will pick those appropriate for our project.

Next, let’s create a function in our Nuxt.js application. We will do this by running the command below:

```javascript
appwrite init function
```
At the successful execution of the above command, we will see a new folder named `functions/<function-name>` in our Nuxt.js application.

### Deploying the Appwrite function
To deploy the Appwrite function, we will run the command below:
```javascript
appwrite deploy function
```
Executing the above command will require us to pick the appropriate function we want to deploy. Upong successful deployment, we will get a message like the one below in our terminal.
```javascript
✓ Success Deployed <function-name> ( functionID)
```
In our Appwrite function console, we will also have a view that looks like the below:


![Deploying Appwrite Function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/buyv9xs0s6710rxsv2up.png)

This signifies the successful deployment of our Appwrite function.

We will also update the function's permissions to allow access within the Nuxt.js application. To do this, navigate to the **Settings** tab and add a role of `any` to the **Executive Access** field:

![Appwrite Function Permission](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t6phyr0sa2v1ko29jjj2.gif)

## Creating the signup page

We will create a signup page where people who will later be assigned roles to perform certain operations within the database can generically create an account. To do this, we will create  a `components/Sign-up.vue` and add the code below:

```javascript
<template>
  <div class="ba b--light-blue bg-light-blue bw3 vh-100 pv5 ph2 athelas">
    <form @submit.prevent="signUp" class="white bg-navy br3 mw6 w-40-m w-70 w-20-l center pa3 shadow-5">
      <h2 class="ttc tc">Sign up</h2>
      <label for="name" class="db mb1 white">Name</label>
      <input name="name" id="name" type="text" class="db mb3 w-100 br3 pa2 ba bw2" placeholder="John Doe" v-model="name">
      <label for="email" class="db mb1 white">Email</label>
      <input name="email" id="email" type="email" class="db mb3 w-100 br3 pa2 ba bw2" placeholder="example@email.com" v-model="email">
      <label for="password" class="db mb1 white">Password</label>
      <input name="password" id="password" type="password" class="db mb3 w-100 br3 pa2 ba bw2" placeholder="••••••••" v-model="password">
      <label for="confirm-password" class="db mb1 white">Confirm Password</label>
      <input name="confirm-password" id="confirm-password" type="password" class="db mb3 w-100 br3 pa2 ba bw2" v-model="confirmPassword" placeholder="••••••••">
      <button type="submit" class="center db ph4 pv2 bg-navy ba br3 white pointer">Sign up</button>
      
      <p>Already have an account? <a href="/signin" class="white b">Sign in</a> </p>
    </form>    
  </div>
</template>
```
Implementing the code block above, we achieved the following:

- Created a functional form to handle input from potential users of our dashboard
- Added the `data` in the Vue script to manage the username, email, and password of the people who will fill out the form

### Adding the signup functionality 
Our interface will need to be connected to Appwrite to authenticate users. To do this, we will add the following code in the `<script>` tag of our `components/Sign-up.vue` file.

```javascript
<script lang="ts">
import Vue from 'vue'
import {account} from '~/init'
export default Vue.extend({
  data: () => ({
    name: "",
    email: "",
    password: "",
    confirmPassword: ""
  }),
  methods: {
    signUp: async function(){
      if (this.password.length >= 8){
        if(this.password === this.confirmPassword) {
          try{
            await account.create('unique()', this.email, this.password, this.name)
            alert("account created successfully")
            window.location.href = '/signin'
          } catch (e) {
            console.log(e)
          }
        } else {
          alert("password do not match")
        }
      } else {
        alert("password length should be up to 8 characters")
      }
    },
    
  }
  
})
</script>
```
The code block above achieves the following:

- Imports the Appwrite SDK initialized in the `init.js` file.
- Creates the `signUp` function in the `methods` property, which performs the following functions:
    - Verifies that the password length is equal to or greater than eight characters.
    - Confirms that the characters in `password` and `confirmPassword` are the same.
    - Accesses Appwrite's services using the `account.create` to create a new account using the user's email, password, and name.
        - To use Appwrite's create account service, it's mandatory to add the `userId`; in this case, we used `uniqueId` to generate one automatically.
        - Adding `email` and `password` is also mandatory.
        - The `name` option is optional; we can create an account without one.
    - `window``*.location.*``href` allowed us to navigate to the insight interface after successful account creation.

Next, let's import the `components/Sign-up.vue` into the `pages/index.vue`, like so: 

```javascript
<template>
  <div>
    <Signup/>
  </div>
</template>
```
At this point, our signup page should look like the below:

![signup page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mx8mddcfjqe0mb2nvsfg.png)

## Creating the sign in interface

We also need to create a sign in page that allows registered users to log in to the dashboard. To do this, we will create a `pages/Signin.vue` and add the code below:

```javascript
<template>
  <div class="ba b--light-blue bg-light-blue bw3 vh-100 pv5 ph2 athelas">
    <form @submit.prevent="signIn" class="bg-navy br3 mw6 w-40-m w-70 w-20-l center pa3 shadow-5 white">
      <h2 class="ttc tc">Sign In</h2>
      <label for="email" class="db mb1 white">Email</label>
      <input name="email" id="email" v-model="email" type="email" class="db mb3 w-100 br3 pa2 ba bw2" placeholder="example@email.com">
      <label for="password" class="db mb1 white">Password</label>
      <input name="password" id="password" v-model="password" type="password" class="db mb3 w-100 br3 pa2 ba bw2" placeholder="••••••••">
      <button type="submit" class="center db ph4 pv2 bg-navy ba br3 white pointer">Sign in</button>
      
    </form>    
  </div>
</template>
```
The code block above achieves the following:

- Creates a functional form to handle input from registered users 
- Adds the `data` in the Vue script to manage the email and password

### Adding the signin functionality 
Our interface must be connected to Appwrite to authenticate users for signing in. To do this, we will add the code below in the `Signin.vue`. 

```javascript
<script lang="ts">
import Vue from 'vue'
import {account} from '~/init'
export default Vue.extend({
  data: () => ({
    email: "",
    password: "",
  }),
  methods: {
    signIn: async function () {
      try{
        let accountDetails = await account.createEmailSession(this.email, this.password)
        alert("user signed in")
        this.$router.push({ path: `/insight/${accountDetails.userId}`})
      } catch (e){
          console.log(e)
      }
    }
  }
  
})
</script>
```
Above, we imported the Appwrite SDK initialized in the `init.js` file. We also created a function called `signIn` that does the following:

- Accesses Appwrite's services using the `account.createEmailSession` to create a new account session using the user's email and password 
- `this.$router.push` allows us to navigate to the insight interface after successful user login

At this point, our interface will look like this:

![Sign-in page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/enzmagh6mh29i8p7trek.png)

## Setting up Appwrite's database

One of the services offered by Appwrite is the **Database Service**, which allows us to store data and fetch it as needed. 

### Creating a database
To create a database in Appwrite, click on the **Database** option in the menu tab, where we can add a database to the system.

![Creating a database](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qd9hisjmou6chy9ist05.png)

### Creating a collection
Appwrite's database services also provide collection services. These collections act as containers for documents. To create a collection, select the desired database from which we can add a new collection.


![Creating a collection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4cogvx4us64thc0180xn.png)


### Creating an attribute
Our document will have some particular attributes. To create them, we will navigate to the **Attributes** section. In our case, we will choose the **Boolean Attribute.** We can then create an **Attribute ID** with the name "doses".


![Creating an attribute](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/op9894upkrx2ttx7aokb.png)


Now, will set the permission roles for the document. Click on the **Settings** tab, and in the **Role** input field, pick the role that best describes to whom we are giving access. 


![Set permission roles](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/612h8o1je26u8kh0v79o.gif)

In our case, the role is **any,** and we will allow all four actions: **create**, **read**, **update**, and **delete**.


## Creating the Insight page

We will be creating a page where we track users' dosages. Every day a user is allowed to take just three doses, after which they are prompted to log in the next day to get access to more doses.

We will start by creating an interface that allows users to log their dosage. To do this, we will create a `pages/_insight/insight.vue` and add the code below:


```javascript
<template>
  <div class="bg-light-blue vh-100 pa3 tc">
    <h2 class="ttc">Real Time Health Data analytics with Appwrite</h2>
    <div class="br3 bg-navy ba near-white b--black-10 shadow-3 w-100 w-60-m w-30-l mw6 center mt5 ph4 pv4 h5">
      <p class="f3">Click on this button to get the dosage</p>
        <button class="link br3 pv2 ph2 mt4 dib black fw6 bg-white ba b--navy pointer inline-flex items-center hover-bg-lightest-blue" @click="getDosage">
          <span class="f4 ml2 pr2">Get dosage</span>
        </button>
    </div>
  </div>
</template>
```
The code above achieves the following:

- Creates an interface where users are redirected after sign up or sign in
- The insight interface allows users to click on a button `getDosage` to track their dosage journey for each day

### Adding the getDosage() functionality
Now we will connect the interface to a working functionality that allows users to log and track their dosage.

```javascript
<script>
import {client, insightFunction} from '~/init'
import { Databases } from "appwrite";
const databases = new Databases(client);
import moment from "moment";
export default {
  data() {
    return {
      permisssionsArray: [],
    }
  },
  mounted() {
    insightFunction().then((res)=> res).catch((error)=> {
      console.log(error)
    })
    this.checkDosage();
    if(this.$route.params.insight){
      try {
        client.subscribe("documents", (response) => {
          this.checkDosage();
        });
      } catch (error) {
        console.log(error, "error");
      }
    }
  },
  methods: {
    moment,
    async getDosage() {
      await databases.createDocument(
        "63ef7e057f16c9d0b811",
        "63ef7e389fdfbe02d8e9",
        "unique()",
        {
          doses: true,
        }
      );
    },
    async checkDosage() {
      const dosageDetails = await databases.listDocuments(
        "63ef7e057f16c9d0b811",
        "63ef7e389fdfbe02d8e9"
      );
      dosageDetails.documents.filter(obj => {
        if( moment(obj.$createdAt).format("YYYY-MM-DD") === moment().format("YYYY-MM-DD")) {
          obj.$permissions.find(element => {
          if(element.includes(this.$route.params.insight)) {
            this.permisssionsArray.push(element)
            if (this.permisssionsArray.length >= 3){
              this.$swal({icon: 'success', title: 'Wait one day before taking another dose. Take a walk instead', timer: 10000, showConfirmButton: false,});
            }
              return;
            } else {
              return;
            }
          })
        }
      })
    }
  }
}
</script>
```
The code above achieves the following:

- Imports the dependencies from the `init.js` file as well as from Appwrite.
- Installed the [moment.js](https://momentjs.com/) package, which we used for checking and comparing the days for the dosages.
- The `getDosage` method accesses the `databases` method from Appwrite to create a new document in the database. This method takes the `database ID`, `collection ID`, Appwrite's `ID.unique()` method, and the attribute value(s) as parameters. In this case, our attribute value is `doses`, which we created on the Appwrite admin dashboard.
- We call the `listMessages()` function, which lists all the messages that were sent to the Appwrite's database.
- Checks whether the user has taken up to 3 doses and shows a notification telling the user to come back the next day.

At this point, our application should look like the below:

![Final application look](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/16aaqna2zveuzrpmybmp.gif)


## Conclusion

This article discusses enhancing user experience by providing data insights using Appwrite's real-time features.

## Resources
- [Appwrite's account API](https://appwrite.io/docs/client/account?sdk=web-default#accountCreateOAuth2Session?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Appwrite real-time features](https://appwrite.io/docs/realtime?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Appwrite's Functions](https://appwrite.io/docs/client/functions?utm_source=hackmamba&utm_medium=hackmamba-blog)