Commit 131cc0bd by Matthew Piatetsky Committed by Renzo Lucioni

Remove old program detail page and Waffle switch gating the new page

The new page is released and stable. The switch and old code are no longer necessary.

ECOM-7482
parent 21a5a425
"""Learner dashboard views""" """Learner dashboard views"""
import waffle
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import Http404 from django.http import Http404
...@@ -67,6 +66,7 @@ def program_details(request, program_uuid): ...@@ -67,6 +66,7 @@ def program_details(request, program_uuid):
'commerce_api_url': reverse('commerce_api:v0:baskets:create'), 'commerce_api_url': reverse('commerce_api:v0:baskets:create'),
} }
# TODO: Tighten this up!
context = { context = {
'urls': urls, 'urls': urls,
'show_program_listing': programs_config.enabled, 'show_program_listing': programs_config.enabled,
...@@ -76,20 +76,15 @@ def program_details(request, program_uuid): ...@@ -76,20 +76,15 @@ def program_details(request, program_uuid):
'user_preferences': get_user_preferences(request.user) 'user_preferences': get_user_preferences(request.user)
} }
if waffle.switch_is_active('new_program_progress'): course_data = meter.progress(programs=[program_data], count_only=False)[0]
course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data)
certificate_data = get_certificates(request.user, program_data)
program_data.pop('courses') program_data.pop('courses')
context.update({ context.update({
'program_data': program_data, 'program_data': program_data,
'course_data': course_data, 'course_data': course_data,
'certificate_data': certificate_data, 'certificate_data': certificate_data,
}) })
return render_to_response('learner_dashboard/program_details_2017.html', context) return render_to_response('learner_dashboard/program_details.html', context)
else:
context.update({'program_data': program_data})
return render_to_response('learner_dashboard/program_details.html', context)
...@@ -42,22 +42,12 @@ ...@@ -42,22 +42,12 @@
getUnselectedCourseRun: function(courseRuns) { getUnselectedCourseRun: function(courseRuns) {
var unselectedRun = {}, var unselectedRun = {},
courseRun, courseRun;
courseImageUrl;
if (courseRuns && courseRuns.length > 0) { if (courseRuns && courseRuns.length > 0) {
courseRun = courseRuns[0]; courseRun = courseRuns[0];
if (courseRun.image && courseRun.image.src) {
courseImageUrl = courseRun.image.src;
} else {
// The course_image_url property is attached by setActiveCourseRun.
// If that hasn't been called, it won't be present yet.
courseImageUrl = courseRun.course_image_url;
}
$.extend(unselectedRun, { $.extend(unselectedRun, {
course_image_url: courseImageUrl,
marketing_url: courseRun.marketing_url, marketing_url: courseRun.marketing_url,
is_enrollment_open: courseRun.is_enrollment_open is_enrollment_open: courseRun.is_enrollment_open
}); });
...@@ -149,8 +139,8 @@ ...@@ -149,8 +139,8 @@
formatDateString: function(run) { formatDateString: function(run) {
var pacingType = run.pacing_type, var pacingType = run.pacing_type,
dateString = '', dateString = '',
start = run.start_date || this.get('start_date'), start = this.get('start_date') || run.start_date,
end = run.end_date || this.get('end_date'), end = this.get('end_date') || run.end_date,
now = new Date(), now = new Date(),
startDate = new Date(start), startDate = new Date(start),
endDate = new Date(end); endDate = new Date(end);
...@@ -181,8 +171,7 @@ ...@@ -181,8 +171,7 @@
}, },
setActiveCourseRun: function(courseRun, userPreferences) { setActiveCourseRun: function(courseRun, userPreferences) {
var startDateString, var startDateString;
courseImageUrl;
if (courseRun) { if (courseRun) {
if (this.valueIsDefined(courseRun.advertised_start)) { if (this.valueIsDefined(courseRun.advertised_start)) {
...@@ -191,16 +180,8 @@ ...@@ -191,16 +180,8 @@
startDateString = this.formatDate(courseRun.start, userPreferences); startDateString = this.formatDate(courseRun.start, userPreferences);
} }
if (courseRun.image && courseRun.image.src) {
courseImageUrl = courseRun.image.src;
} else {
courseImageUrl = courseRun.course_image_url;
}
this.set({ this.set({
certificate_url: courseRun.certificate_url, certificate_url: courseRun.certificate_url,
course_image_url: courseImageUrl || '',
course_run_key: courseRun.key, course_run_key: courseRun.key,
course_url: courseRun.course_url || '', course_url: courseRun.course_url || '',
title: this.context.title, title: this.context.title,
......
(function(define) {
'use strict';
define([
'js/learner_dashboard/views/program_details_view_2017'
],
function(ProgramDetailsView) {
return function(options) {
var ProgramDetails = new ProgramDetailsView(options);
return ProgramDetails;
};
});
}).call(this, define || RequireJS.define);
(function(define) { (function(define) {
'use strict'; 'use strict';
define(['backbone', define(['backbone',
'jquery', 'jquery',
'underscore', 'underscore',
'gettext', 'gettext',
'edx-ui-toolkit/js/utils/html-utils', 'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/certificate_status.underscore', 'text!../../../templates/learner_dashboard/certificate_status.underscore',
'text!../../../templates/learner_dashboard/certificate_icon.underscore' 'text!../../../templates/learner_dashboard/certificate_icon.underscore'
], ],
function( function(
Backbone, Backbone,
$, $,
......
(function(define) {
'use strict';
define(['backbone',
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/certificate_status_2017.underscore',
'text!../../../templates/learner_dashboard/certificate_icon.underscore'
],
function(
Backbone,
$,
_,
gettext,
HtmlUtils,
certificateStatusTpl,
certificateIconTpl
) {
return Backbone.View.extend({
statusTpl: HtmlUtils.template(certificateStatusTpl),
iconTpl: HtmlUtils.template(certificateIconTpl),
initialize: function(options) {
this.$el = options.$el;
this.render();
},
render: function() {
var data = this.model.toJSON();
data = $.extend(data, {certificateSvg: this.iconTpl()});
HtmlUtils.setHtml(this.$el, this.statusTpl(data));
}
});
}
);
}).call(this, define || RequireJS.define);
...@@ -2,16 +2,17 @@ ...@@ -2,16 +2,17 @@
'use strict'; 'use strict';
define(['backbone', define(['backbone',
'jquery', 'jquery',
'underscore', 'underscore',
'gettext', 'gettext',
'edx-ui-toolkit/js/utils/html-utils', 'edx-ui-toolkit/js/utils/html-utils',
'js/learner_dashboard/models/course_enroll_model', 'js/learner_dashboard/models/course_enroll_model',
'js/learner_dashboard/views/upgrade_message_view', 'js/learner_dashboard/views/upgrade_message_view',
'js/learner_dashboard/views/certificate_status_view', 'js/learner_dashboard/views/certificate_status_view',
'js/learner_dashboard/views/course_enroll_view', 'js/learner_dashboard/views/expired_notification_view',
'text!../../../templates/learner_dashboard/course_card.underscore' 'js/learner_dashboard/views/course_enroll_view',
], 'text!../../../templates/learner_dashboard/course_card.underscore'
],
function( function(
Backbone, Backbone,
$, $,
...@@ -21,33 +22,39 @@ ...@@ -21,33 +22,39 @@
EnrollModel, EnrollModel,
UpgradeMessageView, UpgradeMessageView,
CertificateStatusView, CertificateStatusView,
ExpiredNotificationView,
CourseEnrollView, CourseEnrollView,
pageTpl pageTpl
) { ) {
return Backbone.View.extend({ return Backbone.View.extend({
className: 'course-card card', className: 'program-course-card',
tpl: HtmlUtils.template(pageTpl), tpl: HtmlUtils.template(pageTpl),
initialize: function(options) { initialize: function(options) {
this.enrollModel = new EnrollModel(); this.enrollModel = new EnrollModel();
if (options.context && options.context.urls) { if (options.context) {
this.urlModel = new Backbone.Model(options.context.urls); this.urlModel = new Backbone.Model(options.context.urls);
this.enrollModel.urlRoot = this.urlModel.get('commerce_api_url'); this.enrollModel.urlRoot = this.urlModel.get('commerce_api_url');
} }
this.context = options.context || {};
this.render(); this.render();
this.listenTo(this.model, 'change', this.render); this.listenTo(this.model, 'change', this.render);
}, },
render: function() { render: function() {
var filledTemplate = this.tpl(this.model.toJSON()); var data = $.extend(this.model.toJSON(), {
HtmlUtils.setHtml(this.$el, filledTemplate); enrolled: this.context.enrolled || ''
});
HtmlUtils.setHtml(this.$el, this.tpl(data));
this.postRender(); this.postRender();
}, },
postRender: function() { postRender: function() {
var $upgradeMessage = this.$('.upgrade-message'), var $upgradeMessage = this.$('.upgrade-message'),
$certStatus = this.$('.certificate-status'); $certStatus = this.$('.certificate-status'),
$expiredNotification = this.$('.expired-notification'),
expired = this.model.get('expired');
this.enrollView = new CourseEnrollView({ this.enrollView = new CourseEnrollView({
$parentEl: this.$('.course-actions'), $parentEl: this.$('.course-actions'),
...@@ -56,14 +63,14 @@ ...@@ -56,14 +63,14 @@
enrollModel: this.enrollModel enrollModel: this.enrollModel
}); });
if (this.model.get('upgrade_url')) { if (this.model.get('upgrade_url') && !(expired === true)) {
this.upgradeMessage = new UpgradeMessageView({ this.upgradeMessage = new UpgradeMessageView({
$el: $upgradeMessage, $el: $upgradeMessage,
model: this.model model: this.model
}); });
$certStatus.remove(); $certStatus.remove();
} else if (this.model.get('certificate_url')) { } else if (this.model.get('certificate_url') && !(expired === true)) {
this.certificateStatus = new CertificateStatusView({ this.certificateStatus = new CertificateStatusView({
$el: $certStatus, $el: $certStatus,
model: this.model model: this.model
...@@ -75,6 +82,13 @@ ...@@ -75,6 +82,13 @@
$upgradeMessage.remove(); $upgradeMessage.remove();
$certStatus.remove(); $certStatus.remove();
} }
if (expired) {
this.expiredNotification = new ExpiredNotificationView({
$el: $expiredNotification,
model: this.model
});
}
} }
}); });
} }
......
(function(define) {
'use strict';
define(['backbone',
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'js/learner_dashboard/models/course_enroll_model',
'js/learner_dashboard/views/upgrade_message_view_2017',
'js/learner_dashboard/views/certificate_status_view_2017',
'js/learner_dashboard/views/expired_notification_view',
'js/learner_dashboard/views/course_enroll_view_2017',
'text!../../../templates/learner_dashboard/course_card_2017.underscore'
],
function(
Backbone,
$,
_,
gettext,
HtmlUtils,
EnrollModel,
UpgradeMessageView,
CertificateStatusView,
ExpiredNotificationView,
CourseEnrollView,
pageTpl
) {
return Backbone.View.extend({
className: 'program-course-card',
tpl: HtmlUtils.template(pageTpl),
initialize: function(options) {
this.enrollModel = new EnrollModel();
if (options.context) {
this.urlModel = new Backbone.Model(options.context.urls);
this.enrollModel.urlRoot = this.urlModel.get('commerce_api_url');
}
this.context = options.context || {};
this.render();
this.listenTo(this.model, 'change', this.render);
},
render: function() {
var data = $.extend(this.model.toJSON(), {
enrolled: this.context.enrolled || ''
});
HtmlUtils.setHtml(this.$el, this.tpl(data));
this.postRender();
},
postRender: function() {
var $upgradeMessage = this.$('.upgrade-message'),
$certStatus = this.$('.certificate-status'),
$expiredNotification = this.$('.expired-notification'),
expired = this.model.get('expired');
this.enrollView = new CourseEnrollView({
$parentEl: this.$('.course-actions'),
model: this.model,
urlModel: this.urlModel,
enrollModel: this.enrollModel
});
if (this.model.get('upgrade_url') && !(expired === true)) {
this.upgradeMessage = new UpgradeMessageView({
$el: $upgradeMessage,
model: this.model
});
$certStatus.remove();
} else if (this.model.get('certificate_url') && !(expired === true)) {
this.certificateStatus = new CertificateStatusView({
$el: $certStatus,
model: this.model
});
$upgradeMessage.remove();
} else {
// Styles are applied to these elements which will be visible if they're empty.
$upgradeMessage.remove();
$certStatus.remove();
}
if (expired) {
this.expiredNotification = new ExpiredNotificationView({
$el: $expiredNotification,
model: this.model
});
}
}
});
}
);
}).call(this, define || RequireJS.define);
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
'use strict'; 'use strict';
define(['backbone', define(['backbone',
'jquery', 'jquery',
'underscore', 'underscore',
'gettext', 'gettext',
'edx-ui-toolkit/js/utils/html-utils', 'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/course_enroll.underscore' 'text!../../../templates/learner_dashboard/course_enroll.underscore'
], ],
function( function(
Backbone, Backbone,
$, $,
...@@ -17,11 +17,12 @@ ...@@ -17,11 +17,12 @@
pageTpl pageTpl
) { ) {
return Backbone.View.extend({ return Backbone.View.extend({
className: 'course-enroll-view',
tpl: HtmlUtils.template(pageTpl), tpl: HtmlUtils.template(pageTpl),
events: { events: {
'click .enroll-button': 'handleEnroll', 'click .enroll-button': 'handleEnroll'
'change .run-select': 'handleCourseRunSelect'
}, },
initialize: function(options) { initialize: function(options) {
...@@ -29,9 +30,6 @@ ...@@ -29,9 +30,6 @@
this.enrollModel = options.enrollModel; this.enrollModel = options.enrollModel;
this.urlModel = options.urlModel; this.urlModel = options.urlModel;
this.render(); this.render();
if (this.urlModel) {
this.trackSelectionUrl = this.urlModel.get('track_selection_url');
}
}, },
render: function() { render: function() {
...@@ -41,16 +39,23 @@ ...@@ -41,16 +39,23 @@
HtmlUtils.setHtml(this.$el, filledTemplate); HtmlUtils.setHtml(this.$el, filledTemplate);
HtmlUtils.setHtml(this.$parentEl, HtmlUtils.HTML(this.$el)); HtmlUtils.setHtml(this.$parentEl, HtmlUtils.HTML(this.$el));
} }
this.postRender();
},
postRender: function() {
if (this.urlModel) {
this.trackSelectionUrl = this.urlModel.get('track_selection_url');
}
}, },
handleEnroll: function() { handleEnroll: function() {
// Enrollment click event handled here // Enrollment click event handled here
if (!this.model.get('course_run_key')) { var courseRunKey = $('.run-select').val() || this.model.get('course_run_key');
this.$('.select-error').css('visibility', 'visible'); this.model.updateCourseRun(courseRunKey);
} else if (!this.model.get('is_enrolled')) { if (!this.model.get('is_enrolled')) {
// Create the enrollment. // Create the enrollment.
this.enrollModel.save({ this.enrollModel.save({
course_id: this.model.get('course_run_key') course_id: courseRunKey
}, { }, {
success: _.bind(this.enrollSuccess, this), success: _.bind(this.enrollSuccess, this),
error: _.bind(this.enrollError, this) error: _.bind(this.enrollError, this)
...@@ -58,19 +63,9 @@ ...@@ -58,19 +63,9 @@
} }
}, },
handleCourseRunSelect: function(event) {
var courseRunKey = $(event.target).val();
if (courseRunKey) {
this.model.updateCourseRun(courseRunKey);
} else {
// Set back the unselected states
this.model.setUnselected();
}
},
enrollSuccess: function() { enrollSuccess: function() {
var courseRunKey = this.model.get('course_run_key'); var courseRunKey = this.model.get('course_run_key');
window.analytics.track('edx.bi.user.program-details.enrollment');
if (this.trackSelectionUrl) { if (this.trackSelectionUrl) {
// Go to track selection page // Go to track selection page
this.redirect(this.trackSelectionUrl + courseRunKey); this.redirect(this.trackSelectionUrl + courseRunKey);
......
(function(define) {
'use strict';
define(['backbone',
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/course_enroll_2017.underscore'
],
function(
Backbone,
$,
_,
gettext,
HtmlUtils,
pageTpl
) {
return Backbone.View.extend({
className: 'course-enroll-view',
tpl: HtmlUtils.template(pageTpl),
events: {
'click .enroll-button': 'handleEnroll'
},
initialize: function(options) {
this.$parentEl = options.$parentEl;
this.enrollModel = options.enrollModel;
this.urlModel = options.urlModel;
this.render();
},
render: function() {
var filledTemplate;
if (this.$parentEl && this.enrollModel) {
filledTemplate = this.tpl(this.model.toJSON());
HtmlUtils.setHtml(this.$el, filledTemplate);
HtmlUtils.setHtml(this.$parentEl, HtmlUtils.HTML(this.$el));
}
this.postRender();
},
postRender: function() {
if (this.urlModel) {
this.trackSelectionUrl = this.urlModel.get('track_selection_url');
}
},
handleEnroll: function() {
// Enrollment click event handled here
var courseRunKey = $('.run-select').val() || this.model.get('course_run_key');
this.model.updateCourseRun(courseRunKey);
if (!this.model.get('is_enrolled')) {
// Create the enrollment.
this.enrollModel.save({
course_id: courseRunKey
}, {
success: _.bind(this.enrollSuccess, this),
error: _.bind(this.enrollError, this)
});
}
},
enrollSuccess: function() {
var courseRunKey = this.model.get('course_run_key');
window.analytics.track('edx.bi.user.program-details.enrollment');
if (this.trackSelectionUrl) {
// Go to track selection page
this.redirect(this.trackSelectionUrl + courseRunKey);
} else {
this.model.set({
is_enrolled: true
});
}
},
enrollError: function(model, response) {
if (response.status === 403 && response.responseJSON.user_message_url) {
/**
* Check if we've been blocked from the course
* because of country access rules.
* If so, redirect to a page explaining to the user
* why they were blocked.
*/
this.redirect(response.responseJSON.user_message_url);
} else if (this.trackSelectionUrl) {
/**
* Otherwise, go to the track selection page as usual.
* This can occur, for example, when a course does not
* have a free enrollment mode, so we can't auto-enroll.
*/
this.redirect(this.trackSelectionUrl + this.model.get('course_run_key'));
}
},
redirect: function(url) {
window.location.href = url;
}
});
}
);
}).call(this, define || RequireJS.define);
(function(define) { (function(define) {
'use strict'; 'use strict';
define(['backbone', define(['backbone',
'jquery', 'jquery',
'underscore', 'underscore',
'gettext', 'gettext',
'edx-ui-toolkit/js/utils/html-utils', 'edx-ui-toolkit/js/utils/html-utils',
'js/learner_dashboard/collections/course_card_collection', 'js/learner_dashboard/collections/course_card_collection',
'js/learner_dashboard/views/program_header_view', 'js/learner_dashboard/views/program_header_view',
'js/learner_dashboard/views/collection_list_view', 'js/learner_dashboard/views/collection_list_view',
'js/learner_dashboard/views/course_card_view', 'js/learner_dashboard/views/course_card_view',
'text!../../../templates/learner_dashboard/program_details_view.underscore' 'js/learner_dashboard/views/program_details_sidebar_view',
], 'text!../../../templates/learner_dashboard/program_details_view.underscore'
],
function( function(
Backbone, Backbone,
$, $,
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
HeaderView, HeaderView,
CollectionListView, CollectionListView,
CourseCardView, CourseCardView,
SidebarView,
pageTpl pageTpl
) { ) {
return Backbone.View.extend({ return Backbone.View.extend({
...@@ -32,15 +33,37 @@ ...@@ -32,15 +33,37 @@
initialize: function(options) { initialize: function(options) {
this.options = options; this.options = options;
this.programModel = new Backbone.Model(this.options.programData); this.programModel = new Backbone.Model(this.options.programData);
this.courseCardCollection = new CourseCardCollection( this.courseData = new Backbone.Model(this.options.courseData);
this.programModel.get('courses'), this.certificateCollection = new Backbone.Collection(this.options.certificateData);
this.completedCourseCollection = new CourseCardCollection(
this.courseData.get('completed') || [],
this.options.userPreferences
);
this.inProgressCourseCollection = new CourseCardCollection(
this.courseData.get('in_progress') || [],
this.options.userPreferences
);
this.remainingCourseCollection = new CourseCardCollection(
this.courseData.get('not_started') || [],
this.options.userPreferences this.options.userPreferences
); );
this.render(); this.render();
}, },
render: function() { render: function() {
HtmlUtils.setHtml(this.$el, this.tpl()); var completedCount = this.completedCourseCollection.length,
inProgressCount = this.inProgressCourseCollection.length,
remainingCount = this.remainingCourseCollection.length,
totalCount = completedCount + inProgressCount + remainingCount,
data = {
totalCount: totalCount,
inProgressCount: inProgressCount,
remainingCount: remainingCount,
completedCount: completedCount
};
data = $.extend(data, this.programModel.toJSON());
HtmlUtils.setHtml(this.$el, this.tpl(data));
this.postRender(); this.postRender();
}, },
...@@ -48,16 +71,41 @@ ...@@ -48,16 +71,41 @@
this.headerView = new HeaderView({ this.headerView = new HeaderView({
model: new Backbone.Model(this.options) model: new Backbone.Model(this.options)
}); });
new CollectionListView({
el: '.js-course-list', if (this.remainingCourseCollection.length > 0) {
childView: CourseCardView, new CollectionListView({
collection: this.courseCardCollection, el: '.js-course-list-remaining',
context: this.options, childView: CourseCardView,
titleContext: { collection: this.remainingCourseCollection,
el: 'h2', context: this.options
title: 'Course List' }).render();
} }
}).render();
if (this.completedCourseCollection.length > 0) {
new CollectionListView({
el: '.js-course-list-completed',
childView: CourseCardView,
collection: this.completedCourseCollection,
context: this.options
}).render();
}
if (this.inProgressCourseCollection.length > 0) {
// This is last because the context is modified below
new CollectionListView({
el: '.js-course-list-in-progress',
childView: CourseCardView,
collection: this.inProgressCourseCollection,
context: $.extend(this.options, {enrolled: gettext('Enrolled')})
}).render();
}
this.sidebarView = new SidebarView({
el: '.js-program-sidebar',
model: this.programModel,
courseModel: this.courseData,
certificateCollection: this.certificateCollection
});
} }
}); });
} }
......
(function(define) {
'use strict';
define(['backbone',
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'js/learner_dashboard/collections/course_card_collection',
'js/learner_dashboard/views/program_header_view_2017',
'js/learner_dashboard/views/collection_list_view',
'js/learner_dashboard/views/course_card_view_2017',
'js/learner_dashboard/views/program_details_sidebar_view',
'text!../../../templates/learner_dashboard/program_details_view_2017.underscore'
],
function(
Backbone,
$,
_,
gettext,
HtmlUtils,
CourseCardCollection,
HeaderView,
CollectionListView,
CourseCardView,
SidebarView,
pageTpl
) {
return Backbone.View.extend({
el: '.js-program-details-wrapper',
tpl: HtmlUtils.template(pageTpl),
initialize: function(options) {
this.options = options;
this.programModel = new Backbone.Model(this.options.programData);
this.courseData = new Backbone.Model(this.options.courseData);
this.certificateCollection = new Backbone.Collection(this.options.certificateData);
this.completedCourseCollection = new CourseCardCollection(
this.courseData.get('completed') || [],
this.options.userPreferences
);
this.inProgressCourseCollection = new CourseCardCollection(
this.courseData.get('in_progress') || [],
this.options.userPreferences
);
this.remainingCourseCollection = new CourseCardCollection(
this.courseData.get('not_started') || [],
this.options.userPreferences
);
this.render();
},
render: function() {
var completedCount = this.completedCourseCollection.length,
inProgressCount = this.inProgressCourseCollection.length,
remainingCount = this.remainingCourseCollection.length,
totalCount = completedCount + inProgressCount + remainingCount,
data = {
totalCount: totalCount,
inProgressCount: inProgressCount,
remainingCount: remainingCount,
completedCount: completedCount
};
data = $.extend(data, this.programModel.toJSON());
HtmlUtils.setHtml(this.$el, this.tpl(data));
this.postRender();
},
postRender: function() {
this.headerView = new HeaderView({
model: new Backbone.Model(this.options)
});
if (this.remainingCourseCollection.length > 0) {
new CollectionListView({
el: '.js-course-list-remaining',
childView: CourseCardView,
collection: this.remainingCourseCollection,
context: this.options
}).render();
}
if (this.completedCourseCollection.length > 0) {
new CollectionListView({
el: '.js-course-list-completed',
childView: CourseCardView,
collection: this.completedCourseCollection,
context: this.options
}).render();
}
if (this.inProgressCourseCollection.length > 0) {
// This is last because the context is modified below
new CollectionListView({
el: '.js-course-list-in-progress',
childView: CourseCardView,
collection: this.inProgressCourseCollection,
context: $.extend(this.options, {enrolled: gettext('Enrolled')})
}).render();
}
this.sidebarView = new SidebarView({
el: '.js-program-sidebar',
model: this.programModel,
courseModel: this.courseData,
certificateCollection: this.certificateCollection
});
}
});
}
);
}).call(this, define || RequireJS.define);
...@@ -2,17 +2,20 @@ ...@@ -2,17 +2,20 @@
'use strict'; 'use strict';
define(['backbone', define(['backbone',
'jquery', 'jquery',
'edx-ui-toolkit/js/utils/html-utils', 'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/program_header_view.underscore', 'text!../../../templates/learner_dashboard/program_header_view.underscore',
'picturefill' 'text!../../../images/programs/micromasters-program-details.svg',
], 'text!../../../images/programs/xseries-program-details.svg',
function(Backbone, $, HtmlUtils, pageTpl, picturefill) { 'text!../../../images/programs/professional-certificate-program-details.svg'
],
function(Backbone, $, HtmlUtils, pageTpl, MicroMastersLogo,
XSeriesLogo, ProfessionalCertificateLogo) {
return Backbone.View.extend({ return Backbone.View.extend({
breakpoints: { breakpoints: {
min: { min: {
'medium': '768px', medium: '768px',
'large': '1180px' large: '1180px'
} }
}, },
...@@ -24,32 +27,29 @@ ...@@ -24,32 +27,29 @@
this.render(); this.render();
}, },
getLogo: function() {
var logo = false,
type = this.model.get('programData').type;
if (type === 'MicroMasters') {
logo = MicroMastersLogo;
} else if (type === 'XSeries') {
logo = XSeriesLogo;
} else if (type === 'Professional Certificate') {
logo = ProfessionalCertificateLogo;
}
return logo;
},
render: function() { render: function() {
var data = $.extend(this.model.toJSON(), { var data = $.extend(this.model.toJSON(), {
breakpoints: this.breakpoints breakpoints: this.breakpoints,
logo: this.getLogo()
}); });
if (this.model.get('programData')) { if (this.model.get('programData')) {
HtmlUtils.setHtml(this.$el, this.tpl(data)); HtmlUtils.setHtml(this.$el, this.tpl(data));
this.postRender();
}
},
postRender: function() {
// To resolve a bug in IE with picturefill reevaluate images
if (navigator.userAgent.indexOf('MSIE') !== -1 ||
navigator.appVersion.indexOf('Trident/') > 0) {
/* Microsoft Internet Explorer detected in. */
window.setTimeout(function() {
this.reEvaluatePicture();
}.bind(this), 100);
} }
},
reEvaluatePicture: function() {
picturefill({
reevaluate: true
});
} }
}); });
} }
......
(function(define) {
'use strict';
define(['backbone',
'jquery',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/program_header_view_2017.underscore',
'text!../../../images/programs/micromasters-program-details.svg',
'text!../../../images/programs/xseries-program-details.svg',
'text!../../../images/programs/professional-certificate-program-details.svg'
],
function(Backbone, $, HtmlUtils, pageTpl, MicroMastersLogo,
XSeriesLogo, ProfessionalCertificateLogo) {
return Backbone.View.extend({
breakpoints: {
min: {
medium: '768px',
large: '1180px'
}
},
el: '.js-program-header',
tpl: HtmlUtils.template(pageTpl),
initialize: function() {
this.render();
},
getLogo: function() {
var logo = false,
type = this.model.get('programData').type;
if (type === 'MicroMasters') {
logo = MicroMastersLogo;
} else if (type === 'XSeries') {
logo = XSeriesLogo;
} else if (type === 'Professional Certificate') {
logo = ProfessionalCertificateLogo;
}
return logo;
},
render: function() {
var data = $.extend(this.model.toJSON(), {
breakpoints: this.breakpoints,
logo: this.getLogo()
});
if (this.model.get('programData')) {
HtmlUtils.setHtml(this.$el, this.tpl(data));
}
}
});
}
);
}).call(this, define || RequireJS.define);
(function(define) { (function(define) {
'use strict'; 'use strict';
define(['backbone', define(['backbone',
'jquery', 'jquery',
'underscore', 'underscore',
'gettext', 'gettext',
'edx-ui-toolkit/js/utils/html-utils', 'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/upgrade_message.underscore', 'text!../../../templates/learner_dashboard/upgrade_message.underscore'
'text!../../../templates/learner_dashboard/certificate_icon.underscore' ],
],
function( function(
Backbone, Backbone,
$, $,
_, _,
gettext, gettext,
HtmlUtils, HtmlUtils,
upgradeMessageTpl, upgradeMessageTpl
certificateIconTpl
) { ) {
return Backbone.View.extend({ return Backbone.View.extend({
messageTpl: HtmlUtils.template(upgradeMessageTpl), messageTpl: HtmlUtils.template(upgradeMessageTpl),
iconTpl: HtmlUtils.template(certificateIconTpl),
initialize: function(options) { initialize: function(options) {
this.$el = options.$el; this.$el = options.$el;
...@@ -29,7 +26,6 @@ ...@@ -29,7 +26,6 @@
render: function() { render: function() {
var data = this.model.toJSON(); var data = this.model.toJSON();
data = $.extend(data, {certificateSvg: this.iconTpl()});
HtmlUtils.setHtml(this.$el, this.messageTpl(data)); HtmlUtils.setHtml(this.$el, this.messageTpl(data));
} }
}); });
......
(function(define) {
'use strict';
define(['backbone',
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/upgrade_message_2017.underscore'
],
function(
Backbone,
$,
_,
gettext,
HtmlUtils,
upgradeMessageTpl
) {
return Backbone.View.extend({
messageTpl: HtmlUtils.template(upgradeMessageTpl),
initialize: function(options) {
this.$el = options.$el;
this.render();
},
render: function() {
var data = this.model.toJSON();
HtmlUtils.setHtml(this.$el, this.messageTpl(data));
}
});
}
);
}).call(this, define || RequireJS.define);
...@@ -17,7 +17,7 @@ define([ ...@@ -17,7 +17,7 @@ define([
var programData = $.extend({}, data); var programData = $.extend({}, data);
programData.course_runs[0].is_enrolled = isEnrolled; programData.course_runs[0].is_enrolled = isEnrolled;
setFixtures('<div class="course-card card"></div>'); setFixtures('<div class="program-course-card"></div>');
courseCardModel = new CourseCardModel(programData); courseCardModel = new CourseCardModel(programData);
view = new CourseCardView({ view = new CourseCardView({
model: courseCardModel model: courseCardModel
...@@ -26,12 +26,10 @@ define([ ...@@ -26,12 +26,10 @@ define([
validateCourseInfoDisplay = function() { validateCourseInfoDisplay = function() {
// DRY validation for course card in enrolled state // DRY validation for course card in enrolled state
expect(view.$('.header-img').attr('src')).toEqual(course.course_runs[0].image.src);
expect(view.$('.course-details .course-title-link').text().trim()).toEqual(course.title); expect(view.$('.course-details .course-title-link').text().trim()).toEqual(course.title);
expect(view.$('.course-details .course-title-link').attr('href')).toEqual( expect(view.$('.course-details .course-title-link').attr('href')).toEqual(
course.course_runs[0].marketing_url course.course_runs[0].marketing_url
); );
expect(view.$('.course-details .course-text .course-key').html()).toEqual(course.key);
expect(view.$('.course-details .course-text .run-period').html()).toEqual( expect(view.$('.course-details .course-text .run-period').html()).toEqual(
startDate + ' - ' + endDate startDate + ' - ' + endDate
); );
...@@ -99,7 +97,9 @@ define([ ...@@ -99,7 +97,9 @@ define([
it('should show the course advertised start date', function() { it('should show the course advertised start date', function() {
var advertisedStart = 'A long time ago...'; var advertisedStart = 'A long time ago...';
course.course_runs[0].advertised_start = advertisedStart; course.course_runs[0].advertised_start = advertisedStart;
setupView(course, false); setupView(course, false);
expect(view.$('.course-details .course-text .run-period').html()).toEqual( expect(view.$('.course-details .course-text .run-period').html()).toEqual(
advertisedStart + ' - ' + endDate advertisedStart + ' - ' + endDate
); );
...@@ -108,13 +108,12 @@ define([ ...@@ -108,13 +108,12 @@ define([
it('should only show certificate status section if a certificate has been earned', function() { it('should only show certificate status section if a certificate has been earned', function() {
var certUrl = 'sample-certificate'; var certUrl = 'sample-certificate';
expect(view.$('.certificate-status').length).toEqual(0); expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
view.remove(); view.remove();
course.course_runs[0].certificate_url = certUrl; course.course_runs[0].certificate_url = certUrl;
setupView(course, false); setupView(course, false);
expect(view.$('.certificate-status').length).toEqual(1); expect(view.$('.course-certificate .certificate-status').length).toEqual(1);
expect(view.$('.certificate-status .cta-secondary').attr('href')).toEqual(certUrl);
}); });
it('should only show upgrade message section if an upgrade is required', function() { it('should only show upgrade message section if an upgrade is required', function() {
...@@ -135,7 +134,7 @@ define([ ...@@ -135,7 +134,7 @@ define([
course.course_runs[0].certificate_url = ''; course.course_runs[0].certificate_url = '';
setupView(course, false); setupView(course, false);
expect(view.$('.upgrade-message').length).toEqual(0); expect(view.$('.upgrade-message').length).toEqual(0);
expect(view.$('.certificate-status').length).toEqual(0); expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
view.remove(); view.remove();
// Verify that the upgrade message takes priority. // Verify that the upgrade message takes priority.
...@@ -143,7 +142,7 @@ define([ ...@@ -143,7 +142,7 @@ define([
course.course_runs[0].certificate_url = '/path/to/certificate'; course.course_runs[0].certificate_url = '/path/to/certificate';
setupView(course, false); setupView(course, false);
expect(view.$('.upgrade-message').length).toEqual(1); expect(view.$('.upgrade-message').length).toEqual(1);
expect(view.$('.certificate-status').length).toEqual(0); expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
}); });
it('should show a message if an there is an upcoming course run', function() { it('should show a message if an there is an upcoming course run', function() {
...@@ -151,9 +150,7 @@ define([ ...@@ -151,9 +150,7 @@ define([
setupView(course, false); setupView(course, false);
expect(view.$('.header-img').attr('src')).toEqual(course.course_runs[0].image.src);
expect(view.$('.course-details .course-title').text().trim()).toEqual(course.title); expect(view.$('.course-details .course-title').text().trim()).toEqual(course.title);
expect(view.$('.course-details .course-text .course-key').html()).toEqual(course.key);
expect(view.$('.course-details .course-text .run-period').length).toBe(0); expect(view.$('.course-details .course-text .run-period').length).toBe(0);
expect(view.$('.no-action-message').text().trim()).toBe('Coming Soon'); expect(view.$('.no-action-message').text().trim()).toBe('Coming Soon');
expect(view.$('.enrollment-open-date').text().trim()).toEqual( expect(view.$('.enrollment-open-date').text().trim()).toEqual(
...@@ -167,27 +164,21 @@ define([ ...@@ -167,27 +164,21 @@ define([
setupView(course, false); setupView(course, false);
expect(view.$('.header-img').attr('src')).toEqual(course.course_runs[0].image.src);
expect(view.$('.course-details .course-title').text().trim()).toEqual(course.title); expect(view.$('.course-details .course-title').text().trim()).toEqual(course.title);
expect(view.$('.course-details .course-text .course-key').html()).toEqual(course.key);
expect(view.$('.course-details .course-text .run-period').length).toBe(0); expect(view.$('.course-details .course-text .run-period').length).toBe(0);
expect(view.$('.no-action-message').text().trim()).toBe('Not Currently Available'); expect(view.$('.no-action-message').text().trim()).toBe('Not Currently Available');
expect(view.$('.enrollment-opens').length).toEqual(0); expect(view.$('.enrollment-opens').length).toEqual(0);
}); });
it('should link to the marketing site when a URL is available', function() { it('should link to the marketing site when a URL is available', function() {
$.each(['.course-image-link', '.course-title-link'], function(index, selector) { expect(view.$('.course-title-link').attr('href')).toEqual(course.course_runs[0].marketing_url);
expect(view.$(selector).attr('href')).toEqual(course.course_runs[0].marketing_url);
});
}); });
it('should link to the course home when no marketing URL is available', function() { it('should link to the course home when no marketing URL is available', function() {
course.course_runs[0].marketing_url = null; course.course_runs[0].marketing_url = null;
setupView(course, false); setupView(course, false);
$.each(['.course-image-link', '.course-title-link'], function(index, selector) { expect(view.$('.course-title-link').attr('href')).toEqual(course.course_runs[0].course_url);
expect(view.$(selector).attr('href')).toEqual(course.course_runs[0].course_url);
});
}); });
it('should not link to the marketing site or the course home if neither URL is available', function() { it('should not link to the marketing site or the course home if neither URL is available', function() {
...@@ -195,9 +186,7 @@ define([ ...@@ -195,9 +186,7 @@ define([
course.course_runs[0].course_url = null; course.course_runs[0].course_url = null;
setupView(course, false); setupView(course, false);
$.each(['.course-image-link', '.course-title-link'], function(index, selector) { expect(view.$('.course-title-link').length).toEqual(0);
expect(view.$(selector).length).toEqual(0);
});
}); });
}); });
} }
......
...@@ -33,6 +33,9 @@ define([ ...@@ -33,6 +33,9 @@ define([
}; };
beforeEach(function() { beforeEach(function() {
// Stub analytics tracking
window.analytics = jasmine.createSpyObj('analytics', ['track']);
// NOTE: This data is redefined prior to each test case so that tests // NOTE: This data is redefined prior to each test case so that tests
// can't break each other by modifying data copied by reference. // can't break each other by modifying data copied by reference.
singleCourseRunList = [{ singleCourseRunList = [{
...@@ -132,8 +135,6 @@ define([ ...@@ -132,8 +135,6 @@ define([
it('should render the course enroll view when not enrolled', function() { it('should render the course enroll view when not enrolled', function() {
setupView(singleCourseRunList); setupView(singleCourseRunList);
expect(view.$('.enrollment-info').html().trim()).toEqual('Not Enrolled');
expect(view.$('.enroll-button').text().trim()).toEqual('Enroll Now'); expect(view.$('.enroll-button').text().trim()).toEqual('Enroll Now');
expect(view.$('.run-select').length).toBe(0); expect(view.$('.run-select').length).toBe(0);
}); });
...@@ -142,24 +143,10 @@ define([ ...@@ -142,24 +143,10 @@ define([
singleCourseRunList[0].is_enrolled = true; singleCourseRunList[0].is_enrolled = true;
setupView(singleCourseRunList); setupView(singleCourseRunList);
expect(view.$('.view-course-button').text().trim()).toEqual('View Course');
expect(view.$('.enrollment-info').html().trim()).toEqual('enrolled');
expect(view.$('.view-course-link').attr('href')).toEqual(course.course_runs[0].course_url);
expect(view.$('.view-course-link').text().trim()).toEqual('View Course');
expect(view.$('.run-select').length).toBe(0); expect(view.$('.run-select').length).toBe(0);
}); });
it('should allow the learner to view an archived course', function() {
// Regression test for ECOM-4974.
singleCourseRunList[0].is_enrolled = true;
singleCourseRunList[0].is_enrollment_open = false;
singleCourseRunList[0].is_course_ended = true;
setupView(singleCourseRunList);
expect(view.$('.view-course-link').text().trim()).toEqual('View Archived Course');
});
it('should not render anything if course runs are empty', function() { it('should not render anything if course runs are empty', function() {
setupView([]); setupView([]);
...@@ -172,24 +159,8 @@ define([ ...@@ -172,24 +159,8 @@ define([
setupView(multiCourseRunList); setupView(multiCourseRunList);
expect(view.$('.run-select').length).toBe(1); expect(view.$('.run-select').length).toBe(1);
expect(view.$('.run-select').val()).toEqual(''); expect(view.$('.run-select').val()).toEqual(multiCourseRunList[0].key);
expect(view.$('.run-select option').length).toBe(3); expect(view.$('.run-select option').length).toBe(2);
});
it('should switch course run context if an option is selected from the dropdown', function() {
setupView(multiCourseRunList);
spyOn(courseCardModel, 'updateCourseRun').and.callThrough();
expect(view.$('.run-select').val()).toEqual('');
view.$('.run-select').val(multiCourseRunList[1].key);
view.$('.run-select').trigger('change');
expect(view.$('.run-select').val()).toEqual(multiCourseRunList[1].key);
expect(courseCardModel.updateCourseRun)
.toHaveBeenCalledWith(multiCourseRunList[1].key);
expect(courseCardModel.get('course_key')).toEqual(course.key);
}); });
it('should enroll learner when enroll button is clicked with one course run available', function() { it('should enroll learner when enroll button is clicked with one course run available', function() {
...@@ -304,6 +275,15 @@ define([ ...@@ -304,6 +275,15 @@ define([
response.responseJSON.user_message_url response.responseJSON.user_message_url
); );
}); });
it('sends analytics event when enrollment succeeds', function() {
setupView(singleCourseRunList, urls);
spyOn(view, 'redirect');
view.enrollSuccess();
expect(window.analytics.track).toHaveBeenCalledWith(
'edx.bi.user.program-details.enrollment'
);
});
}); });
} }
); );
define([
'backbone',
'jquery',
'js/learner_dashboard/models/course_card_model',
'js/learner_dashboard/models/course_enroll_model',
'js/learner_dashboard/views/course_enroll_view_2017'
], function(Backbone, $, CourseCardModel, CourseEnrollModel, CourseEnrollView) {
'use strict';
describe('Course Enroll View', function() {
var view = null,
courseCardModel,
courseEnrollModel,
urlModel,
setupView,
singleCourseRunList,
multiCourseRunList,
course = {
key: 'WageningenX+FFESx',
uuid: '9f8562eb-f99b-45c7-b437-799fd0c15b6a',
title: 'Systems thinking and environmental sustainability',
owners: [
{
uuid: '0c6e5fa2-96e8-40b2-9ebe-c8b0df2a3b22',
key: 'WageningenX',
name: 'Wageningen University & Research'
}
]
},
urls = {
commerce_api_url: '/commerce',
track_selection_url: '/select_track/course/'
};
beforeEach(function() {
// Stub analytics tracking
window.analytics = jasmine.createSpyObj('analytics', ['track']);
// NOTE: This data is redefined prior to each test case so that tests
// can't break each other by modifying data copied by reference.
singleCourseRunList = [{
key: 'course-v1:WageningenX+FFESx+1T2017',
uuid: '2f2edf03-79e6-4e39-aef0-65436a6ee344',
title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
image: {
src: 'https://example.com/2f2edf03-79e6-4e39-aef0-65436a6ee344.jpg'
},
marketing_url: 'https://www.edx.org/course/food-security-sustainability-systems-wageningenx-ffesx',
start: '2017-02-28T05:00:00Z',
end: '2017-05-30T23:00:00Z',
enrollment_start: '2017-01-18T00:00:00Z',
enrollment_end: null,
type: 'verified',
certificate_url: '',
course_url: 'https://courses.example.com/courses/course-v1:edX+DemoX+Demo_Course',
enrollment_open_date: 'Jan 18, 2016',
is_course_ended: false,
is_enrolled: false,
is_enrollment_open: true,
upgrade_url: ''
}];
multiCourseRunList = [{
key: 'course-v1:WageningenX+FFESx+2T2016',
uuid: '9bbb7844-4848-44ab-8e20-0be6604886e9',
title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
image: {
src: 'https://example.com/9bbb7844-4848-44ab-8e20-0be6604886e9.jpg'
},
short_description: 'Learn how to apply systems thinking to improve food production systems.',
marketing_url: 'https://www.edx.org/course/food-security-sustainability-systems-wageningenx-stesx',
start: '2016-09-08T04:00:00Z',
end: '2016-11-11T00:00:00Z',
enrollment_start: null,
enrollment_end: null,
pacing_type: 'instructor_paced',
type: 'verified',
certificate_url: '',
course_url: 'https://courses.example.com/courses/course-v1:WageningenX+FFESx+2T2016',
enrollment_open_date: 'Jan 18, 2016',
is_course_ended: false,
is_enrolled: false,
is_enrollment_open: true
}, {
key: 'course-v1:WageningenX+FFESx+1T2017',
uuid: '2f2edf03-79e6-4e39-aef0-65436a6ee344',
title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
image: {
src: 'https://example.com/2f2edf03-79e6-4e39-aef0-65436a6ee344.jpg'
},
marketing_url: 'https://www.edx.org/course/food-security-sustainability-systems-wageningenx-ffesx',
start: '2017-02-28T05:00:00Z',
end: '2017-05-30T23:00:00Z',
enrollment_start: '2017-01-18T00:00:00Z',
enrollment_end: null,
type: 'verified',
certificate_url: '',
course_url: 'https://courses.example.com/courses/course-v1:WageningenX+FFESx+1T2017',
enrollment_open_date: 'Jan 18, 2016',
is_course_ended: false,
is_enrolled: false,
is_enrollment_open: true
}];
});
setupView = function(courseRuns, urlMap) {
course.course_runs = courseRuns;
setFixtures('<div class="course-actions"></div>');
courseCardModel = new CourseCardModel(course);
courseEnrollModel = new CourseEnrollModel({}, {
courseId: courseCardModel.get('course_run_key')
});
if (urlMap) {
urlModel = new Backbone.Model(urlMap);
}
view = new CourseEnrollView({
$parentEl: $('.course-actions'),
model: courseCardModel,
enrollModel: courseEnrollModel,
urlModel: urlModel
});
};
afterEach(function() {
view.remove();
urlModel = null;
courseCardModel = null;
courseEnrollModel = null;
});
it('should exist', function() {
setupView(singleCourseRunList);
expect(view).toBeDefined();
});
it('should render the course enroll view when not enrolled', function() {
setupView(singleCourseRunList);
expect(view.$('.enroll-button').text().trim()).toEqual('Enroll Now');
expect(view.$('.run-select').length).toBe(0);
});
it('should render the course enroll view when enrolled', function() {
singleCourseRunList[0].is_enrolled = true;
setupView(singleCourseRunList);
expect(view.$('.view-course-button').text().trim()).toEqual('View Course');
expect(view.$('.run-select').length).toBe(0);
});
it('should not render anything if course runs are empty', function() {
setupView([]);
expect(view.$('.enrollment-info').length).toBe(0);
expect(view.$('.run-select').length).toBe(0);
expect(view.$('.enroll-button').length).toBe(0);
});
it('should render run selection dropdown if multiple course runs are available', function() {
setupView(multiCourseRunList);
expect(view.$('.run-select').length).toBe(1);
expect(view.$('.run-select').val()).toEqual(multiCourseRunList[0].key);
expect(view.$('.run-select option').length).toBe(2);
});
it('should enroll learner when enroll button is clicked with one course run available', function() {
setupView(singleCourseRunList);
expect(view.$('.enroll-button').length).toBe(1);
spyOn(courseEnrollModel, 'save');
view.$('.enroll-button').click();
expect(courseEnrollModel.save).toHaveBeenCalled();
});
it('should enroll learner when enroll button is clicked with multiple course runs available', function() {
setupView(multiCourseRunList);
spyOn(courseEnrollModel, 'save');
view.$('.run-select').val(multiCourseRunList[1].key);
view.$('.run-select').trigger('change');
view.$('.enroll-button').click();
expect(courseEnrollModel.save).toHaveBeenCalled();
});
it('should redirect to track selection when audit enrollment succeeds', function() {
singleCourseRunList[0].is_enrolled = false;
singleCourseRunList[0].mode_slug = 'audit';
setupView(singleCourseRunList, urls);
expect(view.$('.enroll-button').length).toBe(1);
expect(view.trackSelectionUrl).toBeDefined();
spyOn(view, 'redirect');
view.enrollSuccess();
expect(view.redirect).toHaveBeenCalledWith(
view.trackSelectionUrl + courseCardModel.get('course_run_key'));
});
it('should redirect to track selection when enrollment in an unspecified mode is attempted', function() {
singleCourseRunList[0].is_enrolled = false;
singleCourseRunList[0].mode_slug = null;
setupView(singleCourseRunList, urls);
expect(view.$('.enroll-button').length).toBe(1);
expect(view.trackSelectionUrl).toBeDefined();
spyOn(view, 'redirect');
view.enrollSuccess();
expect(view.redirect).toHaveBeenCalledWith(
view.trackSelectionUrl + courseCardModel.get('course_run_key')
);
});
it('should not redirect when urls are not provided', function() {
singleCourseRunList[0].is_enrolled = false;
singleCourseRunList[0].mode_slug = 'verified';
setupView(singleCourseRunList);
expect(view.$('.enroll-button').length).toBe(1);
expect(view.verificationUrl).not.toBeDefined();
expect(view.dashboardUrl).not.toBeDefined();
expect(view.trackSelectionUrl).not.toBeDefined();
spyOn(view, 'redirect');
view.enrollSuccess();
expect(view.redirect).not.toHaveBeenCalled();
});
it('should redirect to track selection on error', function() {
setupView(singleCourseRunList, urls);
expect(view.$('.enroll-button').length).toBe(1);
expect(view.trackSelectionUrl).toBeDefined();
spyOn(view, 'redirect');
view.enrollError(courseEnrollModel, {status: 500});
expect(view.redirect).toHaveBeenCalledWith(
view.trackSelectionUrl + courseCardModel.get('course_run_key')
);
});
it('should redirect to login on 403 error', function() {
var response = {
status: 403,
responseJSON: {
user_message_url: 'redirect/to/this'
}
};
setupView(singleCourseRunList, urls);
expect(view.$('.enroll-button').length).toBe(1);
expect(view.trackSelectionUrl).toBeDefined();
spyOn(view, 'redirect');
view.enrollError(courseEnrollModel, response);
expect(view.redirect).toHaveBeenCalledWith(
response.responseJSON.user_message_url
);
});
it('sends analytics event when enrollment succeeds', function() {
setupView(singleCourseRunList, urls);
spyOn(view, 'redirect');
view.enrollSuccess();
expect(window.analytics.track).toHaveBeenCalledWith(
'edx.bi.user.program-details.enrollment'
);
});
});
}
);
...@@ -8,9 +8,6 @@ define([ ...@@ -8,9 +8,6 @@ define([
describe('Program Details Header View', function() { describe('Program Details Header View', function() {
var view = null, var view = null,
context = { context = {
urls: {
program_listing_url: '/dashboard/programs'
},
programData: { programData: {
uuid: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8', uuid: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8',
title: 'Food Security and Sustainability', title: 'Food Security and Sustainability',
...@@ -68,16 +65,12 @@ define([ ...@@ -68,16 +65,12 @@ define([
}); });
it('should render the header based on the passed in model', function() { it('should render the header based on the passed in model', function() {
var programListUrl = view.$('.breadcrumb-list .crumb:nth-of-type(2) .crumb-link').attr('href'); expect(view.$('.program-title').html()).toEqual(context.programData.title);
expect(view.$('.title').html()).toEqual(context.programData.title);
expect(view.$('.subtitle').html()).toEqual(context.programData.subtitle);
expect(view.$('.org-logo').length).toEqual(context.programData.authoring_organizations.length); expect(view.$('.org-logo').length).toEqual(context.programData.authoring_organizations.length);
expect(view.$('.org-logo').attr('src')) expect(view.$('.org-logo').attr('src'))
.toEqual(context.programData.authoring_organizations[0].certificate_logo_image_url); .toEqual(context.programData.authoring_organizations[0].certificate_logo_image_url);
expect(view.$('.org-logo').attr('alt')) expect(view.$('.org-logo').attr('alt'))
.toEqual(context.programData.authoring_organizations[0].name + '\'s logo'); .toEqual(context.programData.authoring_organizations[0].name + '\'s logo');
expect(programListUrl).toEqual(context.urls.program_listing_url);
}); });
}); });
} }
......
define([ define([
'backbone', 'backbone',
'jquery', 'jquery',
'js/learner_dashboard/views/program_details_view_2017' 'js/learner_dashboard/views/program_details_view'
], function(Backbone, $, ProgramDetailsView) { ], function(Backbone, $, ProgramDetailsView) {
'use strict'; 'use strict';
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
'js/groups/views/cohorts_dashboard_factory', 'js/groups/views/cohorts_dashboard_factory',
'js/header_factory', 'js/header_factory',
'js/learner_dashboard/program_details_factory', 'js/learner_dashboard/program_details_factory',
'js/learner_dashboard/program_details_factory_2017',
'js/learner_dashboard/program_list_factory', 'js/learner_dashboard/program_list_factory',
'js/search/course/course_search_factory', 'js/search/course/course_search_factory',
'js/search/dashboard/dashboard_search_factory', 'js/search/dashboard/dashboard_search_factory',
......
...@@ -746,7 +746,6 @@ ...@@ -746,7 +746,6 @@
'js/spec/learner_dashboard/program_details_sidebar_view_spec.js', 'js/spec/learner_dashboard/program_details_sidebar_view_spec.js',
'js/spec/learner_dashboard/course_card_view_spec.js', 'js/spec/learner_dashboard/course_card_view_spec.js',
'js/spec/learner_dashboard/course_enroll_view_spec.js', 'js/spec/learner_dashboard/course_enroll_view_spec.js',
'js/spec/learner_dashboard/course_enroll_view_spec_2017.js',
'js/spec/markdown_editor_spec.js', 'js/spec/markdown_editor_spec.js',
'js/spec/dateutil_factory_spec.js', 'js/spec/dateutil_factory_spec.js',
'js/spec/navigation_spec.js', 'js/spec/navigation_spec.js',
......
<article class="course" role="region" aria-label="<%- content.display_name %>">
<a href="/courses/<%- course %>/about">
<section class="course-info" aria-hidden="true">
<h2 class="course-name">
<span class="course-organization"><%- org %></span>
<span class="course-code"><%- content.number %></span>
<span class="course-title"><%- content.display_name %></span>
</h2>
<div class="course-date" aria-hidden="true">
<%- interpolate(
gettext("Starts: %(start_date)s"),
{ start_date: start }, true
) %>
</div>
</section>
<div class="sr">
<ul>
<li><%- org %></li>
<li><%- content.number %></li>
<li><%- gettext("Starts") %><time itemprop="startDate" datetime="<%- start %>"><%- start %></time></li>
</ul>
</div>
</a>
</article>
<div class="message col-12 md-col-8"> <p class="certificate-status col-12 md-col-8">
<% // safe-lint: disable=underscore-not-escaped %> <span class="card-msg"><%- gettext('Certificate Status:') %></span>
<span class="certificate-icon green-icon" aria-hidden="true"><%= certificateSvg %></span> <span class="fa fa-check-circle" aria-hidden="true"></span>
<span class="card-msg"><%- gettext('Congratulations! You have earned a certificate for this course.') %></span> <span class="certificate-status-msg"><%- gettext('Certificate Purchased') %></span>
</div> </p>
<div class="action col-12 md-col-4">
<a href="<%- certificate_url %>" class="btn-brand cta-secondary">
<% // safe-lint: disable=underscore-not-escaped %>
<span class="certificate-icon blue-icon" aria-hidden="true"><%= certificateSvg %></span>
<%- gettext('View Certificate') %>
</a>
</div>
<p class="certificate-status col-12 md-col-8">
<span class="card-msg"><%- gettext('Certificate Status:') %></span>
<span class="fa fa-check-circle" aria-hidden="true"></span>
<span class="certificate-status-msg"><%- gettext('Certificate Purchased') %></span>
</p>
<div class="section"> <div class="section">
<div class="course-meta-container col-12 md-col-8 sm-col-12"> <div class="course-meta-container col-12 md-col-8 sm-col-12">
<div class="course-image-container">
<% if ( marketing_url || course_url ) { %>
<a href="<%- marketing_url || course_url %>" class="course-image-link">
<img
class="header-img"
src="<%- course_image_url %>"
<% // safe-lint: disable=underscore-not-escaped %>
alt="<%= interpolate(gettext('%(courseName)s Home Page.'), {courseName: title}, true) %>"/>
</a>
<% } else { %>
<img class="header-img" src="<%- course_image_url %>" alt=""/>
<% } %>
</div>
<div class="course-details"> <div class="course-details">
<h3 class="course-title"> <h5 class="course-title">
<% if ( marketing_url || course_url ) { %> <% if ( marketing_url || course_url ) { %>
<a href="<%- marketing_url || course_url %>" class="course-title-link"> <a href="<%- marketing_url || course_url %>" class="course-title-link">
<%- title %> <%- title %>
...@@ -23,19 +9,20 @@ ...@@ -23,19 +9,20 @@
<% } else { %> <% } else { %>
<%- title %> <%- title %>
<% } %> <% } %>
</h3> </h5>
<div class="course-text"> <div class="course-text">
<% if (start_date && end_date) { %> <% if (enrolled) { %>
<span class="run-period"><%- start_date %> - <%- end_date %></span> <span class="enrolled"><%- enrolled %>: </span>
- <% } %>
<% if (dateString) { %>
<span class="run-period"><%- dateString %></span>
<% } %> <% } %>
<span class="course-key"><%- course_key %></span>
</div> </div>
</div> </div>
</div> <div class="course-actions col-12 md-col-4 sm-col-12"></div>
<div class="course-actions col-12 md-col-4 sm-col-12"> <div class="course-certificate certificate-status"></div>
</div> </div>
</div> </div>
<div class="section action-msg-view"></div> <div class="section action-msg-view"></div>
<div class="section upgrade-message"></div> <div class="section upgrade-message"></div>
<div class="section certificate-status"></div> <div class="section expired-notification"></div>
<div class="section">
<div class="course-meta-container col-12 md-col-8 sm-col-12">
<div class="course-details">
<h5 class="course-title">
<% if ( marketing_url || course_url ) { %>
<a href="<%- marketing_url || course_url %>" class="course-title-link">
<%- title %>
</a>
<% } else { %>
<%- title %>
<% } %>
</h5>
<div class="course-text">
<% if (enrolled) { %>
<span class='enrolled'><%- enrolled %>: </span>
<% } %>
<% if (dateString) { %>
<span class="run-period"><%- dateString %></span>
<% } %>
</div>
</div>
<div class="course-actions col-12 md-col-4 sm-col-12"></div>
<div class="course-certificate certificate-status"></div>
</div>
</div>
<div class="section action-msg-view"></div>
<div class="section upgrade-message"></div>
<div class="section expired-notification"></div>
<% if (is_enrolled) { %> <% if (is_enrolled && (typeof expired === 'undefined' || expired === false)) { %>
<div class="enrollment-info"><%- gettext('enrolled') %></div> <a href="<%- course_url %>" class="view-course-button btn-brand btn cta-primary">
<% if (is_enrollment_open || is_course_ended) { %> <% if (is_course_ended) { %>
<a href="<%- course_url %>" class="btn view-course-link"> <%- gettext('View Archived Course') %>
<% if (is_enrollment_open) { %> <% } else { %>
<%- gettext('View Course') %> <%- gettext('View Course') %>
<% } else if (is_course_ended) { %> <% } %>
<%- gettext('View Archived Course') %> </a>
<% } %>
</a>
<% } %>
<% } else { %> <% } else { %>
<% if (enrollable_course_runs.length > 0) { %> <% if (enrollable_course_runs.length > 0) { %>
<div class="enrollment-info"><%- gettext('Not Enrolled') %></div>
<% if (enrollable_course_runs.length > 1) { %> <% if (enrollable_course_runs.length > 1) { %>
<div class="run-select-container"> <div class="run-select-container">
<div class="select-error"> <label class="select-choice" for="select-<%- course_key %>-run">
<%- gettext('Please select a course date') %> <%- gettext('Choose a course run:') %>
</div>
<label class="sr-only" for="select-<%- course_key %>-run">
<%- gettext('Select Course Run') %>
</label> </label>
<select id="select-<%- course_key %>-run" class="run-select" autocomplete="off"> <select id="select-<%- course_key %>-run" class="run-select field-input input-select" autocomplete="off">
<option value="" selected="selected">
<%- gettext('Choose Course Date') %>
</option>
<% _.each (enrollable_course_runs, function(courseRun) { %> <% _.each (enrollable_course_runs, function(courseRun) { %>
<option <option
value="<%- courseRun.key %>" value="<%- courseRun.key %>"
...@@ -31,19 +21,17 @@ ...@@ -31,19 +21,17 @@
selected="selected" selected="selected"
<% }%> <% }%>
> >
<%= interpolate( <%- courseRun.dateString %>
gettext('Starts %(start)s'),
{ start: courseRun.start_date },
true)
%>
</option> </option>
<% }); %> <% }); %>
</select> </select>
</div> </div>
<% } %> <% } %>
<button type="button" class="btn-brand btn cta-primary enroll-button"> <div class="enroll-button">
<%- gettext('Enroll Now') %> <button type="button" class="btn-brand btn cta-primary">
</button> <%- gettext('Enroll Now') %>
</button>
</div>
<% } else if (upcoming_course_runs.length > 0) {%> <% } else if (upcoming_course_runs.length > 0) {%>
<div class="no-action-message"> <div class="no-action-message">
<%- gettext('Coming Soon') %> <%- gettext('Coming Soon') %>
......
<% if (is_enrolled && (typeof expired === 'undefined' || expired === false)) { %>
<a href="<%- course_url %>" class="view-course-button btn-brand btn cta-primary">
<% if (is_course_ended) { %>
<%- gettext('View Archived Course') %>
<% } else { %>
<%- gettext('View Course') %>
<% } %>
</a>
<% } else { %>
<% if (enrollable_course_runs.length > 0) { %>
<% if (enrollable_course_runs.length > 1) { %>
<div class="run-select-container">
<label class="select-choice" for="select-<%- course_key %>-run">
<%- gettext('Choose a course run:') %>
</label>
<select id="select-<%- course_key %>-run" class="run-select field-input input-select" autocomplete="off">
<% _.each (enrollable_course_runs, function(courseRun) { %>
<option
value="<%- courseRun.key %>"
<% if (key === courseRun.key) { %>
selected="selected"
<% }%>
>
<%- courseRun.dateString %>
</option>
<% }); %>
</select>
</div>
<% } %>
<div class="enroll-button">
<button type="button" class="btn-brand btn cta-primary">
<%- gettext('Enroll Now') %>
</button>
</div>
<% } else if (upcoming_course_runs.length > 0) {%>
<div class="no-action-message">
<%- gettext('Coming Soon') %>
</div>
<div class="enrollment-opens">
<%- gettext('Enrollment Opens on') %>
<span class="enrollment-open-date">
<%- upcoming_course_runs[0].enrollment_open_date %>
</span>
</div>
<% } else { %>
<div class="no-action-message">
<%- gettext('Not Currently Available') %>
</div>
<% } %>
<% } %>
...@@ -15,6 +15,8 @@ from openedx.core.djangolib.js_utils import ( ...@@ -15,6 +15,8 @@ from openedx.core.djangolib.js_utils import (
<%static:require_module module_name="js/learner_dashboard/program_details_factory" class_name="ProgramDetailsFactory"> <%static:require_module module_name="js/learner_dashboard/program_details_factory" class_name="ProgramDetailsFactory">
ProgramDetailsFactory({ ProgramDetailsFactory({
programData: ${program_data | n, dump_js_escaped_json}, programData: ${program_data | n, dump_js_escaped_json},
courseData: ${course_data | n, dump_js_escaped_json},
certificateData: ${certificate_data | n, dump_js_escaped_json},
urls: ${urls | n, dump_js_escaped_json}, urls: ${urls | n, dump_js_escaped_json},
userPreferences: ${user_preferences | n, dump_js_escaped_json}, userPreferences: ${user_preferences | n, dump_js_escaped_json},
}); });
...@@ -24,8 +26,6 @@ ProgramDetailsFactory({ ...@@ -24,8 +26,6 @@ ProgramDetailsFactory({
<%block name="pagetitle">${_("Program Details")}</%block> <%block name="pagetitle">${_("Program Details")}</%block>
<%block name="bodyclass">program-details</%block> <%block name="bodyclass">program-details</%block>
<%include file="_dashboard_navigation_programs.html"/>
<main id="main" aria-label="Content" tabindex="-1"> <main id="main" aria-label="Content" tabindex="-1">
<div class="js-program-details-wrapper"></div> <div class="js-program-details-wrapper program-details-wrapper"></div>
</main> </main>
## Override the default styles_version to the Pattern Library version (version 2)
<%! main_css = "style-learner-dashboard" %>
<%page expression_filter="h"/>
<%inherit file="../main.html" />
<%namespace name='static' file='../static_content.html'/>
<%!
from django.utils.translation import ugettext as _
from openedx.core.djangolib.js_utils import (
dump_js_escaped_json, js_escaped_string
)
%>
<%block name="js_extra">
<%static:require_module module_name="js/learner_dashboard/program_details_factory_2017" class_name="ProgramDetailsFactory2017">
ProgramDetailsFactory2017({
programData: ${program_data | n, dump_js_escaped_json},
courseData: ${course_data | n, dump_js_escaped_json},
certificateData: ${certificate_data | n, dump_js_escaped_json},
urls: ${urls | n, dump_js_escaped_json},
userPreferences: ${user_preferences | n, dump_js_escaped_json},
});
</%static:require_module>
</%block>
<%block name="pagetitle">${_("Program Details")}</%block>
<%block name="bodyclass">program-details</%block>
<main id="main" aria-label="Content" tabindex="-1">
<div class="js-program-details-wrapper program-details-wrapper"></div>
</main>
<header class="js-program-header program-header full-width-banner"></header> <header class="js-program-header program-header full-width-banner"></header>
<div class="program-details-content grid-container"> <section class="program-details-content">
<div class="js-program-progress-view"></div> <div class="program-heading">
<div class="js-course-list row"></div> <% if (inProgressCount === totalCount) { %>
<aside class="js-course-sidebar"></aside> <h3 class="program-heading-title"><%- gettext('Congratulations!') %></h3>
</div> <div class="program-heading-message">
<div><%- interpolate(gettext(
'You have successfully completed all the requirements for the %(title)s %(type)s.'),
{ title: title, type: type }, true) %>
</div>
</div>
<% } else { %>
<h3 class="program-heading-title"><%- gettext('Your Program Journey') %></h3>
<div class="program-heading-message">
<div>
<%- interpolate(gettext(
'Track and plan your progress through the %(count)s courses in this program.'),
{ count: totalCount }, true) %>
</div>
<div><%- gettext('To complete the program, you must earn a verified certificate for each course.') %></div>
</div>
<% } %>
</div>
<div class="course-list-headings">
<% if (inProgressCount) { %>
<div class="in-progress-group">
<h4 class="course-list-heading">
<span class="status"><%- gettext('COURSES IN PROGRESS') %></span>
<span class="count"><%- inProgressCount %></span>
</h4>
<div class="course-list js-course-list-in-progress row"></div>
</div>
<% } %>
<% if (remainingCount) { %>
<div class="remaining-group">
<h4 class="course-list-heading">
<span class="status"><%- gettext('REMAINING COURSES') %></span>
<span class="count"><%- remainingCount %></span>
</h4>
<div class="course-list js-course-list-remaining row"></div>
</div>
<% } %>
<div class="completed-group">
<h4 class="course-list-heading">
<span class="status"><%- gettext('COMPLETED COURSES') %></span>
<span class="count"><%- completedCount %></span>
</h4>
<% if (completedCount) { %>
<div class="course-list js-course-list-completed row"></div>
<% } else { %>
<div class="motivating-section">
<p class='motivating-heading'><%- gettext("As you complete courses, you will see them listed here.") %></p>
<p class='motivating-message'><%- gettext('Complete courses on your schedule to ensure you stand out in your field!') %></p>
</div>
<% } %>
</div>
</div>
</section>
<aside class="js-program-sidebar program-sidebar"></aside>
<header class="js-program-header program-header full-width-banner"></header>
<section class="program-details-content">
<div class="program-heading">
<% if (inProgressCount === totalCount) { %>
<h3 class="program-heading-title"><%- gettext('Congratulations!') %></h3>
<div class="program-heading-message">
<div><%- interpolate(gettext(
'You have successfully completed all the requirements for the %(title)s %(type)s.'),
{ title: title, type: type }, true) %>
</div>
</div>
<% } else { %>
<h3 class="program-heading-title"><%- gettext('Your Program Journey') %></h3>
<div class="program-heading-message">
<div>
<%- interpolate(gettext(
'Track and plan your progress through the %(count)s courses in this program.'),
{ count: totalCount }, true) %>
</div>
<div><%- gettext('To complete the program, you must earn a verified certificate for each course.') %></div>
</div>
<% } %>
</div>
<div class="course-list-headings">
<% if (inProgressCount) { %>
<div class="in-progress-group">
<h4 class="course-list-heading">
<span class="status"><%- gettext('COURSES IN PROGRESS') %></span>
<span class="count"><%- inProgressCount %></span>
</h4>
<div class="course-list js-course-list-in-progress row"></div>
</div>
<% } %>
<% if (remainingCount) { %>
<div class="remaining-group">
<h4 class="course-list-heading">
<span class="status"><%- gettext('REMAINING COURSES') %></span>
<span class="count"><%- remainingCount %></span>
</h4>
<div class="course-list js-course-list-remaining row"></div>
</div>
<% } %>
<div class="completed-group">
<h4 class="course-list-heading">
<span class="status"><%- gettext('COMPLETED COURSES') %></span>
<span class="count"><%- completedCount %></span>
</h4>
<% if (completedCount) { %>
<div class="course-list js-course-list-completed row"></div>
<% } else { %>
<div class="motivating-section">
<p class='motivating-heading'><%- gettext("As you complete courses, you will see them listed here.") %></p>
<p class='motivating-message'><%- gettext('Complete courses on your schedule to ensure you stand out in your field!') %></p>
</div>
<% } %>
</div>
</div>
</section>
<aside class="js-program-sidebar program-sidebar"></aside>
<div class="banner-background-wrapper"> <div class="program-details-header">
<picture> <div class="meta-info grid-container">
<source srcset="<%- programData.banner_image.large.url %>" media="(min-width: <%- breakpoints.min.large %>)"> <% if (logo) { %>
<source srcset="<%- programData.banner_image.medium.url %>" media="(min-width: <%- breakpoints.min.medium %>)"> <span aria-label="<%- gettext(programData.type) %>" class="<%- programData.type.toLowerCase() %> program-details-icon"><%= logo %></span>
<img class="banner-background-image" srcset="<%- programData.banner_image['x-small'].url %>" alt=""> <% } %>
</picture> <h2 class="hd-1 program-title"><%- programData.title %></h2>
</div>
<div class="banner-content grid-container"> <div class='authoring-organizations'>
<h2 class="hd-1 title row"><%- programData.title %></h2> <h2 class="heading">Institutions</h2>
<p class="hd-4 subtitle row"><%- programData.subtitle %></p>
<% if (programData.authoring_organizations.length) { %> <% if (programData.authoring_organizations.length) { %>
<div class="org-wrapper"> <div class="orgs">
<% _.each(programData.authoring_organizations, function(org) { %> <% _.each(programData.authoring_organizations, function(org) { %>
<img src="<%- org.certificate_logo_image_url || org.logo_image_url %>" class="org-logo" alt="<%- StringUtils.interpolate( <img src="<%- org.certificate_logo_image_url || org.logo_image_url %>" class="org-logo" alt="<%- StringUtils.interpolate(
gettext('{organization}\'s logo'), gettext('{organization}\'s logo'),
...@@ -20,20 +19,3 @@ ...@@ -20,20 +19,3 @@
<% } %> <% } %>
</div> </div>
</div> </div>
<nav class="breadcrumb-wrapper grid-container" aria-label="breadcrumb" role="navigation">
<h3 class="sr-only"><%- gettext('You are here') %></h2>
<ol class="breadcrumb-list">
<li class="crumb">
<a href="/" class="crumb-link"><%- gettext('Dashboard') %></a>
<span class="crumb-separator fa fa-chevron-right" aria-hidden="true"></span>
</li>
<li class="crumb">
<a href="<%- urls.program_listing_url %>" class="crumb-link"><%- gettext('Programs') %></a>
<span class="crumb-separator fa fa-chevron-right" aria-hidden="true"></span>
</li>
<li class="crumb active">
<%- programData.title %>
</li>
</ol>
</nav>
<div class="program-details-header">
<div class="meta-info grid-container">
<% if (logo) { %>
<span aria-label="<%- gettext(programData.type) %>" class="<%- programData.type.toLowerCase() %> program-details-icon"><%= logo %></span>
<% } %>
<h2 class="hd-1 program-title"><%- programData.title %></h2>
</div>
<div class='authoring-organizations'>
<h2 class="heading">Institutions</h2>
<% if (programData.authoring_organizations.length) { %>
<div class="orgs">
<% _.each(programData.authoring_organizations, function(org) { %>
<img src="<%- org.certificate_logo_image_url || org.logo_image_url %>" class="org-logo" alt="<%- StringUtils.interpolate(
gettext('{organization}\'s logo'),
{organization: org.name}
) %>">
<% }) %>
</div>
<% } %>
</div>
</div>
<div class="message col-12 md-col-8"> <div class="message certificate-status col-12 md-col-8">
<% // safe-lint: disable=underscore-not-escaped %> <span class="card-msg"><%- gettext('Certificate Status:') %></span>
<span class="certificate-icon green-icon" aria-hidden="true"><%= certificateSvg %></span> <span><%- gettext('Needs verified certificate ') %></span>
<span class="card-msg"><%- gettext('You need a certificate in this course to be eligible for a program certificate.') %></span> <span class="price"> <%- price %></span>
</div> </div>
<div class="action col-12 md-col-4"> <div class="action col-12 md-col-4">
<a href="<%- upgrade_url %>" class="btn-brand cta-primary"> <a href="<%- upgrade_url %>" class="btn-brand btn cta-primary upgrade-button">
<% // safe-lint: disable=underscore-not-escaped %> <%- gettext('Buy Certificate') %>
<span class="certificate-icon green-icon" aria-hidden="true"><%= certificateSvg %></span> <a>
<%- gettext('Upgrade Now') %>
</a>
</div> </div>
<div class="message certificate-status col-12 md-col-8">
<span class="card-msg"><%- gettext('Certificate Status:') %></span>
<span><%- gettext('Needs verified certificate ') %></span>
<span class="price"> <%- price %></span>
</div>
<div class="action col-12 md-col-4">
<a href="<%- upgrade_url %>" class="btn-brand btn cta-primary upgrade-button">
<%- gettext('Buy Certificate') %>
<a>
</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