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"""
import waffle
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.http import Http404
......@@ -67,6 +66,7 @@ def program_details(request, program_uuid):
'commerce_api_url': reverse('commerce_api:v0:baskets:create'),
}
# TODO: Tighten this up!
context = {
'urls': urls,
'show_program_listing': programs_config.enabled,
......@@ -76,20 +76,15 @@ def program_details(request, program_uuid):
'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]
certificate_data = get_certificates(request.user, program_data)
course_data = meter.progress(programs=[program_data], count_only=False)[0]
certificate_data = get_certificates(request.user, program_data)
program_data.pop('courses')
program_data.pop('courses')
context.update({
'program_data': program_data,
'course_data': course_data,
'certificate_data': certificate_data,
})
context.update({
'program_data': program_data,
'course_data': course_data,
'certificate_data': certificate_data,
})
return render_to_response('learner_dashboard/program_details_2017.html', context)
else:
context.update({'program_data': program_data})
return render_to_response('learner_dashboard/program_details.html', context)
return render_to_response('learner_dashboard/program_details.html', context)
......@@ -42,22 +42,12 @@
getUnselectedCourseRun: function(courseRuns) {
var unselectedRun = {},
courseRun,
courseImageUrl;
courseRun;
if (courseRuns && courseRuns.length > 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, {
course_image_url: courseImageUrl,
marketing_url: courseRun.marketing_url,
is_enrollment_open: courseRun.is_enrollment_open
});
......@@ -149,8 +139,8 @@
formatDateString: function(run) {
var pacingType = run.pacing_type,
dateString = '',
start = run.start_date || this.get('start_date'),
end = run.end_date || this.get('end_date'),
start = this.get('start_date') || run.start_date,
end = this.get('end_date') || run.end_date,
now = new Date(),
startDate = new Date(start),
endDate = new Date(end);
......@@ -181,8 +171,7 @@
},
setActiveCourseRun: function(courseRun, userPreferences) {
var startDateString,
courseImageUrl;
var startDateString;
if (courseRun) {
if (this.valueIsDefined(courseRun.advertised_start)) {
......@@ -191,16 +180,8 @@
startDateString = this.formatDate(courseRun.start, userPreferences);
}
if (courseRun.image && courseRun.image.src) {
courseImageUrl = courseRun.image.src;
} else {
courseImageUrl = courseRun.course_image_url;
}
this.set({
certificate_url: courseRun.certificate_url,
course_image_url: courseImageUrl || '',
course_run_key: courseRun.key,
course_url: courseRun.course_url || '',
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) {
'use strict';
define(['backbone',
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/certificate_status.underscore',
'text!../../../templates/learner_dashboard/certificate_icon.underscore'
],
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/certificate_status.underscore',
'text!../../../templates/learner_dashboard/certificate_icon.underscore'
],
function(
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 @@
'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',
'js/learner_dashboard/views/certificate_status_view',
'js/learner_dashboard/views/course_enroll_view',
'text!../../../templates/learner_dashboard/course_card.underscore'
],
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'js/learner_dashboard/models/course_enroll_model',
'js/learner_dashboard/views/upgrade_message_view',
'js/learner_dashboard/views/certificate_status_view',
'js/learner_dashboard/views/expired_notification_view',
'js/learner_dashboard/views/course_enroll_view',
'text!../../../templates/learner_dashboard/course_card.underscore'
],
function(
Backbone,
$,
......@@ -21,33 +22,39 @@
EnrollModel,
UpgradeMessageView,
CertificateStatusView,
ExpiredNotificationView,
CourseEnrollView,
pageTpl
) {
return Backbone.View.extend({
className: 'course-card card',
className: 'program-course-card',
tpl: HtmlUtils.template(pageTpl),
initialize: function(options) {
this.enrollModel = new EnrollModel();
if (options.context && options.context.urls) {
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 filledTemplate = this.tpl(this.model.toJSON());
HtmlUtils.setHtml(this.$el, filledTemplate);
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');
$certStatus = this.$('.certificate-status'),
$expiredNotification = this.$('.expired-notification'),
expired = this.model.get('expired');
this.enrollView = new CourseEnrollView({
$parentEl: this.$('.course-actions'),
......@@ -56,14 +63,14 @@
enrollModel: this.enrollModel
});
if (this.model.get('upgrade_url')) {
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')) {
} else if (this.model.get('certificate_url') && !(expired === true)) {
this.certificateStatus = new CertificateStatusView({
$el: $certStatus,
model: this.model
......@@ -75,6 +82,13 @@
$upgradeMessage.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 @@
'use strict';
define(['backbone',
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/course_enroll.underscore'
],
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/course_enroll.underscore'
],
function(
Backbone,
$,
......@@ -17,11 +17,12 @@
pageTpl
) {
return Backbone.View.extend({
className: 'course-enroll-view',
tpl: HtmlUtils.template(pageTpl),
events: {
'click .enroll-button': 'handleEnroll',
'change .run-select': 'handleCourseRunSelect'
'click .enroll-button': 'handleEnroll'
},
initialize: function(options) {
......@@ -29,9 +30,6 @@
this.enrollModel = options.enrollModel;
this.urlModel = options.urlModel;
this.render();
if (this.urlModel) {
this.trackSelectionUrl = this.urlModel.get('track_selection_url');
}
},
render: function() {
......@@ -41,16 +39,23 @@
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
if (!this.model.get('course_run_key')) {
this.$('.select-error').css('visibility', 'visible');
} else if (!this.model.get('is_enrolled')) {
// 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: this.model.get('course_run_key')
course_id: courseRunKey
}, {
success: _.bind(this.enrollSuccess, this),
error: _.bind(this.enrollError, this)
......@@ -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() {
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);
......
(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) {
'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',
'js/learner_dashboard/views/collection_list_view',
'js/learner_dashboard/views/course_card_view',
'text!../../../templates/learner_dashboard/program_details_view.underscore'
],
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'js/learner_dashboard/collections/course_card_collection',
'js/learner_dashboard/views/program_header_view',
'js/learner_dashboard/views/collection_list_view',
'js/learner_dashboard/views/course_card_view',
'js/learner_dashboard/views/program_details_sidebar_view',
'text!../../../templates/learner_dashboard/program_details_view.underscore'
],
function(
Backbone,
$,
......@@ -22,6 +22,7 @@
HeaderView,
CollectionListView,
CourseCardView,
SidebarView,
pageTpl
) {
return Backbone.View.extend({
......@@ -32,15 +33,37 @@
initialize: function(options) {
this.options = options;
this.programModel = new Backbone.Model(this.options.programData);
this.courseCardCollection = new CourseCardCollection(
this.programModel.get('courses'),
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() {
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();
},
......@@ -48,16 +71,41 @@
this.headerView = new HeaderView({
model: new Backbone.Model(this.options)
});
new CollectionListView({
el: '.js-course-list',
childView: CourseCardView,
collection: this.courseCardCollection,
context: this.options,
titleContext: {
el: 'h2',
title: 'Course List'
}
}).render();
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
});
}
});
}
......
(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 @@
'use strict';
define(['backbone',
'jquery',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/program_header_view.underscore',
'picturefill'
],
function(Backbone, $, HtmlUtils, pageTpl, picturefill) {
'jquery',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/program_header_view.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'
medium: '768px',
large: '1180px'
}
},
......@@ -24,32 +27,29 @@
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
breakpoints: this.breakpoints,
logo: this.getLogo()
});
if (this.model.get('programData')) {
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) {
'use strict';
define(['backbone',
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/upgrade_message.underscore',
'text!../../../templates/learner_dashboard/certificate_icon.underscore'
],
'jquery',
'underscore',
'gettext',
'edx-ui-toolkit/js/utils/html-utils',
'text!../../../templates/learner_dashboard/upgrade_message.underscore'
],
function(
Backbone,
$,
_,
gettext,
HtmlUtils,
upgradeMessageTpl,
certificateIconTpl
upgradeMessageTpl
) {
return Backbone.View.extend({
messageTpl: HtmlUtils.template(upgradeMessageTpl),
iconTpl: HtmlUtils.template(certificateIconTpl),
initialize: function(options) {
this.$el = options.$el;
......@@ -29,7 +26,6 @@
render: function() {
var data = this.model.toJSON();
data = $.extend(data, {certificateSvg: this.iconTpl()});
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([
var programData = $.extend({}, data);
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);
view = new CourseCardView({
model: courseCardModel
......@@ -26,12 +26,10 @@ define([
validateCourseInfoDisplay = function() {
// 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').attr('href')).toEqual(
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(
startDate + ' - ' + endDate
);
......@@ -99,7 +97,9 @@ define([
it('should show the course advertised start date', function() {
var advertisedStart = 'A long time ago...';
course.course_runs[0].advertised_start = advertisedStart;
setupView(course, false);
expect(view.$('.course-details .course-text .run-period').html()).toEqual(
advertisedStart + ' - ' + endDate
);
......@@ -108,13 +108,12 @@ define([
it('should only show certificate status section if a certificate has been earned', function() {
var certUrl = 'sample-certificate';
expect(view.$('.certificate-status').length).toEqual(0);
expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
view.remove();
course.course_runs[0].certificate_url = certUrl;
setupView(course, false);
expect(view.$('.certificate-status').length).toEqual(1);
expect(view.$('.certificate-status .cta-secondary').attr('href')).toEqual(certUrl);
expect(view.$('.course-certificate .certificate-status').length).toEqual(1);
});
it('should only show upgrade message section if an upgrade is required', function() {
......@@ -135,7 +134,7 @@ define([
course.course_runs[0].certificate_url = '';
setupView(course, false);
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();
// Verify that the upgrade message takes priority.
......@@ -143,7 +142,7 @@ define([
course.course_runs[0].certificate_url = '/path/to/certificate';
setupView(course, false);
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() {
......@@ -151,9 +150,7 @@ define([
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-text .course-key').html()).toEqual(course.key);
expect(view.$('.course-details .course-text .run-period').length).toBe(0);
expect(view.$('.no-action-message').text().trim()).toBe('Coming Soon');
expect(view.$('.enrollment-open-date').text().trim()).toEqual(
......@@ -167,27 +164,21 @@ define([
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-text .course-key').html()).toEqual(course.key);
expect(view.$('.course-details .course-text .run-period').length).toBe(0);
expect(view.$('.no-action-message').text().trim()).toBe('Not Currently Available');
expect(view.$('.enrollment-opens').length).toEqual(0);
});
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.$(selector).attr('href')).toEqual(course.course_runs[0].marketing_url);
});
expect(view.$('.course-title-link').attr('href')).toEqual(course.course_runs[0].marketing_url);
});
it('should link to the course home when no marketing URL is available', function() {
course.course_runs[0].marketing_url = null;
setupView(course, false);
$.each(['.course-image-link', '.course-title-link'], function(index, selector) {
expect(view.$(selector).attr('href')).toEqual(course.course_runs[0].course_url);
});
expect(view.$('.course-title-link').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() {
......@@ -195,9 +186,7 @@ define([
course.course_runs[0].course_url = null;
setupView(course, false);
$.each(['.course-image-link', '.course-title-link'], function(index, selector) {
expect(view.$(selector).length).toEqual(0);
});
expect(view.$('.course-title-link').length).toEqual(0);
});
});
}
......
......@@ -33,6 +33,9 @@ define([
};
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 = [{
......@@ -132,8 +135,6 @@ define([
it('should render the course enroll view when not enrolled', function() {
setupView(singleCourseRunList);
expect(view.$('.enrollment-info').html().trim()).toEqual('Not Enrolled');
expect(view.$('.enroll-button').text().trim()).toEqual('Enroll Now');
expect(view.$('.run-select').length).toBe(0);
});
......@@ -142,24 +143,10 @@ define([
singleCourseRunList[0].is_enrolled = true;
setupView(singleCourseRunList);
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.$('.view-course-button').text().trim()).toEqual('View Course');
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() {
setupView([]);
......@@ -172,24 +159,8 @@ define([
setupView(multiCourseRunList);
expect(view.$('.run-select').length).toBe(1);
expect(view.$('.run-select').val()).toEqual('');
expect(view.$('.run-select option').length).toBe(3);
});
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);
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() {
......@@ -304,6 +275,15 @@ define([
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([
describe('Program Details Header View', function() {
var view = null,
context = {
urls: {
program_listing_url: '/dashboard/programs'
},
programData: {
uuid: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8',
title: 'Food Security and Sustainability',
......@@ -68,16 +65,12 @@ define([
});
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.$('.title').html()).toEqual(context.programData.title);
expect(view.$('.subtitle').html()).toEqual(context.programData.subtitle);
expect(view.$('.program-title').html()).toEqual(context.programData.title);
expect(view.$('.org-logo').length).toEqual(context.programData.authoring_organizations.length);
expect(view.$('.org-logo').attr('src'))
.toEqual(context.programData.authoring_organizations[0].certificate_logo_image_url);
expect(view.$('.org-logo').attr('alt'))
.toEqual(context.programData.authoring_organizations[0].name + '\'s logo');
expect(programListUrl).toEqual(context.urls.program_listing_url);
});
});
}
......
define([
'backbone',
'jquery',
'js/learner_dashboard/views/program_details_view_2017'
'js/learner_dashboard/views/program_details_view'
], function(Backbone, $, ProgramDetailsView) {
'use strict';
......
......@@ -30,7 +30,6 @@
'js/groups/views/cohorts_dashboard_factory',
'js/header_factory',
'js/learner_dashboard/program_details_factory',
'js/learner_dashboard/program_details_factory_2017',
'js/learner_dashboard/program_list_factory',
'js/search/course/course_search_factory',
'js/search/dashboard/dashboard_search_factory',
......
......@@ -746,7 +746,6 @@
'js/spec/learner_dashboard/program_details_sidebar_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_2017.js',
'js/spec/markdown_editor_spec.js',
'js/spec/dateutil_factory_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">
<% // safe-lint: disable=underscore-not-escaped %>
<span class="certificate-icon green-icon" aria-hidden="true"><%= certificateSvg %></span>
<span class="card-msg"><%- gettext('Congratulations! You have earned a certificate for this course.') %></span>
</div>
<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>
<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="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">
<h3 class="course-title">
<h5 class="course-title">
<% if ( marketing_url || course_url ) { %>
<a href="<%- marketing_url || course_url %>" class="course-title-link">
<%- title %>
......@@ -23,19 +9,20 @@
<% } else { %>
<%- title %>
<% } %>
</h3>
</h5>
<div class="course-text">
<% if (start_date && end_date) { %>
<span class="run-period"><%- start_date %> - <%- end_date %></span>
-
<% if (enrolled) { %>
<span class="enrolled"><%- enrolled %>: </span>
<% } %>
<% if (dateString) { %>
<span class="run-period"><%- dateString %></span>
<% } %>
<span class="course-key"><%- course_key %></span>
</div>
</div>
</div>
<div class="course-actions col-12 md-col-4 sm-col-12">
<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 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) { %>
<div class="enrollment-info"><%- gettext('enrolled') %></div>
<% if (is_enrollment_open || is_course_ended) { %>
<a href="<%- course_url %>" class="btn view-course-link">
<% if (is_enrollment_open) { %>
<%- gettext('View Course') %>
<% } else if (is_course_ended) { %>
<%- gettext('View Archived Course') %>
<% } %>
</a>
<% } %>
<% 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) { %>
<div class="enrollment-info"><%- gettext('Not Enrolled') %></div>
<% if (enrollable_course_runs.length > 1) { %>
<div class="run-select-container">
<div class="select-error">
<%- gettext('Please select a course date') %>
</div>
<label class="sr-only" for="select-<%- course_key %>-run">
<%- gettext('Select Course Run') %>
<label class="select-choice" for="select-<%- course_key %>-run">
<%- gettext('Choose a course run:') %>
</label>
<select id="select-<%- course_key %>-run" class="run-select" autocomplete="off">
<option value="" selected="selected">
<%- gettext('Choose Course Date') %>
</option>
<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 %>"
......@@ -31,19 +21,17 @@
selected="selected"
<% }%>
>
<%= interpolate(
gettext('Starts %(start)s'),
{ start: courseRun.start_date },
true)
%>
<%- courseRun.dateString %>
</option>
<% }); %>
</select>
</div>
<% } %>
<button type="button" class="btn-brand btn cta-primary enroll-button">
<%- gettext('Enroll Now') %>
</button>
<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') %>
......
<% 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 (
<%static:require_module module_name="js/learner_dashboard/program_details_factory" class_name="ProgramDetailsFactory">
ProgramDetailsFactory({
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},
});
......@@ -24,8 +26,6 @@ ProgramDetailsFactory({
<%block name="pagetitle">${_("Program Details")}</%block>
<%block name="bodyclass">program-details</%block>
<%include file="_dashboard_navigation_programs.html"/>
<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>
## 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>
<div class="program-details-content grid-container">
<div class="js-program-progress-view"></div>
<div class="js-course-list row"></div>
<aside class="js-course-sidebar"></aside>
</div>
<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>
<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">
<picture>
<source srcset="<%- programData.banner_image.large.url %>" media="(min-width: <%- breakpoints.min.large %>)">
<source srcset="<%- programData.banner_image.medium.url %>" media="(min-width: <%- breakpoints.min.medium %>)">
<img class="banner-background-image" srcset="<%- programData.banner_image['x-small'].url %>" alt="">
</picture>
<div class="banner-content grid-container">
<h2 class="hd-1 title row"><%- programData.title %></h2>
<p class="hd-4 subtitle row"><%- programData.subtitle %></p>
<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="org-wrapper">
<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'),
......@@ -20,20 +19,3 @@
<% } %>
</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">
<% // safe-lint: disable=underscore-not-escaped %>
<span class="certificate-icon green-icon" aria-hidden="true"><%= certificateSvg %></span>
<span class="card-msg"><%- gettext('You need a certificate in this course to be eligible for a program certificate.') %></span>
<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 cta-primary">
<% // safe-lint: disable=underscore-not-escaped %>
<span class="certificate-icon green-icon" aria-hidden="true"><%= certificateSvg %></span>
<%- gettext('Upgrade Now') %>
</a>
<a href="<%- upgrade_url %>" class="btn-brand btn cta-primary upgrade-button">
<%- gettext('Buy Certificate') %>
<a>
</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