Commit 97d76337 by Albert St. Aubin

Added upgrade upsell to course info banner and url parameter

TNL-6381
parent f3085378
......@@ -191,7 +191,6 @@ $btn-border-radius: $component-border-radius !default;
$btn-large-padding-vertical: spacing-vertical(small);
$btn-large-padding-horizontal: spacing-horizontal(mid-large);
$btn-base-padding-vertical: spacing-vertical(x-small);
$btn-base-padding-horizontal: spacing-horizontal(base);
$btn-base-font-size: font-size(base);
......
......@@ -45,6 +45,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
days_till_upgrade_deadline=4,
enroll_user=True,
enrollment_mode=CourseMode.VERIFIED,
user_enrollment_mode=None,
course_min_price=100,
days_till_verification_deadline=14,
verification_status=None,
......@@ -72,6 +73,9 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
)
if enroll_user:
if user_enrollment_mode:
CourseEnrollmentFactory.create(course_id=self.course.id, user=self.user, mode=user_enrollment_mode)
else:
enrollment_mode = enrollment_mode or CourseMode.DEFAULT_MODE_SLUG
CourseEnrollmentFactory.create(course_id=self.course.id, user=self.user, mode=enrollment_mode)
......@@ -274,18 +278,64 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
)
self.assertEqual(block.title, 'Course End')
## Tests Verified Upgrade Deadline Date Block
# Tests Verified Upgrade Deadline Date Block
def check_upgrade_banner(self, banner_expected=True, include_url_parameter=True):
"""
Helper method to check for the presence of the Upgrade Banner
"""
url = reverse('info', args=[self.course.id.to_deprecated_string()])
if include_url_parameter:
url += '?upgrade=true'
resp = self.client.get(url)
expected_banner_text = "Give yourself an additional incentive to complete"
if banner_expected:
self.assertIn(expected_banner_text, resp.content)
else:
self.assertNotIn(expected_banner_text, resp.content)
@freeze_time('2015-01-02')
def test_verified_upgrade_deadline_date(self):
self.setup_course_and_user(days_till_upgrade_deadline=1)
self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT)
self.client.login(username='mrrobot', password='test')
block = VerifiedUpgradeDeadlineDate(self.course, self.user)
self.assertEqual(block.date, datetime.now(utc) + timedelta(days=1))
self.assertTrue(block.is_enabled)
self.assertEqual(block.link, reverse('verify_student_upgrade_and_verify', args=(self.course.id,)))
self.check_upgrade_banner()
def test_without_upgrade_deadline(self):
self.setup_course_and_user(enrollment_mode=None)
self.client.login(username='mrrobot', password='test')
block = VerifiedUpgradeDeadlineDate(self.course, self.user)
self.assertFalse(block.is_enabled)
self.assertIsNone(block.date)
self.check_upgrade_banner(banner_expected=False)
@freeze_time('2015-01-02')
def test_verified_upgrade_banner_not_present_past_deadline(self):
self.setup_course_and_user(days_till_upgrade_deadline=-1, user_enrollment_mode=CourseMode.AUDIT)
self.client.login(username='mrrobot', password='test')
block = VerifiedUpgradeDeadlineDate(self.course, self.user)
self.assertFalse(block.is_enabled)
self.check_upgrade_banner(banner_expected=False)
@freeze_time('2015-01-02')
def test_verified_upgrade_banner_cookie(self):
self.setup_course_and_user(days_till_upgrade_deadline=1, user_enrollment_mode=CourseMode.AUDIT)
self.client.login(username='mrrobot', password='test')
# No URL parameter or cookie present, notification should not be shown.
self.check_upgrade_banner(include_url_parameter=False, banner_expected=False)
# Now pass URL parameter-- notification should be shown.
self.check_upgrade_banner(include_url_parameter=True)
# A cookie should be set in the previous call, so it is no longer necessary to pass
# the URL parameter in order to see the notification.
self.check_upgrade_banner(include_url_parameter=False)
# Unfortunately (according to django doc), it is not possible to test expiration of the cookie.
def test_ecommerce_checkout_redirect(self):
"""Verify the block link redirects to ecommerce checkout if it's enabled."""
......
......@@ -65,6 +65,7 @@ from courseware.courses import (
sort_by_start_date,
UserNotEnrolled
)
from courseware.date_summary import VerifiedUpgradeDeadlineDate
from courseware.masquerade import setup_masquerade
from courseware.model_data import FieldDataCache
from courseware.models import StudentModule, BaseStudentModuleHistory
......@@ -337,6 +338,22 @@ def course_info(request, course_id):
if settings.FEATURES.get('ENABLE_MKTG_SITE'):
url_to_enroll = marketing_link('COURSES')
store_upgrade_cookie = False
upgrade_cookie_name = 'show_upgrade_notification'
upgrade_link = None
if request.user.is_authenticated():
show_upgrade_notification = False
if request.GET.get('upgrade', 'false') == 'true':
store_upgrade_cookie = True
show_upgrade_notification = True
elif upgrade_cookie_name in request.COOKIES and bool(request.COOKIES[upgrade_cookie_name]):
show_upgrade_notification = True
if show_upgrade_notification:
upgrade_data = VerifiedUpgradeDeadlineDate(course, user)
if upgrade_data.is_enabled:
upgrade_link = upgrade_data.link
context = {
'request': request,
'masquerade_user': user,
......@@ -348,6 +365,7 @@ def course_info(request, course_id):
'studio_url': studio_url,
'show_enroll_banner': show_enroll_banner,
'url_to_enroll': url_to_enroll,
'upgrade_link': upgrade_link
}
# Get the URL of the user's last position in order to display the 'where you were last' message
......@@ -365,7 +383,17 @@ def course_info(request, course_id):
if CourseEnrollment.is_enrolled(request.user, course.id):
inject_coursetalk_keys_into_context(context, course_key)
return render_to_response('courseware/info.html', context)
response = render_to_response('courseware/info.html', context)
if store_upgrade_cookie:
response.set_cookie(
upgrade_cookie_name,
True,
max_age=10 * 24 * 60 * 60, # set for 10 days
domain=settings.SESSION_COOKIE_DOMAIN,
httponly=True # no use case for accessing from JavaScript
)
return response
def get_last_accessed_courseware(course, request, user):
......
......@@ -9,7 +9,13 @@
});
});
$('.date-summary-verified-upgrade-deadline .date-summary-link').on('click', function() {
Logger.log('edx.course.home.upgrade_verified.clicked', {});
Logger.log('edx.course.home.upgrade_verified.clicked', {location: 'sidebar'});
});
$('.upgrade-banner-button').on('click', function() {
Logger.log('edx.course.home.upgrade_verified.clicked', {location: 'notification'});
});
$('.view-verified-info').on('click', function() {
Logger.log('edx.course.home.learn_about_verified.clicked', {location: 'notification'});
});
};
});
......
<div class="upgrade-banner">
<div class="notification-color-border"></div>
<div class="notification-content">
<div class="upgrade-icon">
<img src="${STATIC_URL}images/edx-verified-mini-cert.png">
</div>
<div class="upgrade-msg">
<h4 class="upgrade-msg">Give yourself an additional incentive to complete</h4>
<p class="view-verified-info">Earn a verified certificate
<a href="https://www.edx.org/verified-certificate" target="_blank">Learn More</a>
</p>
</div>
<div class="upgrade-banner-button">
<a href="/verify_student/upgrade/course-v1:Test+TestX+2015" class="btn-upgrade">Upgrade Now</a>
</div>
</div>
</div>
<div class="date-summary-container">
<div class="date-summary date-summary-verified-upgrade-deadline">
<h3 class="heading">Verification Upgrade Deadline</h3>
......
......@@ -17,9 +17,23 @@ define(['jquery', 'logger', 'js/courseware/course_home_events'], function($, Log
});
});
it('sends an event when "Upgrade to Verified" is clicked', function() {
it('sends an event when "Upgrade to Verified" is clicked from the sidebar', function() {
$('.date-summary-link').click();
expect(Logger.log).toHaveBeenCalledWith('edx.course.home.upgrade_verified.clicked', {});
expect(Logger.log).toHaveBeenCalledWith('edx.course.home.upgrade_verified.clicked', {location: 'sidebar'});
});
it('sends an event when "Upgrade Now" is clicked from the upsell notification', function() {
$('.upgrade-banner-button').click();
expect(Logger.log).toHaveBeenCalledWith(
'edx.course.home.upgrade_verified.clicked', {location: 'notification'}
);
});
it('sends an event when "Learn More" is clicked from the upsell notification', function() {
$('.view-verified-info').click();
expect(Logger.log).toHaveBeenCalledWith(
'edx.course.home.learn_about_verified.clicked', {location: 'notification'}
);
});
});
});
// Upgrade button
$btn-upgrade-border-color: $uxpl-green-base !default;
$btn-upgrade-background: $uxpl-green-base !default;
$btn-upgrade-color: #fcfcfc !default;
$btn-upgrade-focus-color: $btn-upgrade-color !default;
$btn-upgrade-focus-border-color: rgb(0, 155, 0) !default;
$btn-upgrade-focus-background: rgb(0, 155, 0) !default;
$btn-upgrade-active-border-color: $uxpl-green-base !default;
$btn-upgrade-active-background: $uxpl-green-base !default;
//// Notifications
// Upgrade
$notification-highlight-border-color: $uxpl-green-base !default;
$lms-border-color: $uxpl-gray-background !default;
$notification-background: rgb(255, 255, 255) !default
.home {
@include clearfix();
max-width: 1140px;
......@@ -56,6 +73,110 @@ div.info-wrapper {
font-style: normal;
}
div.upgrade-banner {
// This banner uses the Pattern Library's defined variables
@include border-left(0px);
border: 1px solid $lms-border-color;
width: 100%;
display: table;
.notification-color-border {
width: 6px; //Value defined by UX team
min-height: 100%;
margin: 0;
display: table-cell;
background: $notification-highlight-border-color;
}
.notification-content {
display: inline-flex;
align-items: center;
align-content: flex-start;
flex-flow: row wrap;
background: $notification-background;
width: 100%;
padding: $baseline/2 0;
margin-bottom: 0;
justify-content: space-between;
.upgrade-icon {
margin: 0;
padding: $baseline/2 $baseline;
flex-flow: row nowrap;
align-items: center;
// flex: grow, shrink, base
// The 7 was the value that allowed the icon image to grow to the UX
// desired size.
flex: 7 1 50px;
// The following dimensions were added so that the
// icon will adjust as the notification is adjusted
// but will not be smaller or larger than UX requirements.
min-height: 50px;
min-width: 80px;
max-height: 90px;
max-width: 130px;
img {
min-height: 50px;
min-width: 80px;
}
}
.upgrade-msg {
flex: 5 1 60%; //This percentage was required to get the text
// in the message to wrap when collapsed.
flex-direction: column;
margin: 0;
padding: $baseline/2 0;
.msg-title {
font-weight: font-weight(semi-bold);
font-size: font-size(large);
line-height: $base-line-height;
}
.view-verified-info {
margin-top: $baseline/4;
font-weight: font-weight(normal);
font-size: font-size(base);
}
a:link, a:hover, a:visited, a:active {
text-decoration: underline !important;
}
}
.upgrade-banner-button {
@include margin(0, 0, 0, auto);
padding: $baseline/2 $baseline;
}
.btn-upgrade {
@extend %btn-shims;
border-color: $btn-upgrade-border-color;
background: $btn-upgrade-background;
color: $btn-upgrade-color;
// STATE: hover and focus
&:hover,
&.is-hovered,
&:focus,
&.is-focused {
border-color: $btn-upgrade-focus-border-color;
background-color: $btn-upgrade-focus-background;
color: $btn-upgrade-focus-color;
}
// STATE: is disabled
&:disabled,
&.is-disabled {
border-color: $btn-disabled-border-color;
background: $btn-brand-disabled-background;
color: $btn-upgrade-color;
}
}
}
}
> p {
margin-bottom: lh();
}
......
......@@ -81,6 +81,26 @@ from openedx.core.djangolib.markup import HTML, Text
</div>
% endif
% if upgrade_link:
<div class="upgrade-banner">
<div class="notification-color-border"></div>
<div class="notification-content">
<div class="upgrade-icon">
<img src="${STATIC_URL}images/edx-verified-mini-cert.png">
</div>
<div class="upgrade-msg">
<h4 class="msg-title">${_("Give yourself an additional incentive to complete")}</h4>
<p class="view-verified-info">${_("Earn a verified certificate.")}
<a href="https://www.edx.org/verified-certificate" target="_blank">${_("Learn More")}</a>
</p>
</div>
<div class="upgrade-banner-button">
<a href="${upgrade_link}" class="btn-upgrade">${_("Upgrade Now")}</a>
</div>
</div>
</div>
% endif
<h4>${_("Course Updates and News")}</h4>
${HTML(get_course_info_section(request, masquerade_user, course, 'updates'))}
......
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