Skip to content
Snippets Groups Projects
Commit acf8e5b5 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch 'feature/flag_tooltip_in_daily_planning' into 'master'

Feature/flag tooltip in daily planning

Closes #260

See merge request NCER-PD/scheduling-system!177
parents b06de6c0 34ce8645
No related branches found
No related tags found
1 merge request!177Feature/flag tooltip in daily planning
Pipeline #7247 passed
......@@ -43,15 +43,21 @@ def build_duration(duration):
def get_holidays(worker, date):
today_start = datetime.datetime.strptime(date, '%Y-%m-%d').replace(hour=0, minute=0)
today_end = datetime.datetime.strptime(date, '%Y-%m-%d').replace(hour=23, minute=59)
holidays = Holiday.objects.filter(person=worker, datetime_start__lte=today_end, datetime_end__gte=today_start)
today_start = datetime.datetime.strptime(
date, '%Y-%m-%d').replace(hour=0, minute=0)
today_end = datetime.datetime.strptime(
date, '%Y-%m-%d').replace(hour=23, minute=59)
holidays = Holiday.objects.filter(
person=worker, datetime_start__lte=today_end, datetime_end__gte=today_start)
result = []
for holiday in holidays:
minutes = int((holiday.datetime_end - holiday.datetime_start).total_seconds() / 60)
minutes = int(
(holiday.datetime_end - holiday.datetime_start).total_seconds() / 60)
# hack for time zones
start_date = datetime.datetime.combine(today_start, holiday.datetime_start.time())
end_date = datetime.datetime.combine(today_start, holiday.datetime_end.time())
start_date = datetime.datetime.combine(
today_start, holiday.datetime_start.time())
end_date = datetime.datetime.combine(
today_start, holiday.datetime_end.time())
event = {
'duration': build_duration(minutes),
'link_when': start_date,
......@@ -65,14 +71,16 @@ def get_holidays(worker, date):
def remove_holidays(availability, worker, date):
today_start = datetime.datetime.strptime(date, '%Y-%m-%d').replace(hour=0, minute=0)
today_end = datetime.datetime.strptime(date, '%Y-%m-%d').replace(hour=23, minute=59)
holidays_starting_before = Holiday.objects.filter(person=worker, datetime_start__lte=today_start,
datetime_end__gte=today_start)
holidays_starting_today = Holiday.objects.filter(person=worker, datetime_start__lte=today_end,
datetime_start__gte=today_start)
holidays_ending_today = Holiday.objects.filter(person=worker, datetime_end__lte=today_end,
datetime_end__gte=today_start)
today_start = datetime.datetime.strptime(
date, '%Y-%m-%d').replace(hour=0, minute=0)
today_end = datetime.datetime.strptime(
date, '%Y-%m-%d').replace(hour=23, minute=59)
holidays_starting_before = Holiday.objects.filter(
person=worker, datetime_start__lte=today_start, datetime_end__gte=today_start)
holidays_starting_today = Holiday.objects.filter(
person=worker, datetime_start__lte=today_end, datetime_start__gte=today_start)
holidays_ending_today = Holiday.objects.filter(
person=worker, datetime_end__lte=today_end, datetime_end__gte=today_start)
result = []
timestamps = [{
"time": availability.available_from,
......@@ -124,13 +132,17 @@ def get_availabilities(worker, date):
result = []
today = datetime.datetime.strptime(date, '%Y-%m-%d')
weekday = today.weekday() + 1
availabilities = Availability.objects.filter(person=worker, day_number=weekday)
availabilities = Availability.objects.filter(
person=worker, day_number=weekday)
for availability in availabilities:
availabilities_without_holidays = remove_holidays(availability, worker, date)
availabilities_without_holidays = remove_holidays(
availability, worker, date)
for availability_without_holiday in availabilities_without_holidays:
start_date = datetime.datetime.combine(today, availability_without_holiday.available_from)
end_date = datetime.datetime.combine(today, availability_without_holiday.available_till)
start_date = datetime.datetime.combine(
today, availability_without_holiday.available_from)
end_date = datetime.datetime.combine(
today, availability_without_holiday.available_till)
delta = end_date - start_date
minutes = int(delta.total_seconds() / 60)
......@@ -156,7 +168,8 @@ def get_conflicts(worker, date):
if appointment.worker_assigned is not None:
link_when = appointment.datetime_when
link_when = link_when.replace(tzinfo=None)
link_end = link_when + datetime.timedelta(minutes=appointment.length)
link_end = link_when + \
datetime.timedelta(minutes=appointment.length)
event = {
'title': appointment.title(),
'duration': appointment.length,
......@@ -168,12 +181,15 @@ def get_conflicts(worker, date):
}
result.append(event)
links = AppointmentTypeLink.objects.filter(appointment=appointment).all()
links = AppointmentTypeLink.objects.filter(
appointment=appointment).all()
for j, link in enumerate(links):
link_when = link.date_when
if link_when is not None:
link_when = link_when.replace(tzinfo=None)
link_end = link_when + datetime.timedelta(minutes=link.appointment_type.default_duration)
link_end = link_when + \
datetime.timedelta(
minutes=link.appointment_type.default_duration)
event = {
'title': link.appointment_type.description,
'duration': build_duration(link.appointment_type.default_duration),
......@@ -212,7 +228,8 @@ def get_generic_appointment_events(request, date):
link_end = None
if link_when is not None:
link_when = link_when.replace(tzinfo=None)
link_end = link_when + datetime.timedelta(minutes=appointment.length)
link_end = link_when + \
datetime.timedelta(minutes=appointment.length)
event = {
'title': appointment.title(),
'short_title': appointment.title(),
......@@ -250,6 +267,7 @@ def events(request, date):
'appointment_id': appointment.id,
'color': RANDOM_COLORS[i],
'start': appointment.datetime_when.replace(tzinfo=None).strftime("%H:%M"),
'flags': [language.image.url for language in appointment_subject.subject.languages.all()],
# this indicates only location of the first appointment
# (there is small chance to have two appointments in two different places at the same day)
'location': str(appointment.location),
......@@ -257,13 +275,16 @@ def events(request, date):
}
subjects[appointment_subject.id] = subject
links = AppointmentTypeLink.objects.filter(appointment=appointment).all()
links = AppointmentTypeLink.objects.filter(
appointment=appointment).all()
for j, link in enumerate(links):
link_when = link.date_when
link_end = None
if link_when is not None:
link_when = link_when.replace(tzinfo=None)
link_end = link_when + datetime.timedelta(minutes=link.appointment_type.default_duration)
link_end = link_when + \
datetime.timedelta(
minutes=link.appointment_type.default_duration)
event = {
'title': link.appointment_type.description,
'short_title': link.appointment_type.code,
......@@ -330,13 +351,16 @@ def events_persist(request):
event_links = json.loads(request.POST.get('events_to_persist'))
for event_link in event_links:
try:
when = datetime.datetime.strptime(event_link['start'], '%Y-%m-%dT%H:%M:00')
when = datetime.datetime.strptime(
event_link['start'], '%Y-%m-%dT%H:%M:00')
except ValueError:
when = datetime.datetime.strptime(event_link['start'][0:-6], '%Y-%m-%dT%H:%M:00')
when = datetime.datetime.strptime(
event_link['start'][0:-6], '%Y-%m-%dT%H:%M:00')
worker_id = event_link['link_who']
if 'link_id' in event_link:
link_id = event_link['link_id']
appointment_type_link = get_object_or_404(AppointmentTypeLink, pk=link_id)
appointment_type_link = get_object_or_404(
AppointmentTypeLink, pk=link_id)
appointment_type_link.worker_id = worker_id
appointment_type_link.date_when = when
appointment_type_link.save()
......@@ -349,11 +373,13 @@ def events_persist(request):
appointment.save()
events_to_clear = json.loads(request.POST.get('events_to_clear'))
for link_id in events_to_clear:
appointment_type_link = get_object_or_404(AppointmentTypeLink, pk=link_id)
appointment_type_link = get_object_or_404(
AppointmentTypeLink, pk=link_id)
appointment_type_link.worker_id = None
appointment_type_link.date_when = None
appointment_type_link.save()
appointments_to_clear = json.loads(request.POST.get('appointments_to_clear'))
appointments_to_clear = json.loads(
request.POST.get('appointments_to_clear'))
for appointment_id in appointments_to_clear:
appointment = get_object_or_404(Appointment, pk=appointment_id)
appointment.worker_assigned_id = None
......
......@@ -35,6 +35,7 @@ def workers_for_daily_planning(request):
role = unicode(worker.roles.filter(study_id=GLOBAL_STUDY_ID)[0].role)
worker_dict_for_json = {
'id': worker.id,
'flags' : [language.image.url for language in worker.languages.all()],
'availability': worker.availability_percentage(start_date=start_date),
'title': u"{} ({})".format(unicode(worker), role[:1].upper()),
'role': role
......
......@@ -125,7 +125,25 @@ function get_subjects_events(day) {
var boxBody = $("<div class='box-body' id='subject_" + subject.id + "'>");
var boxHeader = $("<div class='box-header with-border'/>");
var title_subject = $(`<h4>${subject.name} (${subject.start}) <span style='float:right;padding-right:5px;'>${subject.location}</span> <span style='float:left;padding-right:5px;'><a title="Edit appointment" target="_blank" href="/appointments/edit/${subject.appointment_id}"><i class="fa fa-pencil-square"></i></a></span></h4>`);
//flags
var flagTooltip = '';
if('flags' in subject){
for(i=0; i<subject.flags.length; i++){
var url = subject.flags[i];
flagTooltip+= `<img class='tooltip_image' src='${url}'/>`;
}
var title_subject = `<h4 class="subject_title" data-toggle="tooltip" data-html="true" title="${flagTooltip}">${subject.name} (${subject.start})</h4>`;
}else{
var title_subject = `<h4 class="subject_title">${subject.name} (${subject.start})</h4>`; //wrap content
}
title_subject = $(`${title_subject}
<span style='padding-right:5px;'>${subject.location}</span>
<span style='padding-right:5px;'>
<a title="Edit appointment" target="_blank" href="/appointments/edit/${subject.appointment_id}">
<i class="fa fa-pencil-square"></i>
</a>
</span>`);
boxHeader.append(title_subject);
title_subject.find('a[title]').tooltip();
$.each(subject.events, function (index_event, event) {
......@@ -160,12 +178,17 @@ function get_subjects_events(day) {
});
});
var location_based_general_appointments = data.generic;
$.each(location_based_general_appointments, function (index, location) {
$.each(location_based_general_appointments, function (index, location) { //Subject Appointment List
var divSubject = $("<div class='col-md-4 col-lg-3 col-sm-12 subjects-events'/>");
var boxSubject = $("<div class='box box-primary'/>").css('border-top-color', location.color);
var boxBody = $("<div class='box-body' id='location_" + location.id + "'>");
var boxHeader = $("<div class='box-header with-border'/>");
var title_location = $(`<h4>${location.name}<span style='float:right;padding-right:5px;'>${location.location}</span><span style='float:left;padding-right:5px;'><a title="Edit appointment" target="_blank" href="/appointments/edit/${location.id}"><i class="fa fa-pencil-square"></i></a></span></h4>`);
var title_location = $(`<h4>${location.name}<span style='padding-right:5px;'>${location.location}</span></h4>
<span style='padding-right:5px;'>
<a title="Edit Appointment" target="_blank" href="/appointments/edit/${location.id}">
<i class="fa fa-pencil-square"></i>
</a>
</span>`);
boxHeader.append(title_location);
title_location.find('a[title]').tooltip();
$.each(location.events, function (index_event, event) {
......@@ -371,6 +394,31 @@ $(document).ready(function () {
resourceLabelText: 'Workers',
refetchResourcesOnNavigate: true,
resourceOrder: '-availability',
resourceRender: function(resourceObj, labelTds, bodyTds) { //Calendar Columns
var title = $(labelTds).text() //get content
$(labelTds).text('') //empty content
var flagTooltip = '';
if('flags' in resourceObj){
for(i=0; i<resourceObj.flags.length; i++){
var url = resourceObj.flags[i];
flagTooltip+= `<img class='tooltip_image' src='${url}'/>`;
}
$(labelTds).prepend(`<span class="column_title" data-toggle="tooltip" data-html="true" title="${flagTooltip}">${title}</span>`) //wrap content
}else{
$(labelTds).prepend(`<span class="column_title">${title}</span>`) //wrap content
}
//buttons
var worker_id = resourceObj.id;
var span = $(`<div style='display:block;'></div>`);
var add_extra_availability_link = `<a style="padding-right:5px;" title="Add Extra Availability or Holiday" target="_blank" href="/doctors/${worker_id}/holiday/add"><i class="fa fa-plus-square-o" aria-hidden="true"></i></a>`;
var edit_worker_link = `<a style="padding-right:5px;" title="Edit Worker" target="_blank" href="/doctors/edit/${worker_id}"><i class="fa fa-pencil-square" aria-hidden="true"></i></a>`;
$(span).append($(add_extra_availability_link));
$(span).append($(edit_worker_link));
$(labelTds).append(span);
$(labelTds).find('a[title]').tooltip();
},
resources: function(callback){
setTimeout(function(){
var view = $('#calendar').fullCalendar('getView');
......@@ -382,6 +430,7 @@ $(document).ready(function () {
start_date: view.start.format('YYYY-MM-DD'),
}
}).then(function(resources){
//Filter out roles
var checked_roles = $('.role_list_item > input:checked').map( (i,e) => e.value).toArray();
resources = resources.filter(resource => checked_roles.includes(resource.role));
callback(resources)
......@@ -432,21 +481,6 @@ $(document).ready(function () {
resizeCalendarColumns();
};
//ADD EDIT BUTTONS
$('.fc-resource-cell').not('.anchored').each(function(resourceColumn){
$(this).addClass('anchored');
var worker_id = $(this).data('resource-id');
var span = $(`<div style='display:block;'></div>`);
var add_extra_availability_link = `<a style="padding-right:5px;" title="Add Extra Availability or Holiday" target="_blank" href="/doctors/${worker_id}/holiday/add"><i class="fa fa-plus-square-o" aria-hidden="true"></i></a>`;
var edit_worker_link = `<a style="padding-right:5px;" title="Edit Worker" target="_blank" href="/doctors/edit/${worker_id}"><i class="fa fa-pencil-square" aria-hidden="true"></i></a>`;
$(span).append($(add_extra_availability_link));
$(span).append($(edit_worker_link));
$(this).append(span);
//$(this).css('padding-left', span.width());
$(this).find('a[title]').tooltip();
});
}
});
})
......
......@@ -26,6 +26,17 @@
list-style: none;
list-style-type:none;
}
.tooltip_image{
width: 20px !important;
margin: 5px;
}
.subject_title{
padding: 0 !important;
}
.subject_title + .tooltip > .tooltip-inner, .column_title + .tooltip > .tooltip-inner {
background-color: #fafafa;
border: solid 1px #ccc;
}
</style>
{% include "includes/datepicker.css.html" %}
{% endblock styles %}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment