241 lines
8.4 KiB
JavaScript
241 lines
8.4 KiB
JavaScript
var edx = edx || {};
|
|
|
|
(function($) {
|
|
'use strict';
|
|
|
|
edx.dashboard = edx.dashboard || {};
|
|
edx.dashboard.donation = {};
|
|
|
|
/**
|
|
* View for making donations for a course.
|
|
* @constructor
|
|
* @param {Object} params
|
|
* @param {Object} params.el - The container element.
|
|
* @param {string} params.course - The ID of the course for the donation.
|
|
*/
|
|
edx.dashboard.donation.DonationView = function(params) {
|
|
/**
|
|
* Dynamically configure a form, which the client can submit
|
|
* to the payment processor.
|
|
* @param {Object} form - The form to modify.
|
|
* @param {string} method - The HTTP method used to submit the form.
|
|
* @param {string} url - The URL where the form data will be submitted.
|
|
* @param {Object} params - Form data, included as hidden inputs.
|
|
*/
|
|
var configureForm = function(form, method, url, params) {
|
|
$('input', form).remove();
|
|
form.attr('action', url);
|
|
form.attr('method', method);
|
|
_.each(params, function(value, key) {
|
|
$('<input>').attr({
|
|
type: 'hidden',
|
|
name: key,
|
|
value: value
|
|
}).appendTo(form);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Fire an analytics event indicating that the user
|
|
* is about to be sent to the external payment processor.
|
|
*
|
|
* @param {string} course - The course ID for the donation.
|
|
*/
|
|
var firePaymentAnalyticsEvent = function(course) {
|
|
analytics.track(
|
|
'edx.bi.user.payment_processor.visited',
|
|
{
|
|
category: 'donations',
|
|
label: course
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Add a donation to the user's cart.
|
|
*
|
|
* @param {string} amount - The amount of the donation (e.g. "23.45")
|
|
* @param {string} course - The ID of the course.
|
|
* @returns {Object} The promise from the AJAX call to the server,
|
|
* which resolves with a data object of the form
|
|
* { payment_url: <string>, payment_params: <Object> }
|
|
*/
|
|
var addDonationToCart = function(amount, course) {
|
|
return $.ajax({
|
|
url: '/shoppingcart/donation/',
|
|
type: 'POST',
|
|
data: {
|
|
amount: amount,
|
|
course_id: course
|
|
}
|
|
});
|
|
};
|
|
|
|
var view = {
|
|
/**
|
|
* Initialize the view.
|
|
*
|
|
* @param {Object} params
|
|
* @param {JQuery selector} params.el - The container element.
|
|
* @param {string} params.course - The ID of the course for the donation.
|
|
* @returns {DonationView}
|
|
*/
|
|
initialize: function(params) {
|
|
this.$el = params.el;
|
|
this.course = params.course;
|
|
_.bindAll(view,
|
|
'render', 'donate', 'startPayment',
|
|
'validate', 'startPayment',
|
|
'displayServerError', 'submitPaymentForm'
|
|
);
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Render the form for making a donation for a course.
|
|
*
|
|
* @returns {DonationView}
|
|
*/
|
|
render: function() {
|
|
var html = _.template($('#donation-tpl').html())({});
|
|
this.$el.html(html);
|
|
this.$amount = $('input[name="amount"]', this.$el);
|
|
this.$submit = $('.action-donate', this.$el);
|
|
this.$errorMsg = $('.donation-error-msg', this.$el);
|
|
this.$paymentForm = $('.payment-form', this.$el);
|
|
this.$submit.click(this.donate);
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Handle a click event on the "donate" button.
|
|
* This will contact the LMS server to add the donation
|
|
* to the user's cart, then send the user to the
|
|
* external payment processor.
|
|
*
|
|
* @param {Object} event - The click event.
|
|
*/
|
|
donate: function(event) {
|
|
// Prevent form submission
|
|
if (event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
// Immediately disable the submit button to prevent duplicate submissions
|
|
this.$submit.addClass('disabled');
|
|
|
|
if (this.validate()) {
|
|
var amount = this.$amount.val();
|
|
addDonationToCart(amount, this.course)
|
|
.done(this.startPayment)
|
|
.fail(this.displayServerError);
|
|
} else {
|
|
// If an error occurred, allow the user to resubmit
|
|
this.$submit.removeClass('disabled');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Send signed payment parameters to the external
|
|
* payment processor.
|
|
*
|
|
* @param {Object} data - The signed payment data received from the LMS server.
|
|
* @param {string} data.payment_url - The URL of the external payment processor.
|
|
* @param {Object} data.payment_data - Parameters to send to the external payment processor.
|
|
*/
|
|
startPayment: function(data) {
|
|
configureForm(
|
|
this.$paymentForm,
|
|
'post',
|
|
data.payment_url,
|
|
data.payment_params
|
|
);
|
|
firePaymentAnalyticsEvent(this.course);
|
|
this.submitPaymentForm(this.$paymentForm);
|
|
},
|
|
|
|
/**
|
|
* Validate the donation amount and mark any validation errors.
|
|
*
|
|
* @returns {boolean} True iff the form is valid.
|
|
*/
|
|
validate: function() {
|
|
var amount = this.$amount.val();
|
|
var isValid = this.validateAmount(amount);
|
|
|
|
if (isValid) {
|
|
this.$amount.removeClass('validation-error');
|
|
this.$errorMsg.text('');
|
|
} else {
|
|
this.$amount.addClass('validation-error');
|
|
this.$errorMsg.text(
|
|
gettext('Please enter a valid donation amount.')
|
|
);
|
|
}
|
|
|
|
return isValid;
|
|
},
|
|
|
|
|
|
/**
|
|
* Validate that the given amount is a valid currency string.
|
|
*
|
|
* @param {string} amount
|
|
* @returns {boolean} True iff the amount is valid.
|
|
*/
|
|
validateAmount: function(amount) {
|
|
var amountRegex = /^\d+.\d{2}$|^\d+$/i;
|
|
if (!amountRegex.test(amount)) {
|
|
return false;
|
|
}
|
|
|
|
if (parseFloat(amount) < 0.01) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Display an error message when we receive an error from the LMS server.
|
|
*/
|
|
displayServerError: function() {
|
|
// Display the error message
|
|
this.$errorMsg.text(gettext('Your donation could not be submitted.'));
|
|
|
|
// Re-enable the submit button to allow the user to retry
|
|
this.$submit.removeClass('disabled');
|
|
},
|
|
|
|
/**
|
|
* Submit the payment from to the external payment processor.
|
|
* This is a separate function so we can easily stub it out in tests.
|
|
*
|
|
* @param {Object} form - The dynamically constructed payment form.
|
|
*/
|
|
submitPaymentForm: function(form) {
|
|
form.submit();
|
|
}
|
|
};
|
|
|
|
view.initialize(params);
|
|
return view;
|
|
};
|
|
|
|
$(document).ready(function() {
|
|
// There may be multiple donation forms on the page
|
|
// (one for each newly enrolled course).
|
|
// For each one, create a new donation view to handle
|
|
// that form, and parameterize it based on the
|
|
// "data-course" attribute (the course ID).
|
|
$('.donate-container').each(function() {
|
|
var $container = $(this);
|
|
var course = $container.data('course');
|
|
var view = new edx.dashboard.donation.DonationView({
|
|
el: $container,
|
|
course: course
|
|
}).render();
|
|
});
|
|
});
|
|
}(jQuery));
|