Build a testimonial page with Appwrite Cloud using Nuxt
Tags: vue, javascript, nuxt, tutorial
Published: 2023-05-13 23:45:10

Most websites have a section dedicated to customer feedback on a product or service, which build trust and encourages others to try. A testimonial page is a statement about the validation and satisfaction of a company tool by happy customer comments on social media platforms like Twitter, LinkedIn, and so on.

Appwrite is an open-source backend platform alternative like Firebase, which provides all the necessary API features like authentication, databases, storage, functions, security and privacy, and so on for developing web, mobile, and flutter applications.

This tutorial will show you how to build a replica with Appwrite and Nuxt. 

See the testimonial on the [official Appwrite](https://appwrite.io/) page.

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


Let’s get started.


## GitHub and Demo

You can reference the complete source code [in this repo](https://github.com/Terieyenike/testimonials-with-appwrite), and to see the testimonial page in action, view the project demo [here](https://testimonials-with-appwrite.vercel.app/).


## Prerequisites

For this tutorial, you need the following:

- Have [Node >= 16](https://nodejs.org/) installed on your machine
- Knowledge of CSS
- Understanding of Vue.js 
- Have an Appwrite Cloud account

Request for an Appwrite Cloud, [here](https://appwrite.io/cloud).


## Setting up Appwrite Cloud

Appwrite Cloud is used to create a new project. On your dashboard, click the “+ Create project” button and give it a name.


![create a project](https://paper-attachments.dropboxusercontent.com/s_C794B99B8F50535167CA9DB330A6162279537D31F669EEC113790BBF0FD83F93_1683903465223_image.png)



## Creating a database

Navigate into the newly created “Testimonials” project, and on the left pane of the dashboard window, click **Databases** and create a database with a name.


![Create databases](https://paper-attachments.dropboxusercontent.com/s_C794B99B8F50535167CA9DB330A6162279537D31F669EEC113790BBF0FD83F93_1683911112198_image.png)


## Creating collections

By clicking on the created database, you can create a collection with the “**+ Create collection**” button. Give this collection ****a name.


![collections](https://paper-attachments.dropboxusercontent.com/s_C794B99B8F50535167CA9DB330A6162279537D31F669EEC113790BBF0FD83F93_1683913420555_image.png)


**Adding attributes**
This section is about creating field parameters to hold all the data necessary to display client-side information. Within the created collections, **testimonial-collection**, click on the **Attributes** tab to make the attributes for this app.


| Attribute Key | Attribute type | Format | Size | Default Value | Required |
| ------------- | -------------- | ------ | ---- | ------------- | -------- |
| comment       | String         |        | 1500 | -             | Yes      |
| imgUrl        | String         | url    |      | -             | Yes      |
| name          | String         |        | 255  | -             | Yes      |
| role          | String         |        | 255  | -             | Yes      |


**PS**: The **Document ID** generates automatically.


![attributes](https://paper-attachments.dropboxusercontent.com/s_C794B99B8F50535167CA9DB330A6162279537D31F669EEC113790BBF0FD83F93_1683924682531_image.png)


**Creating documents**
With all the attributes created in the **Collections**, let’s include some default data by clicking on the Documents tab and the “**+ Create document**” button. Now fill in data in the input field.


![create documents](https://paper-attachments.dropboxusercontent.com/s_C794B99B8F50535167CA9DB330A6162279537D31F669EEC113790BBF0FD83F93_1683925945933_image.png)


Next, select the **Settings** tab within the **Collections**, and update the permissions to manage user access and rights.


![permissions](https://paper-attachments.dropboxusercontent.com/s_C794B99B8F50535167CA9DB330A6162279537D31F669EEC113790BBF0FD83F93_1683924835508_image.png)


Also, you need to register your web app. On the left pane of your dashboard, click on **Overview** and the “**+ Add platform**” button. Choose the **Web App** option from the dropdown.


![register web app](https://paper-attachments.dropboxusercontent.com/s_C794B99B8F50535167CA9DB330A6162279537D31F669EEC113790BBF0FD83F93_1683925177756_image.png)

The asterisk (*) in the input field of the field **Hostname** ensures the web is accessible during development. If not set, cross-origin resource sharing (CORS) errors prevent access to the web app.


## Creating a Nuxt app

Nuxt is an open-source framework built on Vue.js that makes web development powerful. To scaffold a new Nuxt project, run this command in the terminal:

```bash
    npx nuxi init testimonials
```

Follow the on-screen instructions provided with the following commands:

```
    npm install
```

The above command is responsible for installing all the required dependencies. Next, navigate to the project directory and start the development server, which should run on `localhost:3000`:

```
    cd testimonials && npm run dev
```

![Nuxt app](https://paper-attachments.dropboxusercontent.com/s_98E65F8D31234D1FBC487A096B9A677CB51B08BD30207283061A296CA029A8CB_1682106983989_Screenshot+2023-04-20+at+12.16.19.jpg)


## Adding Tailwind CSS

Tailwind CSS is a utility-first CSS framework that uses classes directly in your markup. 

In the terminal, run this command to install the `@nuxtjs/tailwindcss` package:

```
    npm install -D @nuxtjs/tailwindcss
```

**Configuring Tailwind CSS**
Before you can see the action of Tailwind CSS, open the file `nuxt.config.ts` in the root directory and include the module option within the `defineNuxtConfig` object:

```javascript
    export default defineNuxtConfig({
      modules: ["@nuxtjs/tailwindcss"],
    });
```

## Creating environment variables

Environment variables store the secrets keys credentials from unauthorized access in the `.env` file. This step is essential to avoid committing and pushing your secrets to GitHub.

Check out [this resource](https://dev.to/hackmamba/how-to-create-environment-variables-in-nuxtjs-2dh4) on creating environment variables in a Nuxt application.


## Building the UI

The user interface for the testimonial page is a single page application (SPA) showing a collection of statements from satisfied customers or users of a product. 

Create a directory called **components** in the root directory, and include this file named `Testimonials.vue`.

The updated project tree directory should look like this:

```
    .
    ├── components
    │   ├── Testimonials.vue
    ├── pages
    │   └── index.vue
    ├── public
    ├── package.json
    ├── tsconfig.json
    ├── package-lock.json
    ├── README.md
    ├── nuxt.config.js
    └── app.vue
```

Copy-paste the following code into their respective files:

`components/Testimonials.vue`

```JavaScript
    <template>
      <section class="mx-auto max-w-6xl w-4/5 mt-10">
        <div>
          <h1 class="text-3xl font-serif mb-3 md:text-5xl lg:text-6xl">
            Testimonials
          </h1>
          <p class="mb-10 text-slate-700">
            Learn from experts what they love about Appwrite Cloud
          </p>
        </div>
        <div class="grid gap-6 md:grid-cols-2 xl:grid-cols-3">
          <div
            class="border-2 rounded-lg p-4 flex flex-col justify-between transition-all ease-out">
            <p class="text-sm md:text-lg">
              Appwrite provides web and mobile developers with a set of easy-to-use
              and integrate REST APIs to manage their core backend needs
            </p>
            <div class="flex items-center mt-7">
              <img
                src="https://res.cloudinary.com/terieyenike/image/upload/v1635347142/ypz0tuyz60hirt1obdba.jpg"
                class="shrink-0 w-12 h-12 rounded-full border-slate-200 shadow mr-4 bg-black object-cover"
                loading="lazy"
                alt="william smiling" />
              <div>
                <p>
                  <span class="font-bold">Willian Imoh</span>
                </p>
                <p class="text-xs md:text-sm font-light text-slate-700">
                  Product Manager
                </p>
              </div>
            </div>
          </div>
        </div>
      </section>
    </template>
```

The code above will style the page's content using Tailwind CSS, combining classes in each element. After that, import this component into the `index.vue` file in the **pages** folder:

`pages/index.vue`

```javascript
    <template>
      <testimonials />
    </template>
    
    <script setup>
    useHead({
      title: "Read customers' feedback",
    });
    </script>
```


The `useHead` is a Nuxt built-in component that helps to bind metadata to the head of the page, similar to the `<title>` in HTML.

Now, let’s ensure that this page appears in the browser by replacing the component `NuxtWelcome` to `NuxtPage` in the entry point of this project, `app.vue`:

`app.vue`

```javascript
    <template>
      <NuxtPage />
    </template>
```

Head over to your browser, and you should have something like this:


![Testimonial display in the browser](https://paper-attachments.dropboxusercontent.com/s_C794B99B8F50535167CA9DB330A6162279537D31F669EEC113790BBF0FD83F93_1683938966099_image.png)



## Displaying all user’s statement

Let’s display all the feedback from customers or users of a product from the server which uses Appwrite databases API, list documents.

Let’s update the component, `Testimonials.vue`, with this code:

`components/Testimonials.vue`

```javascript
    <template>
      <section class="mx-auto max-w-6xl w-4/5 mt-10">
        <div>
          <h1 class="text-3xl font-serif mb-3 md:text-5xl lg:text-6xl">
            Testimonials
          </h1>
          <p class="mb-10 text-slate-700">
            Learn from experts what they love about Appwrite Cloud
          </p>
        </div>
        <div class="grid gap-6 md:grid-cols-2 xl:grid-cols-3">
          <div
            class="border-2 rounded-lg p-4 flex flex-col justify-between transition-all ease-out"
            v-for="item in items"
            :key="item.$id">
            <p class="text-sm md:text-lg">
              {{ item.comment }}
            </p>
            <div class="flex items-center mt-7">
              <img
                :src="item.imgUrl"
                class="shrink-0 w-12 h-12 rounded-full border-slate-200 shadow mr-4 bg-black object-cover"
                loading="lazy"
                :alt="item.role" />
              <div>
                <p>
                  <span class="font-bold">{{ item.name }}</span>
                </p>
                <p class="text-xs md:text-sm font-light text-slate-700">
                  {{ item.role }}
                </p>
              </div>
            </div>
          </div>
        </div>
      </section>
    </template>
    
    <script setup>
    import { Client, Databases } from "appwrite";
    
    const runtimeConfig = useRuntimeConfig();
    
    const client = new Client();
    const databases = new Databases(client);
    
    client
      .setEndpoint(runtimeConfig.public.API_ENDPOINT)
      .setProject(runtimeConfig.public.PROJECT_ID);
    
    const getComment = databases.listDocuments(
      runtimeConfig.public.DATABASE_ID,
      runtimeConfig.public.COLLECTION_ID
    );
    
    const items = ref(null);
    
    onMounted(() => {
      getComment.then(
        function (response) {
          items.value = response.documents;
        },
        function (error) {
          console.log(error);
        }
      );
    });
    </script>
```

The code above does this:

- Import the Appwrite package and initialize the new instance using the web software development kit (SDK)
- The `useRuntimeConfig()` function is for accessing the environment variables defined in the `nuxt.config.ts` file
- The component mount using the `onMounted` lifecycle hook and the `getComment` function gets all the **items** from the **collections** in the server
- Loop through the items using the `v-for` directive to get the individual testimonial listed in a grid

At this point, the app should look like this:


![final demo](https://paper-attachments.dropboxusercontent.com/s_C794B99B8F50535167CA9DB330A6162279537D31F669EEC113790BBF0FD83F93_1683983556224_image.png)



## Conclusion

Having a testimonial on your website is something every brand should adopt because it makes you look good externally before anyone tries the product. 

To extend this application, you can create a form on your website to allow users to submit feedback to the server.

## Resources
- [Environment variables](https://nuxt.com/docs/guide/going-further/runtime-config)
- [Nuxt documentation](https://nuxt.com/docs)
- [Appwrite databases API](https://appwrite.io/docs/client/databases?sdk=web-default#databasesListDocuments)
- [Styling with Tailwind CSS](https://tailwindcss.com/docs/installation)