MDL-59756 user: Add edit enrolment button in enrol details modal
[moodle.git] / user / amd / src / status_field.js
1 // This file is part of Moodle - http://moodle.org/
2 //
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16 /**
17  * AMD module for the user enrolment status field in the course participants page.
18  *
19  * @module     core_user/status_field
20  * @copyright  2017 Jun Pataleta
21  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22  */
23 define(['core/templates',
24         'jquery',
25         'core/str',
26         'core/config',
27         'core/notification',
28         'core/modal_factory',
29         'core/modal_events',
30         'core/fragment',
31         'core/ajax'
32     ],
33     function(Template, $, Str, Config, Notification, ModalFactory, ModalEvents, Fragment, Ajax) {
35         /**
36          * Action selectors.
37          *
38          * @access private
39          * @type {{EDIT_ENROLMENT: string, SHOW_DETAILS: string, UNENROL: string}}
40          */
41         var SELECTORS = {
42             EDIT_ENROLMENT: '[data-action="editenrolment"]',
43             SHOW_DETAILS: '[data-action="showdetails"]',
44             UNENROL: '[data-action="unenrol"]'
45         };
47         /**
48          * Constructor
49          *
50          * @param {Object} options Object containing options. The only valid option at this time is contextid.
51          * Each call to templates.render gets it's own instance of this class.
52          */
53         var StatusFieldActions = function(options) {
54             this.contextid = options.contextid;
55             this.courseid = options.courseid;
57             // Bind click event to editenrol buttons.
58             this.bindEditEnrol();
60             // Bind click event to unenrol buttons.
61             this.bindUnenrol();
63             // Bind click event to status details buttons.
64             this.bindStatusDetails();
65         };
66         // Class variables and functions.
68         /** @var {number} courseid The course ID. */
69         StatusFieldActions.prototype.courseid = 0;
71         /**
72          * Private method
73          *
74          * @method initModal
75          * @private
76          */
77         StatusFieldActions.prototype.bindEditEnrol = function() {
78             var statusFieldInstsance = this;
80             $(SELECTORS.EDIT_ENROLMENT).click(function(e) {
81                 e.preventDefault();
83                 // The particular edit button that was clicked.
84                 var clickedEditTrigger = $(this);
85                 // Get the parent container (it contains the data attributes associated with the status field).
86                 var parentContainer = clickedEditTrigger.parent();
87                 // Get the name of the user whose enrolment status is being edited.
88                 var fullname = parentContainer.data('fullname');
89                 // Get the user enrolment ID.
90                 var ueid = clickedEditTrigger.attr('rel');
92                 $.when(Str.get_string('edituserenrolment', 'enrol', fullname)).then(function(modalTitle) {
93                     return ModalFactory.create({
94                         large: true,
95                         title: modalTitle,
96                         type: ModalFactory.types.SAVE_CANCEL
97                     });
98                 }).done(function(modal) {
99                     // Handle save event.
100                     modal.getRoot().on(ModalEvents.save, function(e) {
101                         // Don't close the modal yet.
102                         e.preventDefault();
103                         // Submit form data.
104                         statusFieldInstsance.submitEditFormAjax(modal);
105                     });
107                     // Handle hidden event.
108                     modal.getRoot().on(ModalEvents.hidden, function() {
109                         // Destroy when hidden.
110                         modal.destroy();
111                     });
113                     // Set the modal body.
114                     modal.setBody(statusFieldInstsance.getBody(ueid));
116                     // Show the modal!
117                     modal.show();
118                 }).fail(Notification.exception);
119             });
120         };
122         /**
123          * Private method
124          *
125          * @method bindUnenrol
126          * @private
127          */
128         StatusFieldActions.prototype.bindUnenrol = function() {
129             $(SELECTORS.UNENROL).click(function(e) {
130                 e.preventDefault();
131                 var unenrolLink = $(this);
132                 var parentContainer = unenrolLink.parent();
133                 var strings = [
134                     {
135                         key: 'unenrol',
136                         component: 'enrol'
137                     },
138                     {
139                         key: 'unenrolconfirm',
140                         component: 'enrol',
141                         param: {
142                             user: parentContainer.data('fullname'),
143                             course: parentContainer.data('coursename')
144                         }
145                     }
146                 ];
148                 $.when(Str.get_strings(strings)).then(function(results) {
149                     var title = results[0];
150                     var confirmMessage = results[1];
151                     return ModalFactory.create({
152                         body: confirmMessage,
153                         large: true,
154                         title: title,
155                         type: ModalFactory.types.CONFIRM
156                     });
157                 }).done(function(modal) {
158                     // Handle confirm event.
159                     modal.getRoot().on(ModalEvents.yes, function() {
160                         // Build params.
161                         var unenrolParams = {
162                             confirm: 1,
163                             sesskey: Config.sesskey,
164                             ue: $(unenrolLink).attr('rel')
165                         };
166                         // Send data to unenrol page (which will redirect back to the participants page after unenrol).
167                         window.location.href = Config.wwwroot + '/enrol/unenroluser.php?' + $.param(unenrolParams);
168                     });
170                     // Handle hidden event.
171                     modal.getRoot().on(ModalEvents.hidden, function() {
172                         // Destroy when hidden.
173                         modal.destroy();
174                     });
176                     // Display the delete confirmation modal.
177                     modal.show();
178                 }).fail(Notification.exception);
179             });
180         };
182         /**
183          * Private method
184          *
185          * @method bindStatusDetails
186          * @private
187          */
188         StatusFieldActions.prototype.bindStatusDetails = function() {
189             $(SELECTORS.SHOW_DETAILS).click(function(e) {
190                 e.preventDefault();
192                 var detailsButton = $(this);
193                 var parentContainer = detailsButton.parent();
194                 var context = {
195                     "fullname": parentContainer.data('fullname'),
196                     "coursename": parentContainer.data('coursename'),
197                     "enrolinstancename": parentContainer.data('enrolinstancename'),
198                     "status": parentContainer.data('status'),
199                     "statusclass": parentContainer.find('span').attr('class'),
200                     "timestart": parentContainer.data('timestart'),
201                     "timeend": parentContainer.data('timeend')
202                 };
204                 // Get default string for the modal and modal type.
205                 var strings = [
206                     {
207                         key: 'enroldetails',
208                         component: 'enrol'
209                     }
210                 ];
211                 var modalType = ModalFactory.types.CANCEL;
213                 // Find the edit enrolment link.
214                 var editEnrolLink = detailsButton.next(SELECTORS.EDIT_ENROLMENT);
215                 if (editEnrolLink.length) {
216                     // If there's an edit enrolment link for this user, use a SAVE_CANCEL type of modal.
217                     strings.push({key: 'editenrolment', component: 'enrol'});
218                     modalType = ModalFactory.types.SAVE_CANCEL;
219                 }
221                 var modalStringsPromise = Str.get_strings(strings);
222                 var modalPromise = ModalFactory.create({large: true, type: modalType});
223                 $.when(modalStringsPromise, modalPromise).done(function(strings, modal) {
224                     var modalBodyPromise = Template.render('core_user/status_details', context);
225                     modal.setTitle(strings[0]);
226                     modal.setBody(modalBodyPromise);
228                     if (modalType === ModalFactory.types.SAVE_CANCEL) {
229                         // Set the edit enrolment button text.
230                         modal.setSaveButtonText(strings[1]);
231                         // Handle event when the "Edit enrolment" button is clicked.
232                         modal.getRoot().on(ModalEvents.save, function() {
233                             // Trigger click event for the edit enrolment link to show the edit enrolment modal.
234                             $(editEnrolLink).trigger('click');
235                         });
236                     }
238                     modal.show();
240                     // Handle hidden event.
241                     modal.getRoot().on(ModalEvents.hidden, function() {
242                         // Destroy when hidden.
243                         modal.destroy();
244                     });
245                 }).fail(Notification.exception);
246             });
247         };
249         /**
250          * Private method
251          *
252          * @method submitEditFormAjax
253          * @param {Object} modal The the AMD modal object containing the form.
254          * @private
255          */
256         StatusFieldActions.prototype.submitEditFormAjax = function(modal) {
257             var statusFieldInstsance = this;
258             var form = modal.getRoot().find('form');
260             // User enrolment ID.
261             var ueid = $(form).find('[name="ue"]').val();
262             // Status.
263             var status = $(form).find('[name="status"]').val();
265             var params = {
266                 'courseid': this.courseid,
267                 'ueid': ueid,
268                 'status': status
269             };
271             // Enrol time start.
272             var timeStartEnabled = $(form).find('[name="timestart[enabled]"]');
273             if (timeStartEnabled.is(':checked')) {
274                 var timeStartYear = $(form).find('[name="timestart[year]"]').val();
275                 var timeStartMonth = $(form).find('[name="timestart[month]"]').val() - 1;
276                 var timeStartDay = $(form).find('[name="timestart[day]"]').val();
277                 var timeStartHour = $(form).find('[name="timestart[hour]"]').val();
278                 var timeStartMinute = $(form).find('[name="timestart[minute]"]').val();
279                 var timeStart = new Date(timeStartYear, timeStartMonth, timeStartDay, timeStartHour, timeStartMinute);
280                 params.timestart = timeStart.getTime() / 1000;
281             }
283             // Enrol time end.
284             var timeEndEnabled = $(form).find('[name="timeend[enabled]"]');
285             if (timeEndEnabled.is(':checked')) {
286                 var timeEndYear = $(form).find('[name="timeend[year]"]').val();
287                 var timeEndMonth = $(form).find('[name="timeend[month]"]').val() - 1;
288                 var timeEndDay = $(form).find('[name="timeend[day]"]').val();
289                 var timeEndHour = $(form).find('[name="timeend[hour]"]').val();
290                 var timeEndMinute = $(form).find('[name="timeend[minute]"]').val();
291                 var timeEnd = new Date(timeEndYear, timeEndMonth, timeEndDay, timeEndHour, timeEndMinute);
292                 params.timeend = timeEnd.getTime() / 1000;
293             }
295             var request = {
296                 methodname: 'core_enrol_edit_user_enrolment',
297                 args: params
298             };
300             Ajax.call([request])[0].done(function(data) {
301                 if (data.result) {
302                     // Dismiss the modal.
303                     modal.hide();
305                     // Reload the page, don't show changed data warnings.
306                     if (typeof window.M.core_formchangechecker !== "undefined") {
307                         window.M.core_formchangechecker.reset_form_dirty_state();
308                     }
309                     window.location.reload();
311                 } else {
312                     // Serialise the form data and reload the form fragment to show validation errors.
313                     var formData = JSON.stringify(form.serialize());
314                     modal.setBody(statusFieldInstsance.getBody(ueid, formData));
315                 }
316             }).fail(Notification.exception);
317         };
319         /**
320          * Private method
321          *
322          * @method getBody
323          * @private
324          * @param {Number} ueid The user enrolment ID associated with the user.
325          * @param {string} formData Serialized string of the edit enrolment form data.
326          * @return {Promise}
327          */
328         StatusFieldActions.prototype.getBody = function(ueid, formData) {
329             var params = {
330                 'ueid': ueid
331             };
332             if (typeof formData !== 'undefined') {
333                 params.formdata = formData;
334             }
335             return Fragment.loadFragment('enrol', 'user_enrolment_form', this.contextid, params).fail(Notification.exception);
336         };
338         return /** @alias module:core_user/editenrolment */ {
339             // Public variables and functions.
340             /**
341              * Every call to init creates a new instance of the class with it's own event listeners etc.
342              *
343              * @method init
344              * @public
345              * @param {object} config - config variables for the module.
346              */
347             init: function(config) {
348                 (new StatusFieldActions(config));
349             }
350         };
351     });