Dashboards, graphical user interfaces comprising a composition of data visually presented to users, are essential to modern web and mobile applications. They are everywhere — from laptops displaying our screen time to mobile phones— and all everyday tools and technologies have dashboards.
In this article, we will build a dashboard using Appwrite, a backend-as-a-service (BaaS) platform, to manage and display the data on the client side of the customized medication dashboard using its core APIs in a Nuxt project.
Our final app will look something like this:
GitHub
Check out the complete source code in this repo.
Prerequisites
To follow along with this tutorial, the following are required:
- Node and node package manager (npm) installed on our machine
- Basic knowledge of Vue, JavaScript, and CSS
- Docker installation
- Appwrite instance; check this article on setup
What is Appwrite Pink Design system?
Companies create design systems with a set of reusable components for developer ease of use and to create beautiful experiences and interfaces more quickly.
Pink Design is an open-source design system for prioritizing collaboration and improving the accessibility of web and mobile apps through carefully created components and styles.
Setting up Appwrite
To get started, we need to log in to our Appwrite console. Use this command to run the Appwrite instance in the browser:
localhost:80
Now, create a new project by clicking the Create Project button. Name this project Medications Dashboard.
Next, navigate into the new project to create a database, collections, and add attributes.
Creating a database
In the left pane of the Appwrite console dashboard, click Databases and create a new database with the name medications.
Creating collections
After clicking the created database, medications, we will create a collection to serve as a container for our documents. Give the new collection the name medications collection.
Adding attributes
Attributes represent the fields in our database. To create attributes, click the Attributes tab to add a new attribute.
Here is the final result for each attribute:
Let's fill in each of these fields. Click the Documents tab and "AddDocument".
Update permissions
Here, we will configure permissions for our collection. Under the Permissions section, update the role to Any and check Read. Afterwards, click the Update button to confirm the selection.
Scaffolding a Nuxt App
Nuxt is a progressive frontend framework built on top of Vue. We'll first want to scaffold a Nuxt development environment to get started. Do so quickly by using this command:
npx nuxi init <project-name>
For this project, the is named medications-dashboard.
Next, navigate to the project directory and run the following to install the project dependencies:
npm install
Start the frontend server in development mode when the project’s dependencies have finished installing with the command:
npm run dev -- -o
View the scaffolded application at http://localhost:3000
.
Installing Dependencies
Let's install the following packages to our project: the Appwrite software development kit (SDK) and the Pink Design.
npm install appwrite
npm install @appwrite.io/pink
Check the installed dependencies in the package.json
file:
Building a customized dashboard
Before creating the UI, let's import the Pink Design library into our project, giving us access to the Pink Design classes. Inside the pages folder, add the following imports in the index.vue
file:
The second import with pink-icons is applicable when we need to add icons to our app.
Creating project components
In the Nuxt root project directory, create a folder named components and create the following files: MedicalDetails.vue
, NavBar.vue
, PatientInfo.vue
, and UserInfo.vue
.
For each of these components, copy and paste the following code:
// components/MedicalDetails.vue
<template>
<div class="container">
<div>
<h2 class="eyebrow-heading-2">Medication History</h2>
<ul class="list">
<li
class="list-item">
<span class="icon-arrow-circle-right" aria-hidden="true"></span>
<span class="text">Pain in the chest region</span>
</li>
<li
class="list-item">
<span class="icon-arrow-circle-right" aria-hidden="true"></span>
<span class="text">Cortisol levels</span>
</li>
<li class="list-item"></li>
</ul>
</div>
<div>
<h2 class="eyebrow-heading-2">Upcoming Doses</h2>
<ul class="list">
<li class="list-item">
<span class="text u-bold">Check in:</span>
February 28, 2023
</li>
<li class="list-item">
<span class="text u-bold">Doctor to see:</span>
Dr. Tolu Hernandez
</li>
<li class="list-item">
<span class="text u-bold">Shot:</span>
Vaccination
</li>
</ul>
</div>
</div>
</template>
The code above within the <template>
does the following:
- container holds the content of the other elements
- eyebrow-heading-2 is a typography feature that supports the main heading
- list used to group related content in a list
- list-item ****is a necessary class when list items begin with an icon
- icon-arrow-circle-right is a class to add an icon within the list-item element
- text represents body text
// components/NavBar.vue
<template>
<div class="container">
<header class="u-flex u-main-space-between u-cross-center">
<NuxtLink to="/" class="u-bold">Med</NuxtLink>
<img
class="avatar"
src="https://res.cloudinary.com/terieyenike/image/upload/v1666716203/teri.jpg"
alt="portrait - teri" />
</header>
</div>
</template>
Let's break down the code snippet above:
- In the header element, the class u-flex styles the container as flex, whereas the u-main-space-between distributes the items, the text and image evenly
- NuxtLink is a component for navigation to the home route
- u-bold is a class to make the text bold
- avatar is a class responsible for displaying an image preview
// components/PatientInfo.vue
<template>
<div class="container">
<h2 class="eyebrow-heading-2">Other Information</h2>
<div class="u-flex u-cross-center u-gap-24">
<div>
<p class="u-bold">Sex: <span>Male</span></p>
<p class="u-bold">Age: <span>31</span></p>
</div>
<div>
<p class="u-bold">Diabetic: <span>No</span></p>
<p class="u-bold">Blood: <span>O+</span></p>
</div>
</div>
</div>
</template>
In this component, the code does the following:
-
u-gap-24
adds spacing of 1.5rem from the h2 element
// components/UserInfo.vue
<template>
<div class="container">
<section class="u-flex u-flex-vertical u-cross-center">
<h1 class="heading-level-1">Medic Dashboard</h1>
<p>
Welcome, <span class="eyebrow-heading-2">{{ name }}!</span>
</p>
</section>
</div>
</template>
<script setup>
const name = 'Teri';
</script>
For this code block, we included the composition API:
- In the script section, we assigned a variable
- Just as in previous components, we are using the Pink Design classes
- Pass the declared variable in the element
Let's update the code to reflect all the changes made in the components directory in our pages/index.vue file. Copy and paste the following code:
// pages/index.vue
<template>
<nav-bar />
<user-info />
<medical-details />
<patient-info />
</template>
<script setup>
...
useHead({
title: 'Medications Dashboard',
})
</script>
The code above does the following:
- Imports each of the components in .
- The useHead components in the code above help to bind the metadata, title to the head of the page.
Our app will look like this:
Integrating Appwrite
With the UI complete, let's create a file named utils.js in our Nuxt project root directory.
Copy and paste the following code:
// utils.js
import { Client, Databases } from "appwrite";
const client = new Client();
const databases = new Databases(client);
client
.setEndpoint('http://localhost/v1')
.setProject('[PROJECT_ID]')
;
export const getList = databases.listDocuments('[DATABASE_ID]', '[COLLECTION_ID]');
The code snippet above does the following:
- Imports the required module, Client, and Databases
- Creates a new instance for the Client and Databases
- Initializes the Appwrite web SDK using the client variable, which will interact with Appwrite services
PS: We can get all the required IDs from our Appwrite console when setting up the instance
Updating the UI
Back to the MedicalDetails.vue component, let's update the code with the following:
// components/MedicalDetails.vue
<template>
<div class="container">
<div>
<h2 class="eyebrow-heading-2">Medication History</h2>
<ul class="list" v-for="medication in medications" :key="medication.$id">
<li
class="list-item"
v-for="item in medication.medicationHistory"
:key="item.$id">
<span class="icon-arrow-circle-right" aria-hidden="true"></span>
<span class="text">{{ item }}</span>
</li>
<li class="list-item"></li>
</ul>
</div>
<div>
<h2 class="eyebrow-heading-2">Upcoming Doses</h2>
<ul class="list" v-for="item in medications" :key="item.$id">
<li class="list-item">
<span class="text u-bold">Check in:</span>
{{ item.date.slice(0, 10) }}
</li>
<li class="list-item">
<span class="text u-bold">Doctor to see:</span>
{{ item.nameOfDoctor }}
</li>
<li class="list-item">
<span class="text u-bold">Shot:</span>
{{ item.typeOfDose }}
</li>
</ul>
</div>
</div>
</template>
<script setup>
import { getList } from '@/utils';
const medications = ref(null);
onMounted(() => {
getList.then(
function (response) {
medications.value = response.documents;
},
function (error) {
console.log(error);
}
);
});
</script>
The code block above does the following:
Using the Appwrite List Documents Databases API,
- We can query the list of documents from the Appwrite console
- Display the details using the v-for directives to loop through the object.
Finally, the app should look like this:
Conclusion
The Pink Design System is great for developers who need to build customized systems like dashboards for their products. It would help make the process faster and give you control over structuring the look and feel of an app embedded with classes.
Like every other dashboard on the internet, the primary purpose of creating one is to personalise different user profiles. Appwrite comes in handy as one of the best backend servers that populate data to the client side.
In this post, we learned how to use the Appwrite Databases service to query and list documents stored in Appwrite on the client side and Pink, an innovative approach that provides components to build dynamic and usable products.