Create a Temperature converter using NextJs, Tailwind CSS & Strapi
Tags: nextjs, tailwindcss, strapi, tutorial
Published: 2021-11-05 09:37:54


This article will show you how to build a Temperature Converter with Next.js and Tailwind CSS as frontend and Strapi headless CMS as backend. You can find a link to the finished frontend code [here](https://github.com/chyke007/strapi-nextjs-tutorial-temperature), as well as the finished backend [here](https://github.com/chyke007/strapi-tutorial-temperature)

## Prerequisite

Before starting this tutorial, you need to have

- Node.js installed on your local machine (v12 or v14) - Check this [tutorial](https://codex.so/how-to-install-the-latest-node-js-npm-and-yarn) for instructions on how to install Node.js
- Basic understanding of Strapi - Get started with this [quick guide](https://strapi.io/documentation/developer-docs/latest/getting-started/quick-start.html)
- Basic knowledge of [Next.js](https://nextjs.org/docs/getting-started)
- Basic knowledge of [Tailwind CSS](https://tailwindcss.com/docs)

## What is Next Js

Next.js is an awesome React framework for building highly dynamic applications. It comes with pre-rendering, automatic code-splitting amongst many other great features out of the box.

## What is Tailwind CSS

Tailwind is a utility-first CSS framework for rapidly building custom user interfaces. By using Tailwind, we can write our css directly in our HTML classes. This leads to a faster development time.

## What is Strapi

Strapi is a Node.js open-source headless CMS that allows us to develop APIs and manage content easily without the hassle of building out a project from scratch.

We can easily build out APIs faster and consume the contents via APIs using any REST API client or GraphQL.


## Scaffolding a Strapi Project

To setup a new Strapi Project is quite straightforward and simple as running these few commands:

```bash
    npx create-strapi-app temperature-converter --quickstart
```

Change `temperature-converter` to the preferred name of your project

**Nb: During the setup we would not be using any Strapi template**

This will install and create a Strapi application and set up the project locally.

After installation, the browser would open a page on localhost:1337 which would prompt to set up first admin account to proceed with Strapi.

## Building the Temperature collection

Next, we will create a new collection type that will store the details of each temperature converter.
In this article, we will create a collection type called ‘temperature’ that has these fields: from, to, multiplier, offset, offset_add



![](https://paper-attachments.dropbox.com/s_1F009F9E3EE9CBA1F20D406E4458E971D06EA9323A4B53D1F0303E815DE8B180_1633617995927_Screenshot+2021-10-07+at+15.46.29.png)


Clicking “Continue” would bring up another screen to select the fields for this collection. Choose the “Text” field from the list and provide `from` as its name. 


![](https://paper-attachments.dropbox.com/s_1F009F9E3EE9CBA1F20D406E4458E971D06EA9323A4B53D1F0303E815DE8B180_1633618391565_Screenshot+2021-10-07+at+15.53.03.png)


Click “Advanced settings” and check the “Required field” box to ensure this field is required when creating a new temperature converter.


![](https://paper-attachments.dropbox.com/s_1F009F9E3EE9CBA1F20D406E4458E971D06EA9323A4B53D1F0303E815DE8B180_1634595892206_Screenshot+2021-10-18+at+23.24.46.png)


We click on the Add another field to add the remaining fields. Below is a table showing the properties for each field in this collection:

| **Field Name** | **Field Type**  | Required |
| -------------- | --------------- | -------- |
| from           | short text      | true     |
| to             | short text      | true     |
| multiplier     | number(decimal) | true     |
| offset         | number(float)   | true     |
| offset_add     | number(decimal) | true     |

## Seeding Strapi

We would now need to seed our collection to have the predefined parameters we need in our formula.

To add data to the collection, we select the Temperature Collection on the left sidebar, click “Add New Temperature” and fill in the details.


![](https://paper-attachments.dropbox.com/s_1F009F9E3EE9CBA1F20D406E4458E971D06EA9323A4B53D1F0303E815DE8B180_1634596425965_Screenshot+2021-10-18+at+23.33.42.png)


After Seeding we would have the collection populated as such:

![](https://paper-attachments.dropbox.com/s_1F009F9E3EE9CBA1F20D406E4458E971D06EA9323A4B53D1F0303E815DE8B180_1634597346696_Screenshot+2021-10-18+at+23.49.02.png)



## Allowing Public access

By default, whenever you create an API, Strapi creates six endpoints from the name given to the API. The endpoints generated for temperature should look like this:

![](https://paper-attachments.dropbox.com/s_1F009F9E3EE9CBA1F20D406E4458E971D06EA9323A4B53D1F0303E815DE8B180_1634597663434_Screenshot+2021-10-18+at+23.54.19.png)


By default, they’re all going to be restricted from public access. We need to tell Strapi that you’re okay with exposing these checked endpoints to the public. Go to *Settings > Users & Permissions Plugin*  ****** *> Roles* and click to edit the *Public Role*. Next scroll down to permissions and check `find`  for Temperature.

This endpoint: http://localhost:1337/temperatures should now be available


## Scaffolding a NextJs project

**Create a Next.js app**

To create a Next.js app, open your terminal, `cd` into the directory you’d like to create the app in, and run the following command:

```bash
    npx create-next-app -e with-tailwindcss nextjs-temperature
```

This would also configure Tailwind CSS with the project.

**Run the** **Next.js** **development server**

Next we `cd` into the newly created directory, in our case that would be `nextjs-temperature`

```
    cd nextjs-temperature
```

After which we start up the development server, by running this command:

```
    npm run dev
```

If everything was set up fine, the next.js server should now be running on http://localhost:3000 we should get this shown on our browser:



![](https://paper-attachments.dropbox.com/s_1F009F9E3EE9CBA1F20D406E4458E971D06EA9323A4B53D1F0303E815DE8B180_1634387555599_Screenshot+2021-10-16+at+13.32.30.png)



## Building NextJs Components

After setup we should have a folder structure such as this:

![](https://paper-attachments.dropbox.com/s_1F009F9E3EE9CBA1F20D406E4458E971D06EA9323A4B53D1F0303E815DE8B180_1634568345150_Screenshot+2021-10-18+at+15.45.40.png)


Next, we create the temperature converter page. We open the `index.js` file in our favourite text editor, we delete its contents and replace them with the file content below:

```
    import Head from 'next/head'
    import { useState, useEffect } from 'react'
    import { converter, fetchQuery, getUniqueTemp } from '../utils/helper'
    export default function Home({ temperatures }) {
      const [answer, setAnswer] = useState('')
      const [from, setFrom] = useState('C')
      const [to, setTo] = useState('F')
      const [temperature, setTemperature] = useState(1)
      const [options, setOptions] = useState([])
      useEffect(() => {
        setOptions(getUniqueTemp(temperatures, 'from'))
      }, [temperatures])
      
      const handleSubmit = (e) => {
        e.preventDefault()
        setAnswer(`${converter(temperatures, from, to, Number(temperature))} ${to}`)
      }
    
      return (
        <div className="flex flex-col items-center justify-center min-h-screen py-2">
          <Head>
            <title>Temperature Converter</title>
            <link rel="icon" href="/favicon.ico" />
          </Head>
          <main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-center">
            <h1 className="text-6xl font-bold">
              Temperature {' '}
              <a className="text-blue-600" href="https://nextjs.org">
               Converter
              </a>
            </h1>
            <form className="space-y-4 text-gray-700" onSubmit={handleSubmit}>
      <div className="flex flex-wrap">
       
      </div>
      <div className="flex flex-wrap -mx-2 space-y-4 md:space-y-0">
        <div className="w-full px-2 md:w-1/2">
          <label className="block mb-1">From</label>
          <select className="w-full h-10 pl-3 pr-6 text-base placeholder-gray-600 border rounded-lg appearance-none focus:shadow-outline" placeholder="Select From" value={from} onChange={ (e) => { setFrom(e.target.value)}}>
          {options.map(e => (
             <option value={e} key={e}>{e}</option>
          ))}
         </select>
        </div>
        <div className="w-full px-2 md:w-1/2">
          <label className="block mb-1" >To</label>
          <select className="w-full h-10 pl-3 pr-6 text-base placeholder-gray-600 border rounded-lg appearance-none focus:shadow-outline" placeholder="Select To" value={to} onChange={ (e) => { setTo(e.target.value)}}>
          {options.map(e => (
             <option value={e} key={e}>{e}</option>
          ))}
         </select>
        </div>
      </div>
      <div className="flex flex-wrap -mx-2 space-y-4 md:space-y-0">
        <div className="w-full px-2 md:w-1/2">
          <label className="block mb-1">Value</label>
          <input className="w-full h-10 px-3 text-base placeholder-gray-600 border rounded-lg focus:shadow-outline" type="number" value={temperature} onChange={ (e) => { setTemperature(e.target.value)}}/>
        </div>
        <div className="w-full px-2 md:w-1/2">
        <input className="w-full h-10 px-3 my-7 cursor-pointer text-base placeholder-gray-600 border rounded-lg focus:shadow-outline hover:bg-blue-600 hover:text-white" type="submit" value="Convert"/>
        </div>
      </div>
    </form>
            <div>
              Result is : {answer}
            </div>
          </main>
        </div>
      )
    }
    export async function getStaticProps() {
      const temperatures = await fetchQuery('temperatures')
      return {
        props: {
          temperatures
        }
      }
    }
```

This file is the entry point to our app. We use it to  create out a design for the app, and also set up our functionalities to handle the conversion process. We proceed to create a **utils** folder at the root of our project and create a file called `helper.js` in it, this file would be where we place all helper functions.

This `helper.js` file would contain basic helper functions that would help us convert the temperature as well as get data from the Strapi backend server.

```
    const baseUrl = process.env.BASE_URL || 'localhost:1337'
    export const converter = (temperatures, from, to, val) => {
      let temperature = {}
      let answer = 0
      switch(`${from}-${to}`){
        case 'F-C':
          temperature = getFields(temperatures, from, to)
          answer = (((val + temperature.offset) * temperature.multiplier ) + temperature.offset_add)
          break;
        case 'C-F':
          temperature = getFields(temperatures, from, to)
          answer = (((val + temperature.offset) * temperature.multiplier ) + temperature.offset_add)
          break;
        case 'C-K':
          temperature = getFields(temperatures, from, to)
          answer = (((val + temperature.offset) * temperature.multiplier ) + temperature.offset_add)
          break;
        case 'K-C':
          temperature = getFields(temperatures, from, to)
          answer = (((val + temperature.offset) * temperature.multiplier ) + temperature.offset_add)
          break;
        case 'F-K':
          temperature = getFields(temperatures, from, to)
          answer = (((val + temperature.offset) * temperature.multiplier ) + temperature.offset_add)
          break;
        case 'K-F':
          temperature = getFields(temperatures, from, to)
          answer = (((val + temperature.offset) * temperature.multiplier ) + temperature.offset_add)
          break;
        default:
          answer = val
          break;
      }
      return answer
    }
    export const getFields = (array, from, to) => {
      return array.find(x => x.from === from && x.to === to)
    }
    export const fetchQuery = async (path, params = null) => {
      let url
      if (params !== null) {
        url = `${baseUrl}/${path}/${params}`
      } else {
        url = `${baseUrl}/${path}`
      }
      const response = await fetch(`http://${url}`)
      const data = await response.json()
      return data
    }
    export const getUniqueTemp = (arr, key) => {
      let keys = arr.map(function(item) { return item[key]; })
      return [...new Set(keys)]
    }
```

## Finished App

The finished app looks like this:

![](https://paper-attachments.dropbox.com/s_1F009F9E3EE9CBA1F20D406E4458E971D06EA9323A4B53D1F0303E815DE8B180_1634732683979_Screenshot+2021-10-20+at+13.24.38.png)

## Conclusion

And that's it, we saw how to set up a temperature converter using Strapi, Next.js and Tailwind CSS. This article can be taken further to be used as a base for other kinds of conversions. This goes to show what we can achieve using this setup and the possibilities therein.