Overview

  • How to add a Vue timesheet to your application

  • How to display daily totals

  • How to customize the appearance using CSS themes

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

How to Create a Vue Timesheet Project

As the first step, we will create a new Vue project and add the required dependencies.

1. Create a new Vue project using Vue CLI:

vue create vue-timesheet

2. To display the timesheet, we’ll use the Vue Scheduler component from DayPilot Pro for JavaScript. The Vue Scheduler component displays resources as rows by default but you can switch it to a special mode where it displays days on the vertical axis and hours of day on the horizontal axis.

First, it is necessary to install the DayPilot Pro Vue package (daypilot-pro-vue) from npm.daypilot.org:

yarn add https://npm.daypilot.org/daypilot-pro-vue/trial/2021.4.5120.tar.gz

3. You can also generate a new Vue project using the DayPilot UI Builder online application. The UI Builder lets you customize the Timesheet appearance and create a new Vue project including the preconfigured Vue timesheet component.

How to Add a Vue Timesheet Component

vue timesheet default configuration

Create a new component (timesheet.vue) and add DayPilot Scheduler using <DayPilotScheduler> tag:

<template>
  <DayPilotScheduler id="dp" :config="config" />
</template>

<script>
import {DayPilot, DayPilotScheduler} from 'daypilot-pro-vue'

export default {
  name: 'Timesheet',
  data: function() {
    return {
      config: {
        // ...
      },
    }
  },
  components: {
    DayPilotScheduler
  },
}
</script>

The config object defines the Scheduler properties and event handlers.

First, it’s necessary to switch the Vue Scheduler component to the timesheet mode:

config: {
  viewType: "Days",
  /// ...
},

To display the October 2021, use startDate and days properties:

config: {
  startDate: "2021-10-01",
  days: 31,
  // ...
},

The time headers (the horizontal axis) will display hours of day and 15-minute intervals:

config: {
  timeHeaders: [{"groupBy":"Hour"},{"groupBy":"Cell","format":"mm"}],
  scale: "CellDuration",
  cellDuration: 15,
  // ...
},

This is how the initial configuration looks now. In the mounted() event handler, we also load sample timesheet records using the loadEvents() method.

<template>
  <DayPilotScheduler id="dp" :config="config" ref="timesheet" />
</template>

<script>
import {DayPilotScheduler} from 'daypilot-pro-vue'

export default {
  name: 'Timesheet',
  data: function() {
    return {
      config: {
        startDate: "2021-10-01",
        days: 31,
        timeHeaders: [{"groupBy":"Hour"},{"groupBy":"Cell","format":"mm"}],
        scale: "CellDuration",
        cellDuration: 15,
        viewType: "Days",
        showNonBusiness: true,
        businessWeekends: false,
      },
    }
  },
  props: {
  },
  components: {
    DayPilotScheduler
  },
  computed: {
    // DayPilot.Scheduler object - https://api.daypilot.org/daypilot-scheduler-class/
    scheduler: function () {
      return this.$refs.timesheet.control;
    }
  },
  methods: {
    loadEvents() {
      const events = [
        {
          id: 1,
          start: "2021-10-05T09:30:00",
          end: "2021-10-05T11:30:00",
          text: "Event 1"
        },
        {
          id: 2,
          start: "2021-10-05T12:00:00",
          end: "2021-10-05T15:00:00",
          text: "Event 2"
        }
      ];
      this.config.events = events;
    },
  },
  mounted: function() {
    this.loadEvents();
    this.scheduler.scrollTo("2021-10-01T09:00:00");
    this.scheduler.message("Welcome!");
  }
}
</script>

To learn more on using the Vue Scheduler component, please see the Vue Scheduler: Build a Reservation Application in 5 Minutes tutorial.

How to Style the Vue Timesheet using CSS

vue timesheet css styling theme

The Vue timesheet component can be styled using CSS. The Scheduler includes a default CSS theme which is enabled by default. You can customize the appearance using one of the following methods:

  1. You can create a custom CSS theme using the online Theme Designer. The Theme Designer will generate a CSS file which you can download and include in your project. You can switch to the custom theme using the theme property.

  2. You can also directly override selected styles of the default theme.

As we only want to change the event appearance, we will use method #2 and override the event CSS classes:

<style>
body .scheduler_default_event_inner {
  border-radius: 17px;
  padding-left: 10px;
  background: #6aa84f;
  border: none;
  color: #ffffff;
}

body .scheduler_default_event_bar {
  display: none;
}

body .scheduler_default_event_float_inner {
  color: #ffffff;
}

body .scheduler_default_event_float_inner::after {
  border-color: transparent #ffffff transparent transparent;
}
</style>

How to Display Duration of Timesheet Events

vue timesheet event duration

By default, the Timesheet event displays the default text (defined using the text property), aligned to the left.

We will add event duration and display it on the right side of the event using an event active area.

config: {
  // ...
  onBeforeEventRender: args => {
    const duration = new DayPilot.Duration(args.data.start, args.data.end);
    args.data.areas = [
      { right: 2, top: 0, bottom: 0, width: 30, html: duration.toString('h:mm'), style: 'display: flex; align-items: center', fontColor: "#fff"}
    ];
  },
  // ...
}

How to Calculate Daily Totals

vue timesheet daily totals

First, define custom row header columns using rowHeaderColumns property:

config: {
  rowHeaderColumns: [
    {name: "Date"},
    {name: "Day"},
    {name: "Total"},
  ],
  // ...
}

Now you can define the column content using onBeforeRowHeaderRender event. You can also use this event to customize the appearance of the header cells (background color, font color, text alignment) and add icons with additional functionality using active areas.

config: {
  onBeforeRowHeaderRender: args => {
    const day = args.row.start.toString("dddd");
    args.row.columns[1].text = `${day}`;

    const duration = args.row.events.totalDuration();
    if (duration.totalSeconds() === 0) {
      return;
    }

    let hours = duration.toString('H:mm');
    if (duration.totalDays() >= 1) {
      hours = Math.floor(duration.totalHours()) + ':' + duration.toString('mm');
    }
    args.row.columns[2].text = `${hours} hours`;
  },
}

The first column (“Date”) will display the default content (the date). It uses the datePattern property of the current locale to format the date. If you don’t like the default text, you can override it using args.row.columns[0].text property.

The second column (“Day”) displays the day of week:

const day = args.row.start.toString("dddd");
args.row.columns[1].text = `${day}`;

The third column (“Total”) displays the daily total. You can get the total duration of all events in a row using the args.row.events.totalDuration() method.

const duration = args.row.events.totalDuration();

This method returns a DayPilot.Duration object. Now you can format the duration using the toString() method.

let hours = duration.toString('H:mm');
args.row.columns[2].text = `${hours} hours`;