I am working on a drag-drop app for managing employees' shifts, it basically consists of two parts:
1- employees cards on the top (these contain all unassigned employees who have not any shifts)
2- calendar (HTML table element) for the assigned employees and their shifts on weekdays [the app](https://i.stack.imgur.com/5MLJ2.png)
each employee has availability for all weekdays something like this
const DEFAULT_MEMBER_AVAILABILITY = {
friday: { start: '10:00', end: '23:00', all_day: false }, // part-time availability in friday
monday: { start: 'null', end: 'null', all_day: false }, // not available in monday
saturday: { start: '00:00', end: '00:00', all_day: true },// full-time availability in saturday
sunday: { start: '00:00', end: '00:00', all_day: true },
thursday: { start: '00:00', end: '00:00', all_day: true },
tuesday: { start: '00:00', end: '00:00', all_day: true },
wednesday: { start: '00:00', end: '00:00', all_day: true },
};
to show a member's availability just hover on his card and the first row will be colored based on his availability like this:
1- not available on the day: red
2- full-time: green
3- part-time: yellow
[hover on a card](https://i.stack.imgur.com/uRaDU.png)
and the slots will be reset again when the mouse leaves the card.
the user can assign a shift to an employee by dragging his card and dropping it on the first row.
while dragging the first row will be colored based on his availability like the previous rules.
[dragging an employee card](https://i.stack.imgur.com/E50Rp.png)
once dropping the employee card will be removed from top and a new row inserted in calender with a new shift in the day dropped on.
the problem is when I drop a card the card is removed and the card which is next to it and will be **in the removed card position** behave as I hover on it (shows the related member availabilty) even the mouse on the calender.
**note\***
I am using event delegtion since the dom cahnges alot with 'removing cards' and 'adding cards' with something like this:
this.#employeesCardsContainer.addEventListener(
'mouseenter',
this.#handleEmployeesCardsMouseEnter.bind(this),
true
);
I am not sure if this is helpful or not
"the card which is next to it and will be in the removed card position"
I think the problem happen because of this,I think the mouse position is not being updated while dragging and when dropping the browser behave as the mouse still in his position before dragging.
Related
I have a datasource which has bookings that that i want to render in fullcalendar eg
{
title: 'booked',
groupId: 'unique',
start: '2020-02-11T08:00:00',
end: '2020-02-11T10:00:00',
color: 'blue'
}
However i also have recurring free slots which i want the user to click to eventually make a booking.
{
title: 'Available',
daysOfWeek: [ 1,2,3,4],
startTime: '8:00:00',
endTime: '10:00:00',
color: 'red',
}
The aim is that if there is already a booked event in the same time block , the recurring event 'Available' in this slot will not be displayed
How can i achieve this . I am assuming it is with eventRender
I have a jsfiddle here that shows the events competing for the same time block
https://jsfiddle.net/ryan_ramsumair/mqhzs3v2/5/
Thank you
I have downloaded and been experimenting with FullCalendar and it does almost everything I need for a resource scheduling app I am developing for my company's use. I just need to try and get it to display the events a bit differently and was hoping someone might be able to help.
I currently have it configured to display like this:
However, I am ultimately need it to display like this (side by side):
This is for a sequential process and it is important to convey the order of events and if one event (blue) extends into another day then the next day's event(s) (purple) have to wait until that one is done. This is not as clear in the top image as the bottom one.
Is this something that can be configured or will this require me to modify the source or intercept the event render and manipulate it there?
Thanks!
[EDIT] Added code snippets:
TEMPLATE:
<FullCalendar ref="fullCalendar"
default-view="resourceTimelineMonth"
:plugins="calendarPlugins"
:events="calEvents"
:resources="calResources"
:weekends="true"
:editable="true"
:event-overlap="false"
:slot-width="100"/>
SCRIPT:
data () {
return {
...
calendarPlugins: [ interactionPlugin, resourceTimelinePlugin ],
calEvents: [
{ resourceId: "101", title: 'WO123', start: '2019-11-01T07:00:00', end: '2019-11-01T12:00:00', backgroundColor: 'red' },
{ resourceId: "101", title: 'WO127', start: '2019-11-01T12:00:00', end: '2019-11-01T18:00:00', backgroundColor: 'green' },
{ resourceId: "101", title: 'WO144', start: '2019-11-01T18:00:00', end: '2019-11-02T03:00:00', backgroundColor: 'blue' },
{ resourceId: "101", title: 'WO145', start: '2019-11-02T03:00:00', end: '2019-11-02T10:00:00', backgroundColor: 'purple' }
],
calResources: [
{id: "101", title: "KM101"},
{id: "102", title: "KM102"},
{id: "103", title: "KM103"},
{id: "104", title: "KM104"},
{id: "105", title: "KM105"},
],
...
}
As I hinted at in the comments above, the reason you don't see what you're hoping for is because when you compress each slot to a single day, fullCalendar appears to switch to an "all-day" mode of display, where it ceases to take the specific times of day into account, and simply indicates the day(s) in which the event occurs.
The way to get a display the way (or close to the way) you want is to reduce the slot duration to half a day (which clearly creates the least division of the day you can do), and also modify the slot labels slightly to suit. Once the slot duration involves hours, fullCalendar will start taking the time component of the event into account again when it renders.
I don't know vue.js syntax and can't make a demo of it, so I've done the code and demo below in vanilla JS, but hopefully you can translate that into the syntax used by the vue plugin without any difficulty.
Options to add to your calendar config:
slotDuration: { hours: 12 },
slotLabelFormat: [
{ weekday: "short" },
{ hour: "2-digit", },
],
Live demo: https://codepen.io/ADyson82/pen/VwwXowr
See https://fullcalendar.io/docs/date-display for relevant documentation.
I need to filter out any overlaps of start and end (moment.js) times of the following eg array of objects
[{ start: moment("2019-03-23T15:55:00.000"), end: moment("2019-03-23T16:55:00.000")},
{ start: moment("2019-03-23T14:40:00.000"), end: moment("2019-03-23T17:30:00.000")},
{ start: moment("2019-03-23T18:45:00.000"), end: moment("2019-03-23T19:45:00.000")},
{ start: moment("2019-03-23T17:10:00.000"), end: moment("2019-03-23T20:00:00.000")},
{ start: moment("2019-03-23T21:35:00.000"), end: moment("2019-03-23T22:35:00.000")},
{ start: moment("2019-03-23T19:15:00.000"), end: moment("2019-03-23T22:05:00.000")},
{ start: moment("2019-03-23T22:30:00.000"), end: moment("2019-03-23T23:30:00.000"),
}]
In the above example, the dates are all on the same day (03/23), so when looking at the times, I need to loop through each object and take the EARLIEST start time along with the LATEST end time with no overlap. I need a final array of alternating start, end, start, end ... times.
So, for the above example, I need to filter right down to just the following:
start: 14:40:00
end: 17:30:00
start: 18:45:00
end: 20:00:00
start: 21:35:00
end: 23:30:00
As you can see, the second start time only occurs after the first end time, and the final end time is basically the last available end time. The earliest start available in the whole set is 14:40:00 so it gets the first slot.
Further example is the start time 17:10:00; This start time is already covered by during the first start/end time, so it is ignored, however its paired end time of 20:00:00 is AFTER 19:45:00 so it replaces that end time in the cycle.
I hope this makes sense, please let me know if not.
What I have come up with still contains overlap and I'm not happy with it even if it worked.
times.forEach(time => {
// start with the first object
if (filtered.length === 0) {
filtered.push({'start': time.start, 'end': time.end});
}
// if this start time is AFTER the prior end time, add it
if (time.start.isAfter(filtered[filtered.length-1]['end'])) {
filtered.push({'start': time.start, 'end': time.end});
}
if (time.start.isBefore(filtered[filtered.length-1]['end'])) {
// replace the prior end time
filtered[filtered.length-1]['end'] = time.end;
}
});
As I said, clearly this is not great, but not sure how best to accomplish.
boundaries = [];
times.forEach (time => {
boundaries.push ({type: "start", value: time.start});
boundaries.push ({type: "end", value: time.end})
});
This will give you an array of boundaries looking like this:
[
{type: "start", value: moment("2019-03-23T15:55:00.000")},
{type: "end", value: moment("2019-03-23T16:55:00.000")},
{type: "start", value: moment("2019-03-23T14:40:00.000")},
{type: "end", value: moment("2019-03-23T17:30:00.000")},
{type: "start", value: moment("2019-03-23T18:45:00.000")},
{type: "end", value: moment("2019-03-23T19:45:00.000")},
{type: "start", value: moment("2019-03-23T17:10:00.000")},
{type: "end", value: moment("2019-03-23T20:00:00.000")},
{type: "start", value: moment("2019-03-23T21:35:00.000")},
{type: "end", value: moment("2019-03-23T22:35:00.000")},
{type: "start", value: moment("2019-03-23T19:15:00.000")},
{type: "end", value: moment("2019-03-23T22:05:00.000")},
{type: "start", value: moment("2019-03-23T22:30:00.000")},
{type: "end", value: moment("2019-03-23T23:30:00.000")}
]
Now sort this array by value and iterate over sorted array, counting how may "start" boundaries you passed minus how many "end" boundaries you passed. I.e. increment counter on every "start" boundary, and decrement it on every "end" boundary.
Every time counter goes from zero to non-zero, output filtered "start" boundary. Every time counter drops from non-zero to zero, output filtered "end" boundary.
I'm working with FullCalendar and I'm using it for a business which has varying hours
Mon, Tue, Wed, Fri is 09:00 - 17:00.
Thu is 09:00 - 19:00.
businessHours: {
start: '09:00', // a start time (10am in this example)
end: '17:00', // an end time (6pm in this example)
dow: [ 1, 2, 3, 5]
// days of week. an array of zero-based day of week integers (0=Sunday)
// (Monday-Thursday in this example)
}
http://fullcalendar.io/docs/display/businessHours/
How can this be achieved?
To use variable hours for business hours, you need to use background events like this:
events:
[
{
id: 'available_hours',
start: '2015-1-13T8:00:00',
end: '2015-1-13T19:00:00',
rendering: 'background'
},
{
id: 'available_hours',
start: '2015-1-14T8:00:00',
end: '2015-1-14T17:00:00',
rendering: 'background'
},
{
id: 'work',
start: '2015-1-13T10:00:00',
end: '2015-1-13T16:00:00',
constraint: 'available_hours'
}
]
Notice in the last event it has the constraint filled in? This says that this can only be placed within an available hours slot. Using constraints, you can make flexible business hours.
For more information, see this link,
http://fullcalendar.io/docs/event_ui/eventConstraint/
Try this - Adding an event for each business hour, like so:
{
...
events: [
// business hours 1
{
className: 'fc-nonbusiness',
start: '09:00',
end: '17:00',
dow: [1, 2, 3, 4], // monday - thursday
rendering: 'inverse-background'
},
// business hours 2
{
className: 'fc-nonbusiness',
start: '10:00',
end: '15:00',
dow: [6], // saturday
rendering: 'inverse-background'
}],
...
}
NOTE : className and rendering are important options for this to work.
Good Luck.
Like others I'm having problems getting timed events to show up on the agendaWeek view. If you look at the events below, the first two are mine and show up as all day events. The last one is from the documentation and shows up in the correct time block. I've been staring at this so long I'm sure I'm missing something simple. Can anyone else see it?
$(document).ready(function() {
$("#calendar").fullCalendar({
defaultView: 'agendaWeek',
month:0,//current year assumed, first day of month assumed
date: 4,
height: 650,
header: {left: 'title',center:'agendaWeek'},
events: [
{
title : 'Fred',
start : '2010-01-04 08:00:00',
end : '2010-01-04 09:00:00',
allday : false
},
{
title : 'Betty',
start : '2010-01-06 08:00:00',
allday : false
},
{
title : 'event3',
start : '2010-01-05 12:30:00',
allDay : false // will make the time show
}
]
});
});
</script>
I fixed my problem as follows: Where you have allday you need allDay with a capital D.
Cheers!