diff --git a/lms/static/js/ccx/schedule.js b/lms/static/js/ccx/schedule.js index 20ffdc1c38..2a3b1814f5 100644 --- a/lms/static/js/ccx/schedule.js +++ b/lms/static/js/ccx/schedule.js @@ -104,23 +104,41 @@ var edx = edx || {}; // Add unit handler $('#add-unit-button').on('click', function(event) { event.preventDefault(); - var chapter = self.chapter_select.val(), - sequential = self.sequential_select.val(), - vertical = self.vertical_select.val(), - units = self.find_lineage(self.schedule, - chapter, - sequential === 'all' ? null : sequential, - vertical === 'all' ? null: vertical), - start = self.get_datetime('start'), - due = self.get_datetime('due'); - units.map(self.show); - var unit = units[units.length - 1]; - if (unit !== undefined && start) { unit.start = start; } - if (unit !== undefined && due) { unit.due = due; } - self.schedule_apply([unit], self.show); - self.schedule_collection.set(self.schedule); - self.dirty = true; - self.render(); + // Default value of time is 00:00. + var start, chapter, sequential, vertical, units, due; + start = self.get_datetime('start'); + chapter = self.chapter_select.val(); + sequential = self.sequential_select.val(); + vertical = self.vertical_select.val(); + units = self.find_lineage( + self.schedule, + chapter, + sequential === 'all' ? null : sequential, + vertical === 'all' ? null : vertical + ); + due = self.get_datetime('due'); + var errorMessage = self.valid_dates(start, due); + if (_.isUndefined(errorMessage)) { + units.map(self.show); + var unit = units[units.length - 1]; + if (!_.isUndefined(unit)) { + if (!_.isNull(start)) { + unit.start = start; + } + if (!_.isNull(due)) { + unit.due = due; + } + } + self.schedule_apply([unit], self.show); + self.schedule_collection.set(self.schedule); + self.dirty = true; + self.render(); + } else { + self.dirty = false; + $('#ccx_schedule_error_message').text(errorMessage); + $('#ajax-error').show().focus(); + $('#dirty-schedule').hide(); + } }); // Handle save button @@ -251,9 +269,27 @@ var edx = edx || {}; } }, + valid_dates: function(start, due) { + var errorMessage; + // Start date is compulsory and due date is optional. + if (_.isEmpty(start) && !_.isEmpty(due)) { + errorMessage = gettext("Please enter valid start date and time."); + } else if (!_.isEmpty(start) && !_.isEmpty(due)) { + var requirejs = window.require || RequireJS.require; + var moment = requirejs("moment"); + var parsedDueDate = moment(due, 'YYYY-MM-DD HH:mm'); + var parsedStartDate = moment(start, 'YYYY-MM-DD HH:mm'); + if (parsedDueDate.isBefore(parsedStartDate)) { + errorMessage = gettext("Due date cannot be before start date."); + } + } + return errorMessage; + }, + get_datetime: function(which) { var date = $('form#add-unit input[name=' + which + '_date]').val(); var time = $('form#add-unit input[name=' + which + '_time]').val(); + time = _.isEmpty(time) ? "00:00" : time; if (date && time) { return date + ' ' + time; } return null; diff --git a/lms/static/js/spec/ccx/schedule_spec.js b/lms/static/js/spec/ccx/schedule_spec.js index 01364a680f..9dd6e4fa08 100644 --- a/lms/static/js/spec/ccx/schedule_spec.js +++ b/lms/static/js/spec/ccx/schedule_spec.js @@ -124,7 +124,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/ccx/schedule'], val = "i4x://edX/DemoX/sequential/edx_introduction"; view.sequential_select.val(val); view.sequential_select.change(); - val = "i4x://edX/DemoX/vertical/vertical_0270f6de40fc", + val = "i4x://edX/DemoX/vertical/vertical_0270f6de40fc"; view.vertical_select.val(val); view.vertical_select.change(); expect(view.vertical_select.val()).toEqual(val); @@ -141,11 +141,53 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/ccx/schedule'], view.vertical_select.val(val); view.vertical_select.change(); var unit = view.find_unit(view.schedule, 'i4x://edX/DemoX/chapter/d8a6192ade314473a78242dfeedfbf5b'); + view.set_datetime('start', '2015-12-12 10:00'); + view.set_datetime('due', '2015-12-12 10:30'); expect(unit.hidden).toBe(true); $('#add-unit-button').click(); expect(unit.hidden).toBe(false); }); + it("add unit when start date is greater the due date", function() { + var val = 'i4x://edX/DemoX/chapter/d8a6192ade314473a78242dfeedfbf5b'; + view.chapter_select.val(val); + view.chapter_select.change(); + val = "i4x://edX/DemoX/sequential/edx_introduction"; + view.sequential_select.val(val); + view.sequential_select.change(); + val = "i4x://edX/DemoX/vertical/vertical_0270f6de40fc"; + view.vertical_select.val(val); + view.vertical_select.change(); + var unit = view.find_unit(view.schedule, 'i4x://edX/DemoX/chapter/d8a6192ade314473a78242dfeedfbf5b'); + // start date is before due date + view.set_datetime('start', '2015-11-13 10:45'); + view.set_datetime('due', '2015-11-12 10:00'); + expect(unit.hidden).toBe(true); + $('#add-unit-button').click(); + // Assert unit is not added to schedule + expect(unit.hidden).toBe(true); + }); + + it("add unit when start date is missing", function() { + var val = 'i4x://edX/DemoX/chapter/d8a6192ade314473a78242dfeedfbf5b'; + view.chapter_select.val(val); + view.chapter_select.change(); + val = "i4x://edX/DemoX/sequential/edx_introduction"; + view.sequential_select.val(val); + view.sequential_select.change(); + val = "i4x://edX/DemoX/vertical/vertical_0270f6de40fc"; + view.vertical_select.val(val); + view.vertical_select.change(); + var unit = view.find_unit(view.schedule, 'i4x://edX/DemoX/chapter/d8a6192ade314473a78242dfeedfbf5b'); + // start date is missing + view.set_datetime('start', null); + view.set_datetime('due', '2015-12-12 10:00'); + expect(unit.hidden).toBe(true); + $('#add-unit-button').click(); + // Assert unit is not added to schedule + expect(unit.hidden).toBe(true); + }); + it("gets a datetime string from date and time fields", function() { view.set_datetime('start', '2015-12-12 10:45'); expect($('form#add-unit input[name=start_date]')).toHaveValue('2015-12-12'); diff --git a/lms/static/js/spec/main.js b/lms/static/js/spec/main.js index bf5ee49a10..86634d607f 100644 --- a/lms/static/js/spec/main.js +++ b/lms/static/js/spec/main.js @@ -316,7 +316,7 @@ }, 'js/ccx/schedule': { exports: 'js/ccx/schedule', - deps: ['jquery', 'underscore', 'backbone', 'gettext'] + deps: ['jquery', 'underscore', 'backbone', 'gettext', 'moment'] }, // Backbone classes loaded explicitly until they are converted to use RequireJS