Add speed bump when leaving timesheet page w/ unsaved changes

Also add save/undo buttons to top as well as bottom of timesheet.
This commit is contained in:
Lance Edgar 2016-10-14 13:57:57 -05:00
parent e153390c15
commit 9e7cb532c8
4 changed files with 127 additions and 57 deletions

View file

@ -20,6 +20,10 @@
width: auto;
}
.timesheet-header td.filters .buttons {
margin-bottom: 0;
}
.timesheet-header td.menu {
padding: 0.5em;
vertical-align: top;
@ -46,7 +50,7 @@
border-bottom: 1px solid black;
border-right: 1px solid black;
clear: both;
margin-top: 0.3em;
margin: 0.3em 0;
width: 100%;
}
@ -82,3 +86,11 @@
.timesheet tbody tr.total {
font-weight: bold;
}
/******************************
* below timesheet...
******************************/
div.buttons {
margin-top: 0;
}

View file

@ -9,19 +9,51 @@
${h.stylesheet_link(request.static_url('tailbone:static/css/timesheet.css'))}
<script type="text/javascript">
var data_modified = false;
var okay_to_leave = true;
var previous_selections = {};
window.onbeforeunload = function() {
if (! okay_to_leave) {
return "If you leave this page, you will lose all unsaved changes!";
}
}
function employee_selected(uuid, name) {
$('.timesheet-wrapper form').submit();
$('#filter-form').submit();
}
function confirm_leave() {
if (data_modified) {
if (confirm("If you navigate away from this page now, you will lose " +
"unsaved changes.\n\nAre you sure you wish to do this?")) {
okay_to_leave = true;
return true;
}
return false;
}
return true;
}
$(function() {
$('.timesheet-wrapper form').submit(function() {
$('#filter-form').submit(function() {
$('.timesheet-header').mask("Fetching data");
});
$('.timesheet-header select').each(function() {
previous_selections[$(this).attr('name')] = $(this).val();
});
$('.timesheet-header select').selectmenu({
change: function(event, ui) {
$(ui.item.element).parents('form').submit();
if (confirm_leave()) {
$('#filter-form').submit();
} else {
var select = ui.item.element.parents('select');
select.val(previous_selections[select.attr('name')]);
select.selectmenu('refresh');
}
}
});
@ -30,7 +62,10 @@
});
$('.week-picker button.nav').click(function() {
$('.week-picker #date').val($(this).data('date'));
if (confirm_leave()) {
$('.week-picker #date').val($(this).data('date'));
$('#filter-form').submit();
}
});
$('.week-picker #date').datepicker({
@ -39,7 +74,7 @@
changeMonth: true,
showButtonPanel: true,
onSelect: function(dateText, inst) {
$(this).parents('form').submit();
$('#filter-form').submit();
}
});
@ -50,7 +85,7 @@
<%def name="context_menu()"></%def>
<%def name="timesheet()">
<%def name="timesheet(edit_form=None, edit_tools=None)">
<style type="text/css">
.timesheet thead th {
width: ${'{:0.2f}'.format(100.0 / 9)}%;
@ -59,7 +94,7 @@
<div class="timesheet-wrapper">
${form.begin()}
${form.begin(id='filter-form')}
<table class="timesheet-header">
<tbody>
@ -99,6 +134,10 @@
</div>
</div>
% if edit_tools:
${edit_tools()}
% endif
</td><!-- filters -->
<td class="menu">
@ -112,8 +151,8 @@
<td class="tools">
<div class="grid-tools">
<div class="week-picker">
<button class="nav" data-date="${prev_sunday.strftime('%m/%d/%Y')}">&laquo; Previous</button>
<button class="nav" data-date="${next_sunday.strftime('%m/%d/%Y')}">Next &raquo;</button>
<button type="button" class="nav" data-date="${prev_sunday.strftime('%m/%d/%Y')}">&laquo; Previous</button>
<button type="button" class="nav" data-date="${next_sunday.strftime('%m/%d/%Y')}">Next &raquo;</button>
<label>Jump to week:</label>
${form.text('date', value=sunday.strftime('%m/%d/%Y'))}
</div>
@ -126,6 +165,10 @@
${form.end()}
% if edit_form:
${edit_form()}
% endif
<table class="timesheet">
<thead>
<tr>
@ -167,6 +210,11 @@
% endif
</tbody>
</table>
% if edit_form:
${h.end_form()}
% endif
</div><!-- timesheet-wrapper -->
</%def>

View file

@ -152,10 +152,12 @@
// mark day as modified, close dialog
editing_day.addClass('modified');
$('#save-changes').button('enable');
$('#undo-changes').button('enable');
$('.save-changes').button('enable');
$('.undo-changes').button('enable');
update_row_hours(editing_day.parents('tr:first'));
editor.dialog('close');
data_modified = true;
okay_to_leave = false;
}
},
{
@ -176,13 +178,15 @@
$(this).parents('.shift:first').remove();
});
$('#save-changes').click(function() {
$('.save-changes').click(function() {
$(this).button('disable').button('option', 'label', "Saving Changes...");
okay_to_leave = true;
$('#schedule-form').submit();
});
$('#undo-changes').click(function() {
$('.undo-changes').click(function() {
$(this).button('disable').button('option', 'label', "Refreshing...");
okay_to_leave = true;
location.href = '${url('schedule.edit')}';
});
@ -232,14 +236,20 @@
% endfor
</%def>
${h.form(url('schedule.edit'), id="schedule-form")}
${self.timesheet()}
${h.end_form()}
<%def name="edit_tools()">
<div class="buttons">
<button type="button" class="save-changes" disabled="disabled">Save Changes</button>
<button type="button" class="undo-changes" disabled="disabled">Undo Changes</button>
</div>
</%def>
<div class="buttons">
<button type="button" id="save-changes" disabled="disabled">Save Changes</button>
<button type="button" id="undo-changes" disabled="disabled">Undo Changes</button>
</div>
<%def name="edit_form()">
${h.form(url('schedule.edit'), id='schedule-form')}
</%def>
${self.timesheet(edit_form=edit_form, edit_tools=edit_tools)}
${edit_tools()}
<div id="day-editor" style="display: none;">
<div class="shifts"></div>

View file

@ -48,6 +48,11 @@ class ScheduleView(TimeSheetView):
"""
View for editing (full) schedule.
"""
# first process filters; will redirect if any were received
form = Form(self.request, schema=ShiftFilter)
self.process_filter_form(form)
# okay then, maybe process saved shift data
if self.request.method == 'POST':
# organize form data by uuid / field
@ -61,47 +66,42 @@ class ScheduleView(TimeSheetView):
data[field][uuid] = self.request.POST[key]
break
# if no fields, don't apply changes (filter form uses POST also)
if any(data.itervalues()):
# apply delete operations
deleted = []
for uuid, value in data['delete'].iteritems():
assert value == 'delete'
shift = Session.query(model.ScheduledShift).get(uuid)
assert shift
Session.delete(shift)
deleted.append(uuid)
# apply delete operations
deleted = []
for uuid, value in data['delete'].iteritems():
assert value == 'delete'
# apply create / update operations
created = {}
updated = {}
time_format = '%a %d %b %Y %I:%M %p'
for uuid, employee_uuid in data['start_time'].iteritems():
if uuid in deleted:
continue
if uuid.startswith('new-'):
shift = model.ScheduledShift()
shift.employee_uuid = data['employee_uuid'][uuid]
shift.store_uuid = data['store_uuid'][uuid]
Session.add(shift)
created[uuid] = shift
else:
shift = Session.query(model.ScheduledShift).get(uuid)
assert shift
Session.delete(shift)
deleted.append(uuid)
updated[uuid] = shift
start_time = datetime.datetime.strptime(data['start_time'][uuid], time_format)
shift.start_time = make_utc(localtime(self.rattail_config, start_time))
end_time = datetime.datetime.strptime(data['end_time'][uuid], time_format)
shift.end_time = make_utc(localtime(self.rattail_config, end_time))
# apply create / update operations
created = {}
updated = {}
time_format = '%a %d %b %Y %I:%M %p'
for uuid, employee_uuid in data['start_time'].iteritems():
if uuid in deleted:
continue
if uuid.startswith('new-'):
shift = model.ScheduledShift()
shift.employee_uuid = data['employee_uuid'][uuid]
shift.store_uuid = data['store_uuid'][uuid]
Session.add(shift)
created[uuid] = shift
else:
shift = Session.query(model.ScheduledShift).get(uuid)
assert shift
updated[uuid] = shift
start_time = datetime.datetime.strptime(data['start_time'][uuid], time_format)
shift.start_time = make_utc(localtime(self.rattail_config, start_time))
end_time = datetime.datetime.strptime(data['end_time'][uuid], time_format)
shift.end_time = make_utc(localtime(self.rattail_config, end_time))
self.request.session.flash("Changes were applied: created {}, updated {}, "
"deleted {} Scheduled Shifts".format(
len(created), len(updated), len(deleted)))
return self.redirect(self.request.route_url('schedule.edit'))
self.request.session.flash("Changes were applied: created {}, updated {}, "
"deleted {} Scheduled Shifts".format(
len(created), len(updated), len(deleted)))
return self.redirect(self.request.route_url('schedule.edit'))
form = Form(self.request, schema=ShiftFilter)
self.process_filter_form(form)
context = self.get_timesheet_context()
context['form'] = form
context['page_title'] = "Edit Schedule"