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. Buy a license.

New React Project with TypeScript Support

Lets start with creating a new React project using yarn create. The --typescript switch will add TypeScript support to the React project.

yarn create react-app react-scheduler-typescript --typescript

When using the --typescript switch the project source code files will end with *.tsx instead of *.jsx 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 yarn:

yarn add https://npm.daypilot.org/daypilot-pro-react/trial/2019.4.4052.tar.gz

Now we can create a simple React component that will wrap DayPilot Scheduler:

src/scheduler/Scheduler.tsx

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

interface SchedulerProps {}

export default class Scheduler extends React.Component<SchedulerProps, any> {

    constructor(props: SchedulerProps) {
        super(props);
    }

    render() {
        return (
            <DayPilotScheduler/>
        );
    }
}

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.png

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 from 'react';
import {DayPilotScheduler} from "daypilot-pro-react";

interface SchedulerProps {}

export default class Scheduler extends React.Component<SchedulerProps, any> {

    constructor(props: SchedulerProps) {
        super(props);
    }

    render() {
        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"},
                ]}
            />
        );
    }
}

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

react-scheduler-typescript-reservation-locations.png

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 from 'react';
import {DayPilotScheduler} from "daypilot-pro-react";

interface SchedulerProps {
}

export default class Scheduler extends React.Component<SchedulerProps, any> {

    constructor(props: SchedulerProps) {
        super(props);
    }

    render() {
        return (
            <DayPilotScheduler
                startDate={"2019-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"},
                ]}
            />
        );
    }
}

Our updated reservation scheduler looks like this now:

react-scheduler-typescript-time-axis.png

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 events property of the Scheduler component:

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

interface SchedulerProps {
}

export default class Scheduler extends React.Component<SchedulerProps, any> {

    constructor(props: SchedulerProps) {
        super(props);
    }

    render() {
        return (
            <DayPilotScheduler
                startDate={"2019-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: "2019-11-03T00:00:00",
                        end: "2019-11-09T00:00:00",
                        resource: "A",
                        barColor: "#3d85c6"
                    },
                    {
                        id: 2,
                        text: "Reservation 2",
                        start: "2019-11-04T00:00:00",
                        end: "2019-11-08T00:00:00",
                        resource: "C",
                        barColor: "#38761d"
                    }
                ]}
            />
        );
    }
}

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

react-scheduler-typescript-loading-reservations.png

Full TypeScript Source Code

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

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

interface SchedulerProps {

}

export default class Scheduler extends React.Component<SchedulerProps, any> {

    scheduler?: DayPilot.Scheduler;

    constructor(props: SchedulerProps) {
        super(props);

        this.state = {
            startDate: "2019-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: "2019-11-03T00:00:00",
                    end: "2019-11-09T00:00:00",
                    resource: "A",
                    barColor: "#3d85c6"
                },
                {
                    id: 2,
                    text: "Reservation 2",
                    start: "2019-11-04T00:00:00",
                    end: "2019-11-08T00:00:00",
                    resource: "C",
                    barColor: "#38761d"
                },
                {
                    id: 3,
                    text: "Reservation 3",
                    start: "2019-11-02T00:00:00",
                    end: "2019-11-05T00:00:00",
                    resource: "D",
                    barColor: "#f1c232"
                },
                {
                    id: 4,
                    text: "Reservation 4",
                    start: "2019-11-03T00:00:00",
                    end: "2019-11-06T00:00:00",
                    resource: "E",
                    barColor: "#cc0000"
                }
            ]
        };
    }

    componentDidMount(): void {
        this.scheduler && this.scheduler.scrollTo("2019-11-01");
    }

    render() {
        var {...config} = this.state;
        return (
            <div>

                <DayPilotScheduler
                    {...config}
                    onEventMoved={args => {
                        this.scheduler && this.scheduler.message("Event moved: " + args.e.data.text);
                    }}
                    onEventResized={args => {
                        this.scheduler && this.scheduler.message("Event resized: " + args.e.data.text);
                    }}
                    onTimeRangeSelected={args => {
                        DayPilot.Modal.prompt("New reservation:", "Reservation").then(modal => {
                            this.scheduler && this.scheduler.clearSelection();
                            if (!modal.result) {
                                return;
                            }
                            this.scheduler && this.scheduler.events.add({
                                id: DayPilot.guid(),
                                text: modal.result,
                                start: args.start,
                                end: args.end,
                                resource: args.resource
                            });
                        });
                    }}
                    onEventClicked={args => {
                        let e = args.e;
                        DayPilot.Modal.prompt("Edit reservation:", e.data.text).then(modal => {
                            this.scheduler && this.scheduler.clearSelection();
                            if (!modal.result) {
                                return;
                            }
                            e.data.text = modal.result;
                            this.scheduler && this.scheduler.events.update(e);
                        });
                    }}
                    ref={component => {
                        if (!component) {
                            return;
                        }
                        this.scheduler = component.control;
                    }}
                />
            </div>
        );
    }
}