Merge pull request #16969 from edx/LEARNER-3058

LEARNER-3058 Move hero upsell to sidebar
This commit is contained in:
Matthew Piatetsky
2018-01-04 14:48:18 -05:00
committed by GitHub
6 changed files with 81 additions and 311 deletions

View File

@@ -29,30 +29,6 @@
<div class="page-content">
<div class="layout layout-1t2t">
<main class="layout-col layout-col-b">
<div class="section">
<div class="vc-message tex2jax_ignore" role="group" aria-labelledby="vc-title" tabindex="-1" style="display: none;">
<h3 class="vc-title vc-fade vc-polite-only">Pursue a verified certificate</h3>
<button class="vc-toggle vc-fade vc-polite-only btn-link" type="button" aria-controls="moreinfo"
aria-expanded="true" aria-label="Show/Hide">Show less
</button>
<div class="vc-hero vc-fade">
<img src="img/sample-certificate.png"
alt="Sample verified certificate with your name, the course title, the logo of the institution and the signatures of the instructors for this course."/>
</div>
<ul class="vc-selling-points vc-fade">
<li class="vc-selling-point">Official proof of completion</li>
<li class="vc-selling-point">Easily shareable certificate</li>
<li class="vc-selling-point">Proven motivator to complete the course</li>
<li class="vc-selling-point">Certificate purchases help us continue to offer free courses</li>
</ul>
<div class="vc-cta vc-fade vc-polite-only">
<a class="btn btn-upgrade" data-creative="original_hero" data-position="hero" href="#">Upgrade ($100)</a>
</div>
</div>
</div>
<div class="section section-dates">
<div class="welcome-message">
<div class="dismiss-message">
@@ -110,6 +86,21 @@
</li>
</ul>
</div>
<div class="section section-upgrade">
<h3 class="hd hd-6">Pursue a verified certificate</h3>
<div class="upgrade-container">
<p>
<a class="btn-brand btn-upgrade"
href="${upgrade_url}"
data-creative="sidebarupsell"
data-position="sidebar-message">
Upgrade $49
</a>
</p>
<p><button class="btn-link btn-small promo-learn-more">Learn More</button></p>
</div>
<img src="https://courses.edx.org/static/images/edx-verified-mini-cert.png" alt="">
</div>
<div class="section section-dates">
<h3 class="hd hd-6 section-title handouts-header">Important Course Dates</h3>
<div class="date-summary-container">

View File

@@ -144,75 +144,17 @@ export class CourseHome { // eslint-disable-line import/prefer-default-export
);
}
/**
* Persists the collapsed state of the upgrade message. If the message is collapsed,
* this information is persisted to local storage. Expanding the message *removes* the
* key from local storage.
*/
persistUpgradeMessageState(collapsed) {
if (window.localStorage) {
if (collapsed) {
window.localStorage.setItem(this.msgStateStorageKey, true);
} else {
window.localStorage.removeItem(this.msgStateStorageKey);
}
}
}
configureUpgradeMessage() {
const $vcMessage = $('.vc-message');
const $vcDismissToggle = $('.vc-toggle', $vcMessage);
const logEventProperties = { courseRunKey: this.courseRunKey };
Logger.log('edx.bi.course.upgrade.hero.displayed', logEventProperties);
// Get height of container and button
let vcHeight = $vcMessage.outerHeight();
// Update based on window
window.onresize = () => {
if (!$vcMessage.hasClass('polite')) {
vcHeight = $vcMessage.outerHeight();
}
};
function collapseMessage(duration = 400) {
$('.vc-fade').fadeOut(duration, () => {
$vcDismissToggle.text(gettext('Show more')).attr('aria-expanded', false);
$('.vc-polite-only').fadeIn(duration);
$vcMessage.height('auto').addClass('polite');
});
}
// Use the previously-persisted state to determine the initial display state of the message.
if (window.localStorage && window.localStorage.getItem(this.msgStateStorageKey)) {
collapseMessage(0);
}
$vcMessage.show();
$vcDismissToggle.click(() => {
if ($vcMessage.hasClass('polite')) {
// Expand message
Logger.log('edx.bi.course.upgrade.hero.expanded', logEventProperties);
this.persistUpgradeMessageState(false);
$('.vc-fade').fadeOut(400);
$vcMessage.animate({ height: vcHeight }, 400, () => {
$vcMessage.height('auto').removeClass('polite');
$vcDismissToggle.text(gettext('Show less')).attr('aria-expanded', true);
$('.vc-fade').fadeIn(400);
});
} else {
// Collapse message
Logger.log('edx.bi.course.upgrade.hero.collapsed', logEventProperties);
this.persistUpgradeMessageState(true);
collapseMessage();
}
Logger.log('edx.bi.course.upgrade.sidebarupsell.displayed', logEventProperties);
$('.section-upgrade .btn-upgrade').click(() => {
Logger.log('edx.bi.course.upgrade.sidebarupsell.clicked', logEventProperties);
Logger.log('edx.course.enrollment.upgrade.clicked', { location: 'sidebar-message' });
});
$('.btn-upgrade', $vcMessage).click(() => {
Logger.log('edx.bi.course.upgrade.hero.clicked', logEventProperties);
Logger.log('edx.course.enrollment.upgrade.clicked', { location: 'hero' });
$('.promo-learn-more').click(() => {
$('.action-toggle-verification-sock').click();
$('.action-toggle-verification-sock')[0].scrollIntoView({ behavior: 'smooth', alignToTop: true });
});
}
}

View File

@@ -50,54 +50,21 @@ describe('Course Home factory', () => {
describe('Upgrade message events', () => {
const segmentEventProperties = {
promotion_id: 'courseware_verified_certificate_upsell',
creative: 'original_hero',
creative: 'sidebarupsell',
name: 'In-Course Verification Prompt',
position: 'hero',
position: 'sidebar-message',
};
it('should send events to Segment and edX on initial load', () => {
expect(window.analytics.track).toHaveBeenCalledWith('Promotion Viewed', segmentEventProperties);
expect(Logger.log).toHaveBeenCalledWith('edx.bi.course.upgrade.hero.displayed', { courseRunKey: runKey });
expect(Logger.log).toHaveBeenCalledWith('edx.bi.course.upgrade.sidebarupsell.displayed', { courseRunKey: runKey });
});
it('should send events to Segment and edX after clicking the upgrade button ', () => {
$('.vc-message .btn-upgrade').click();
$('.section-upgrade .btn-upgrade').click();
expect(window.analytics.track).toHaveBeenCalledWith('Promotion Viewed', segmentEventProperties);
expect(Logger.log).toHaveBeenCalledWith('edx.bi.course.upgrade.hero.clicked', { courseRunKey: runKey });
expect(Logger.log).toHaveBeenCalledWith('edx.course.enrollment.upgrade.clicked', { location: 'hero' });
});
});
describe('upgrade message display toggle', () => {
let $message;
let $toggle;
beforeEach(() => {
$.fx.off = true;
$message = $('.vc-message');
$toggle = $('.vc-toggle', $message);
expect($message.length).toEqual(1);
expect($toggle.length).toEqual(1);
});
it('hides/shows the message and writes/removes a key from local storage', () => {
// NOTE (CCB): Ideally this should be two tests--one for collapse, another for expansion.
// After a couple hours I have been unable to make these two tests pass, probably due to
// issues with the initial state of local storage.
expect($message.is(':visible')).toBeTruthy();
expect($message.hasClass('polite')).toBeFalsy();
expect($toggle.text().trim()).toEqual('Show less');
$toggle.click();
expect($message.hasClass('polite')).toBeTruthy();
expect($toggle.text().trim()).toEqual('Show more');
expect(window.localStorage.getItem(home.msgStateStorageKey)).toEqual('true');
$toggle.click();
expect($message.hasClass('polite')).toBeFalsy();
expect($toggle.text().trim()).toEqual('Show less');
expect(window.localStorage.getItem(home.msgStateStorageKey)).toBeNull();
expect(Logger.log).toHaveBeenCalledWith('edx.bi.course.upgrade.sidebarupsell.clicked', { courseRunKey: runKey });
expect(Logger.log).toHaveBeenCalledWith('edx.course.enrollment.upgrade.clicked', { location: 'sidebar-message' });
});
});
});

View File

@@ -58,40 +58,6 @@ from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, SHOW_REV
</header>
<div class="page-content">
<main class="page-content-main">
% if upgrade_url and upgrade_price:
<div class="section">
<div class="vc-message tex2jax_ignore" role="group" aria-labelledby="vc-title" tabindex="-1" style="display: none;">
<h3 class="vc-title vc-fade vc-polite-only">Pursue a verified certificate</h3>
<button class="vc-toggle vc-fade vc-polite-only btn-link" type="button" aria-controls="moreinfo"
aria-expanded="true" aria-label="${_("Show/Hide")}">
${_("Show less")}
</button>
<div class="vc-hero vc-fade">
<img src="${static.url('course_experience/images/verified-cert.png')}"
alt="${_("Sample verified certificate with your name, the course title, the logo of the institution and the signatures of the instructors for this course.")}"/>
</div>
<ul class="vc-selling-points vc-fade">
<li class="vc-selling-point">${_("Official proof of completion")}</li>
<li class="vc-selling-point">${_("Easily shareable certificate")}</li>
<li class="vc-selling-point">${_("Proven motivator to complete the course")}</li>
<li class="vc-selling-point">${_("Certificate purchases help us continue to offer free courses")}</li>
</ul>
<div class="vc-cta vc-fade vc-polite-only">
<a class="btn btn-upgrade"
href="${ upgrade_url }"
data-creative="hero_matthew_smith"
data-position="hero">${_("Upgrade ({price})").format(price=upgrade_price)}</a>
</div>
</div>
</div>
% endif
% if course_home_message_fragment:
${HTML(course_home_message_fragment.body_html())}
% endif
@@ -147,6 +113,23 @@ from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, SHOW_REV
</ul>
</div>
% endif
% if upgrade_url and upgrade_price:
<div class="section section-upgrade">
<h3 class="hd hd-6">${_("Pursue a verified certificate")}</h3>
<div class="upgrade-container">
<p>
<a class="btn-brand btn-upgrade"
href="${upgrade_url}"
data-creative="sidebarupsell"
data-position="sidebar-message">
${_("Upgrade ({price})").format(price=upgrade_price)}
</a>
</p>
<p><button class="btn-link btn-small promo-learn-more">${_('Learn More')}</button></p>
</div>
<img src="https://courses.edx.org/static/images/edx-verified-mini-cert.png" alt="">
</div>
% endif
% if dates_fragment:
<div class="section section-dates">
${HTML(dates_fragment.body_html())}

View File

@@ -512,15 +512,15 @@ class CourseHomeFragmentViewTests(ModuleStoreTestCase):
def assert_upgrade_message_not_displayed(self):
response = self.client.get(self.url)
self.assertNotIn('vc-message', response.content)
self.assertNotIn('section-upgrade', response.content)
def assert_upgrade_message_displayed(self):
response = self.client.get(self.url)
self.assertIn('vc-message', response.content)
self.assertIn('section-upgrade', response.content)
url = EcommerceService().get_checkout_page_url(self.verified_mode.sku)
self.assertIn('<a class="btn btn-upgrade"', response.content)
self.assertIn('<a class="btn-brand btn-upgrade"', response.content)
self.assertIn(url, response.content)
self.assertIn('Upgrade (${price})</a>'.format(price=self.verified_mode.min_price), response.content)
self.assertIn('Upgrade (${price})'.format(price=self.verified_mode.min_price), response.content)
def test_no_upgrade_message_if_logged_out(self):
self.client.logout()