How to Build a Hospital Record App with NextJs and Strapi
Tags: javascript, strapi, nextjs
Published: 2022-04-20 09:20:12

## Introduction

Hospital records help to provide information on the background health conditions of prospective patients. There is a need to have an easily retrievable and accessible means of getting this record. We will solve this case study using the Strapi Content Management System to access and store patient records in an application.


## Goal

In this article, we will build a Record application focusing on Patient Records. The app will focus on managing patient records in relations using the Strapi CMS and will provide all records to any patient when a request is made. These records will be fetched from an API and managed in Strapi.
 

## Prerequisites

To follow up on this tutorial, prior knowledge of NextJs and APIs is required.

## What is Strapi?

Strapi is an open-source, headless Content Management System that was developed using the Nodejs Javascript framework. Strapi provides users with features to enable them to store, manipulate, and manage content across their application workflows. It's simple and easy to use, and with its administrative panel, users can easily monitor and manage their content.
What's more? With Strapi, we can integrate APIs that can provide and manage content stored on the Strapi CMS.


## Setting up a Strapi Project

To set up our Strapi back-end, we will first create a directory for our project using the following code in CLI:

```
       mkdir recordapp
```

This creates a folder for our project `recordapp`. Next, we move into this folder:

```
    cd recordapp
```

Then, we install Strapi:

```
    npx create-strapi-app@latest record-backend --quickstart
```

The command above sets up Strapi for our app with all required dependencies and creates a new folder `record-backend` for this.


![Strapi Installation](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1642862285081_11.png)


Once the installation is complete, it will start up the server which you can view in your browser via the specified link. In your browser, you will have a result similar to the image below:


![Sign up Page](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1642862454591_1.png)


Here, simply fill in the required details and create a user account to access your dashboard. 


![Strapi Dashboard](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1642862800388_2.png)


Here we will set up the collection for our application.

Before we create our Strapi collection for our data, we have to understand how our hospital record app should operate. The application is to be able to facilitate identifying specific patient records on query. We will use `MeiliSearch` to make looking up of content in each record easier. With this, we can easily search for and get results from our Strapi collection showing content that have data related to the search keyword.

To set up our content, we will start by defining the content we wish to store on Strapi. To do this: first click on the `Create your first Content Type` button.


![Creating a Collection type](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1644330749846_patient+creation1.png)


On the new page that opens up, click on `Create new collection type`.


![Defining the collection type](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1644330777246_patient+creation2.png)


On the next page, we get different content types we can create for our collection.


![Adding content to the Collection](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1644331162849_patient+creation3.png)


We will create fields for the patients. These fields will include: name, surname, age, blood_type, ailment, medicine, last_visit, allergies, next_of_kin, next_of_kin_contact, gender, and address. All of these fields will be text fields except the age and last visit which would be of type number and date respectively.


![Patient Collection Contents](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1644331741977_created+fields.png)


Above are all the fields for the patient record. After creation, click on the `save` button at the top right.

## Building the Records App

With our content setup on Strapi CMS complete, the next thing we need to do is to build the front-end of our application. To do this, we will be using the [NextJs](https://nextjs.org/) framework which is an open-source Javascript framework developed on [NodeJs](https://nodejs.org/en/) to render applications on server-side as opposed to client-side rendering by [ReactJs](https://reactjs.org/).

To install NextJs, enter the following command in your terminal:

```
      npx create-next-app hospitalrecords
```

We will be using Tailwind CSS to scaffold our application. This can be installed in CLI with the following command:

```
    npm install -D tailwindcss postcss autoprefixer
    npx tailwindcss init -p
```

This creates a project folder `hospitalrecords` in your current directory. The created folder has the NextJs framework installed and we will use it to scaffold our application. The images below show what our finished app will look like.

Landing Section:

![Preview of landing section of the app](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1643314808003_app1.png)


Search Section:

![Search section of the hospital App](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1643314829758_app2.png)


Patient Info section:

![Patient info display section](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1644086261530_datqa+display.png)


Here is the tree structure of our application:


    ...
     ┣ 📂pages
     ┃ ┣ 📂api
     ┃ ┃ ┗ 📜hello.js
     ┃ ┣ 📂Components
     ┃ ┃ ┣ 📜Cards.js
     ┃ ┃ ┣ 📜Data.js
     ┃ ┃ ┣ 📜Footer.js
     ┃ ┃ ┣ 📜Landing.js
     ┃ ┃ ┣ 📜Record.js
     ┃ ┃ ┗ 📜Topnav.js
     ┃ ┣ 📜index.js
     ┃ ┗ 📜_app.js
     ┣ 📂public
     ┃ ┣ 📜favicon.ico
     ┃ ┣ 📜hosrecords.png
     ┃ ┗ 📜vercel.svg
     ┣ 📂styles
     ┃ ┣ 📜globals.css
     ┃ ┗ 📜Home.module.css
     ┣ 📜.eslintrc.json
     ┣ 📜.gitignore
     ┣ 📜next.config.js
     ┣ 📜package-lock.json
     ┣ 📜package.json
     ┣ 📜postcss.config.js
     ┣ 📜README.md
     ┗ 📜tailwind.config.js

Here, the `index.js` file contains all the components for the web page. In this file, we have:

```
    import styles from '../styles/Home.module.css'
    import Topnav from './Components/Topnav'
    import Landing from './Components/Landing'
    import Record from './Components/Record'
    import Cards from './Components/Cards'
    import Footer from './Components/Footer'
    export default function Home() {
      return (
        <div className="font-Roboto">
          <Topnav/>
          <Landing/>
          <Record/>
          <Cards/>
          <Footer/>
        </div>
      )
    }
```

Taking the components in order, the `Topnav` component contains the website’s navigation bar and has the following code:

```
    import { React, useState } from "react";
    import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
    import { faBars } from "@fortawesome/free-solid-svg-icons";
    import { faTimes } from "@fortawesome/free-solid-svg-icons";
    function Topnav() {
      const [show, setShow] = useState(false);
      return (
        <header>
          <div
            className=" w-screen fixed flex items-center justify-center px-2 top-2 z-20"
            
          >
            <nav className=" container flex items-start py-4 mt-4 sm:mt-12 backdrop-blur-md relative">
              {/* <nav className=" z-20 fixed container flex items-start py-4 mt-4 sm:mt-12 backdrop-blur top-1 lg:left-20 lg:w-full md:left-0 sm:left-0"> */}
              <div className=" relative">
                <h1 className=" text-blue-600 font-bold text-2xl">
                  Hospital Records
                </h1>
              </div>
              <ul className="hidden sm:flex flex-1 justify-end items-center gap-12 text-slate-900 uppercase text-base font-medium md:py-1">
                <li className="cursor-pointer">
                  <a href="#Home">Home</a>
                </li>
                <li className=" cursor-pointer">
                  <a href="#Search">Search</a>
                </li>
                <li className=" cursor-pointer">
                  <a href="http://strapi.io" target="_blank" rel="noreferrer">About Strapi</a>
                </li>
              </ul>
              {show ? (
                <ul className="navigation sm:flex flex-1 md:hidden justify-end items-center gap-12 text-slate-900 uppercase text-xs md:py-1">
                  <li className="cursor-pointer">
                    <a href="#Home" onClick={() => setShow(!show)}>Home</a>
                  </li>
                  <li className=" cursor-pointer">
                    <a href="#Search" onClick={() => setShow(!show)}>Search</a>
                  </li>
                  <li className=" cursor-pointer">
                    <a href="http://strapi.io" target="_blank" rel="noreferrer" onClick={() => setShow(!show)}>About Strapi</a>
                  </li>
                </ul>
              ) : null}
              <div
                className="flex sm:hidden flex-1 justify-end z-40"
                onClick={() => setShow(!show)}
              >
                <FontAwesomeIcon
                  className=" text-2xl"
                  icon={show ? faTimes : faBars}
                />
              </div>
            </nav>
          </div>
        </header>
      );
    }
    export default Topnav;
```

Next, `Landing.js` is the website’s landing section:

```
    import React from "react";
    import Image from "next/image";
    function Landing() {
      return (
        <div>
          <section className=" relative" id="Home">
            {/* hero section */}
            <div className=" container flex flex-col-reverse lg:flex-row items-center gap-12 mt-14 lg:mt-28">
              {/* content */}
              <div className="flex flex-1 flex-col items-center lg:items-start">
                <h2 className=" text-3xl text-blue-600 md:text-4xl lg:text-5xl text-center lg:text-left mb-6">
                  Hospital Patient Records available on Search
                </h2>
                <p className=" text-lg text-center lg:text-left mb-6 text-gray-600">
                  A simple app mimicking digitalized hospital records. Built on
                  NextJs and powered by Strapi.
                </p>
                <div className=" flex justify-center flex-wrap gap-6">
                  <button className=" btn border-2 hover:bg-white hover:text-blue-600 hover:border-blue-600 hover:border-2">
                    <a href="#Search">Try it out</a>
                  </button>
                </div>
              </div>
              {/* image */}
              <div className=" flex justify-center flex-1 mb-10 md:mb-16 lg:mb-0 z-10">
                <Image
                  src="/hosrecords.png"
                  height={500}
                  width={500}
                  className=" w-5/6 h-5/6 sm:h-3/4 md:w-full md:h-full"
                  alt="stethoscope and record"
                />
              </div>
            </div>
            {/* container attachment shape */}
            <div className="hidden md:flex items-center justify-center overflow-hidden absolute h-96 w-2/4 top-14 right-0 lg:-bottom-28 lg:right-36 lg:w-2/5">
              <svg
                viewBox="0 0 500 500"
                xmlns="http://www.w3.org/2000/svg"
                width="450px"
                id="blobSvg"
              >
                <defs>
                  <linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%">
                    <stop offset="0%" stop-color="rgb(37, 99, 235)"></stop>
                    <stop offset="100%" stop-color="rgb(196, 224, 229)"></stop>
                  </linearGradient>
                </defs>
                <path fill="url(#gradient)">
                  <animate
                    attributeName="d"
                    dur="8000ms"
                    repeatCount="indefinite"
                    values="M439.5,306Q444,362,396.5,392Q349,422,299.5,459.5Q250,497,211.5,440.5Q173,384,111,375Q49,366,54,308Q59,250,67.5,200Q76,150,106.5,102Q137,54,193.5,49.5Q250,45,300.5,60Q351,75,381.5,115.5Q412,156,423.5,203Q435,250,439.5,306Z;
                    M442.5,289.5Q387,329,378,393Q369,457,309.5,429.5Q250,402,188.5,432.5Q127,463,118.5,397Q110,331,103.5,290.5Q97,250,78,195Q59,140,100,100Q141,60,195.5,52Q250,44,293,72.5Q336,101,359,137.5Q382,174,440,212Q498,250,442.5,289.5Z;
                    M435.5,310Q457,370,412.5,412Q368,454,309,459Q250,464,188,464.5Q126,465,83,418Q40,371,56.5,310.5Q73,250,91,209.5Q109,169,134,130.5Q159,92,204.5,67Q250,42,310.5,41.5Q371,41,379.5,105.5Q388,170,401,210Q414,250,435.5,310Z;
                    M456,301Q426,352,388.5,388.5Q351,425,300.5,414Q250,403,200.5,412Q151,421,116.5,384Q82,347,79.5,298.5Q77,250,61.5,191Q46,132,105,117Q164,102,207,84.5Q250,67,288.5,92Q327,117,378,132Q429,147,457.5,198.5Q486,250,456,301Z;
                    M413,296.5Q411,343,388.5,397Q366,451,308,427Q250,403,194.5,422.5Q139,442,86.5,408.5Q34,375,47,312.5Q60,250,76,204.5Q92,159,119.5,115.5Q147,72,198.5,63.5Q250,55,292.5,79Q335,103,372.5,130Q410,157,412.5,203.5Q415,250,413,296.5Z;
                    M439.5,306Q444,362,396.5,392Q349,422,299.5,459.5Q250,497,211.5,440.5Q173,384,111,375Q49,366,54,308Q59,250,67.5,200Q76,150,106.5,102Q137,54,193.5,49.5Q250,45,300.5,60Q351,75,381.5,115.5Q412,156,423.5,203Q435,250,439.5,306Z
                    "
                    fill="url(#gradient)"
                  ></animate>
                </path>
              </svg>
            </div>
          </section>
        </div>
      );
    }
    export default Landing;
```

The `Records` component contains the search bar for patient records.

```
    import React from "react";
    
    function Record(props) {
      return (
        <div>
          <section className=" bg-gray-100 py-20 mt-20 lg:mt-60" id="Search">
            <div className="sm:w-3/4 lg:w-5/12 mx-auto">
              <h2 className=" text-3xl text-blue-600 text-center font-bold">
                Search for Records
              </h2>
              <p className=" text-gray-600 text-center mt-4">
                Enter a random name in the search box below and see what records pop
                up....
              </p>
              <div className=" flex flex-col sm:flex-row gap-6 mt-8">
                <input
                  type="text"
                  placeholder="Enter patient name"
                  className=" focus:outline-none flex-1 px-2 py-3 rounded-md text-black border-2 border-blue-600"
                ></input>
                <button className=" btn flex-1 border-2 hover:bg-white hover:text-blue-600 hover:border-blue-600 hover:border-2">
                  Search
                </button>
                {/* grid collection */}
              </div>
            </div>
          </section>
        </div>
      );
    }
    export default Record;
```

`Card.js` is where the fetched data from Strapi will be displayed to the user:

```
    import {React, useState} from 'react';
    import Data from './data';
    function Cards() {
      const [data, moreData] = useState(false)
      const pull_data =(dat)=>{
        moreData(dat)
        console.log(dat)
      }
      return <div className=' relative'>
      <div className=" container grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-16 max-w-screen-lg mt-8 py-12">
          <div className=' flex flex-col rounded-md shadow-2xl'>
              <div className=' p-6 flex flex-col items-center'>
                  <h1 className=' text-4xl font-black text-blue-600 uppercase'>M</h1>
                  <h3 className=' mt-6 mb-2 text-xl'>Samuel Harrison</h3>
                  <hr className=' w-2/5 border-b border-blue-600'></hr>
                  <div className=' flex p-6'>
                  <button className=" btn hover:bg-white hover:text-blue-600 border-2 hover:border-blue-600 hover:border-2">
                  More Info
                </button>
                  </div>
              </div>
          </div>
          <div className=' flex flex-col rounded-md shadow-2xl'>
              <div className=' p-6 flex flex-col items-center'>
                  <h1 className=' text-4xl font-black text-blue-600 uppercase'>F</h1>
                  <h3 className=' mt-6 mb-2 text-xl'>Anita Florence</h3>
                  <hr className=' w-2/5 border-b border-blue-600'></hr>
                  <div className=' flex p-6'>
                  <button className=" btn hover:bg-white hover:text-blue-600 border-2 hover:border-blue-600 hover:border-2">
                  More Info
                </button>
                  </div>
              </div>
          </div>
          <div className=' flex flex-col rounded-md shadow-2xl'>
              <div className=' p-6 flex flex-col items-center'>
                  <h1 className=' text-4xl font-black text-blue-600 uppercase'>M</h1>
                  <h3 className=' mt-6 mb-2 text-xl'>James Micheal</h3>
                  <hr className=' w-2/5 border-b border-blue-600'></hr>
                  <div className=' flex p-6'>
                  <button className=" btn hover:bg-white hover:text-blue-600 border-2 hover:border-blue-600 hover:border-2"
                  onClick={()=> moreData(true)}
                  >
                  More Info
                </button>
                  </div>
              </div>
          </div>
      </div>
      {/* More info on Patient Data */}
      <Data open= {data} func={pull_data}/>
      </div>
    }
    export default Cards;
```

It contains a child component `Data` that completely displays a selected patient’s data. `Data.js` contains the following lines of code:

```
    import { React, useState } from "react";
    function Data(props) {
      // const [newData, setNewData] = useState(null);
      // props.func(newData)
      const handleclick = () => {
          props.func(false)
      };
      console.log(props.open);
      return (
        <div>
          {props.open ? (
            <div className=" absolute h-full flex justify-center items-center w-full top-0 backdrop-blur-md flex-col">
              <button
                className="btn hover:bg-white hover:text-blue-600 border-2 hover:border-blue-600 hover:border-2 mb-1"
                onClick={() => handleclick()}
              >
                Close
              </button>
              <div className=" relative py-3 px-6 bg-white font-Roboto font-medium shadow-2xl">
                <h1 className=" text-center text-3xl font-extrabold mb-5">M</h1>
                <h3 className=" mb-1">Name: John Doe</h3>
                <p className=" mb-1">Age: 25</p>
                <p className=" mb-1">Blood Type: O</p>
                <p className=" mb-1">Ailment: Cancer</p>
                <p className=" mb-1">Medicine: Aspirin</p>
                <p className=" mb-1">Last visit: 12/12/12</p>
                <p className=" mb-1">Allergies: None</p>
                <p className=" mb-1">Next of Kin: Isaac Doe</p>
                <p className=" mb-1">Next of Kin Contact: 0700000</p>
                <p className=" mb-1">1, Main Street, Dublin, Ireland</p>
              </div>
            </div>
          ) : null}
        </div>
      );
    }
    export default Data;
```

Currently, the `Card` and `Data` components contain hard-coded values but these will be replaced as we proceed with building the application.

And finally, there’s the `Footer.js` Component with the following code:

```
    import React from 'react';
    function Footer() {
      return <footer className=' bg-blue-600 py-8 flex items-center justify-center mt-10'>
        <div>
            <h3 className=' text-white font-medium text-xl'>Made with StrapiCMS and NextJs</h3>
        </div>
      </footer>;
    }
    export default Footer;
```

Next in the tree above are the style sheets. The `global.module.css` file has been slightly modified to make use of Tailwind styles.

```
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    @import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
    .btn{
      @apply shadow-md py-3 px-6 rounded-md transition duration-300 text-white bg-blue-600 outline-none 
    }
    .navigation{
      text-transform: uppercase;
      opacity: 0;
    }
      @media screen and (max-width: 640px){
        .navigation{
          @apply  absolute h-screen bg-white z-30 w-screen left-0 flex items-center justify-center flex-col gap-44 uppercase font-bold text-2xl top-0 transition-opacity ease-in opacity-100
        }
      }
    
    html,
    body {
      padding: 0;
      margin: 0;
      font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
        Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
        scroll-behavior: smooth;
    }
    a {
      color: inherit;
      text-decoration: none;
    }
    * {
      box-sizing: border-box;
    }

There is also a custom font defined here which was used in the application. Also, I’ve made changes to the properties of the `container`Tailwind class, and added the font imported above in the `tailwind.config.js` file:

    module.exports = {
      content: [
        "./pages/**/*.{js,ts,jsx,tsx}",
        "./components/**/*.{js,ts,jsx,tsx}",
      ],
      theme: {
        extend: {},
        fontFamily: {
          Roboto: ["Roboto, sans-serif"]
        },
        container: {
          center: true,
          padding: "1rem",
          screens: {
            lg: "1124px",
            xl: "1124px",
            "2xl": "1124px",
          },
        },
      },
      plugins: [],
    }
```

You can run the application with the `npm run dev` command in CLI to get a result similar to the images above.

## Building the Patients API

For the purpose of this tutorial, we will be building a simple API to handle our patient’s data. For this, we will be making use of Node.js, express.js and a JSON file. 
First, we will create a new folder called `api handler` . This file will be where we will build and set up our API. Next we will create a JSON file containing our data. The file will be called `patients.json` and will contain the following:

```
    [
      {
        "name": "John",
        "surname": "Doe",
        "age": "25",
        "bloodtype": "O",
        "ailment": "Cancer",
        "medicine": "Aspirin",
        "last_visit": "2020-06-01",
        "allergies": "None",
        "next_of_kin": "Isaac Doe",
        "next_of_kin_contact": "07000000",
        "gender": "male",
        "address": "1, Main Street, Dublin, Ireland"
      },
      {
        "name": "Newton",
        "surname": "Dannet",
        "age": "46",
        "bloodtype": "AB",
        "ailment": "none",
        "medicine": "Aspirin",
        "last_visit": "2020-03-12",
        "allergies": "None",
        "next_of_kin": "Clover Dannet",
        "next_of_kin_contact": "071111111",
        "gender": "male",
        "address": "1, Main Street, Dublin, Ireland"
      },
      {
        "name": "Grace",
        "surname": "Dommy",
        "age": "64",
        "bloodtype": "A",
        "ailment": "Diabetes",
        "medicine": "Aspirin",
        "last_visit": "2020-01-01",
        "allergies": "None",
        "next_of_kin": "Anny Dommy",
        "next_of_kin_contact": "0722222",
        "gender": "female",
        "address": "1, Main Street, Dublin, Ireland"
      },
      {
        "name": "Henry",
        "surname": "Derry",
        "age": "19",
        "bloodtype": "AB",
        "ailment": "none",
        "medicine": "none",
        "last_visit": "2021-09-01",
        "allergies": "None",
        "next_of_kin": "Ben Derry",
        "next_of_kin_contact": "07333333",
        "gender": "male",
        "address": "1, Main Street, Dublin, Ireland"
      },
      {
        "name": "Fred",
        "surname": "Eddy",
        "age": "28",
        "bloodtype": "B",
        "ailment": "none",
        "medicine": "Aspirin",
        "last_visit": "2022-01-011",
        "allergies": "None",
        "next_of_kin": "Eddy Edd",
        "next_of_kin_contact": "07444444",
        "gender": "male",
        "address": "1, Main Street, Dublin, Ireland"
      },
      {
        "name": "Stella",
        "surname": "Morico",
        "age": "14",
        "bloodtype": "O",
        "ailment": "none",
        "medicine": "none",
        "last_visit": "2021-05-23",
        "allergies": "Peanuts",
        "next_of_kin": "Ella Morico",
        "next_of_kin_contact": "07555555",
        "gender": "female",
        "address": "1, Main Street, Dublin, Ireland"
      }
    ]
```

Above is the structure of our sample patient data. Here, we have six patients in total with their corresponding records. For our API, we will require the `Express.js` framework. This can installed via CLI with the following bash code:

```bash
    npm install express --save
```

The above command installs Express.js and adds it to the dependencies. With this installed, we can now set up the server. Create a new file called `server.js` in the working directory and add the following code to it:

```
    var express = require('express');
    var app = express();
    var fs = require('fs');
    
    app.use(function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "*");
        res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
        res.header("Access-Control-Allow-Headers", "x-access-token, Origin, X-Requested-With, Content-Type, Accept");
        next();
      });
    
    app.get("/fetchpatients", function(req, res) {
        fs.readFile(__dirname + "/" + "patients.json", 'utf8', function(err, data) {
            console.log(data);
            res.end(data);
        })
    })
    
    var server = app.listen(8081, function() {
        var host = server.address().address;
        var port = server.address().port;
        console.log("Listening at http://%s:%s", host, port);
    });
```

The above code sets up our server. It makes use of the `file system` module to access the `JSON` file we earlier created for the patient data. The server is set to listen on port `8081`. We can run this with the following command: 

```
    node server.js
```

You will get a message saying: `Listening at http://:::8081`. You can navigate to the port `8081` in your browser via `http://localhost:8081/fetchpatients` to view the JSON response.


![API Response](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1644008254967_json+response.png)


With this, our API is complete and we can now link it to Strapi to manage the relationship between the data.


## Integrating the App with Strapi

With the API setup complete, we will proceed by first adding data from the API to our Strapi collection. Then, we will integrate `milisearch` into the application to fetch data and add search functionality.

First, we will install and make use of [Axios](https://www.npmjs.com/package/axios) to perform our fetch and post requests. we can install this with the following command in CLI

```bash
    npm install axios
```

After installation we can use this to fetch our JSON response from our API. Back in the `index.js` file, add the following code:

```
    ...
    import axios from 'axios';
    import { useEffect } from 'react'
    
    export default function Home() {
      const url = "http://localhost:8081/fetchpatients"
      useEffect(() => {
        const fetchData = async () => {
          const result = await axios.get(url);
          console.log(result)
        };
        fetchData();
      }, []);
    ...
```

The code above uses `axios` to fetch the data from our API running on port 8081. It then runs an asynchronous function that awaits the fetch request and logs it in the browser console.

**Adding Data to Strapi**
To allow access to the Strapi collection we have to make changes to the user roles. To do this, navigate in the dashboard to the settings pane on the left navigation menu. Select `Roles` under `Users and Permissions`. Click on `Public`, select the `patient-name` collection and check all checkboxes.


![Setting up Permissions for the Collection](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1644513300396_permissions.png)


Finally, click on the `Save` button at the top-right to save these changes.

Back within our `index.js` file, we will make modifications to send our API data to our Strapi Collection.

```
    ...
    import { useEffect, useState } from "react";
    ...
    export default function Home() {
    ...
    const url2 = "http://localhost:1337/api/patient-names";
    var response;
    const [sent,dataSent] = useState(false);
     useEffect(() => {
        const fetchData = async () => {
          const result = await axios.get(url);
          response = result.data;
          console.log(response);
          sendData();
        };
        fetchData();
      }, []);
    
    const sendData = async () => {
        if (sent==false) {
          try {
            response.forEach((response) => {
              // console.log(response.name);
              axios.post(url2, {
                data: {
                  name: response.name,
                  surname: response.surname,
                  age: response.age,
                  blood_type: response.bloodtype,
                  ailment: response.ailment,
                  medicine: response.medicine,
                  last_visit: response.last_visit,
                  allergies: response.allergies,
                  next_of_kin: response.next_of_kin,
                  next_of_kin_contact: response.next_of_kin_contact,
                  gender: response.gender,
                  address: response.address,
                },
              });
            });
          } catch (error) {
            console.log(error);
          }
          dataSent(true)
        } else {
          console.log("data already uploadedd")
        }
       
      };
```

The code above stores our API response in a variable called `response`. A function `sendData()` is then called. This function maps through the response from the API and for each response, it sends the corresponding data to Strapi. At the end, if we view our Strapi `Content-manager`  we will see six entries in our `Patient name` collection.


![New entries added to our Collection](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1644698391457_strapi+content.png)


We can view the content of each entry by clicking on them. We get a window displaying each of the fields and their values.


![Opening an individual Patient Data in the Collection](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1644698526370_opened+content.png)


**Integrating Meilisearch**
To use Meilisearch locally, we will download and run an instance of it. [This can be downloaded from Meilisearch Local](https://docs.meilisearch.com/learn/getting_started/installation.html#download-and-launch). Opening the downloaded application shows a terminal with the Meilisearch instance hosted on local host:


![Opening a Meilisearch instance](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1645097773444_meilisearch+terminal.png)


If we navigate in the browser to the specified URL, we can see the Meilisearch interface:


![Viewing the instance of Meilisearch in the browser](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1645097782761_meilisearch+localhost.png)


To make use of Meilisearch from within our application, we would need to install it via CLI with the following command:

```bash
    npm install meilisearch
```

Back in the `records.js` file, we will add an import for the `meilisearch` module.

```
    import MeiliSearch from "meilisearch";
```

Then we create a client and set the host to the Meilisearch instance URL

```
    const [initialValue, setInitialValue] = useState("");
      const [query, setQuery] = useState([])
      const client = new MeiliSearch({
        host: "http://127.0.0.1:7700/",
        apiKey: "masterKey",
      });
      const index = client.index("patient");
      const search = async () => {
        const documents = await axios.get(
          "http://localhost:1337/api/patient-names"
        );
        var result = documents.data.data;
        let response = await index.addDocuments(result);
        console.log(response);
      };
      const handlesearch = async () => {
        const search = await index.search(initialValue);
        console.log(search);
        console.log(search.hits);
      };
      search();
```

The code above instantiates a client for our data. An index is created using this client and data is fetched from the Strapi collection and stored in it. The results are added to the index and displayed in the console. The `index.search` method is used to find `strings` in the data and it’s what we will implement in our search functionality. In this case, it is searching for the string “Stella”. Note that if the `index.search` method takes an empty string `""` then all data will be displayed as results.

Next, we will need to pass the results of our search query to the `Cards` components to display only the patients that match the search query. In the `handlesearch` function, we add:

```
    ...
    props.func(search.hits)
```

Then, we will get this props in the parent component `Index.js` with the following code:

```
    const [getQuery, setQuery] = useState([])
      const pull_data =(dat)=>{
        setQuery(dat)
      }
```

While also passing the function as a props to the `Records` component.

```
    <Record func={pull_data}/>
```

With this we get the results of the search query from the `Records` component. We can then pass these results to the `Cards` component and display them.

```
    <Cards results={getQuery}/>
```

Next, we iterate over the number of results and display the corresponding data. To do this, add the following to the `Cards.js` file

```
    function Cards({results}) {
    ...
    return (
        <div className=" relative">
          <div className=" container grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-16 max-w-screen-lg mt-8 py-12">
            {results.map((item, index) => (
              <div className=" flex flex-col rounded-md shadow-2xl" key={index}>
                <div className=" p-6 flex flex-col items-center">
                  <h1 className=" text-4xl font-black text-blue-600 uppercase">
                    {item.attributes.gender == "male" ? "M" : "F"  }
                  </h1>
                  <h3 className=" mt-6 mb-2 text-xl">{item.attributes.name}</h3>
                  <hr className=" w-2/5 border-b border-blue-600"></hr>
                  <div className=" flex p-6">
                    <button className=" btn hover:bg-white hover:text-blue-600 border-2 hover:border-blue-600 hover:border-2" onClick={()=> moreData(true)}>
                      More Info
                    </button>
                  </div>
                </div>
              </div>
            ))}
    ...
```

The above code displays the cards with the corresponding data, and the number of displayed cards changes based on the search input.


![Patients Records from our Strapi Collection](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1645106967284_displayed+cards.png)


If we were to search for a particular name, you only get that card displayed.


![Using the search functionality to display specific data](https://paper-attachments.dropbox.com/s_4CEB1709545EE5A98AF843517CC491D45DB40FFD03ECDC6279A99EF939E99636_1645107032947_searched+result.png)


With Meilisearch, we can search for any data pertaining to a patient. This could be age, next of kin or even a health condition.

Finally, we need to display the entire patient data when the user clicks on the `more info` button. We will need to pass the data from the clicked card to the `Data.js` component. We will first create a variable for this:

```
    const [fullData, getFullData] = useState([]);
```

Then, use the `More info` button to change the value of this state by modifying its `onClick` event-listener as follows:

```
     onClick={() => {
      moreData(true)
      getFullData(item)
    }}
```

We can now pass the `fullData` as props to the `Data` component.

```
    <Data open={data} func={pull_data} info={fullData}/>
```

To display this data in the `Data.js` file, we will make the following modifications:

```
    ...
    <div className=" relative py-3 px-6 bg-white font-Roboto font-medium shadow-2xl">
                <h1 className=" text-center text-3xl font-extrabold mb-5">M</h1>
                <h3 className=" mb-1">Name: {props.info.attributes.name}</h3>
                <p className=" mb-1">Age: {props.info.attributes.age}</p>
                <p className=" mb-1">Blood Type: {props.info.attributes.blood_type}</p>
                <p className=" mb-1">Ailment: {props.info.attributes.ailment}</p>
                <p className=" mb-1">Medicine: {props.info.attributes.medicine}</p>
                <p className=" mb-1">Last visit: {props.info.attributes.last_visit}</p>
                <p className=" mb-1">Allergies: {props.info.attributes.allergies}</p>
                <p className=" mb-1">Next of Kin: {props.info.attributes.next_of_kin}</p>
                <p className=" mb-1">Next of Kin Contact: {props.info.attributes.next_of_kin_contact}</p>
                <p className=" mb-1">Address: {props.info.attributes.address}</p>
              </div>
    ...
```

With this, we have the correct data displayed when we click on the `More info` button.


## Conclusion

In this tutorial, we learned about the Strapi CMS and how we can use it to build a hospital records application. We also learned how to make use of a search functionality to manage our data.


## Resources

[The repository containing all the code used in this tutorial can be found here](https://github.com/Victory-ET/Strapi-Hospital-Records-App)