Commit e91c82d6 by Tasawer

Refactor backbone structure of checkout page + update styling

ECOM-1901
parent a111aa06
...@@ -80,5 +80,5 @@ class CheckoutPageTest(UserMixin, CourseCatalogTestMixin, TestCase): ...@@ -80,5 +80,5 @@ class CheckoutPageTest(UserMixin, CourseCatalogTestMixin, TestCase):
self.assertContains( self.assertContains(
response, response,
'You are purchasing {} credit hours for'.format(self.credit_hours) 'Purchase {} credits from'.format(self.credit_hours)
) )
from collections import OrderedDict
import json import json
from django.conf import settings from django.conf import settings
...@@ -27,7 +28,7 @@ class Checkout(TemplateView): ...@@ -27,7 +28,7 @@ class Checkout(TemplateView):
raise Http404 raise Http404
# Make button text for each processor which will be shown to user. # Make button text for each processor which will be shown to user.
processors_dict = {} processors_dict = OrderedDict()
for path in settings.PAYMENT_PROCESSORS: for path in settings.PAYMENT_PROCESSORS:
processor = get_processor_class(path).NAME.lower() processor = get_processor_class(path).NAME.lower()
if processor == 'cybersource': if processor == 'cybersource':
......
define([
'backbone',
'js/models/provider_model'
],
function (Backbone, ProviderModel) {
'use strict';
return Backbone.Collection.extend({
model: ProviderModel,
url: lmsRootUrl + '/api/credit/v1/providers/',
setUrl: function (providerIds) {
this.url += '?provider_ids=' + providerIds;
}
}
);
}
);
define([
'backbone',
'js/models/user_eligibility_model'
],
function (Backbone, EligibilityModel) {
'use strict';
return Backbone.Collection.extend({
model: EligibilityModel,
url: lmsRootUrl + '/api/credit/v1/eligibility/',
setUrl: function (username, courseKey) {
this.url += '?username=' + username + '&course_key=' + courseKey;
}
}
);
}
);
define([
'backbone'
],
function (Backbone) {
'use strict';
// Stores our provider information
return Backbone.Model.extend({});
}
);
define([
'backbone'
],
function (Backbone) {
'use strict';
// Stores our user eligibility information
return Backbone.Model.extend({});
}
);
...@@ -4,22 +4,31 @@ require([ ...@@ -4,22 +4,31 @@ require([
'js/models/user_model', 'js/models/user_model',
'js/models/tracking_model', 'js/models/tracking_model',
'js/models/course_model', 'js/models/course_model',
'js/collections/provider_collection',
'js/collections/user_eligibility_collection',
'js/views/clickable_view', 'js/views/clickable_view',
'js/views/analytics_view', 'js/views/analytics_view',
'js/views/payment_button_view', 'js/views/payment_button_view',
'js/utils/utils', 'js/utils/utils',
'js/views/provider_view' 'js/views/provider_view',
'js/views/user_eligibility_view'
], ],
function( $,Backbone, UserModel, TrackingModel, CourseModel, ClickableView, AnalyticsView, PaymentButtonView, Utils, ProviderView ) { function( $,Backbone, UserModel, TrackingModel, CourseModel, ProviderCollection, EligibilityCollection, ClickableView, AnalyticsView, PaymentButtonView, Utils, ProviderView, EligibilityView ) {
new PaymentButtonView({ new PaymentButtonView({
el: $( '#payment-buttons' ) el: $( '#payment-buttons' )
}); });
new ProviderView({ new ProviderView({
el: $( '.provider-details' ) el: $( '.provider-details' ),
collection: new ProviderCollection()
}); });
new EligibilityView({
collection: new EligibilityCollection()
});
var courseModel = new CourseModel(), var courseModel = new CourseModel(),
trackingModel = new TrackingModel(), trackingModel = new TrackingModel(),
userModel = new UserModel(); userModel = new UserModel();
......
define([ define([
'jquery', 'jquery',
'underscore', 'underscore',
'backbone' 'backbone',
'text!templates/provider_details.html'
], ],
function( $, _, Backbone ) { function ($, _, Backbone, providerTemplate) {
return Backbone.View.extend({ return Backbone.View.extend({
initialize: function() { initialize: function () {
this.template = _.template($('#provider-details-tpl').text()); this.getProviders();
this.getProviders(); },
this.checkEligibility();
},
getProviders: function () { getProviders: function () {
var providersIds = this.$el[0].dataset.providersIds; var self = this;
var url = lmsRootUrl + '/api/credit/v1/providers/?provider_id=' + providersIds;
var self = this;
$.ajax({
url: url,
method: 'GET',
success: function(response) {
if (response.length) {
var html = self.template(response[0]); //currently we are assuming only one provider
self.$el.html(html);
self.toggleProviderContent(true);
} else {
self.toggleProviderContent(false);
}
},
error: function() {
self.toggleProviderContent(false);
}
})
},
checkEligibility: function () { this.collection.setUrl(this.$el[0].dataset.providersIds);
var $courseDetails = $("#course-name"); this.collection.fetch({
var username = $courseDetails.data("username"); success: function (collection) {
var courseKey = $courseDetails.data("course_key"); self.renderProviderDetail(collection);
var url = lmsRootUrl + '/api/credit/v1/eligibility/?username=' + username + '&course_key=' + courseKey; },
var self = this; error: function () {
$.ajax({ self.toggleProviderContent(false);
url: url, }
method: 'GET',
success: function(response) {
if (response.length) {
var deadline = new Date(response[0]["deadline"]);
var formattedDate = deadline.getMonth() + "/" + deadline.getDay() + "/" + deadline.getFullYear();
$(".eligibility-details").find(".deadline-date").text(formattedDate);
self.toggleProviderContent(true);
} else {
self.toggleProviderContent(false);
} }
}, );
error: function() { },
self.toggleProviderContent(false);
renderProviderDetail: function (collection) {
var providerData = collection.toJSON(),
template;
if (providerData.length) {
// Currently we are assuming that we are having only one provider
template = _.template(providerTemplate);
$('.title').find('.provider-name').text(providerData[0]['display_name']);
this.$el.html(template(providerData[0]));
this.toggleProviderContent(true);
} else {
this.toggleProviderContent(false);
} }
}) },
},
toggleProviderContent: function( isEnabled ) { toggleProviderContent: function (isEnabled) {
// On request failure hide provider panel and show error message. // On request failure hide provider panel and show error message.
$( '.provider-panel' ).toggleClass('hide', !isEnabled); $('.provider-panel').toggleClass('hide', !isEnabled);
$( '.error-message').toggleClass('hide', isEnabled ); $('.error-message').toggleClass('hide', isEnabled);
}
} }
}); );
}); }
);
define([
'jquery',
'underscore',
'backbone'
],
function ($, _, Backbone) {
return Backbone.View.extend({
initialize: function () {
this.checkEligibility();
},
checkEligibility: function () {
var $courseDetails = $('#course-name'),
username = $courseDetails.data('username'),
courseKey = $courseDetails.data('course_key'),
self = this;
this.collection.setUrl(username, courseKey);
this.collection.fetch({
success: function (collection) {
self.renderEligibilityDate(collection);
},
error: function () {
self.toggleProviderContent(false);
}
}
);
},
renderEligibilityDate: function (collection) {
// For getting full month name, default lang is set to 'en-us',
// It will be translated in django template
var eligibilityData = collection.toJSON(),
deadline, formattedDate;
if (eligibilityData.length) {
deadline = new Date(eligibilityData[0]['deadline']);
formattedDate = deadline.toLocaleString('en-us', {month: 'long'}) + ' ' + deadline.getDay() + ',' + deadline.getFullYear();
$('.eligibility-details').find('.deadline-date').text(formattedDate);
this.toggleProviderContent(true);
} else {
this.toggleProviderContent(false);
}
},
toggleProviderContent: function (isEnabled) {
// On request failure hide provider panel and show error message.
$('.provider-panel').toggleClass('hide', !isEnabled);
$('.error-message').toggleClass('hide', isEnabled);
}
}
);
}
);
...@@ -9,42 +9,34 @@ ...@@ -9,42 +9,34 @@
.credit-checkout { .credit-checkout {
padding-bottom: 30px; padding-bottom: 30px;
.header-title {
padding-left: 20px;
}
.title { .title {
color: $text-color; color: $text-color;
margin: 0;
margin-bottom: 20px;
span.course-title { span.course-title {
color: $brand-primary; color: $brand-primary;
} }
} }
.course-details .course-image, .advatanges-panel .course-image,
.provider-details .provider-image { .provider-details .provider-image {
width: 200px; width: 200px;
} }
.course-details, .advatanges-panel,
.provider-details { .provider-details {
padding: 20px 0; padding: 20px 0;
} }
.provider-details { .provider-details {
border-bottom: 1px solid $gray-light;
.show-instructions { .show-instructions {
padding-left: initial; padding-left: initial;
} }
} }
.eligibility-details { .eligibility-details {
border-bottom: 1px solid $gray-light; margin-bottom: 20px;
margin-bottom: 20px;
.date {
margin-bottom: 20px;
}
} }
.total-price { .total-price {
...@@ -56,34 +48,58 @@ ...@@ -56,34 +48,58 @@
margin-top: 20px; margin-top: 20px;
.payment-button { .payment-button {
width: 100%; background-color: $brand-success;
border-color: $brand-success;
} }
} }
.course-details { div.advantages p {
.row { color: $gray;
overflow: hidden; }
}
.advatanges-panel {
background-color: $gray-lighter;
.row {
.col-md-4 {
.advantages { .advantages {
background-color: white; background-color: white;
padding: 10px 15px; padding: 10px 15px;
margin-bottom: -1000px; margin-bottom: 15px;
padding-bottom: 1000px;
} }
} }
} }
}
div.advantages p { .course-details {
color: $gray; border-bottom: 1px solid $gray-light;
} }
.payment-button {
width: 100%;
margin-bottom: 2px;
}
.cap-image {
max-width: 20px;
margin-bottom: 5px;
} }
/* Small devices (tablets, 768px and up) */ /* Small devices (tablets, 768px and up) */
@media (min-width: $grid-float-breakpoint-max) { @media (min-width: $screen-sm-min) {
.payment-button {
width: 49%;
}
.checkout-controls { .course-details {
float: right; border-bottom: none;
.col-xs-6 { }
width: initial;
} }
/* Medium devices (desktops, 992px and up) */
@media (min-width: $screen-md-min) {
.payment-button {
width: auto;
} }
} }
<div class="col-sm-2 hidden-xs">
<img alt="<%= display_name %>" class="img-responsive provider-image" src="<%= thumbnail_url %>">
</div>
<div class="col-sm-10">
<h3 class="title"><%= gettext('About Credit at ') %> <%= id %> </h3>
<p><%= gettext( description ) %></p>
<button class="btn btn-link show-instructions" data-toggle="collapse" data-target="#fulfillment-instructions"><%=
gettext( "How does credit works?" ) %>
</button>
<div class="collapse" id="fulfillment-instructions">
<h4 class="text-uppercase"><%= gettext('credit with ') %><%= display_name %> </h4>
<%= fulfillment_instructions %>
</div>
</div>
...@@ -6,42 +6,22 @@ ...@@ -6,42 +6,22 @@
{% block content %} {% block content %}
<div class="container credit-checkout"> <div class="container credit-checkout">
<div class="course-details well"> <div class="row center-block course-details">
<div class="row center-block "> <div class="col-sm-11">
<h4 class="header-title title"> <h3 class="title">
{% blocktrans count hours=credit_seats.0.attr.credit_hours %} {% blocktrans with provider='<span class="provider-name"></span>' count hours=credit_seats.0.attr.credit_hours %}
You are purchasing 1 credit hour for: Purchase 1 credit from {{ provider }} for:
{% plural %} {% plural %}
You are purchasing {{ hours }} credit hours for: Purchase {{ hours }} credits from {{ provider }} for:
{% endblocktrans %} {% endblocktrans %}
<span id="course-name" data-course_key="{{ course }}" data-username="{{ request.user }}" <span id="course-name" data-course_key="{{ course }}" data-username="{{ request.user }}"
class="course-title text-nowrap">{{ course.name }}</span> class="course-title text-nowrap">{{ course.name }}</span>
</h4> </h3>
<div class="col-sm-4"> </div>
<div class="advantages"> <div class="col-sm-1 price text-right">
<strong>{% trans "You deserved it." %}</strong> <strong>${{ credit_seats.0.stockrecords.first.price_excl_tax }}</strong>
<p>
{% trans "The hard work is over; you passed the course. Now get the credit you deserve to start or complete a degree." %}
</p>
</div>
</div>
<div class="col-sm-4">
<div class="advantages">
<strong>{% trans "It's affordable." %}</strong>
<p>
{% trans "The credit offered on edX is generally lower than for-credit courses on campus." %}
</p>
</div>
</div>
<div class="col-sm-4">
<div class="advantages">
<strong>{% trans "It opens doors." %}</strong>
<p>
{% trans "It is estimated that most job openings by 2018 will require a college degree. Start your path to success." %}
</p>
</div>
</div>
</div> </div>
</div> </div>
<div class="provider-container"> <div class="provider-container">
<div class="alert alert-danger error-message hide" role="alert"> <div class="alert alert-danger error-message hide" role="alert">
...@@ -52,26 +32,14 @@ ...@@ -52,26 +32,14 @@
{# data will be loaded with underscore template #} {# data will be loaded with underscore template #}
</div> </div>
<div class="row center-block eligibility-details">
<div class="col-sm-3"></div>
<div class="col-sm-9 date">
{# date will be added with ajax call #}
{% blocktrans with date='<span class="deadline-date"></span>' %}
Credit eligibility expires on {{ date }}
{% endblocktrans %}
<span class="price pull-right">
{% trans "Price" %}: ${{ credit_seats.0.stockrecords.first.price_excl_tax }}
</span>
</div>
</div>
<div class="row center-block text-right total-price"> <div class="row center-block text-right total-price">
<div class="col-sm-12">{% trans "Total:" %} ${{ credit_seats.0.stockrecords.first.price_excl_tax }}</div> <div class="col-sm-12">{% trans "Total:" %}
${{ credit_seats.0.stockrecords.first.price_excl_tax }}</div>
</div> </div>
<div id="payment-buttons" class="row center-block checkout-controls"> <div id="payment-buttons" class="row checkout-controls center-block text-right">
{% for processor_name, button_text in payment_processors.items %} <div class="col-sm-12">
<div class="col-xs-6 "> {% for processor_name, button_text in payment_processors.items %}
<button data-track-type="click" <button data-track-type="click"
data-track-event="edx.bi.ecommerce.credit.payment_selected" data-track-event="edx.bi.ecommerce.credit.payment_selected"
data-track-category="{{ processor_name }}" data-track-category="{{ processor_name }}"
...@@ -79,23 +47,79 @@ ...@@ -79,23 +47,79 @@
data-sku="{{ credit_seats.0.stockrecords.first.partner_sku }}" data-sku="{{ credit_seats.0.stockrecords.first.partner_sku }}"
data-course-id="{{ course.id }}" data-course-id="{{ course.id }}"
class="btn btn-primary payment-button" class="btn btn-primary payment-button"
> >
{{ button_text }} {{ button_text }}
</button> </button>
</div> {% endfor %}
{% endfor %} </div>
</div>
<div class="row center-block eligibility-details text-right">
<div class="col-sm-12">
{# date will be added with ajax call #}
<small>
{% blocktrans with date='<span class="deadline-date"></span>' %}
Credit eligibility expires on {{ date }}
{% endblocktrans %}
</small>
</div>
</div>
</div>
</div>
<div class="advatanges-panel well">
<div class="row center-block">
<div class="col-md-12">
<img class="cap-image" src="{% static "images/cap.png" %}" alt=""/>
<strong>Earn Academic Credit for Your Accomplishments</strong>
</div>
</div>
<div class="row center-block ">
<div class="col-md-4">
<div class="advantages">
<strong>{% trans "You deserved it." %}</strong>
<p>
{% trans "The hard work is over - you passed the course! Now get the credit you deserve to start or complete a degree." %}
</p>
</div>
</div>
<div class="col-md-4">
<div class="advantages">
<strong>{% trans "It's affordable." %}</strong>
<p>
{% trans "The credit offered through edX generally costs less than the same credit at most institutions." %}
</p>
</div>
</div>
<div class="col-md-4">
<div class="advantages">
<strong>{% trans "It opens doors." %}</strong>
<p>
{% trans "Many of today's most in-demand jobs require a college degree. Start your path to success!" %}
</p>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="row center-block">
<strong>{% trans "Questions?" %}</strong>
</div>
<div class="row center-block">
{% blocktrans with link='<a href="https://www.edx.org/gfa">our FAQs to view common quistions about our certificates.</a>' %}
Please read {{ link }}
{% endblocktrans %}
</div>
</div> </div>
<form id="payment-processor-form"> <form id="payment-processor-form">
</form> </form>
<script type="text/template" id="provider-details-tpl">
{% include "edx/credit/provider-details.underscore" %}
</script>
<script> <script>
var lmsRootUrl = "{{ lms_url_root }}"; var lmsRootUrl = "{{ lms_url_root }}";
</script> </script>
......
<div class="col-sm-3 hidden-xs">
<img alt="<%- display_name %>" class="provider-image" src="">
</div>
<div class="col-sm-9">
<h3 class="title"><%- display_name %></h3>
<p><%- gettext( description ) %></p>
<button class="btn btn-link show-instructions" data-toggle="collapse" data-target="#fulfillment-instructions"><%= gettext( "How does it works?" ) %></button>
<div class="collapse" id="fulfillment-instructions">
<h4 class="text-uppercase"><%= gettext('how credit works with ') %><%- display_name %> </h4>
<%= fulfillment_instructions %>
</div>
</div>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment