Using Bryntum Calendar to Coordinate Caregiver Availability in Health Care
Tags: javascript, react, tailwindcss, tutorial
Published: 2023-08-10 12:11:12

The [Bryntum Calendar](https://www.bryntum.com/products/calendar/) is a web component that you can use to display and manage calendar events. It has type definitions using TypeScript as well as a well-documented [API](https://bryntum.com/docs/calendar/api/api), making it easy to integrate with popular libraries and frameworks, including [React](https://reactjs.org/) and [Vue.js](https://vuejs.org/). 

The Bryntum Calendar component is beneficial for project management applications that need to show users a project timeline or applications that need resource management with a calendar view. This includes applications providing health-care or home care services, where resource allocation and coordination are essential.

In this article, you'll build an application to coordinate caregiver availability for family members using React, [Tailwind CSS](https://tailwindcss.com/docs/installation), and the Bryntum Calendar component. While doing so, you'll learn about working with JSON data, creating stateful React components, and displaying events in a calendar view using the Bryntum Calendar.

## Building the Caregiver Application

Before you begin this tutorial, you'll need [Node.js](https://nodejs.org/en/) version 14 or newer as well as [npm](https://www.npmjs.com/) version 6 or newer installed on your computer. You'll also need a code editor like [Visual Studio Code](https://code.visualstudio.com/).

You can follow along with this tutorial using this [GitHub repository](https://github.com/Anshuman71/caregiver-bryntum).

### Set Up the Project

To begin, run the following command to create a new React project, `caregiver-app`, using `create-react-app`:

```bash
npx create-react-app caregiver-app
```

Then change the directory to the newly created project:

```bash
cd caregiver-app
```

Run the following command to install Tailwind CSS and its dependencies:

```bash
npm install -D tailwindcss postcss autoprefixer
```

Next, run `npx tailwindcss init -p` to initialize Tailwind CSS in the project. This command will generate `tailwind.config.js` and `postcss.config.js` files, where you can configure color schemes and plug-ins.

Update the `content` list in the `tailwind.config.js` file to watch for Tailwind CSS class updates in all files:

```jsx
/** @type {import('tailwindcss').Config} */ 
module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```

Finally, add `@tailwind` directives to the `./src/index.css` so you can use Tailwind CSS classes in all our components:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

### Create Your Page Layout

Now that you've set up the project, it's time to create a simple app layout with a navigation bar at the top and a drop-down menu to select your desired family member. Here's a rough mock up:

![App mockup](https://i.imgur.com/QdYTLcy.png)

Before going further, you need a data source to fetch the list of caregivers and the caregiving schedules for family members. To do that, create a new `src/data.json` file. The `data.json` has two keys:
- `Caregivers`, a list of caregiver details objects
- The caregiving `schedules` for each family member

Each caregiving schedule item has a caregiver linked to it using the `resourceId` attribute that maps to the caregiver's `id`, as shown below.

![Caregiver and schedule structure](https://i.imgur.com/xjz5GRU.png)

The `caregivers` object structure is as follows:

```json
{
  "id": "steve", // unique resource id

  "name": "Steve Rogers", // name of the caregiver

  "eventColor": "blue" // color for the calendar event
}

```

  

The `schedule` object structure looks like this:

  

```json

{
  "<family-member>": [
    {
      "startDate": "<appointment-start-date>",

      "id": "<unique-id-number>",
      "endDate": "<appointment-start-date>",

      "name": "<slot-name>",

      "resourceId": "<caregiver-id>"
    }

    // ... more appointments
  ]

  // ... other family member's schedules
}

```

You can copy the below JSON as sample data for your `data.json` file.

```json
{
  "caregivers": [
    {
      "id": "steve",
      "name": "Steve Rogers",
      "eventColor": "blue"
    },
    {
      "id": "tony",
      "name": "Tony Stark",
      "eventColor": "orange"
    },
    {
      "id": "bruce",
      "name": "Bruce Banner",
      "eventColor": "green"
    },
    {
      "id": "natasha",
      "name": "Natasha Romano ff",
      "eventColor": "pink"
    }
  ],
  "schedule": {
    "Grand Pa": [
      {
        "startDate": "Thu Sep 08 2022 16:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 96,
        "endDate": "Thu Sep 08 2022 18:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "tony"
      },
      {
        "startDate": "Fri Sep 09 2022 06:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 91,
        "endDate": "Fri Sep 09 2022 07:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "natasha"
      },
      {
        "startDate": "Thu Sep 08 2022 05:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 82,
        "endDate": "Thu Sep 08 2022 07:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "steve"
      },
      {
        "startDate": "Mon Sep 05 2022 18:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 62,
        "endDate": "Mon Sep 05 2022 20:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "bruce"
      },
      {
        "startDate": "Tue Sep 06 2022 11:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 93,
        "endDate": "Tue Sep 06 2022 12:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "tony"
      },
      {
        "startDate": "Fri Sep 09 2022 08:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 2,
        "endDate": "Fri Sep 09 2022 10:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "natasha"
      },
      {
        "startDate": "Mon Sep 05 2022 16:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 79,
        "endDate": "Mon Sep 05 2022 17:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "bruce"
      },
      {
        "startDate": "Sun Sep 04 2022 09:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 15,
        "endDate": "Sun Sep 04 2022 10:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "natasha"
      }
    ],
    "Grand Ma": [
      {
        "startDate": "Fri Sep 09 2022 18:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 12,
        "endDate": "Fri Sep 09 2022 20:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "bruce"
      },
      {
        "startDate": "Fri Sep 09 2022 17:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 96,
        "endDate": "Fri Sep 09 2022 19:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "natasha"
      },
      {
        "startDate": "Mon Sep 05 2022 05:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 98,
        "endDate": "Mon Sep 05 2022 07:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "tony"
      },
      {
        "startDate": "Fri Sep 09 2022 06:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 91,
        "endDate": "Fri Sep 09 2022 07:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "natasha"
      },
      {
        "startDate": "Thu Sep 08 2022 05:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 65,
        "endDate": "Thu Sep 08 2022 07:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "steve"
      },
      {
        "startDate": "Mon Sep 05 2022 18:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 62,
        "endDate": "Mon Sep 05 2022 20:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "bruce"
      },
      {
        "startDate": "Wed Sep 07 2022 11:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 18,
        "endDate": "Wed Sep 07 2022 13:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "steve"
      }
    ],
    "Uncle": [
      {
        "startDate": "Sun Sep 04 2022 17:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 47,
        "endDate": "Sun Sep 04 2022 18:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "steve"
      },
      {
        "startDate": "Tue Sep 06 2022 04:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 24,
        "endDate": "Tue Sep 06 2022 06:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "natasha"
      },
      {
        "startDate": "Thu Sep 08 2022 06:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 83,
        "endDate": "Thu Sep 08 2022 07:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "bruce"
      },
      {
        "startDate": "Sun Sep 04 2022 16:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 52,
        "endDate": "Sun Sep 04 2022 18:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "tony"
      },
      {
        "startDate": "Wed Sep 07 2022 12:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 53,
        "endDate": "Wed Sep 07 2022 13:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "natasha"
      },
      {
        "startDate": "Sun Sep 04 2022 04:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 48,
        "endDate": "Sun Sep 04 2022 06:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "steve"
      },
      {
        "startDate": "Sun Sep 04 2022 02:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 19,
        "endDate": "Sun Sep 04 2022 03:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "tony"
      }
    ],
    "Dad": [
      {
        "startDate": "Fri Sep 09 2022 10:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 86,
        "endDate": "Fri Sep 09 2022 12:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "natasha"
      },
      {
        "startDate": "Sun Sep 04 2022 12:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 26,
        "endDate": "Sun Sep 04 2022 14:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "tony"
      },
      {
        "startDate": "Wed Sep 07 2022 07:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 87,
        "endDate": "Wed Sep 07 2022 08:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "bruce"
      },
      {
        "startDate": "Thu Sep 08 2022 20:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 37,
        "endDate": "Thu Sep 08 2022 21:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "natasha"
      },
      {
        "startDate": "Mon Sep 05 2022 01:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 3,
        "endDate": "Mon Sep 05 2022 02:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "tony"
      },
      {
        "startDate": "Mon Sep 05 2022 00:00:00 GMT+0000 (Coordinated Universal Time)",
        "id": 93,
        "endDate": "Mon Sep 05 2022 01:00:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "steve"
      },
      {
        "startDate": "Tue Sep 06 2022 08:30:00 GMT+0000 (Coordinated Universal Time)",
        "id": 10,
        "endDate": "Tue Sep 06 2022 10:30:00 GMT+0000 (Coordinated Universal Time)",
        "name": "Caregiver assigned",
        "resourceId": "bruce"
      }
    ]
  }
}
```

> This example uses a static JSON file, but you can also use an API or database as the source.

Import the `data.json` file in the `App.js` and retrieve the list of members using the `Object.keys` method:

```jsx
import "./App.css";
import { useState } from "react";
import data from "./data.json";

const ALL_MEMBERS = Object.keys(data.schedule); // get list of members from object
```

Then create a simple navigation bar at the top using Tailwind CSS classes:

```jsx
import "./App.css";
import { useState } from "react";
import data from "./data.json";

const ALL_MEMBERS = Object.keys(data.schedule); // get list of members from object

function App() {
  return (
    <div className={"flex flex-col max-w-[1200px] mx-auto"}>
      <nav
        className={
          "flex flex-row items-center bg-green-600 p-2 py-3 text-white shadow shadow-sm shadow-gray-500"
        }
      >
        <p className={"text-lg"}>Caregiver PRO</p>
        <p className={"mx-10"}>|</p>
        <i className={"font-light text-sm"}>
          We ensure the best care for your loved ones.
        </i>
      </nav>
    </div>
  );
}

export default App;
```

Run `npm start` to start the application:

![Navigation bar](https://i.imgur.com/sq2Ppgo.png)

Now create a drop-down menu using the `<select>` HTML element and populate it with the `<option>` elements by mapping over the `ALL_MEMBERS` array:

```jsx
import "./App.css";
import { useState } from "react";
import data from "./data.json";

const ALL_MEMBERS = Object.keys(data.schedule); // get list of members from object

function App() {
  return (
    <div className={"flex flex-col max-w-[1200px] mx-auto"}>
      <nav
        className={
          "flex flex-row items-center bg-green-600 p-2 py-3 text-white shadow shadow-sm shadow-gray-500"
        }
      >
        <p className={"text-lg"}>Caregiver PRO</p>
        <p className={"mx-10"}>|</p>
        <i className={"font-light text-sm"}>
          We ensure the best care for your loved ones.
        </i>
      </nav>
      <main className={"mt-10"}>
        <div className={"mb-10"}>
          <label htmlFor={"member"}>Select member</label>
          <select
            id={"member"}
            value={member}
            className={"ml-2 bg-gray-100 border-2 rounded border-green-600"}
          >
            {ALL_MEMBERS.map((member) => (
              <option key={member} value={member}>
                {member}
              </option>
            ))}
          </select>
        </div>
        <div className={"bg-gray-200 h-[500px] text-lg"}>
          Calendar goes here
        </div>
      </main>
    </div>
  );
}

export default App;
```

Create a `member` state variable using the `useState` React hook to allow users to select a family member. Add an `onChange` event handler to the `<select>` element to update the `member` state whenever the user selects a new member:

```jsx
import "./App.css";
import { useState } from "react";
import data from "./data.json";

const ALL_MEMBERS = Object.keys(data.schedule); // get list of members from object

function App() {
  const [member, setMember] = useState("Grand Ma");
  return (
    <div className={"flex flex-col max-w-[1200px] mx-auto"}>
      <nav
        className={
          "flex flex-row items-center bg-green-600 p-2 py-3 text-white shadow shadow-sm shadow-gray-500"
        }
      >
        <p className={"text-lg"}>Caregiver PRO</p>
        <p className={"mx-10"}>|</p>
        <i className={"font-light text-sm"}>
          We ensure the best care for your loved ones.
        </i>
      </nav>
      <main className={"mt-10"}>
        <div className={"mb-10"}>
          <label htmlFor={"member"}>Select member</label>
          <select
            id={"member"}
            value={member}
            onChange={(e) => setMember(e.target.value)}
            className={"ml-2 bg-gray-100 border-2 rounded border-green-600"}
          >
            {ALL_MEMBERS.map((member) => (
              <option key={member} value={member}>
                {member}
              </option>
            ))}
          </select>
        </div>
        <div className={"bg-gray-200 h-[500px] text-lg"}>
          Calendar goes here
        </div>
      </main>
    </div>
  );
}

export default App;
```

![Basic application layout](https://i.imgur.com/pYbOk15.png)

The application layout is ready. Now you need to plug in the Bryntum Calendar to show user-friendly schedules.

### Add the Bryntum Calendar Layout

To add the Bryntum Calendar layout, you need to sign up for a [free trial of the Bryntum Calendar](https://www.bryntum.com/download/). Bryntum serves the calendar component from a private registry, so you need to specify the registry URL to `npm` using the following command:

```bash
npm config set "@bryntum:registry=https://npm.bryntum.com"
```

Since Bryntum's registry is authenticated, you need to log in using the credentials you signed up with:

```bash
npm login --registry=https://npm.bryntum.com
```

> **Please note:** The "@" should be replaced with ".." in the login email. For example, "someone@example.com" will become "someone..example.com" with "trial" as the password.

Now, run the following command to install the Bryntum Calendar dependencies:

```bash
npm i @bryntum/calendar@npm:@bryntum/calendar-trial@^5.1.2 @bryntum/calendar-react@5.1.2
```

Import the Stockholm theme for Bryntum Calendar in the `index.css` file:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

@import "@bryntum/calendar/calendar.stockholm.css"; # add this line
```

Then import the `BryntumCalendar` component in the `App.js` file and create a `CALENDAR_CONFIG` object with the `date` that the calendar will open:

```jsx
import "./App.css";
import { useState } from "react";
import data from "./data.json";
import { BryntumCalendar } from "@bryntum/calendar-react";

const CALENDAR_CONFIG = {
  date: new Date(2022, 8, 4), // calendar will open at this date
};

const ALL_MEMBERS = Object.keys(data.schedule); // get list of members from object
```

Pass the `CALENDAR_CONFIG` as `config`, `caregivers` as the `resources`, and the `data.schedule[member]` as the `events` prop to the `BryntumCalendar`:

```jsx
import "./App.css";
import { useState } from "react";
import data from "./data.json";
import { BryntumCalendar } from "@bryntum/calendar-react";

const CALENDAR_CONFIG = {
  date: new Date(2022, 8, 4),
};
const ALL_MEMBERS = Object.keys(data.schedule); // get list of members from object

function App() {
  const [member, setMember] = useState("Grand Ma");
  return (
    <div className={"flex flex-col max-w-[1200px] mx-auto"}>
      <nav
        className={
          "flex flex-row items-center bg-green-600 p-2 py-3 text-white shadow shadow-sm shadow-gray-500"
        }
      >
        <p className={"text-lg"}>Caregiver PRO</p>
        <p className={"mx-10"}>|</p>
        <i className={"font-light text-sm"}>
          We ensure the best care for your loved ones.
        </i>
      </nav>
      <main className={"mt-10"}>
        <div className={"mb-10"}>
          <label htmlFor={"member"}>Select member</label>
          <select
            id={"member"}
            value={member}
            onChange={(e) => setMember(e.target.value)}
            className={"ml-2 bg-gray-100 border-2 rounded border-green-600"}
          >
            {ALL_MEMBERS.map((member) => (
              <option key={member} value={member}>
                {member}
              </option>
            ))}
          </select>
        </div>
        <BryntumCalendar
          config={CALENDAR_CONFIG}
          resources={data.caregivers}
          events={data.schedule[member]}
        />
      </main>
    </div>
  );
}

export default App;
```

In this case, since the `member` is in a React state, whenever the user selects a new member from the drop-down, the calendar will re-render and show the caregiver schedule for the selected member. And with this final step, the Caregiver PRO is ready:

![Final application](https://i.imgur.com/ajmC9ww.png)

The users can add new caregiver appointments by checking the missing slots and selecting a caregiver from the list while making the appointment. Or they can change the view to daily or monthly, or see it as a list by selecting the **Agenda** view.

Here, you can see the Caregiver PRO in action:

![Caregiver in action](https://i.imgur.com/f7NgSSZ.gif)

## Conclusion

Upon completion of this tutorial, you will have a fully functioning Caregiver PRO application. To create this application, you learned how to set up a React project with Tailwind CSS styling, and you used a JSON file as the data source to display the list of events. Later, you used the [Bryntum Calendar](https://www.bryntum.com/products/calendar/) component to display calendar events and make booking caregivers for family members simpler. You can extend this example further and use [Bryntum Calendar events](https://www.bryntum.com/docs/calendar/guide/Calendar/integration/react/events) to read or store events from a remote API.

Are you already using the Bryntum Calendar? We would love to hear how it's [making your life easier](https://www.bryntum.com/company/testimonials/).

[Bryntum](https://www.bryntum.com) is a software company specializing in creating beautiful and performant web components, including the [Calendar](https://www.bryntum.com/docs/calendar), [Scheduler](https://www.bryntum.com/docs/scheduler), and [Gantt](https://www.bryntum.com/docs/gantt) chart. Want to learn more? Try our scheduling and Gantt components at [bryntum.com](https://www.bryntum.com/).