DEV Community

Cover image for Create a Temperature converter using NextJs, Tailwind CSS & Strapi
Shada for Strapi

Posted on • Originally published at strapi.io

Create a Temperature converter using NextJs, Tailwind CSS & Strapi

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, as well as the finished backend here

Prerequisite

Before starting this tutorial, you need to have

  • Node.js installed on your local machine (v12 or v14) - Check this tutorial for instructions on how to install Node.js
  • Basic understanding of Strapi - Get started with this quick guide
  • Basic knowledge of Next.js
  • Basic knowledge of Tailwind CSS

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:

    npx create-strapi-app temperature-converter --quickstart
Enter fullscreen mode Exit fullscreen mode

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

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.

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

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.

After Seeding we would have the collection populated as such:

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:

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:

    npx create-next-app -e with-tailwindcss nextjs-temperature
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

    npm run dev
Enter fullscreen mode Exit fullscreen mode

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:

Building NextJs Components

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

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
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

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)]
    }
Enter fullscreen mode Exit fullscreen mode

Finished App

The finished app looks like this:

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.

Latest comments (0)