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

Merge branch 'feature/add_daily_planning_to_appointment_creation' into 'master'

Issue #275 Added read-only daily planning view below new appointment form.

Closes #275

See merge request NCER-PD/scheduling-system!189
parents d65a4953 7765c985
No related branches found
No related tags found
1 merge request!189Issue #275 Added read-only daily planning view below new appointment form.
Pipeline #7572 passed
...@@ -248,148 +248,146 @@ function remove_event(event) { ...@@ -248,148 +248,146 @@ function remove_event(event) {
add_event(event, event.color, event.subject_id, event.location_id, boxBody); add_event(event, event.color, event.subject_id, event.location_id, boxBody);
} }
$(document).ready(function () { function addDailyPlanningCalendar(calendar_selector, replace_all, calendar_dict_props){
$('#calendar').fullCalendar({
var customButtons = {
datePickerButton: {
text: 'select',
click: function () {
var $btnCustom = $('.fc-datePickerButton-button');
if ($(".calendar-datepicker").length > 0) {
$(".calendar-datepicker").remove();
}
else {
$btnCustom.after('<div class="calendar-datepicker"/>');
$(".calendar-datepicker").datepicker().on('changeDate', function (ev) {
$(calendar_selector).fullCalendar('gotoDate', ev.date);
$(".calendar-datepicker").remove();
});
}
}
},
save: {
text: 'Save',
click: function () {
calendarEvents = $(calendar_selector).fullCalendar('clientEvents');
eventsToPersist = [];
var saveButton = $(".fc-save-button");
var currentBorder = saveButton.css('border-color');
$.each(calendarEvents, function (i, calendar_event) {
if (calendar_event.rendering !== "background") {
eventsToPersist.push({
'link_id': calendar_event.link_id,
'appointment_id': calendar_event.appointment_id,
'link_who': parseInt(calendar_event.resourceId),
'start': calendar_event.start.format()
});
if (calendar_event.link_id !== undefined) {
var index = eventsCleared.indexOf(calendar_event.link_id);
if (index > -1) {
eventsCleared.splice(index, 1);
}
} else {
var index = appointmentsCleared.indexOf(calendar_event.appointment_id);
if (index > -1) {
appointmentsCleared.splice(index, 1);
}
}
}
});
$.post({
url: events_url,
data: {
events_to_persist: JSON.stringify(eventsToPersist),
events_to_clear: JSON.stringify(eventsCleared),
appointments_to_clear: JSON.stringify(appointmentsCleared)
},
dataType: "json"
}).done(function (data) {
saveButton.css('border-color', 'green');
setTimeout(function () {
saveButton.css('border-color', currentBorder);
}, 200);
}).error(function (data) {
console.log(data);
saveButton.css('border-color', 'red');
showErrorInfo("There was an unexpected problem with saving data. " + "Please contact administrators.");
setTimeout(function () {
saveButton.delay(200).css('border-color', currentBorder);
}, 200);
});
}
},
clear: {
text: 'Clear',
click: function () {
calendarEvents = $(calendar_selector).fullCalendar('clientEvents');
$.each(calendarEvents, function (i, calendar_event) {
remove_event(calendar_event);
});
}
},
toPdf: {
text: 'PDF',
click: function () {
var srcEl = document.getElementById("calendar");
var parent = srcEl.parentNode;
var container = document.createElement("div");
container.style.backgroundColor = "#FFFFFF";
container.style.width = "3840px";
document.body.appendChild(container);
container.appendChild(srcEl);
var pdf = new jsPDF('l', 'mm', [1485, 270]);
pdf.addHTML(container, function () {
pdf.save('daily-planning.pdf');
parent.appendChild(srcEl);
document.body.removeChild(container);
});
}
}
};
var default_properties = {
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives', schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
defaultView: 'agendaDay', defaultView: 'agendaDay',
eventDurationEditable: false, eventDurationEditable: false,
eventStartEditable: true, eventStartEditable: true,
editable: true, editable: true,
selectable: true, selectable: true,
eventOverlap: function (stillEvent, movingEvent) { droppable: true,
if (stillEvent.rendering === "background") {
return true;
}
return false;
},
weekends: false, weekends: false,
selectHelper: true,
groupByResource: true,
displayEventTime: true,
scrollTime: '08:00', scrollTime: '08:00',
slotDuration: '00:30', slotDuration: '00:30',
snapDuration: '00:05', snapDuration: '00:05',
displayEventTime: true,
resourceOrder: 'role',
resourceGroupField: 'role',
dragRevertDuration: 0,
minTime: "08:00:00", minTime: "08:00:00",
maxTime: "19:00:00", maxTime: "19:00:00",
groupByResource: true,
height: "auto",
customButtons: {
datePickerButton: {
text: 'select',
click: function () {
var $btnCustom = $('.fc-datePickerButton-button');
if ($(".calendar-datepicker").length > 0) {
$(".calendar-datepicker").remove();
}
else {
$btnCustom.after('<div class="calendar-datepicker"/>');
$(".calendar-datepicker").datepicker().on('changeDate', function (ev) {
$('#calendar').fullCalendar('gotoDate', ev.date);
$(".calendar-datepicker").remove();
});
}
}
},
save: {
text: 'Save',
click: function () {
calendarEvents = $('#calendar').fullCalendar('clientEvents');
eventsToPersist = [];
var saveButton = $(".fc-save-button");
var currentBorder = saveButton.css('border-color');
$.each(calendarEvents, function (i, calendar_event) {
if (calendar_event.rendering !== "background") {
eventsToPersist.push({
'link_id': calendar_event.link_id,
'appointment_id': calendar_event.appointment_id,
'link_who': parseInt(calendar_event.resourceId),
'start': calendar_event.start.format()
});
if (calendar_event.link_id !== undefined) {
var index = eventsCleared.indexOf(calendar_event.link_id);
if (index > -1) {
eventsCleared.splice(index, 1);
}
} else {
var index = appointmentsCleared.indexOf(calendar_event.appointment_id);
if (index > -1) {
appointmentsCleared.splice(index, 1);
}
}
}
});
$.post({
url: events_url,
data: {
events_to_persist: JSON.stringify(eventsToPersist),
events_to_clear: JSON.stringify(eventsCleared),
appointments_to_clear: JSON.stringify(appointmentsCleared)
},
dataType: "json"
}).done(function (data) {
saveButton.css('border-color', 'green');
setTimeout(function () {
saveButton.css('border-color', currentBorder);
}, 200);
}).error(function (data) {
console.log(data);
saveButton.css('border-color', 'red');
showErrorInfo("There was an unexpected problem with saving data. " +
"Please contact administrators.");
setTimeout(function () {
saveButton.delay(200).css('border-color', currentBorder);
}, 200);
});
}
},
clear: {
text: 'Clear',
click: function () {
calendarEvents = $('#calendar').fullCalendar('clientEvents');
$.each(calendarEvents, function (i, calendar_event) {
remove_event(calendar_event);
});
}
},
toPdf: {
text: 'PDF',
click: function () {
var srcEl = document.getElementById("calendar");
var parent = srcEl.parentNode;
var container = document.createElement("div");
container.style.backgroundColor = "#FFFFFF";
container.style.width = "3840px";
document.body.appendChild(container);
container.appendChild(srcEl);
var pdf = new jsPDF('l', 'mm', [1485, 270]);
pdf.addHTML(container, function () {
pdf.save('daily-planning.pdf');
parent.appendChild(srcEl);
document.body.removeChild(container);
});
}
}
},
viewRender: function (view, element) {
var date = view.start.format('YYYY-MM-DD');
$('#calendar').fullCalendar('removeEvents');
get_subjects_events(date);
},
businessHours: { businessHours: {
start: '08:00', start: '08:00',
end: '19:00' end: '19:00'
}, },
dragRevertDuration: 0,
height: "auto",
customButtons: customButtons,
header: { header: {
left: 'prev,next today', left: 'prev,next today',
center: 'title, datePickerButton', center: 'title, datePickerButton',
right: 'save, clear, toPdf' right: 'save, clear, toPdf'
}, },
droppable: true, // VIEW
viewRender: function (view, element) {
var date = view.start.format('YYYY-MM-DD');
$(calendar_selector).fullCalendar('removeEvents');
get_subjects_events(date);
},
// RESOURCES
resourceOrder: 'role',
resourceGroupField: 'role',
resourceAreaWidth: '15%', resourceAreaWidth: '15%',
resourceLabelText: 'Workers', resourceLabelText: 'Workers',
refetchResourcesOnNavigate: true, refetchResourcesOnNavigate: true,
...@@ -421,7 +419,7 @@ $(document).ready(function () { ...@@ -421,7 +419,7 @@ $(document).ready(function () {
}, },
resources: function(callback){ resources: function(callback){
setTimeout(function(){ setTimeout(function(){
var view = $('#calendar').fullCalendar('getView'); var view = $(calendar_selector).fullCalendar('getView');
$.ajax({ $.ajax({
url: resources_url, url: resources_url,
type: 'GET', type: 'GET',
...@@ -431,13 +429,14 @@ $(document).ready(function () { ...@@ -431,13 +429,14 @@ $(document).ready(function () {
} }
}).then(function(resources){ }).then(function(resources){
//Filter out roles //Filter out roles
var checked_roles = $('.role_list_item > input:checked').map( (i,e) => e.value).toArray(); if($('.role_list_item > input').length > 0){
resources = resources.filter(resource => checked_roles.includes(resource.role)); var checked_roles = $('.role_list_item > input:checked').map( (i,e) => e.value).toArray();
callback(resources) resources = resources.filter(resource => checked_roles.includes(resource.role));
}
callback(resources);
}); });
}, 0); }, 0);
}, },
events: [],
eventRender: function (event, element) { eventRender: function (event, element) {
if (event.rendering !== 'background') { if (event.rendering !== 'background') {
var content = var content =
...@@ -457,6 +456,13 @@ $(document).ready(function () { ...@@ -457,6 +456,13 @@ $(document).ready(function () {
} else { } else {
} }
}, },
// EVENTS
eventOverlap: function (stillEvent, movingEvent) {
if (stillEvent.rendering === "background") {
return true;
}
return false;
},
selectAllow: function (selectInfo) { selectAllow: function (selectInfo) {
return false; return false;
}, },
...@@ -471,7 +477,6 @@ $(document).ready(function () { ...@@ -471,7 +477,6 @@ $(document).ready(function () {
eventDragStart: function (event, jsEvent, view) { eventDragStart: function (event, jsEvent, view) {
$('.popover').popover('hide'); $('.popover').popover('hide');
}, },
selectHelper: true,
drop: function (date, jsEvent, ui, resourceId) { drop: function (date, jsEvent, ui, resourceId) {
$(this).remove(); $(this).remove();
}, },
...@@ -482,9 +487,20 @@ $(document).ready(function () { ...@@ -482,9 +487,20 @@ $(document).ready(function () {
}; };
setTimeout(function() {resizeCalendarColumns()}, 100); setTimeout(function() {resizeCalendarColumns()}, 100);
} }
}); };
})
; // REPLACE DEFAULT PROPERTIES
if(replace_all){
default_properties = calendar_dict_props;
}else{
for (var key in calendar_dict_props) {
default_properties[key] = calendar_dict_props[key];
}
}
$(calendar_selector).fullCalendar(default_properties);
}
//RESIZE COLUMNS AND ENABLE HORIZONTAL SCROLL //RESIZE COLUMNS AND ENABLE HORIZONTAL SCROLL
function resizeCalendarColumns(){ function resizeCalendarColumns(){
......
...@@ -4,12 +4,16 @@ ...@@ -4,12 +4,16 @@
{% block styles %} {% block styles %}
{{ block.super }} {{ block.super }}
<!-- DataTables --> <!-- DataTables -->
<link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}"> <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}">
<!-- fullCalendar 2.2.5--> <!-- fullCalendar 2.2.5-->
<link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.min.css' %}"> <link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.min.css' %}">
<link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.print.css' %}" media="print"> <link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.print.css' %}" media="print">
<link rel="stylesheet" href="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar_custom.print.css' %}" media="print" />
<link rel="stylesheet" href="{% static 'fullcalendar-scheduler/scheduler.min.css' %}">
<link rel="stylesheet" href="{% static 'css/daily_planning.css' %}">
{% include "includes/datetimepicker.css.html" %} {% include "includes/datetimepicker.css.html" %}
<link rel="stylesheet" href="{% static 'css/appointment.css' %}"> <link rel="stylesheet" href="{% static 'css/appointment.css' %}">
...@@ -18,6 +22,17 @@ ...@@ -18,6 +22,17 @@
text-align: center !important; text-align: center !important;
margin: 0; margin: 0;
} }
.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> </style>
{% endblock styles %} {% endblock styles %}
...@@ -47,49 +62,61 @@ New appointment for visit from {{visit_start}} to {{visit_end}} ...@@ -47,49 +62,61 @@ New appointment for visit from {{visit_start}} to {{visit_end}}
<form method="post" action="" class="form-horizontal"> <form method="post" action="" class="form-horizontal">
{% csrf_token %} {% csrf_token %}
<div class="box-body"> <div class="row">
<div class="col-sm-6"> <div class="box-body">
{% for field in form %} <div class="col-md-6">
<div class="form-group {% if field.errors %}has-error{% endif %} {% if field|is_checkbox %}multi-checkboxes{% endif %}"> {% for field in form %}
<label class="col-sm-4 control-label"> <div class="form-group {% if field.errors %}has-error{% endif %} {% if field|is_checkbox %}multi-checkboxes{% endif %}">
{{ field.label }} <label class="col-sm-4 control-label">
</label> {{ field.label }}
</label>
<div class="col-sm-8">
{{ field|add_class:'form-control' }} <div class="col-sm-8">
{{ field|add_class:'form-control' }}
</div>
{% if field.errors %}
<span class="help-block">
{{ field.errors }}
</span>
{% endif %}
</div>
{% endfor %}
</div>
<div class="col-md-6">
<div class="box box-primary">
<div class="box-body no-padding">
<div id="side_calendar"></div>
</div> </div>
{% if field.errors %}
<span class="help-block">
{{ field.errors }}
</span>
{% endif %}
</div>
{% endfor %}
</div>
<div class="col-md-6">
<div class="box box-primary">
<div class="box-body no-padding">
<div id="calendar"></div>
</div> </div>
</div> </div>
</div> </div><!-- /.box-body -->
</div><!-- /.box-body --> </div>
<div class="row">
<div class="box-footer">
<div class="box-footer"> <div class="col-sm-6">
<div class="col-sm-6"> <button type="submit" class="btn btn-block btn-success">Add</button>
<button type="submit" class="btn btn-block btn-success">Add</button> </div>
</div> <div class="col-sm-6">
<div class="col-sm-6"> <a href="{% url 'web.views.visits' %}" class="btn btn-block btn-default">Cancel</a>
<a href="{% url 'web.views.visits' %}" class="btn btn-block btn-default">Cancel</a> </div>
</div> </div><!-- /.box-footer -->
</div><!-- /.box-footer --> </div>
</form> </form>
</div> </div>
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-body no-padding">
<div id="calendar"></div>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}
...@@ -101,8 +128,9 @@ New appointment for visit from {{visit_start}} to {{visit_end}} ...@@ -101,8 +128,9 @@ New appointment for visit from {{visit_start}} to {{visit_end}}
<script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script> <script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script> <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script>
<script src="{% static 'AdminLTE/plugins/moment.js/moment.min.js' %}"></script> <script src="{% static 'AdminLTE/plugins/moment.js/moment.min.js' %}"></script>
<script src="{% static 'AdminLTE/plugins/fullcalendar/fullcalendar.min.js' %}"></script>
<script src="{% static 'js/appointment.js' %}"></script> <script src="{% static 'js/appointment.js' %}"></script>
<script src="{% static 'fullcalendar-scheduler/lib/fullcalendar.min.js' %}"></script>
<script src="{% static 'fullcalendar-scheduler/scheduler.min.js' %}"></script>
<script> <script>
$(function () { $(function () {
$('#table').DataTable({ $('#table').DataTable({
...@@ -113,14 +141,16 @@ New appointment for visit from {{visit_start}} to {{visit_end}} ...@@ -113,14 +141,16 @@ New appointment for visit from {{visit_start}} to {{visit_end}}
"info": true, "info": true,
"autoWidth": false "autoWidth": false
}); });
$('#calendar').fullCalendar({ //SIDE CALENDAR
defaultDate: moment('{{visit_start}}'), addDailyPlanningCalendar('#side_calendar', true, {
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
defaultDate: moment.max(moment('{{visit_start}}'), moment()),
editable: false,
header: { header: {
left: 'prev,next today', left: 'prev,next today',
center: 'title', center: 'title',
right: 'month,agendaWeek' right: 'month,agendaWeek'
}, },
editable: false,
dayClick: function (date, jsEvent, view) { dayClick: function (date, jsEvent, view) {
var dateString = date.format(); var dateString = date.format();
if (dateString.indexOf("T") >= 0) { if (dateString.indexOf("T") >= 0) {
...@@ -129,6 +159,7 @@ New appointment for visit from {{visit_start}} to {{visit_end}} ...@@ -129,6 +159,7 @@ New appointment for visit from {{visit_start}} to {{visit_end}}
dateString = dateString + " 09:00"; dateString = dateString + " 09:00";
} }
document.getElementById("id_datetime_when").value = dateString; document.getElementById("id_datetime_when").value = dateString;
$('#id_datetime_when').change();
getWorkerAvailability(); getWorkerAvailability();
}, },
eventClick: function (calEvent, jsEvent, view) { eventClick: function (calEvent, jsEvent, view) {
...@@ -214,7 +245,35 @@ New appointment for visit from {{visit_start}} to {{visit_end}} ...@@ -214,7 +245,35 @@ New appointment for visit from {{visit_start}} to {{visit_end}}
} }
$('select.search_worker_availability, input[name="datetime_when"], input[name="length"]').on("change", getWorkerAvailability); $('select.search_worker_availability, input[name="datetime_when"], input[name="length"]').on("change", getWorkerAvailability);
$("#id_datetime_when").on("change paste keyup", function() {
var date = $("#id_datetime_when").val();
date = moment(date);
$('#calendar').fullCalendar('gotoDate', date);
});
var resources_url = '{% url 'web.api.workers.daily_planning' %}';
var events_url = '{% url 'web.api.events_persist' %}';
$(document).ready(function () {
addDailyPlanningCalendar('#calendar', false, {
eventDurationEditable: false,
eventStartEditable: false,
editable: false,
selectable: false,
droppable: false,
customButtons: {},
header: {
left: '',
center: 'title',
right: ''
}
});
});
</script> </script>
{% include "includes/datetimepicker.js.html" %} {% include "includes/datetimepicker.js.html" %}
<script src="{% static 'js/daily_planning.js' %}"></script>
{% endblock scripts %} {% endblock scripts %}
...@@ -85,6 +85,10 @@ ...@@ -85,6 +85,10 @@
$('#calendar').fullCalendar('refetchResources'); $('#calendar').fullCalendar('refetchResources');
} }
$(document).ready(function () {
addDailyPlanningCalendar('#calendar', false, {});
});
</script> </script>
{% include "includes/datepicker.js.html" %} {% include "includes/datepicker.js.html" %}
<script src="{% static 'js/daily_planning.js' %}"></script> <script src="{% static 'js/daily_planning.js' %}"></script>
......
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