Scheduler load resources data from api

1 Answer 165 Views
Scheduler
Daniel
Top achievements
Rank 1
Daniel asked on 07 May 2021, 12:43 PM | edited on 07 May 2021, 12:45 PM

Hello everyone,

I'm trying to load and set the resources from an api call as you can see in the following code with the line in resources with: "data: this.state.vehicles".

import React, {Component} from "react";
import {Scheduler, TimelineView} from "@progress/kendo-react-scheduler";
import {Day, ZonedDate} from "@progress/kendo-date-math";
import {guid} from "@progress/kendo-react-common";
import TaskForm from "../components/TaskForm"
import {TaskItem} from "../components/TaskItem";
import axios from "axios";

class DriveShiftsSchedulerPage extends Component {
    constructor(props) {
        super(props);

        this.state = {
            data: [],
            date: new Date,
            vehicles: []
        }

        this.handleDataChange = this.handleDataChange.bind(this);
        this.handleDateChange = this.handleDateChange.bind(this);
    }

    loadWeekDriveShiftsAndVehicles(date) {

        let curr = new Date(date);
        let first = curr.getDate() - curr.getDay() + 1;
        let last = first + 6;

        let startDate = new Date(curr.setDate(first));
        let endDate = new Date(curr.setDate(last));

        startDate.setHours(0, 0, 0, 0);
        endDate.setHours(23, 59, 59, 999);

        const config = {
            headers: {
                "Content-type": "application/json",
                "Authorization": `Bearer ${this.props.token}`,
            },
        };

        axios.get("api/getVehiclesAndDriveShifts?start_date=" + this.convertToPhpDateTime(startDate) +
            "&end_date=" + this.convertToPhpDateTime(endDate), config)
            .then(res => {
                this.setState({
                    vehicles: res.data[0].map(dataItem => (
                        {
                            text: dataItem.label,
                            value: dataItem.id,
                            color: "#5392E4"
                        }
                    ))
                });
            });

    }

    componentDidMount() {
        let curr = new Date;
        this.loadWeekDriveShiftsAndVehicles(curr);
    }

    handleDataChange({created, updated, deleted}) {
        this.setState({
            data: this.state.data.filter((item) => deleted.find(current => current.TaskID === item.TaskID) === undefined)
                .map((item) => updated.find(current => current.TaskID === item.TaskID) || item)
                .concat(created.map((item) => Object.assign({}, item, {TaskID: guid()})))
        });

        let data = (created.length !== 0) ? created : (updated.length !== 0) ? updated : deleted;

        let crudId = (created.length !== 0) ? 1 : (updated.length !== 0) ? 0 : -1;

        const mechanicId = data[0].PersonIDs;

        data = data.map(item => ({
            id: item.TaskID,
            start_date: this.convertToPhpDateTime(item.Start),
            end_date: this.convertToPhpDateTime(item.End),
            comment: item.Comment !== undefined ? item.Comment : null,
            task_template_id: item.TaskTemplateId !== undefined ? item.TaskTemplateId.id : null,
            vehicle_id: item.VehicleId !== undefined ? item.VehicleId.id : null,
            user_time_spent: null,
            task_state_id: item.TaskStateId !== undefined ? item.TaskStateId.id : 2,
            priority_id: item.PriorityId !== undefined ? item.PriorityId.id : 3,
            periodicity_end_date: null,
            created_user_id: this.props.userId,
            changed_user_id: this.props.userId,
            active: true,
            deadline_execution: null,
            title: item.Title
        }));

        const config = {
            headers: {
                "Content-type": "application/json",
                "Authorization": `Bearer ${this.props.token}`
            }
        };

        axios.post("api/saveTask", {
            data: data[0],
            crudId: crudId,
            mechanicId: mechanicId
        }, config).then(res => {
            //console.log(res);
        });
    }

    handleDateChange(event) {
        const newDate = event.value instanceof ZonedDate ? event.value._utcDate : event.value;
        const oldDate = this.state.date;

        //console.log(newDate);

        if (oldDate.getWeekNumber() !== newDate.getWeekNumber()) {
            this.loadWeekDriveShiftsAndVehicles(newDate);
        }

        this.setState({
            date: newDate
        });
    }

    render() {
        return (
            <Scheduler
                height={"100%"}
                data={this.state.data}
                onDataChange={this.handleDataChange}
                onDateChange={this.handleDateChange}
                date={this.state.date}
                modelFields={{
                    id: "TaskID",
                    title: "Title",
                    description: "Comment",
                    start: "Start",
                    end: "End",
                    projectId: "ProjectId",
                    vehicleId: "VehicleId",
                    taskTemplateId: "TaskTemplateId",
                    recurrenceRule: "RecurrenceRule",
                    recurrenceId: "RecurrenceID",
                    recurrenceExceptions: "RecurrenceException",
                    color: "color"
                }}
                editItem={TaskItem}
                form={TaskForm}
                editable={{
                    add: true,
                    remove: true,
                    drag: true,
                    resize: true,
                    edit: true
                }}
                group={{
                    resources: ["Vehicles"],
                    orientation: "vertical"
                }}
                resources={[{
                    name: "Vehicles",
                    data: this.state.vehicles,
                    field: "VehicleIDs",
                    valueField: "value",
                    textField: "text",
                    colorField: "color"
                }]}
            >
                <TimelineView title="Timeline View"
                              slotDuration={60}
                              slotDivisions={1}
                              numberOfDays={2}
                              workDayStart={"00:00"}
                              workDayEnd={"23:59"}
                              showWorkHours={true}
                />
            </Scheduler>
        );
    }

    loadWeekTasks(date) {

        let curr = new Date(date);
        let first = curr.getDate() - curr.getDay() + 1;
        let last = first + 6;

        let startDate = new Date(curr.setDate(first));
        let endDate = new Date(curr.setDate(last));

        startDate.setHours(0, 0, 0, 0);
        endDate.setHours(23, 59, 59, 999);

        const config = {
            headers: {
                "Content-type": "application/json",
                "Authorization": `Bearer ${this.props.token}`,
            },
        };

        axios.get("api/getTasks?start_date=" + this.convertToPhpDateTime(startDate) +
            "&end_date=" + this.convertToPhpDateTime(endDate), config)
            .then(res => {
                this.setState({
                    data: res.data.map(dataItem => (
                        {
                            TaskID: dataItem.id,
                            Start: this.parseAdjust(dataItem.start_date),
                            End: this.parseAdjust(dataItem.end_date),
                            isAllDay: false,
                            ProjectId: {
                                id: dataItem.template !== null ? dataItem.template.vehicle.project.id : (dataItem.vehicle !== null ? dataItem.vehicle.project.id : undefined),
                                projectId: dataItem.template !== null ? dataItem.template.vehicle.project.project_id : (dataItem.vehicle !== null ? dataItem.vehicle.project.project_id : undefined)
                            },
                            VehicleId: {
                                id: dataItem.template !== null ? dataItem.template.vehicle.id : (dataItem.vehicle !== null ? dataItem.vehicle.id : undefined),
                                label: dataItem.template !== null ? dataItem.template.vehicle.label : (dataItem.vehicle !== null ? dataItem.vehicle.label : undefined)
                            },
                            TaskTemplateId: {
                                id: dataItem.template !== null ? dataItem.template.id : undefined,
                                title: dataItem.template !== null ? dataItem.template.title : undefined
                            },
                            TaskStateId: {
                                id: dataItem.task_state_id
                            },
                            PriorityId: {
                                id: dataItem.priority_id
                            },
                            Comment: dataItem.comment === null ? undefined : dataItem.comment,
                            Title: dataItem.title === null ? undefined : dataItem.title,
                            PersonIDs: dataItem.users[0].id,
                        }
                    ))
                });
            });

    }

    convertToPhpDateTime(date) {
        const year = date.getFullYear();
        const month = date.getMonth() + 1;
        const day = date.getDate();
        const hours = date.getHours();
        const minutes = date.getMinutes();
        const seconds = date.getSeconds();
        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    }

    parseAdjust(date) {
        return new Date(date);
    };
}

export default DriveShiftsSchedulerPage;

It happens that the vertical scroll bar is shown without being needed. In my case it shows the vertical scroll bar and it isn't needed at all because of the few elements that are loaded. I also get an Warning saying `NaN` is an invalid value for the `width` css style property.

This problem doesn't happen if I set the resources data explicitly like for example:

data: [
                        {text: "Sascha", value: 35, color: "#5392E4"},
                        {text: "Alex", value: 39, color: "#5392E4"},
                        {text: "Daniel", value: 91, color: "#5392E4"},
                        {text: "Planned", value: 200, color: "#5392E4"}
                    ]

So I ask, is there a way to load the resources data on the componentDidMount method from an api, and have everything working well with the scheduler as like the data was inserted explicitly like on the code above?

Thanks in advance.

Best Regards,

Daniel

1 Answer, 1 is accepted

Sort by
0
Kiril
Telerik team
answered on 10 May 2021, 05:40 AM

Hi Daniel,

It is possible to set the resources data dynamically. As the `resources` and the `group` properties are tightly related, we recommend having some logic which does not group the resources, unless its data is loaded.

I have prepared the following stackblitz example which demonstrates async resources, as well as dynamic grouping based on the resources data:
https://stackblitz.com/edit/react-yycewg-pu2sok?file=app/main.jsx

I was not able to replicate the described vertical scroll issue, so I'm kindly asking for your assistance. Would you be able to extend the stackblitz example to a point where the described issue is reproducible so we can further investigate.

As for the `width` error, it is related to groups being applied without the resources data available. Please refer to the example above for more information about how to grouo only available resources.

Please let me know how can i further assist you.

Regards,
Kiril
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Tags
Scheduler
Asked by
Daniel
Top achievements
Rank 1
Answers by
Kiril
Telerik team
Share this question
or