The below is my appointment_calendar.js. I also use the scheduler plugin for Fullcalendar for resources.
frappe.views.calendar["Appointments"] = {
field_map: {
"start": "start_time",
"end": "end_time",
"title": "title",
"allDay": "allDay",
"resourceId": "staff",
"description": "notes",
"rendering": "rendering"
},
gantt: false,
options: {
header: {
left: 'prev, title, next',
center: 'today',
right: ' listOneWeek, listOneDay, agendaOneDay, agendaOneWeek'
},
views: {
listOneDay: {
type: 'list',
titleFormat: 'ddd, DD MMMM YYYY',
duration: { days: 1 },
buttonText: 'Day list',
noEventsMessage: "No appointments for this date"
},
listOneWeek: {
type: 'list',
duration: { days: 7 },
buttonText: 'Week list',
noEventsMessage: "No appointments for this week"
},
agendaOneDay: {
type: 'agendaDay',
titleFormat: 'ddd, DD MMMM YYYY',
duration: { days: 1 },
buttonText: 'Day',
slotDuration: "01:00",
slotLabelInterval: "01:00",
minTime: "07:00:00",
maxTime: "22:00:00"
},
agendaOneWeek: {
type: 'agendaDay',
duration: { days: 7 },
buttonText: 'Week',
slotDuration: "01:00:00",
minTime: "07:00:00",
maxTime: "22:00:00"
}
},
defaultView: 'agendaOneDay',
allDaySlot: false,
slotEventOverlap: false,
editable: false,
resources: function(callback) {
return frappe.call({
method: "myapp.myapp.doctype.appointments.appointments.get_resources",
type: "GET",
callback: function(r) {
var resources = r.message || [];
callback(resources);
}
})
},
},
color_map: {
"paid_scheduled": "green",
"paid_open": "purple",
"paid_complete": "blue",
"unpaid_scheduled": "red",
"unpaid_open": "pink",
"unpaid_complete": "yellow",
"background": "#b9fff5"
},
get_events_method: "myapp.myapp.doctype.appointments.appointments.get_events",
get_css_class: function(data) {
if (data.rendering == "background") {
return "background";
}
if (data.payment_status == "Paid" && data.appointment_status == "Scheduled") {
return "paid_scheduled";
} else if (data.payment_status == "Paid" && data.appointment_status == "Open") {
return "paid_open";
} else if (data.payment_status == "Paid" && data.appointment_status == "Complete") {
return "paid_complete";
} else if (data.payment_status == "Not Paid" && data.appointment_status == "Scheduled") {
return "unpaid_scheduled";
} else if (data.payment_status == "Not Paid" && data.appointment_status == "Open") {
return "unpaid_open";
} else if (data.payment_status == "Not Paid" && data.appointment_status == "Complete") {
return "unpaid_complete";
}
}
};
Fullcalendar also has features for mouseover events. Let’s see if we can combine that and Frappe mouseover to get the desired result. Check the link below
Event Clicking & Hovering - Docs v3 | FullCalendar