---
title: "JQuery Scheduler 24-Hour Rotating Crew Shift Rota Example | Mobiscroll"
component: "Scheduler"
framework: "jQuery"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/jquery/scheduler/24-hour-manufacturing-shift-rota-planning"
---

# 24-Hour Rotating Crew Shift Rota - jQuery Scheduler demo

Build a 24-hour rotating crew rota with the JQuery Scheduler — three crews, three shifts, and automatic conflict resolution when shifts move.

- [Live demo](https://demo.mobiscroll.com/jquery/scheduler/24-hour-manufacturing-shift-rota-planning)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-jquery/tree/main/src/demos/eventcalendar/scheduler/24-hour-manufacturing-shift-rota-planning)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/scheduler/24-hour-manufacturing-shift-rota-planning.md), [Angular](https://demo.mobiscroll.com/angular/scheduler/24-hour-manufacturing-shift-rota-planning.md), [React](https://demo.mobiscroll.com/react/scheduler/24-hour-manufacturing-shift-rota-planning.md), [Vue](https://demo.mobiscroll.com/vue/scheduler/24-hour-manufacturing-shift-rota-planning.md)

## Description

The scheduler can be configured for industrial or service environments requiring 24/7 coverage, such as manufacturing lines or critical infrastructure maintenance. This setup uses three resources (Crew A, Crew B, Crew C) to demonstrate a cyclical, rotating roster, like the 3-Crew, 3-Shift Rota.

To visualize the continuous operation and manage shifts that span midnight, the scheduler view is configured with a custom, 24-hour cycle, starting at 06:00 and ending at 06:00 the following day. This is achieved using the custom day-offset feature added to the `startTime` (e.g., '20:00-1') and `endTime` (e.g., '08:00+1') properties under the [`view`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-view) option, which initiates the view relative to the previous or next calendar day. Furthermore, to ensure compliance with 8-hour shift lengths and prevent invalid scheduling, the drag-and-drop functionality is constrained by setting the [`dragTimeStep`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragTimeStep) to 8 hours, requiring all events to be moved only in 8-hour increments and anchoring the alignment with the [`dragTimeStepBase: 'viewStart'`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragTimeStepBase) option. The drag-and-drop logic is implemented for automatic conflict resolution: when an event is dragged to a different time or resource column within the same day, it automatically updates and shifts any conflicting events (those sharing the same time slot or resource column) to maintain scheduling integrity and prevent overlaps.

## What this demo shows

- A desktop weekly scheduler for 24-hour shift planning, with a fixed week strip, repeated resources for each day, and a vertically scrollable time grid running from 6 AM to 6 AM the following day.
- **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 strip**: The fixed strip below the header displays the days in the selected week, with the current date highlighted by a blue circle.
- **Resources**: Each day shows the same three resources: Crew A, Crew B, and Crew C.
- **Resource columns**: Each crew has its own column within the day column, keeping resources grouped by date.
- **Time grid**: The scheduler uses a custom 24-hour range from 6 AM to 6 AM the next day, with midnight marked by a stronger horizontal line.
- **Scrolling behavior**: The time grid scrolls vertically through the hours of the selected week.
- **Timed events**: Shifts appear as colored event cards with a colored stripe, bold shift title, and start and end time. Morning Shift runs from 6 AM to 2 PM, Afternoon Shift from 2 PM to 10 PM, and Night Shift from 10 PM to 6 AM.
- **Event overlap**: Shift events cannot overlap.
- **Shift coverage**: By default, each resource has a scheduled shift. Users can delete, create, or move shifts.
- **Missing shifts**: When a shift is deleted, the affected resource column is highlighted with a red background to show that no shift is scheduled for that resource.
- **Available shift slots**: When a resource has no shift, hovering over an available 8-hour shift period highlights the slot in green.
- **Shift repositioning**: Moving a shift can automatically update another shift on the same day to preserve coverage.
- **Current time**: A blue current-time line appears across the time grid.
- **Hover behavior**: Hovering over the time grid shows a time indicator that follows the cursor in 8-hour increments.
- **Event interaction**: Hovering over or selecting an event highlights it.
- **Toast messages**: Clicking an occupied time slot or trying to create a shift when every slot is already assigned shows an "Already assigned" toast at the bottom center of the scheduler. Deleting a shift shows a deletion toast with the shift name.

## Best for

- **Manufacturing and production facilities**: Schedule morning, afternoon, and night shifts across production lines, departments, or work crews while maintaining continuous coverage.
- **Warehousing and logistics operations**: Coordinate warehouse teams, loading crews, dispatch staff, and distribution personnel across multiple shifts.
- **Construction and field service teams**: Manage rotating crews, subcontractors, inspectors, and site personnel working across different schedules and locations.
- **Security and monitoring services**: Plan guard rotations, patrol schedules, control room operators, and emergency response teams around the clock.
- **Healthcare and care facilities**: Organize nurse rotations, support staff schedules, and departmental coverage across day, evening, and overnight shifts.
- **Hospitality and tourism businesses**: Schedule hotel staff, front desk teams, housekeeping crews, event staff, and service personnel.
- **Retail operations**: Manage store associates, supervisors, cashiers, and department teams while balancing staffing levels during peak and off-peak hours.
- **Transportation and aviation services**: Coordinate drivers, dispatchers, pilots, cabin crews, ground staff, and maintenance teams.
- **Customer support and contact centers**: Plan agent coverage across time zones, shifts, and support channels to meet service level requirements.
- **Public services and emergency organizations**: Schedule firefighters, police officers, emergency medical personnel, and municipal service teams.
- **Media, broadcasting, and operations centers**: Coordinate production crews, technical operators, studio staff, and live-event teams that require continuous coverage.
- **IT and DevOps teams**: Manage on-call rotations, support shifts, operations coverage, and incident response schedules for 24/7 systems.

## 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
- [`getEvents`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-getEvents) - method
- [`cssClass`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-cssClass) - option
- [`data`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-data) - option
- [`dragToMove`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToMove) - option
- [`dragToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToCreate) - option
- [`clickToCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-clickToCreate) - option
- [`dragToResize`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragToResize) - option
- [`dragTimeStep`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-dragTimeStep) - option
- [`eventDelete`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-eventDelete) - option
- [`eventOverlap`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-eventOverlap) - option
- [`extendDefaultEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-extendDefaultEvent) - option
- [`onCellHoverIn`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onCellHoverIn) - event
- [`setOptions`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-setOptions) - method
- [`colors`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-colors) - option
- [`onCellHoverOut`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onCellHoverOut) - event
- [`onEventCreate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventCreate) - event
- [`onEventClick`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventClick) - event
- [`onEventDelete`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventDelete) - event
- [`onEventDragStart`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventDragStart) - event
- [`onEventUpdateFailed`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventUpdateFailed) - event
- [`onEventUpdate`](https://mobiscroll.com/docs/jquery/eventcalendar/api#event-onEventUpdate) - event
- [`updateEvent`](https://mobiscroll.com/docs/jquery/eventcalendar/api#method-updateEvent) - method
- [`groupBy`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-groupBy) - option
- [`resources`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-resources) - option
- [`renderResource`](https://mobiscroll.com/docs/jquery/eventcalendar/api#renderer-renderResource) - renderer
- [`view`](https://mobiscroll.com/docs/jquery/eventcalendar/api#opt-view) - option

## Code

### JS

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

$(function () {
  var draggedEventStart;
  var draggedEventEnd;
  var draggedEventResource;
  var availableSlotOnHover;
  var redResources = {};
  var currentColors = [];

  var morningColor = '#4a8c4d';
  var afternoonColor = '#f87c6b';
  var nightColor = '#8567AD';

  var shifts = {
    morning: { startHour: 6, endHour: 14, title: 'Morning Shift', color: '#4a8c4d' },
    afternoon: { startHour: 14, endHour: 22, title: 'Afternoon Shift', color: '#f87c6b' },
    night: { startHour: 22, endHour: 6, nextDay: true, title: 'Night Shift', color: '#8567AD' },
  };

  function getShiftByHour(hour) {
    if (hour >= 6 && hour < 14) {
      return shifts.morning;
    }
    if (hour >= 14 && hour < 22) {
      return shifts.afternoon;
    }
    if (hour >= 22 || hour < 6) {
      return shifts.night;
    }
    return shifts.afternoon;
  }

  function calculateStart(start) {
    var d = new Date(start);
    var originalHour = d.getHours();
    var shift = getShiftByHour(originalHour);
    d.setHours(shift.startHour, 0, 0, 0);
    if (shift.startHour === 22 && originalHour < 6) {
      d.setDate(d.getDate() - 1);
    }
    return d;
  }

  function calculateEnd(start) {
    var d = new Date(start);
    var startHour = d.getHours();
    var shift = getShiftByHour(d.getHours());
    d.setHours(shift.endHour, 0, 0, 0);
    if (shift.nextDay && startHour === 22) {
      d.setDate(d.getDate() + 1);
    }
    return d;
  }

  function getTitle(startHours) {
    return getShiftByHour(startHours).title;
  }

  function getColor(startHours) {
    return getShiftByHour(startHours).color;
  }

  function getAvailableSlots(inst, resourceId, dayStart) {
    var dayEnd = new Date(dayStart);
    dayEnd.setDate(dayEnd.getDate() + 1);
    dayEnd.setHours(6, 0, 0, 0);
    var dayEvents = inst.getEvents(dayStart, dayEnd);
    var slots = { morning: true, afternoon: true, night: true };
    dayEvents.forEach(function (e) {
      if (e.resource === resourceId) {
        slots.morning = slots.afternoon = slots.night = false;
      } else {
        var startHour = new Date(e.start).getHours();
        if (startHour === 6) {
          slots.morning = false;
        } else if (startHour === 14) {
          slots.afternoon = false;
        } else if (startHour === 22) {
          slots.night = false;
        }
      }
    });
    return slots;
  }

  function clearColorsForResource(currentColors, resourceId, date) {
    var base = new Date(date);
    base.setHours(0, 0, 0, 0);
    var baseTime = +base;
    return currentColors.filter(function (c) {
      if (c.resource === resourceId) {
        var cDate = new Date(c.start);
        cDate.setHours(0, 0, 0, 0);
        if (+cDate === baseTime) {
          var hour = new Date(c.start).getHours();
          if (hour === 6 || hour === 14 || hour === 22) {
            return false;
          }
        }
      }
      return true;
    });
  }

  $('#demo-24-hour-manufacturing-shift-rota-planning')
    .mobiscroll()
    .eventcalendar({
      cssClass: 'mds-24-hour-manufacturing-calendar',
      data: [
        { resource: 'A', title: 'Morning Shift', start: '2026-10-23T06:00', end: '2026-10-23T14:00', color: morningColor },
        {
          resource: 'B',
          title: 'Afternoon Shift',
          start: '2026-10-23T14:00',
          end: '2026-10-23T22:00',
          color: afternoonColor,
        },
        { resource: 'C', title: 'Night Shift', start: '2026-10-23T22:00', end: '2026-10-24T06:00', color: nightColor },
        { resource: 'A', title: 'Morning Shift', start: '2026-10-24T06:00', end: '2026-10-24T14:00', color: morningColor },
        {
          resource: 'B',
          title: 'Afternoon Shift',
          start: '2026-10-24T14:00',
          end: '2026-10-24T22:00',
          color: afternoonColor,
        },
        { resource: 'C', title: 'Night Shift', start: '2026-10-24T22:00', end: '2026-10-25T06:00', color: nightColor },
        // Showing partial data. Download full source.
      ],
      dragToMove: true,
      dragToCreate: false,
      clickToCreate: 'single',
      dragToResize: false,
      dragTimeStep: 480,
      dragTimeStepBase: 'viewStart',
      eventDelete: true,
      eventOverlap: false,
      extendDefaultEvent: function (args) {
        var start = new Date(args.start);
        var newStart = calculateStart(start);
        var newEnd = calculateEnd(start);
        var title = getTitle(newStart.getHours());
        var color = getColor(newStart.getHours());
        return {
          title: title,
          start: newStart,
          end: newEnd,
          color: color,
        };
      },
      onCellHoverIn: function (args, inst) {
        var hoveredDate = new Date(args.date);
        var shift = getShiftByHour(hoveredDate.getHours());
        if (!shift) {
          return;
        }

        var dayStart = new Date(args.date);
        dayStart.setHours(6, 0, 0, 0);
        var availableSlots = getAvailableSlots(inst, args.resource.id, dayStart);
        var slotKey = Object.keys(availableSlots).find(function (key) {
          return availableSlots[key] && shifts[key].startHour === shift.startHour;
        });
        if (slotKey) {
          var startTime = new Date(dayStart);
          startTime.setHours(shifts[slotKey].startHour, 0, 0, 0);
          var endTime = new Date(+startTime + 8 * 60 * 60 * 1000 - 1);
          availableSlotOnHover = {
            background: '#c1ffe180',
            cssClass: 'available-slot mbsc-font-icon mbsc-icon-plus',
            start: +startTime + 1,
            end: endTime,
            resource: args.resource.id,
          };
          currentColors = [].concat(currentColors, [availableSlotOnHover]);
          inst.setOptions({ colors: currentColors });
        }
      },
      onCellHoverOut: function (args, inst) {
        currentColors = currentColors.filter(function (c) {
          return availableSlotOnHover !== c;
        });
        inst.setOptions({ colors: currentColors });
        availableSlotOnHover = null;
      },
      onEventCreate: function (args, inst) {
        var event = args.event;
        var dayStart = new Date(event.start);
        dayStart.setHours(6, 0, 0, 0);
        var dayEnd = new Date(dayStart);
        dayEnd.setDate(dayEnd.getDate() + 1);
        dayEnd.setHours(6, 0, 0, 0);
        var dayEvents = inst.getEvents(dayStart, dayEnd);
        var conflict = dayEvents.find(function (ev) {
          return ev.resource === event.resource || +new Date(ev.start) === +new Date(event.start);
        });
        if (conflict) {
          mobiscroll.toast({
            message: 'Already assigned',
          });
          return false;
        }
        currentColors = clearColorsForResource(currentColors, event.resource, event.start);
        var day = new Date(event.start);
        day.setHours(0, 0, 0, 0);
        redResources[event.resource + day.toISOString()] = false;
        inst.setOptions({ colors: currentColors });
        availableSlotOnHover = null;
      },
      onEventClick: function () {
        mobiscroll.toast({
          message: 'Already assigned',
        });
      },
      onEventDelete: function (args, inst) {
        var colorStart = new Date(args.event.start);
        colorStart.setHours(6, 0, 0, 0);
        var colorEnd = new Date(args.event.start);
        var colorEndDate = colorEnd.getDate();
        colorEnd.setDate(colorEndDate + 1);
        colorEnd.setHours(6, 0, 0, 0);

        if (currentColors.length) {
          currentColors.push({ start: colorStart, end: colorEnd, background: '#ffdbd280', resource: args.event.resource });
        } else {
          currentColors = [{ start: colorStart, end: colorEnd, background: '#ffdbd280', resource: args.event.resource }];
        }
        var resource = args.event.resource;
        var day = new Date(args.event.start);
        day.setHours(0, 0, 0, 0);
        redResources[resource + day.toISOString()] = true;
        inst.setOptions({
          colors: currentColors,
        });
        mobiscroll.toast({
          message: args.event.title + ' deleted',
        });
      },
      onEventDragStart: function (args) {
        draggedEventStart = args.event.start;
        draggedEventEnd = args.event.end;
        draggedEventResource = args.event.resource;
      },
      onEventUpdateFailed: function () {
        mobiscroll.toast({
          message: 'Already assigned',
        });
      },
      onEventUpdate: function (args, inst) {
        var event = args.event;
        var dayStart = new Date(event.start);
        dayStart.setHours(6, 0, 0, 0);
        var dragStartDay = new Date(draggedEventStart);
        dragStartDay.setHours(6, 0, 0, 0);
        if (+dayStart !== +dragStartDay) {
          return false;
        }

        var dayEvents = inst.getEvents(dayStart);
        var conflicts = dayEvents.filter(function (ev) {
          return ev.id !== event.id && (ev.resource === event.resource || +new Date(ev.start) === +new Date(event.start));
        });
        var evStart = new Date(event.start);
        event.title = getTitle(evStart.getHours());
        event.color = getColor(evStart.getHours());

        if (conflicts.length) {
          var shouldReturn = false;
          conflicts.forEach(function (sh, i) {
            if (sh.resource === event.resource) {
              if (+event.start === +new Date(sh.start)) {
                shouldReturn = true;
              }
              sh.resource = draggedEventResource;
              conflicts[i] = sh;
            } else {
              sh.start = draggedEventStart;
              sh.end = draggedEventEnd;
              var start = new Date(draggedEventStart);
              sh.title = getTitle(start.getHours());
              sh.color = getColor(start.getHours());
              conflicts[i] = sh;
            }
          });
          if (shouldReturn) {
            return false;
          }
          inst.updateEvent([].concat(conflicts, [event]));
        } else {
          if (
            dayEvents.some(function (ev) {
              return ev.id === event.id;
            })
          ) {
            inst.updateEvent([event]);
          }
        }

        currentColors = clearColorsForResource(currentColors, event.resource, event.start);
        var day = new Date(event.start);
        day.setHours(0, 0, 0, 0);
        redResources[event.resource + day.toISOString()] = false;
        if (!conflicts.length && event.resource !== draggedEventResource) {
          var colorEnd = new Date(dayStart);
          colorEnd.setDate(colorEnd.getDate() + 1);
          colorEnd.setHours(6, 0, 0, 0);
          currentColors.push({ start: dayStart, resource: args.oldEvent.resource, background: '#ffdbd280', end: colorEnd });
          redResources[args.oldEvent.resource + day.toISOString()] = true;
        }
        inst.setOptions({ colors: currentColors });
        draggedEventStart = null;
        draggedEventEnd = null;
        draggedEventResource = null;
      },
      groupBy: 'date',
      resources: [
        { id: 'A', name: 'Crew A' },
        { id: 'B', name: 'Crew B' },
        { id: 'C', name: 'Crew C' },
      ],
      renderResource: function (res, day) {
        var style = redResources[res.id + day.toISOString()]
          ? ' style="color: #53000080; background: #ffdbd280; margin: -0.5em; padding: 0.5em"'
          : '';
        return '<div' + style + '>' + res.name + '</div>';
      },
      view: {
        scheduler: {
          type: 'week',
          allDay: false,
          startTime: '06:00',
          endTime: '06:00+1',
          timeCellStep: 120,
          timeLabelStep: 120,
        },
      },
    });
});
```

### HTML

```html
<div id="demo-24-hour-manufacturing-shift-rota-planning"></div>
```

### CSS

```css
.mds-24-hour-manufacturing-calendar .mbsc-schedule-events {
  left: 0;
  right: 0;
}

.mds-24-hour-manufacturing-calendar .mbsc-schedule-time-wrapper {
  height: 2.5em;
}

.mds-24-hour-manufacturing-calendar .mbsc-schedule-item {
  height: 2.5em;
}

.mds-24-hour-manufacturing-calendar .mbsc-schedule-color.available-slot {
  z-index: auto;
}

.mds-24-hour-manufacturing-calendar .mbsc-schedule-color.available-slot .mbsc-schedule-color-text {
  position: absolute;
  z-index: 1;
  pointer-events: none;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 35px;
  height: 35px;
  border: none;
  border-radius: 50%;
  background: linear-gradient(135deg, #33333380, #00000080);
  box-sizing: border-box;
}

.mds-24-hour-manufacturing-calendar .mbsc-schedule-color.available-slot.mbsc-font-icon:before {
  position: absolute;
  z-index: 2;
  pointer-events: none;
  top: 50%;
  left: 50%;
  color: #e0fff0;
  font-size: 12px;
  opacity: 0.8;
  transform: translate(-50%, -50%);
}
```

## Implementation notes

- Use `type: 'week'` with `allDay: false`, `startTime: '06:00'`, `endTime: '06:00+1'`, `timeCellStep: 120`, and `timeLabelStep: 120`. The `+1` suffix in `endTime` extends the view past midnight into the next calendar day, creating a continuous 24-hour column anchored at 06:00 per day.
- Define 3 resources (Crew A, B, C) and set `groupBy: 'date'` so all crews appear side by side under each day column.
- Define 3 shift objects each with `startHour`, `endHour`, `title`, and `color`: Morning (06-14, green), Afternoon (14-22, orange), Night (22-06 with `nextDay: true`, purple). Write a `getShiftByHour(hour)` helper that returns the matching shift for any given hour.
- Set `dragToMove: true`, `dragToCreate: false`, `dragToResize: false`, `clickToCreate: 'single'`, `eventDelete: true`, and `eventOverlap: false`. Set `dragTimeStep: 480` (8 hours in minutes) and `dragTimeStepBase: 'viewStart'` to snap all move operations to exact shift boundaries aligned to the 06:00 view start.
- Use `extendDefaultEvent` to snap click-created events to shift boundaries: call `getShiftByHour` on the clicked hour to determine the containing shift, then set `start`/`end` to that shift's boundaries (advancing the end date by one day for the Night shift), and derive `title` and `color` from the shift.
- In `onCellHoverIn`, determine the hovered shift via `getShiftByHour`, call `getAvailableSlots` to find which of the 3 shift slots are free for that resource and day, and if the hovered slot is free, push a color entry with a green background and a plus-icon `cssClass` to the `colors` array. Remove it in `onCellHoverOut`.
- In `onEventCreate`, define the day window as 06:00-06:00+1 and look for a conflict - another event on the same resource or at the same start hour. If found, show an "Already assigned" `Toast` and return `false`. On success, clear the hover-slot color for that resource/day and reset the red-resource flag.
- Store the original start, end, and resource in state via `onEventDragStart`. In `onEventUpdate`, first block cross-day moves (return `false` if the drop day's 06:00 boundary differs from the drag day's). Then find conflicts within the same day: if a conflicting event shares the same resource, reassign it to the dragged event's original resource; if it shares the same time slot, move it to the dragged event's original time and update its title and color. Return `false` if the exact drop position is already occupied. After resolving, update `colors` and the red-resource indicator for the source resource.
- In `onEventDelete`, remove the event from state, apply a red color overlay spanning 06:00-06:00+1 for that resource, set `redResources[resourceId + dayISO]` to `true`, and show a `Toast`.
- Use `renderResource` (Angular: `resourceTemplate`, Vue: `#resource` slot) with a `(resource, day)` signature: apply a red background style to the crew name div when `redResources[res.id + day.toISOString()]` is `true` for that crew and day.

## 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: [Doctors Availability](https://demo.mobiscroll.com/jquery/scheduler/doctors-availability-calendar-planner.md) - Display per-doctor availability in JQuery Scheduler — color-coded tracks mark open slots per doctor, automatically respecting working hours.
- Next: [Drop Assignee on Event](https://demo.mobiscroll.com/jquery/scheduler/drop-assignee-on-event-from-list.md) - Drag team members from an external list onto existing meetings in the JQuery Scheduler — with visual drop feedback and conflict validation.
