---
title: "JQuery Timeline Work Order Scheduling Example | Mobiscroll"
component: "Timeline"
framework: "jQuery"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/jquery/timeline/work-order-scheduling"
---

# Work Order Scheduling - jQuery Timeline demo

Schedule work orders across grouped resources — drivers, trucks, and contractors — on a JQuery timeline.

- [Live demo](https://demo.mobiscroll.com/jquery/timeline/work-order-scheduling)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-jquery/tree/main/src/demos/eventcalendar/timeline/work-order-scheduling)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/timeline/work-order-scheduling.md), [Angular](https://demo.mobiscroll.com/angular/timeline/work-order-scheduling.md), [React](https://demo.mobiscroll.com/react/timeline/work-order-scheduling.md), [Vue](https://demo.mobiscroll.com/vue/timeline/work-order-scheduling.md)

## Description

When scheduling work orders and synchronizing them across various assets, the timeline can be of enormous value. Resources of the same type can be grouped and arranged in multi-depth hierarchies. The list of various assets, employees, contractors can be added and organized under it.

For add/edit a custom form with the necessary fields (including resources) can be built. Resources linked to a work order can be of various categories, eg. drivers, trucks, contractors and will show up in their respective rows.

You can use the [date header template](https://demo.mobiscroll.com/jquery/timeline/hour-day-week-month-quarter-year-header-footer-template) and add a simple [event template](https://demo.mobiscroll.com/jquery/timeline/timeline-custom-event-rendering) to show the $ value and print the total daily revenue below every day in the header.

## What this demo shows

- A desktop weekly timeline for work order scheduling, with Monday to Friday working days arranged horizontally and a hierarchical resource tree arranged vertically on the left.
- **Header navigation** The month and year label in the top left opens date navigation, while the blue previous and next arrows and the Today button on the right make it easy to move between weeks and jump back to the current day.
- **Week view** The fixed strip below the header shows the selected work week from Monday to Friday, using the `DD DDD MMM YYYY` date format.
- **Daily totals** A summary row below the date labels displays aggregated daily revenue in dollars.
- **Time grid** The timeline shows working hours from 5 AM to 9 PM with hourly columns under each day.
- **Resources** The left side shows expandable and collapsible resource groups, including parent groups such as Contractors, Employees, and Equipment.
- **Resource hierarchy** Nested resources are grouped by department or category, such as Cement masons and Drivers, before listing individual team members.
- **Current time** Demonstrates a current time indicator, shown as a vertical blue line with the current time label.
- **Hover behavior** Hovering over the time grid shows a time indicator that follows the cursor in 15-minute increments.
- **Event cards** Events are rendered as colored cards with a colored stripe on the left, the exact start and end time below the title, the project name in bold, and the project value shown as a badge next to the title.
- **Event positioning** Events are positioned by assigned resource, date, start time, and end time.
- **Multi-resource assignments** The same project can be assigned to multiple resources at the same time and appears in each assigned resource row.
- **Resource utilization** Different projects can be assigned to different employees during the same day, making resource usage visible across the timeline.
- **Event creation** New events can be created by double-clicking an individual resource row in the timeline or by clicking and dragging across a time range.
- **New event dialog** Creating an event opens a dialog with fields for Title, Location, Bill to customer ($), and Notes.
- **Resource assignment** The event dialog includes start and end time selection and a checklist for choosing the resources where the event should appear.
- **Time selection** The start and end inputs open a time picker with range selection.
- **Event editing** Clicking or tapping an existing event opens the same dialog in edit mode with the current values prefilled.
- **Editable properties** In edit mode, event details can be changed before saving.
- **Save and close behavior** Clicking outside the dialog or pressing Cancel closes the editor without applying changes, while Save updates or save the event.
- **Delete flow** The edit dialog includes a Delete work order action that removes the event from the timeline.
- **Undo feedback** After deletion, a centered bottom toast appears with an Undo action so the deleted event can be restored.
- **Event interaction** Events are highlighted on hover and show drag and resize handles for repositioning or changing duration.
- **Event selection** Clicking an event selects and highlights it.
- **Vertical scrolling** The resource area scrolls vertically so many resources can be displayed in one timeline.
- **Horizontal scrolling** The timeline supports horizontal scrolling for navigating a larger date range.

## Best for

- **Work order scheduling** Planning jobs across employees, contractors, equipment, and other assets in a single timeline.
- **Construction and field service planning** Assigning crews, vehicles, tools, and subcontractors to project work by day and hour.
- **Multi-resource dispatching** Scheduling the same job across several resource types when one work order requires multiple people or assets.
- **Revenue-aware scheduling** Showing daily revenue totals and per-project values directly in the timeline while planning work.
- **Hierarchical resource management** Organizing large resource lists by group, department, role, or asset type without losing the time-based scheduling context.
- **Interactive schedule editing** Supporting create, edit, delete, drag, resize, and undo flows for teams that need to adjust work orders directly from the calendar UI.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-themeVariant) - option
- [`view`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-view) - option
- [`clickToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToResize) - option
- [`dragTimeStep`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragTimeStep) - option
- [`data`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-data) - option
- [`resources`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-resources) - option
- [`extendDefaultEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-extendDefaultEvent) - option
- [`onEventClick`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventClick) - event
- [`isVisible`](https://mobiscroll.com/docs/jquery/popup/api#method-isVisible) - method
- [`onEventCreated`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventCreated) - event
- [`close`](https://mobiscroll.com/docs/jquery/popup/api#method-close) - method
- [`onEventDeleted`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventDeleted) - event
- [`addEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-addEvent) - method
- [`renderTimelineDay`](https://mobiscroll.com/docs/jquery/eventcalendar/api#renderer-renderTimelineDay) - renderer
- [`renderTimelineEventContent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#renderer-renderTimelineEventContent) - renderer
- [`setOptions`](https://mobiscroll.com/docs/jquery/popup/api#method-setOptions) - method
- [`headerText`](https://mobiscroll.com/docs/jquery/popup/api#opt-headerText) - option
- [`buttons`](https://mobiscroll.com/docs/jquery/popup/api#opt-buttons) - option
- [`updateEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-updateEvent) - method
- [`navigateToEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-navigateToEvent) - method
- [`cssClass`](https://mobiscroll.com/docs/jquery/popup/api#opt-cssClass) - option
- [`anchor`](https://mobiscroll.com/docs/jquery/popup/api#opt-anchor) - option
- [`open`](https://mobiscroll.com/docs/jquery/popup/api#method-open) - method
- [`display`](https://mobiscroll.com/docs/jquery/popup/api#opt-display) - option
- [`fullScreen`](https://mobiscroll.com/docs/jquery/popup/api#opt-fullScreen) - option
- [`scrollLock`](https://mobiscroll.com/docs/jquery/popup/api#opt-scrollLock) - option
- [`onClose`](https://mobiscroll.com/docs/jquery/popup/api#event-onClose) - event
- [`removeEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-removeEvent) - method
- [`responsive`](https://mobiscroll.com/docs/jquery/popup/api#opt-responsive) - option
- [`width`](https://mobiscroll.com/docs/jquery/popup/api#opt-width) - option
- [`touchUi`](https://mobiscroll.com/docs/jquery/popup/api#opt-touchUi) - option
- [`controls`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-controls) - option
- [`select`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-select) - option
- [`startInput`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-startInput) - option
- [`endInput`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-endInput) - option
- [`timeWheels`](https://mobiscroll.com/docs/jquery/datepicker/api#localization-timeWheels) - option
- [`showRangeLabels`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-showRangeLabels) - option
- [`touchUi`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-touchUi) - option
- [`stepMinute`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-stepMinute) - option
- [`minTime`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-minTime) - option
- [`maxTime`](https://mobiscroll.com/docs/jquery/datepicker/api#opt-maxTime) - option
- [`onChange`](https://mobiscroll.com/docs/jquery/datepicker/api#event-onChange) - event

## Code

### JS

```js
mobiscroll.setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

$(function () {
  function getCostString(cost) {
    return cost.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  }
  var calendar;
  var popup;
  var range;
  var oldEvent;
  var tempEvent = {};
  var deleteEvent;
  var restoreEvent;
  var $title = $('#work-order-title');
  var $location = $('#work-order-location');
  var $bill = $('#work-order-bill');
  var $notes = $('#work-order-notes');
  var $deleteButton = $('#work-order-delete');
  var $resources = $('#work-order-resources');
  var myResources = [
    {
      id: 'contractors',
      name: 'Contractors',
      collapsed: true,
      eventCreation: false,
      children: [
        {
          id: 'builders',
          name: 'Builders',
          eventCreation: false,
          children: [
            {
              id: 'b1',
              name: 'Jude Chester',
            },
            {
              id: 'b2',
              name: 'Willis Kane',
            },
          ],
        },
        {
          id: 'carpenters',
          name: 'Carpenters',
          eventCreation: false,
          children: [
            {
              id: 'c1',
              name: 'Derek Austyn',
            },
            {
              id: 'c2',
              name: 'Merv Kenny',
            },
          ],
        },
      ],
    },
    {
      id: 'employees',
      name: 'Employees',
      eventCreation: false,
      children: [
        {
          id: 'cement_masons',
          name: 'Cement masons',
          eventCreation: false,
          children: [
            {
              id: 'ce1',
              name: 'Ford Kaiden',
            },
            {
              id: 'ce2',
              name: 'Jewell Ryder',
            },
          ],
        },
        {
          id: 'divers',
          name: 'Drivers',
          eventCreation: false,
          children: [
            {
              id: 'd1',
              name: 'Fred Valdez',
            },
            {
              id: 'd2',
              name: 'Jon Drake',
            },
            {
              id: 'd3',
              name: 'Lou Andie',
            },
            {
              id: 'd4',
              name: 'Leon Porter',
            },
          ],
        },
      ],
    },
    {
      id: 'equipment',
      name: 'Equipment',
      collapsed: true,
      eventCreation: false,
      children: [
        {
          id: 'concrete_mixers',
          name: 'Concrete mixers',
          eventCreation: false,
          children: [
            {
              id: 'cm1',
              name: 'AL 45 RFT',
            },
            {
              id: 'cm2',
              name: 'KQ 62 PVZ',
            },
            {
              id: 'cm3',
              name: 'RG 91 ZAL',
            },
            {
              id: 'cm4',
              name: 'XF 83 GFM',
            },
          ],
        },
        {
          id: 'concrete_pumps',
          name: 'Concrete pumps',
          eventCreation: false,
          children: [
            {
              id: 'cp1',
              name: 'GF 61 BVM',
            },
            {
              id: 'cp2',
              name: 'YC 55 ECT',
            },
          ],
        },
      ],
    },
  ];

  calendar = $('#demo-work-order-scheduling')
    .mobiscroll()
    .eventcalendar({
      view: {
        timeline: {
          type: 'week',
          startDay: 1,
          endDay: 5,
          startTime: '05:00',
          endTime: '22:00',
        },
      },
      clickToCreate: true,
      dragToCreate: true,
      dragToMove: true,
      dragToResize: true,
      dragTimeStep: 30,
      data: [
        {
          start: '2026-10-23T06:00',
          end: '2026-10-23T14:00',
          title: 'Farmhouse TPH',
          location: '3339 Spruce Drive',
          resource: ['d2', 'cm2', 'd4', 'cp1', 'cm2', 'ce2', 'b1'],
          color: '#12ca6c',
          cost: 48000,
        },
        {
          start: '2026-10-24T08:00',
          end: '2026-10-24T18:00',
          title: 'Block of flats KXT',
          location: '4698 Mercer Street',
          resource: ['d1', 'cm1', 'd3', 'cp1', 'cm3', 'ce2', 'b2'],
          color: '#c170c3',
          cost: 36000,
        },
        {
          start: '2026-10-25T12:00',
          end: '2026-10-25T20:00',
          title: 'Apartment house UGL',
          location: '3647 Tavern Place',
          resource: ['d3', 'cm2', 'd4', 'cp2', 'cm3', 'ce1', 'b2'],
          color: '#03c9d2',
          cost: 50000,
        },
        {
          start: '2026-10-26T11:00',
          end: '2026-10-26T19:00',
          title: 'Detached house WKB',
          location: '956 Dovetail Estates',
          resource: ['d1', 'cm3', 'd4', 'cp3', 'cm4', 'c2', 'b1', 'ce2'],
          color: '#ff1515',
          cost: 55000,
        },
        {
          start: '2026-10-27T10:00',
          end: '2026-10-27T18:00',
          title: 'Apartment house XAZ',
          location: '4919 Jett Lane, Inglewood',
          resource: ['d1', 'cm4', 'd4', 'cp1', 'cm2', 'c2', 'b2'],
          color: '#12ca6c',
          cost: 62000,
        },
        {
          start: '2026-10-27T08:00',
          end: '2026-10-27T16:00',
          title: 'Block of flats DRG',
          location: '486 Sycamore Fork Road',
          resource: ['d2', 'cm1', 'd3', 'cp2', 'ce2', 'c1', 'b1'],
          color: '#efd414',
          cost: 39000,
        },
        {
          start: '2026-10-28T09:00',
          end: '2026-10-28T17:00',
          title: 'Farmhouse YQK',
          location: '1563 Retreat Avenue',
          resource: ['d2', 'cm4', 'd4', 'cm2', 'cp1', 'c2', 'b2'],
          color: '#cf49d8',
          cost: 45000,
        },
        {
          start: '2026-10-29T07:00',
          end: '2026-10-29T15:00',
          title: 'Apartment house SWP',
          location: '628 Daylene Drive',
          resource: ['d2', 'cm3', 'd3', 'cm1', 'cp2', 'c1', 'b1'],
          color: '#c170c3',
          cost: 53000,
        },
        {
          start: '2026-10-30T10:00',
          end: '2026-10-30T18:00',
          title: 'Detached house OZL',
          location: '1830 Rinehart Road',
          resource: ['d3', 'cm2', 'd4', 'cp2', 'cm3', 'ce1', 'b2'],
          color: '#ff1515',
          cost: 47000,
        },
        {
          start: '2026-10-31T11:00',
          end: '2026-10-31T19:00',
          title: 'Farmhouse PSZ',
          location: '2410 Union Street',
          resource: ['d1', 'cm3', 'd4', 'cp3', 'cm4', 'c2', 'b1', 'ce2'],
          color: '#ff1515',
          cost: 64000,
        },
      ],
      resources: myResources,
      extendDefaultEvent: function () {
        return {
          title: 'Work order',
          location: '',
          cost: 0,
        };
      },
      onEventClick: function (args) {
        oldEvent = $.extend({}, args.event);
        tempEvent = args.event;

        if (!popup.isVisible()) {
          createEditPopup(args);
        }
      },
      onEventCreated: function (args) {
        popup.close();

        // Store temporary event
        tempEvent = args.event;
        createAddPopup(args.target);
      },
      onEventDeleted: function (args) {
        mobiscroll.snackbar({
          button: {
            action: function () {
              calendar.addEvent(args.event);
            },
            text: 'Undo',
          },
          message: 'Event deleted',
        });
      },
      renderTimelineDay: function (args) {
        var formatDate = mobiscroll.formatDate;
        var events = args.events;
        var costs = 0;

        if (events) {
          for (var i = 0; i < events.length; ++i) {
            costs += events[i].cost;
          }
        }

        return (
          '<div class="md-work-order-date">' +
          formatDate('DD DDD MMM YYYY', args.date) +
          '</div>' +
          '<div class="md-work-order-date-title">Total revenue: $' +
          getCostString(costs) +
          '</div>'
        );
      },
      renderTimelineEventContent: function (event) {
        return '<div>' + event.title + '<span class="md-work-order-price-tag">$' + getCostString(event.original.cost) + '</span></div>';
      },
    })
    .mobiscroll('getInst');

  function createAddPopup(elm) {
    // Hide delete button inside add popup
    $deleteButton.hide();

    deleteEvent = true;
    restoreEvent = false;

    // Set popup header text and buttons for adding
    popup.setOptions({
      headerText: 'New work order',
      buttons: [
        'cancel',
        {
          text: 'Add',
          keyCode: 'enter',
          handler: function () {
            calendar.updateEvent(tempEvent);

            // Navigate the calendar to the correct view
            calendar.navigateToEvent(tempEvent);

            deleteEvent = false;
            popup.close();
          },
          cssClass: 'mbsc-popup-button-primary',
        },
      ],
    });

    // Fill popup with a new event data
    $title.mobiscroll('getInst').value = tempEvent.title;
    $location.mobiscroll('getInst').value = tempEvent.location;
    $bill.mobiscroll('getInst').value = tempEvent.cost;
    $notes.mobiscroll('getInst').value = '';
    range.setVal([tempEvent.start, tempEvent.end]);
    setCheckboxes(tempEvent.resource);

    // Set anchor for the popup
    popup.setOptions({ anchor: elm });

    popup.open();
  }

  function createEditPopup(args) {
    var ev = args.event;
    // Show delete button inside edit popup
    $deleteButton.show();

    deleteEvent = false;
    restoreEvent = true;

    // Set popup header text and buttons for editing
    popup.setOptions({
      headerText: 'Edit work order',
      buttons: [
        'cancel',
        {
          text: 'Save',
          keyCode: 'enter',
          handler: function () {
            var date = range.getVal();
            var updatedEvent = {
              id: ev.id,
              title: $title.val(),
              location: $location.val(),
              cost: +$bill.val() || 0,
              notes: $notes.val(),
              start: date[0],
              end: date[1],
              color: ev.color,
              resource: ev.resource,
            };

            // Update event with the new properties on save button click
            calendar.updateEvent(updatedEvent);

            // Navigate the calendar to the correct view
            calendar.navigateToEvent(updatedEvent);

            restoreEvent = false;
            popup.close();
          },
          cssClass: 'mbsc-popup-button-primary',
        },
      ],
    });

    // Fill popup with the selected event data
    $title.mobiscroll('getInst').value = ev.title || '';
    $location.mobiscroll('getInst').value = ev.location || '';
    $bill.mobiscroll('getInst').value = ev.cost || 0;
    $notes.mobiscroll('getInst').value = ev.description || '';
    range.setVal([ev.start, ev.end]);
    setCheckboxes(ev.resource);

    // Set anchor for the popup
    popup.setOptions({ anchor: args.domEvent.currentTarget });
    popup.open();
  }

  function setCheckboxes(resources) {
    $('.work-order-checkbox').each(function (i, elm) {
      $(elm).mobiscroll('getInst').checked = resources.indexOf($(elm).data('value')) !== -1;
    });
  }

  function appendChekboxes() {
    var checkboxes = '<div class="mbsc-grid mbsc-no-padding"><div class="mbsc-row">';

    for (var i = 0; i < myResources.length; ++i) {
      for (var j = 0; j < myResources[i].children.length; ++j) {
        var resource = myResources[i].children[j];

        checkboxes += '<div class="mbsc-col-sm-4"><div class="mbsc-form-group-title">' + resource.name + '</div>';

        for (var k = 0; k < resource.children.length; ++k) {
          var r = resource.children[k];
          checkboxes +=
            '<label class="md-work-order-checkbox-label"><input class="work-order-checkbox" data-value="' +
            r.id +
            '" type="checkbox" mbsc-checkbox data-theme="material" data-label="' +
            r.name +
            '"/></label>';
        }
        checkboxes += '</div>';
      }
    }
    checkboxes += '</div></div>';

    $resources.append(checkboxes);
    mobiscroll.enhance($resources[0]);
  }

  popup = $('#demo-work-order-popup')
    .mobiscroll()
    .popup({
      display: 'bottom',
      contentPadding: false,
      fullScreen: true,
      scrollLock: false,
      onClose: function () {
        if (deleteEvent) {
          calendar.removeEvent(tempEvent);
        } else if (restoreEvent) {
          calendar.updateEvent(oldEvent);
        }
      },
      responsive: {
        medium: {
          display: 'center',
          width: 520,
          fullScreen: false,
          touchUi: false,
        },
      },
    })
    .mobiscroll('getInst');

  $title.on('input', function (ev) {
    // Update current event's title
    tempEvent.title = ev.target.value;
  });

  $location.on('input', function (ev) {
    // Update current event's location
    tempEvent.location = ev.target.value;
  });

  $bill.on('input', function (ev) {
    // Update current event's cost
    tempEvent.cost = +ev.target.value || 0;
  });

  $notes.on('change', function (ev) {
    // Update current event's description
    tempEvent.description = ev.target.value;
  });

  $('#demo-work-order-popup').on('change', '.work-order-checkbox', function (ev) {
    var tempResource = tempEvent.resource;
    var resources = tempResource ? (Array.isArray(tempResource) ? tempResource : [tempResource]) : [];
    var val = $(ev.target).data('value');

    if (ev.target.checked && resources.indexOf(val) === -1) {
      resources.push(val);
    } else {
      resources = resources.filter(function (value) {
        return value != val;
      });
    }
    tempEvent.resource = resources;
  });

  range = $('#work-order-date')
    .mobiscroll()
    .datepicker({
      controls: ['time'],
      select: 'range',
      startInput: '#work-order-start',
      endInput: '#work-order-end',
      timeWheels: '|h:mm A|',
      showRangeLabels: false,
      touchUi: false,
      stepMinute: 30,
      minTime: '06:00',
      maxTime: '22:00',
      onChange: function (args) {
        var date = args.value;

        // Update event's start date
        tempEvent.start = date[0];
        tempEvent.end = date[1];
      },
    })
    .mobiscroll('getInst');

  $deleteButton.on('click', function () {
    // Delete current event on button click
    calendar.removeEvent(tempEvent);

    // Save a local reference to the deleted event
    var deletedEvent = tempEvent;

    popup.close();

    mobiscroll.snackbar({
      button: {
        action: function () {
          calendar.addEvent(deletedEvent);
        },
        text: 'Undo',
      },
      duration: 10000,
      message: 'Event deleted',
    });
  });

  appendChekboxes();
});
```

### HTML

```html
<div id="demo-work-order-scheduling" class="md-work-order-scheduling"></div>

<div style="display:none;">
    <div id="demo-work-order-popup">
        <div class="mbsc-form-group">
            <label>
            Title
            <input mbsc-input id="work-order-title" />
        </label>
            <label>
            Location
            <input mbsc-input id="work-order-location" />
        </label>
            <label>
            Bill to customer ($)
            <input mbsc-input id="work-order-bill" />
        </label>
            <label>
            Notes
            <textarea mbsc-textarea id="work-order-notes"></textarea>
        </label>
        </div>
        <div class="mbsc-form-group">
            <label>
            Starts
            <input mbsc-input id="work-order-start" />
        </label>
            <label>
            Ends
            <input mbsc-input id="work-order-end" />
        </label>
            <div id="work-order-date"></div>
        </div>
        <div id="work-order-resources" class="mbsc-form-group">

        </div>

        <div class="mbsc-button-group">
            <button class="mbsc-button-block" id="work-order-delete" mbsc-button data-color="danger" data-variant="outline">Delete work order</button>
        </div>
    </div>
</div>
```

### CSS

```css
.md-work-order-checkbox-label.mbsc-checkbox {
    padding-top: 5px;
    padding-bottom: 5px;
}

.md-work-order-date {
    font-size: 14px;
    border-bottom: 1px solid #ccc;
    padding: 5px 10px;
}

.md-work-order-date-title {
    font-size: 13px;
    padding: 5px 10px;
    line-height: 18px;
    opacity: 0.6;
}

.md-work-order-price-tag {
    display: inline-block;
    font-size: 11px;
    line-height: 16px;
    vertical-align: middle;
    border: 1px solid currentColor;
    border-radius: 5px;
    margin: 0 10px;
    padding: 0px 5px;
    opacity: 0.6;
}

.md-work-order-scheduling .mbsc-timeline-parent {
    height: 32px;
}
```

## Implementation notes

- Use the timeline view with `type: 'week'` and `startDay: 1` / `endDay: 5` to show a Mon-Fri planning week.
- Define a three-level resource tree: top-level groups → subcategory groups → individual leaf resources. Set `eventCreation: false` on all group and subgroup nodes so events are only associated with individual resources, not with the category rows themselves.
- Set `collapsed: true` on top-level groups that should start folded, such as Contractors and Equipment.
- Assign a work order to multiple resources by setting its `resource` property to an array of leaf resource IDs. The event will appear in every row whose ID is included in the array.
- Enable `clickToCreate="double"` for double-click creation and `dragToCreate={true}` for drag-based creation. Set `dragToMove: true` and `dragToResize: true` to allow repositioning and resizing. Use `dragTimeStep: 30` to snap all drag operations to 30-minute increments.
- Use `extendDefaultEvent` to pre-populate sensible defaults (title, location, cost) on every newly created work order event.
- Use `renderTimelineEventContent` (Angular: `timelineEventContentTemplate`, Vue: `#timelineEventContent` slot) to display a custom event body that shows the work order title alongside a cost badge.
- Use `renderTimelineDay` (Angular: `timelineDayTemplate`, Vue: `#timelineDay` slot) to render a custom column header for each day. Calculate the total daily revenue by summing the `cost` field from the `events` array provided in the render args, and display it below the date label.
- Use `onEventCreated` to intercept newly created events and open the add popup. Use `onEventClick` to open the edit popup for existing events. Pass `args.target` from `onEventCreated` as the popup `anchor` so the anchored popover positions itself relative to the new event.
- Build the popup with the `Popup` component. Use the `responsive` option to show a full-screen bottom sheet on mobile and a fixed-width anchored popover on larger screens.
- Include a resource assignment section in the popup using checkboxes for each leaf resource, grouped visually by subcategory. Initialize the checked state from the event's `resource` array and write it back on save so the work order is reassigned across the correct rows.
- After saving, call `navigateToEvent` on the calendar instance ref to scroll the timeline to the updated or newly created work order.
- For deletion, remove the event immediately from the data array and show a `Snackbar` with an Undo action that restores it if the user reverses the action.

## Run it in your project

1. If not signed up yet, or don't own a license, you can [start a free trial](https://mobiscroll.com/starttrial).

2. Clone the repository:

   ```
   git clone https://github.com/acidb/mobiscroll-demos-jquery.git
   ```

3. If not installed yet, install the Mobiscroll CLI from NPM:

   ```
   npm install -g @mobiscroll/cli
   ```

4. Config Mobiscroll - open a terminal window in the root directory and run:

   ```
   mobiscroll config jquery
   ```

5. Install dependencies - open a terminal window in the root directory and run:

   ```
   npm install
   ```

6. Run the project:

   ```
   npm run dev
   ```

On a trial, add `--trial` to the config command: `mobiscroll config jquery --trial`.

Running a demo locally requires a Mobiscroll trial or a license; setup is per framework at https://mobiscroll.com/docs/jquery/getting-started/installation

## Related demos

- Previous: [Employee Shift Scheduling](https://demo.mobiscroll.com/jquery/timeline/employee-shifts.md) - Plan employee shifts on a JQuery Timeline — show workers as resource rows with morning and afternoon slots, and manage shifts with a custom add/edit dialog.
- Next: [Timezone Meeting Planner](https://demo.mobiscroll.com/jquery/timeline/timezone-meeting-planner.md) - Plan team meetings across time zones with the JQuery Timeline — show per-resource availability in working, flex, and time-off blocks, with local-time events.
