Files
edx-platform/lms/static/js/dashboard/donation.js
2014-12-15 13:11:33 -05:00

245 lines
8.5 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);