Compare commits

...

10 Commits

Author SHA1 Message Date
Adam Butterworth
abe3d03f58 fix: update snapshot to reflect new ids 2019-03-08 12:44:00 -05:00
Adam Butterworth
7af4b71faa fix: add unique ids to Icon components 2019-03-08 12:35:35 -05:00
Robert Raposa
7f2c5b32b1 Merge pull request #7 from edx/robrap/update-readme
Update README.rst
2019-03-08 09:44:26 -05:00
Robert Raposa
6e0f9cf30a fix(docs): update README.rst
Add a note to clarify that this component is not really
a flexible site footer at this time.
2019-03-06 09:36:43 -05:00
Robert Raposa
3dc70a890f Merge pull request #6 from edx/robrap/ARCH-378-add-test
fix(analytics): add test and fix youtube
2019-01-22 16:26:43 -05:00
Robert Raposa
a37ef7f701 fix(analytics): add test and fix youtube
Adds unit testing and fixes analytics for youtube.
2019-01-22 16:18:14 -05:00
Robert Raposa
a19c762cf7 Merge pull request #5 from edx/robrap/ARCH-378-add-events
feat(analytics): add trackEvent for external links
2019-01-22 13:49:42 -05:00
Robert Raposa
045e28d0ef feat(analytics): add track events for links
- Add required prop for handleAllTrackEvents.
- Add EVENT_NAMES to help support event overrides.

BREAKING CHANGE: New required prop handleAllTrackEvents.
2019-01-22 11:37:37 -05:00
Robert Raposa
e39ac1ca43 Merge pull request #4 from edx/robrap/README-to-rst
Convert README to rst.
2019-01-16 16:51:08 -05:00
Robert Raposa
2ed1a1aa8c Convert README to rst.
Used pandoc to automate file format conversion.
2019-01-15 11:43:49 -05:00
8 changed files with 270 additions and 138 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
coverage
dist
node_modules
.idea/

View File

@@ -1,33 +0,0 @@
# frontend-component-footer
[![Build Status](https://api.travis-ci.org/edx/frontend-component-footer.svg?branch=master)](https://travis-ci.org/edx/frontend-component-footer) [![Coveralls](https://img.shields.io/coveralls/edx/frontend-component-footer.svg?branch=master)](https://coveralls.io/github/edx/frontend-component-footer)
[![npm_version](https://img.shields.io/npm/v/@edx/frontend-component-footer.svg)](@edx/frontend-component-footer)
[![npm_downloads](https://img.shields.io/npm/dt/@edx/frontend-component-footer.svg)](@edx/frontend-component-footer)
[![license](https://img.shields.io/npm/l/@edx/frontend-component-footer.svg)](@edx/frontend-component-footer)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
frontend-component-footer is a library containing a site footer component for use when building edX frontend applications.
## Usage
To install frontend-component-footer into your project:
```
npm i --save @edx/frontend-component-footer
```
The component expects properties specifying the various URLs that are linked in the footer. See the
sample app in src/index.jsx for an example of how the SiteFooter component can be specified.
## Development
Start the dev server
```
npm i && npm start
```
Build the component.
```
npm run build
```

46
README.rst Normal file
View File

@@ -0,0 +1,46 @@
frontend-component-footer
=========================
|Build Status| |Coveralls| |npm_version| |npm_downloads| |license|
|semantic-release|
frontend-component-footer is a library containing a site footer
component for use when building edX frontend applications.
At this time, this componenet is hard-coded to match the legacy LMS site footer, including all of its links.
Note: As implemented, it should really be called the ``frontend-component-lms-footer``.
Usage
-----
To install frontend-component-footer into your project::
npm i --save @edx/frontend-component-footer
The component expects properties specifying the various URLs that are
linked in the footer. See the sample app in src/index.jsx for an example
of how the SiteFooter component can be specified.
Development
-----------
Start the dev server::
npm i && npm start
Build the component::
npm run build
.. |Build Status| image:: https://api.travis-ci.org/edx/frontend-component-footer.svg?branch=master
:target: https://travis-ci.org/edx/frontend-component-footer
.. |Coveralls| image:: https://img.shields.io/coveralls/edx/frontend-component-footer.svg?branch=master
:target: https://coveralls.io/github/edx/frontend-component-footer
.. |npm_version| image:: https://img.shields.io/npm/v/@edx/frontend-component-footer.svg
:target: @edx/frontend-component-footer
.. |npm_downloads| image:: https://img.shields.io/npm/dt/@edx/frontend-component-footer.svg
:target: @edx/frontend-component-footer
.. |license| image:: https://img.shields.io/npm/l/@edx/frontend-component-footer.svg
:target: @edx/frontend-component-footer
.. |semantic-release| image:: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
:target: https://github.com/semantic-release/semantic-release

16
package-lock.json generated
View File

@@ -21666,6 +21666,16 @@
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
}
},
"watch": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz",
"integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=",
"dev": true,
"requires": {
"exec-sh": "^0.2.0",
"minimist": "^1.2.0"
}
}
}
},
@@ -24627,9 +24637,9 @@
}
},
"watch": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz",
"integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz",
"integrity": "sha1-NApxe952Vyb6CqB9ch4BR6VR3ww=",
"dev": true,
"requires": {
"exec-sh": "^0.2.0",

View File

@@ -19,7 +19,8 @@
"start": "NODE_ENV=development BABEL_ENV=development node_modules/.bin/webpack-dev-server --config=config/webpack.dev.config.js --progress",
"test": "jest --coverage",
"snapshot": "jest --updateSnapshot",
"travis-deploy-once": "travis-deploy-once"
"travis-deploy-once": "travis-deploy-once",
"watch": "watch 'npm run build' ./src"
},
"repository": {
"type": "git",
@@ -68,6 +69,7 @@
"source-map-loader": "^0.2.1",
"style-loader": "^0.20.2",
"travis-deploy-once": "^5.0.0",
"watch": "^1.0.2",
"webpack": "^4.19.1",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.9",
@@ -76,7 +78,6 @@
"peerDependencies": {
"@edx/paragon": "^3.8.0",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.6.0",
"html-webpack-plugin": "^3.2.0",
"prop-types": "^15.5.10",
"react": "^16.4.2",

View File

@@ -1,81 +1,112 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { mount } from 'enzyme';
import FooterLogo from '../../../edx-footer.png';
import SiteFooter from '../../index';
import SiteFooter, { EVENT_NAMES } from './index';
const completeSiteFooterComponent = mockHandleAllTrackEvents =>
(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
handleAllTrackEvents={mockHandleAllTrackEvents}
/>);
describe('<SiteFooter />', () => {
it('renders correctly', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
/>)
.toJSON();
expect(tree).toMatchSnapshot();
describe('renders correctly', () => {
it('renders with social and mobile links', () => {
const mockHandleAllTrackEvents = jest.fn();
const tree = renderer
.create(completeSiteFooterComponent(mockHandleAllTrackEvents))
.toJSON();
expect(tree).toMatchSnapshot();
});
it('does not render social links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
handleAllTrackEvents={jest.fn()}
showSocialLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
});
it('does not render mobile links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
handleAllTrackEvents={jest.fn()}
showMobileLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
});
});
it('does not render social links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
showSocialLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
});
describe('handles analytics', () => {
it('calls handleAllTrackEvents prop when external links clicked', () => {
const mockHandleAllTrackEvents = jest.fn();
const footer = mount((completeSiteFooterComponent(mockHandleAllTrackEvents)));
const externalLinks = footer.find("a[target='_blank']");
it('does not render mobile links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
showMobileLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
expect(externalLinks).toHaveLength(8);
externalLinks.forEach((externalLink) => {
const callIndex = mockHandleAllTrackEvents.mock.calls.length;
externalLink.simulate('click');
expect(mockHandleAllTrackEvents.mock.calls[callIndex]).toEqual([
EVENT_NAMES.FOOTER_LINK,
{
category: 'outbound_link',
label: externalLink.prop('href'),
},
]);
});
});
});
});

View File

@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<SiteFooter /> does not render mobile links 1`] = `
exports[`<SiteFooter /> renders correctly does not render mobile links 1`] = `
<footer
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
@@ -180,6 +180,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<li>
<a
href="https://www.facebook.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Facebook"
@@ -187,7 +188,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-facebook-square fa-2x"
id="Icon1"
id="edx-footer-icon-facebook"
/>
<span
className="sr-only"
@@ -199,6 +200,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<li>
<a
href="https://www.twitter.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Twitter"
@@ -206,7 +208,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-twitter-square fa-2x"
id="Icon1"
id="edx-footer-icon-twitter"
/>
<span
className="sr-only"
@@ -218,6 +220,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<li>
<a
href="https://www.youtube.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Youtube"
@@ -225,7 +228,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-youtube-square fa-2x"
id="Icon1"
id="edx-footer-icon-youtube"
/>
<span
className="sr-only"
@@ -237,6 +240,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<li>
<a
href="https://www.linkedin.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="LinkedIn"
@@ -244,7 +248,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-linkedin-square fa-2x"
id="Icon1"
id="edx-footer-icon-linkedin"
/>
<span
className="sr-only"
@@ -256,6 +260,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<li>
<a
href="https://plus.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Google+"
@@ -263,7 +268,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-google-plus-square fa-2x"
id="Icon1"
id="edx-footer-icon-google"
/>
<span
className="sr-only"
@@ -275,6 +280,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<li>
<a
href="https://reddit.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Reddit"
@@ -306,7 +312,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
</footer>
`;
exports[`<SiteFooter /> does not render social links 1`] = `
exports[`<SiteFooter /> renders correctly does not render social links 1`] = `
<footer
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
@@ -486,6 +492,7 @@ exports[`<SiteFooter /> does not render social links 1`] = `
<li>
<a
href="https://store.apple.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
@@ -499,6 +506,7 @@ exports[`<SiteFooter /> does not render social links 1`] = `
<li>
<a
href="https://play.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
@@ -524,7 +532,7 @@ exports[`<SiteFooter /> does not render social links 1`] = `
</footer>
`;
exports[`<SiteFooter /> renders correctly 1`] = `
exports[`<SiteFooter /> renders correctly renders with social and mobile links 1`] = `
<footer
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
@@ -704,6 +712,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://www.facebook.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Facebook"
@@ -711,7 +720,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-facebook-square fa-2x"
id="Icon1"
id="edx-footer-icon-facebook"
/>
<span
className="sr-only"
@@ -723,6 +732,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://www.twitter.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Twitter"
@@ -730,7 +740,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-twitter-square fa-2x"
id="Icon1"
id="edx-footer-icon-twitter"
/>
<span
className="sr-only"
@@ -742,6 +752,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://www.youtube.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Youtube"
@@ -749,7 +760,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-youtube-square fa-2x"
id="Icon1"
id="edx-footer-icon-youtube"
/>
<span
className="sr-only"
@@ -761,6 +772,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://www.linkedin.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="LinkedIn"
@@ -768,7 +780,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-linkedin-square fa-2x"
id="Icon1"
id="edx-footer-icon-linkedin"
/>
<span
className="sr-only"
@@ -780,6 +792,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://plus.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Google+"
@@ -787,7 +800,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-google-plus-square fa-2x"
id="Icon1"
id="edx-footer-icon-google"
/>
<span
className="sr-only"
@@ -799,6 +812,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://reddit.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Reddit"
@@ -822,6 +836,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://store.apple.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
@@ -835,6 +850,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://play.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>

View File

@@ -2,7 +2,26 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Hyperlink, Icon } from '@edx/paragon';
const EVENT_NAMES = {
FOOTER_LINK: 'edx.bi.footer.link',
};
class SiteFooter extends React.Component {
constructor(props) {
super(props);
this.externalLinkClickHandler = this.externalLinkClickHandler.bind(this);
}
externalLinkClickHandler(event) {
const label = event.currentTarget.getAttribute('href');
const eventName = EVENT_NAMES.FOOTER_LINK;
const properties = {
category: 'outbound_link',
label,
};
this.props.handleAllTrackEvents(eventName, properties);
}
renderSiteLogo() {
return (
<img src={this.props.siteLogo} alt={`${this.props.siteName} logo`} />
@@ -33,32 +52,70 @@ class SiteFooter extends React.Component {
{/* TODO: Use Paragon HyperLink with Icon. */}
{/* Would need to add rel to paragon if we still need it. */}
<li>
<a href={facebookUrl} title="Facebook" rel="noopener noreferrer" target="_blank">
<Icon className={['fa', 'fa-facebook-square', 'fa-2x']} screenReaderText={`Like ${siteName} on Facebook`} />
<a
href={facebookUrl}
title="Facebook"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon id="edx-footer-icon-facebook" className={['fa', 'fa-facebook-square', 'fa-2x']} screenReaderText={`Like ${siteName} on Facebook`} />
</a>
</li>
<li>
<a
href={twitterUrl}
title="Twitter"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon id="edx-footer-icon-twitter" className={['fa', 'fa-twitter-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Twitter`} />
</a>
</li>
<li>
<a href={twitterUrl} title="Twitter" rel="noopener noreferrer" target="_blank">
<Icon className={['fa', 'fa-twitter-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Twitter`} />
<a
href={youTubeUrl}
title="Youtube"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon id="edx-footer-icon-youtube" className={['fa', 'fa-youtube-square', 'fa-2x']} screenReaderText={`Subscribe to the ${siteName} YouTube channel`} />
</a>
</li>
<li>
<a href={youTubeUrl} title="Youtube" rel="noopener noreferrer" target="_blank">
<Icon className={['fa', 'fa-youtube-square', 'fa-2x']} screenReaderText={`Subscribe to the ${siteName} YouTube channel`} />
<a
href={linkedInUrl}
title="LinkedIn"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon id="edx-footer-icon-linkedin" className={['fa', 'fa-linkedin-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on LinkedIn`} />
</a>
</li>
<li>
<a href={linkedInUrl} title="LinkedIn" rel="noopener noreferrer" target="_blank">
<Icon className={['fa', 'fa-linkedin-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on LinkedIn`} />
<a
href={googlePlusUrl}
title="Google+"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon id="edx-footer-icon-google" className={['fa', 'fa-google-plus-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Google+`} />
</a>
</li>
<li>
<a href={googlePlusUrl} title="Google+" rel="noopener noreferrer" target="_blank">
<Icon className={['fa', 'fa-google-plus-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Google+`} />
</a>
</li>
<li>
<a href={redditUrl} title="Reddit" rel="noopener noreferrer" target="_blank">
<a
href={redditUrl}
title="Reddit"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-reddit-square', 'fa-2x']} screenReaderText={`Subscribe to the ${siteName} subreddit`} />
</a>
</li>
@@ -80,7 +137,7 @@ class SiteFooter extends React.Component {
mobileLinks = (
<ul className="d-flex flex-row justify-content-between list-unstyled max-width-264 p-0 mb-5">
<li>
<a href={appleAppStoreUrl} rel="noopener noreferrer" target="_blank">
<a href={appleAppStoreUrl} rel="noopener noreferrer" target="_blank" onClick={this.externalLinkClickHandler}>
<img
className="max-height-39"
alt={`Download the ${siteName} mobile app from the Apple App Store`}
@@ -89,7 +146,7 @@ class SiteFooter extends React.Component {
</a>
</li>
<li>
<a href={googlePlayUrl} rel="noopener noreferrer" target="_blank">
<a href={googlePlayUrl} rel="noopener noreferrer" target="_blank" onClick={this.externalLinkClickHandler}>
<img
className="max-height-39"
alt={`Download the ${siteName} mobile app from Google Play`}
@@ -136,7 +193,7 @@ class SiteFooter extends React.Component {
<div className="area-3">
<h2>Legal</h2>
<ul className="list-unstyled p-0 m-0">
<li><a href={termsOfServiceUrl}>Terms of Service &amp; Honor Code</a></li>
<li><a href={termsOfServiceUrl}>Terms of Service & Honor Code</a></li>
<li><a href={privacyPolicyUrl}>Privacy Policy</a></li>
<li><a href={this.renderMarketingSiteUrl('/accessibility')}>Accessibility Policy</a></li>
<li><a href={this.renderMarketingSiteUrl('/trademarks')}>Trademark Policy</a></li>
@@ -188,6 +245,7 @@ SiteFooter.propTypes = {
showMobileLinks: PropTypes.bool,
appleAppStoreUrl: PropTypes.string,
googlePlayUrl: PropTypes.string,
handleAllTrackEvents: PropTypes.func.isRequired,
};
SiteFooter.defaultProps = {
@@ -212,3 +270,4 @@ SiteFooter.defaultProps = {
};
export default SiteFooter;
export { EVENT_NAMES };