feat: Remove upgrade sock from course pages (#556)

REV-2220: The upgrade sock is being removed from the remaining course pages in favor of the new Value Prop work.
This commit is contained in:
Brian Mesick
2021-07-30 12:55:09 -04:00
committed by GitHub
parent fae2396977
commit 8c41e182a2
8 changed files with 0 additions and 369 deletions

View File

@@ -13,7 +13,6 @@ import ContentTools from './content-tools';
import CourseBreadcrumbs from './CourseBreadcrumbs';
import NotificationTrigger from './NotificationTrigger';
import CourseSock from '../../generic/course-sock';
import { useModel } from '../../generic/model-store';
import useWindowSize, { responsiveBreakpoints } from '../../generic/tabs/useWindowSize';
@@ -39,10 +38,7 @@ function Course({
].filter(element => element != null).map(element => element.title);
const {
canShowUpgradeSock,
celebrations,
offer,
org,
verifiedMode,
} = course;
@@ -109,15 +105,6 @@ function Course({
open
/>
)}
{canShowUpgradeSock && (
<CourseSock
courseId={courseId}
offer={offer}
orgKey={org}
pageLocation="Course Content Page"
verifiedMode={verifiedMode}
/>
)}
<ContentTools course={course} />
{ /** [MM-P2P] Experiment */ }
{ MMP2P.meta.modalLock && <MMP2PBlockModal options={MMP2P} /> }

View File

@@ -79,14 +79,6 @@ describe('Course', () => {
expect(getByRole(celebrationModal, 'heading', { name: 'Congratulations!' })).toBeInTheDocument();
});
it('displays upgrade sock', async () => {
const courseMetadata = Factory.build('courseMetadata', { can_show_upgrade_sock: true });
const testStore = await initializeTestStore({ courseMetadata, excludeFetchSequence: true }, false);
render(<Course {...mockData} courseId={courseMetadata.id} />, { store: testStore });
expect(screen.getByRole('button', { name: 'Learn About Verified Certificates' })).toBeInTheDocument();
});
it('displays notification trigger and toggles active class on click', async () => {
useWindowSize.mockReturnValue({ width: 1200 });
render(<Course {...mockData} />);

View File

@@ -6,7 +6,6 @@ Factory.define('courseMetadata')
.extend(courseMetadataBase)
.option('host', '')
.attrs({
can_show_upgrade_sock: false,
content_type_gating_enabled: false,
course_expired_message: null,
end: null,

View File

@@ -1,262 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import { sendTrackEvent, sendTrackingLogEvent } from '@edx/frontend-platform/analytics';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import LearnerQuote1 from './assets/learner-quote.png';
import LearnerQuote2 from './assets/learner-quote2.png';
import { UpgradeButton } from '../upgrade-button';
import VerifiedCert from '../assets/edX_certificate.png';
export default class CourseSock extends Component {
constructor(props) {
super(props);
this.state = { showUpsell: false };
this.sockElement = React.createRef();
this.commonEventProperties = {
courserun_key: this.props.courseId,
org_key: this.props.orgKey,
};
this.promotionEventProperties = {
creative: 'original_sock',
name: 'In-Course Verification Prompt',
position: 'sock',
promotion_id: 'courseware_verified_certificate_upsell',
...this.commonEventProperties,
};
}
componentDidMount() {
sendTrackEvent('Promotion Viewed', this.promotionEventProperties);
}
handleClick = () => {
this.setState(state => ({
showUpsell: !state.showUpsell,
}));
const toggleLogEvent = this.state.showUpsell ? 'edx.bi.course.sock.toggle_opened'
: 'edx.bi.course.sock.toggle_closed';
sendTrackEvent(toggleLogEvent, {
from_page: this.props.pageLocation,
...this.commonEventProperties,
});
sendTrackEvent('Promotion Clicked', this.promotionEventProperties);
}
logClick = () => {
sendTrackingLogEvent('edx.course.enrollment.upgrade.clicked', {
location: 'sock',
...this.commonEventProperties,
});
const onCourseHome = this.props.pageLocation === 'Home Page';
sendTrackEvent('edx.bi.ecommerce.upsell_links_clicked', {
...this.commonEventProperties,
linkCategory: 'green_upgrade',
linkName: onCourseHome ? 'course_home_sock' : 'in_course_sock',
linkType: 'button',
pageName: onCourseHome ? 'course_home' : 'in_course',
});
}
showToUser = () => {
this.setState({
showUpsell: true,
}, () => {
if (this.sockElement.current) {
this.sockElement.current.scrollIntoView({ behavior: 'smooth' });
}
});
}
render() {
if (!this.props.verifiedMode) {
return null;
}
const buttonClass = this.state.showUpsell ? 'btn-primary' : 'btn-outline-primary';
return (
<div ref={this.sockElement} className="verification-sock container py-5">
<div className="d-flex justify-content-center">
<button type="button" aria-expanded="false" className={`btn ${buttonClass}`} onClick={this.handleClick}>
<FormattedMessage
id="coursesock.upsell.heading"
defaultMessage="Learn About Verified Certificates"
description="The heading for the upsell dialog"
/>
</button>
</div>
{this.state.showUpsell && (
<>
<h2 className="mt-3 mb-4">
<FormattedMessage
id="coursesock.upsell.verifiedcert"
defaultMessage="{siteName} Verified Certificate"
values={{
siteName: getConfig().SITE_NAME,
}}
/>
</h2>
<div className="row flex-row-reverse">
<div className="col-md-4 col-lg-6 d-flex flex-column">
<div>
<img alt="Example Certificate" src={VerifiedCert} className="d-block img-thumbnail mb-3 ml-md-auto" />
</div>
<div className="position-relative flex-grow-1 d-flex flex-column justify-content-end align-items-md-end">
<div style={{ position: 'sticky', bottom: '4rem' }}>
<UpgradeButton
size="lg"
offer={this.props.offer}
onClick={this.logClick}
verifiedMode={this.props.verifiedMode}
className="mb-3"
data-creative="original_sock"
data-position="sock"
/>
</div>
</div>
</div>
<div className="col-md-8 col-lg-6">
<h3 className="h5">
<FormattedMessage
id="coursesock.upsell.why"
defaultMessage="Why upgrade?"
/>
</h3>
<ul>
<li>
<FormattedMessage
id="coursesock.upsell.reason1"
defaultMessage="Official proof of completion"
/>
</li>
<li>
<FormattedMessage
id="coursesock.upsell.reason2"
defaultMessage="Easily shareable certificate"
/>
</li>
<li>
<FormattedMessage
id="coursesock.upsell.reason3"
defaultMessage="Proven motivator to complete the course"
/>
</li>
<li>
<FormattedMessage
id="coursesock.upsell.reason4"
defaultMessage="Certificate purchases help {siteName} continue to offer free courses"
values={{
siteName: getConfig().SITE_NAME,
}}
/>
</li>
</ul>
<h3 className="h5">
<FormattedMessage
id="coursesock.upsell.howtitle"
defaultMessage="How it works"
/>
</h3>
<ul>
<li>
<FormattedMessage
id="coursesock.upsell.how1"
defaultMessage="Pay the Verified Certificate upgrade fee"
/>
</li>
<li>
<FormattedMessage
id="coursesock.upsell.how2"
defaultMessage="Verify your identity with a webcam and government-issued ID"
/>
</li>
<li>
<FormattedMessage
id="coursesock.upsell.how3"
defaultMessage="Study hard and pass the course"
/>
</li>
<li>
<FormattedMessage
id="coursesock.upsell.how4"
defaultMessage="Share your certificate with friends, employers, and others"
/>
</li>
</ul>
<h3 className="h5">
<FormattedMessage
id="coursesock.upsell.storytitle"
defaultMessage="{siteName} Learner Stories"
values={{
siteName: getConfig().SITE_NAME,
}}
/>
</h3>
<div className="media my-3">
<img className="mr-3" style={{ maxWidth: '4rem' }} alt="Christina Fong" src={LearnerQuote1} />
<div className="media-body">
<FormattedMessage
id="coursesock.upsell.story1"
defaultMessage="My certificate has helped me showcase my knowledge on my
resume - I feel like this certificate could really help me land
my dream job!"
/>
<p className="font-weight-bold">
&mdash; <FormattedMessage
id="coursesock.upsell.learner"
description="Name of learner"
defaultMessage="{name}, {siteName} Learner"
values={{
name: 'Christina Fong',
siteName: getConfig().SITE_NAME,
}}
/>
</p>
</div>
</div>
<div className="media my-3">
<img className="mr-3" style={{ maxWidth: '4rem' }} alt="Chery Troell" src={LearnerQuote2} />
<div className="media-body">
<FormattedMessage
id="coursesock.upsell.story2"
defaultMessage="I wanted to include a verified certificate on my resume and my profile to
illustrate that I am working towards this goal I have and that I have
achieved something while I was unemployed."
/>
<p className="font-weight-bold">
&mdash; <FormattedMessage
id="coursesock.upsell.learner"
description="Name of learner"
defaultMessage="{name}, {siteName} Learner"
values={{
name: 'Cheryl Troell',
siteName: getConfig().SITE_NAME,
}}
/>
</p>
</div>
</div>
</div>
</div>
</>
)}
</div>
);
}
}
CourseSock.defaultProps = {
courseId: null,
offer: null,
orgKey: null,
};
CourseSock.propTypes = {
courseId: PropTypes.string,
offer: PropTypes.shape({}),
orgKey: PropTypes.string,
pageLocation: PropTypes.string.isRequired,
verifiedMode: PropTypes.shape({}).isRequired,
};

View File

@@ -1,82 +0,0 @@
import React from 'react';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import {
render, screen, fireEvent, initializeMockApp, initializeTestStore,
} from '../../setupTest';
import CourseSock from './CourseSock';
jest.mock('@edx/frontend-platform/analytics');
describe('Course Sock', () => {
let store;
const mockData = {
verifiedMode: {
upgradeUrl: 'test-url',
price: 1234,
currency: 'dollars',
currencySymbol: '$',
},
pageLocation: 'Course Content Page',
};
beforeAll(async () => {
// We need to mock AuthService to implicitly use `getAuthenticatedUser` within `AppContext.Provider`.
await initializeMockApp();
store = await initializeTestStore();
const { courseware } = store.getState();
mockData.courseId = courseware.courseId;
});
it('hides upsell information on load', () => {
render(<CourseSock {...mockData} />);
expect(screen.getByRole('button', { name: 'Learn About Verified Certificates' })).toBeInTheDocument();
expect(screen.queryByText('edX Verified Certificate')).not.toBeInTheDocument();
});
it.only('handles click', () => {
sendTrackEvent.mockClear();
render(<CourseSock {...mockData} />);
const learnMoreButton = screen.getByRole('button', { name: 'Learn About Verified Certificates' });
fireEvent.click(learnMoreButton);
expect(screen.getByText('edX Verified Certificate')).toBeInTheDocument();
const { currencySymbol, price } = mockData.verifiedMode;
const upsellButton = screen.getByText(`Upgrade for ${currencySymbol}${price}`);
expect(upsellButton).toBeInTheDocument();
fireEvent.click(upsellButton);
expect(sendTrackEvent).toHaveBeenCalledTimes(4);
expect(sendTrackEvent).toHaveBeenCalledWith('Promotion Viewed', {
courserun_key: 'course-v1:edX+DemoX+Demo_Course_1',
creative: 'original_sock',
name: 'In-Course Verification Prompt',
org_key: null,
position: 'sock',
promotion_id: 'courseware_verified_certificate_upsell',
});
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.course.sock.toggle_closed', {
courserun_key: 'course-v1:edX+DemoX+Demo_Course_1',
from_page: 'Course Content Page',
org_key: null,
});
expect(sendTrackEvent).toHaveBeenCalledWith('Promotion Clicked', {
courserun_key: 'course-v1:edX+DemoX+Demo_Course_1',
creative: 'original_sock',
name: 'In-Course Verification Prompt',
org_key: null,
position: 'sock',
promotion_id: 'courseware_verified_certificate_upsell',
});
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.ecommerce.upsell_links_clicked', {
org_key: null,
courserun_key: mockData.courseId,
linkCategory: 'green_upgrade',
linkName: 'in_course_sock',
linkType: 'button',
pageName: 'in_course',
});
fireEvent.click(learnMoreButton);
expect(screen.queryByText('edX Verified Certificate')).not.toBeInTheDocument();
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -1,3 +0,0 @@
import CourseSock from './CourseSock';
export default CourseSock;