Overview

  • React TypeScript project that uses a React Scheduler component to display reservations for multiple locations

  • The TypeScript definitions provide real-time code completion (including suggestions and type checks) in your IDE (e.g. Visual Studio, IntelliJ WebStorm)

  • Reservation locations are displayed on the vertical axis

  • Includes a trial version of DayPilot Pro for JavaScript (see License below)

License

Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript.

New React Project with TypeScript Support

Lets start with creating a new React project using create-react-app. The --template typescript switch will add TypeScript support to our new React project.

npx create-react-app my-app --template typescript

When using the --typescript template switch the project source code files will end with *.tsx instead of *.js and the TypeScript code will be automatically compiled during builds.

Creating a React Scheduler Component in TypeScript

In order to create the Scheduler component that will display and manage our reservations it is necessary to import daypilot-pro-react package. This package includes a React version of DayPilot Pro for JavaScript and it includes the React Scheduler component which will help us create the reservation UI.

The daypilot-pro-react package is hosted at npm.daypilot.org and we can add it to our project using npm:

npm install https://npm.daypilot.org/daypilot-pro-react/trial/2023.2.5582.tar.gz

Now we can create a functional React component (with Hooks API) that will wrap DayPilot Scheduler:

src/scheduler/Scheduler.tsx

import React, { FC } from 'react';
import { DayPilotScheduler } from "daypilot-pro-react";

interface SchedulerProps {}

const Scheduler: FC<SchedulerProps> = () => {
  return <DayPilotScheduler />;
}

export default Scheduler;

We can add our Scheduler component to App.tsx to test it:

src/App.tsx

import React from 'react';
import './App.css';
import Scheduler from "./scheduler/Scheduler";

const App: React.FC = () => {
  return (
      <div>
        <Scheduler />
      </div>
  );
}

export default App;

It doesn't display much at this moment but we got it working!

react scheduler typescript first version

Displaying Locations on the Y Axis

Now that our Scheduler is initialized we can start adding features.

The first thing to configure is the Y axis which will display the reservation locations. In the Scheduler component, the rows are defined using resources property and this property is also available in the React component. So lets load the resources as a static array first:

import React, { FC } from 'react';
import { DayPilotScheduler } from "daypilot-pro-react";

interface SchedulerProps {}

const Scheduler: FC<SchedulerProps> = () => {
  return (
    <DayPilotScheduler
      resources={[
        {name: "Location A", id: "A"},
        {name: "Location B", id: "B"},
        {name: "Location C", id: "C"},
        {name: "Location D", id: "D"},
        {name: "Location E", id: "E"},
        {name: "Location F", id: "F"},
      ]}
    />
  );
}

export default Scheduler;

If you open the React web application in the browser now you will see the rows with our locations:

react scheduler typescript reservation locations

Defining the Time Axis of the Scheduler

By default, the Scheduler displays a single day and one cell per hour. The default start of the time line is today.

We want it to show the full year and one cell per day instead. This can be set using startDatedays, and scale properties. Lets also adjust the time headers on the X axis using timeHeaders property:

import React, { FC } from 'react';
import { DayPilotScheduler } from "daypilot-pro-react";

interface SchedulerProps {}

const Scheduler: FC<SchedulerProps> = () => {
  return (
    <DayPilotScheduler
      startDate={"2023-01-01"}
      days={365}
      scale={"Day"}
      timeHeaders={[
        {groupBy: "Month"},
        {groupBy: "Day", format: "d"}
      ]}
      resources={[
        {name: "Location A", id: "A"},
        {name: "Location B", id: "B"},
        {name: "Location C", id: "C"},
        {name: "Location D", id: "D"},
        {name: "Location E", id: "E"},
        {name: "Location F", id: "F"},
      ]}
    />
  );
}

export default Scheduler;

Our updated reservation scheduler looks like this now:

react scheduler typescript time axis

Loading Reservations

The last step of this tutorial will be adding the reservation data that will be displayed in the Scheduler grid.

The reservations are defined using the events attribute of the Scheduler component:

import React, { FC } from 'react';
import { DayPilotScheduler } from "daypilot-pro-react";

interface SchedulerProps {}

const Scheduler: FC<SchedulerProps> = () => {
  return (
    <DayPilotScheduler
      startDate={"2023-01-01"}
      days={365}
      scale={"Day"}
      timeHeaders={[
        {groupBy: "Month"},
        {groupBy: "Day", format: "d"}
      ]}
      resources={[
        {name: "Location A", id: "A"},
        {name: "Location B", id: "B"},
        {name: "Location C", id: "C"},
        {name: "Location D", id: "D"},
        {name: "Location E", id: "E"},
        {name: "Location F", id: "F"},
      ]}
      events={[
        {
          id: 1,
          text: "Reservation 1",
          start: "2023-11-03T00:00:00",
          end: "2023-11-09T00:00:00",
          resource: "A",
          barColor: "#3d85c6"
        },
        {
          id: 2,
          text: "Reservation 2",
          start: "2023-11-04T00:00:00",
          end: "2023-11-08T00:00:00",
          resource: "C",
          barColor: "#38761d"
        }
      ]}
    />
  );
}

export default Scheduler;

You can see that the reservations are now displayed in the matching rows:

react scheduler typescript loading reservations

Full TypeScript Source Code

Here is the full TypeScript source code of our Scheduler component:

import React, { useState, useEffect, useRef } from 'react';
import { DayPilot, DayPilotScheduler } from "daypilot-pro-react";

const Scheduler: React.FC = () => {
    const [config, setConfig] = useState<DayPilot.SchedulerConfig>({
        startDate: "2023-01-01",
        days: 365,
        scale: "Day",
        eventHeight: 50,
        timeHeaders: [
            { groupBy: "Month" },
            { groupBy: "Day", format: "d" }
        ],
        cellWidth: 50,
        resources: [
            { name: "Location A", id: "A" },
            { name: "Location B", id: "B" },
            { name: "Location C", id: "C" },
            { name: "Location D", id: "D" },
            { name: "Location E", id: "E" },
            { name: "Location F", id: "F" },
        ],
        events: [
            {
                id: 1,
                text: "Reservation 1",
                start: "2023-11-03T00:00:00",
                end: "2023-11-09T00:00:00",
                resource: "A",
                barColor: "#3d85c6"
            },
            {
                id: 2,
                text: "Reservation 2",
                start: "2023-11-04T00:00:00",
                end: "2023-11-08T00:00:00",
                resource: "C",
                barColor: "#38761d"
            },
            {
                id: 3,
                text: "Reservation 3",
                start: "2023-11-02T00:00:00",
                end: "2023-11-05T00:00:00",
                resource: "D",
                barColor: "#f1c232"
            },
            {
                id: 4,
                text: "Reservation 4",
                start: "2023-11-03T00:00:00",
                end: "2023-11-06T00:00:00",
                resource: "E",
                barColor: "#cc0000"
            }
        ],
        onEventMoved: async (args: DayPilot.SchedulerEventMovedArgs) => {
            schedulerRef.current!.control.message("Event moved: " + args.e.data.text);
        },
        onEventResized: async (args: DayPilot.SchedulerEventResizedArgs) => {
            schedulerRef.current!.control.message("Event resized: " + args.e.data.text);
        },
        onTimeRangeSelected: async (args: DayPilot.SchedulerTimeRangeSelectedArgs) => {
            const modal = await DayPilot.Modal.prompt("New reservation:", "Reservation");
            schedulerRef.current!.control.clearSelection();
            if (modal.canceled) {
                return;
            }
            schedulerRef.current!.control.events.add({
                id: DayPilot.guid(),
                text: modal.result,
                start: args.start,
                end: args.end,
                resource: args.resource
            });
        },
        onEventClicked: async (args: any) => {
            let e = args.e;
            const modal = await DayPilot.Modal.prompt("Edit reservation:", e.data.text);
            schedulerRef.current!.control.clearSelection();
            if (modal.canceled) {
                return;
            }
            e.data.text = modal.result;
            schedulerRef.current!.control.events.update(e);
        }
    });

    const schedulerRef = useRef<DayPilotScheduler>(null);

    useEffect(() => {
        if (schedulerRef.current) {
            schedulerRef.current.control.scrollTo("2023-11-01");
        }
    }, []);

    return (
        <div>
            <DayPilotScheduler
                {...config}
                ref={schedulerRef}
            />
        </div>
    );
}

export default Scheduler;

History

  • May 29, 2023: Upgraded to React 18, Hooks API, DayPilot Pro 2023.2.5582

  • December 16, 2020: Upgraded to React 17, DayPilot Pro 2020.4.4817

  • October 1, 2019: Initial release. React 16.