Compare commits

..

37 Commits

Author SHA1 Message Date
AlasdairSwan
5aae6e8336 Merge pull request #26 from edx/alasdair/version-bump
fix(version): trivial update to minor version bump
2019-05-07 12:12:33 -04:00
AlasdairSwan
ae18ad45b9 fix(version): trivial update to minor version bump 2019-05-07 11:56:32 -04:00
AlasdairSwan
0e15bb7e55 Merge pull request #24 from edx/alasdair/revert-social-media-links
Revert social media links PR
2019-05-07 11:30:02 -04:00
AlasdairSwan
ff664b9d3b Revert social media links PR 2019-05-07 11:24:04 -04:00
AlasdairSwan
da91fb6392 Merge pull request #23 from edx/alasdair/fontawesome-svg-and-social-link-array-prop
fix(sociallinks): array for social props BREAKING CHANGE: props change
2019-05-07 10:29:25 -04:00
AlasdairSwan
f265c7daa6 fix(sociallinks): array for social props BREAKING CHANGE: props change 2019-05-06 15:08:50 -04:00
albemarle
3037e4d8a6 Merge pull request #22 from edx/albemarle/i18n-travis
build: validate i18n
2019-05-06 10:20:20 -04:00
albemarle
b2a7696c0e build: validate i18n 2019-05-03 15:32:30 -04:00
albemarle
6dc8f64ccb Merge pull request #19 from edx/albemarle/more-i18n
fix(i18n): use up-to-date i18n-concat.js
2019-04-09 15:46:31 -04:00
albemarle
0453d7fbaa fix(i18n): use up-to-date i18n-concat.js 2019-04-09 15:38:46 -04:00
Robert Raposa
fa6d38f422 Merge pull request #18 from edx/albemarle/check-changes
fix(i18n): add detect_changed_source_translations target to stop jobs erroring
2019-04-05 16:52:44 -04:00
albemarle
9f3e945d4e fix(i18n): add detect_changed_source_translations target to stop jobs erroring 2019-04-05 16:42:50 -04:00
edX Transifex Bot
429d19291d fix(i18n): update translations 2019-04-05 16:21:24 -04:00
Matt Tuchfarber
e27bc8de39 Merge pull request #16 from edx/tuchfarber/remove_translation_fail
fix: remove incorrect translation files
2019-04-05 15:38:56 -04:00
Matt Tuchfarber
cd0b84c223 fix: remove incorrect translation files
Remove translation files that were generated by an incorrect transifex
config
2019-04-05 15:33:23 -04:00
Matt Tuchfarber
26810c99e6 Merge pull request #15 from edx/tuchfarber/make_umd_build
Generate builds so they can be used in server rendered apps
2019-04-05 15:20:44 -04:00
Matt Tuchfarber
2fb8ea2608 Generate builds so they can be used in server rendered apps
Current build uses window everywhere, thus breaking server rendered apps
2019-04-05 12:34:52 -04:00
albemarle
16c6da229b Merge pull request #14 from edx/tuchfarber/fix_i18n_quoting
Fix i18n paths
2019-04-04 15:26:50 -04:00
Matt Tuchfarber
fb8de7a59c Fix i18n paths 2019-04-04 15:13:55 -04:00
Robert Raposa
21a9e6c5e1 Merge pull request #13 from edx/robrap/ARCH-460-change-file-ext
fix: update file extension
2019-03-21 14:52:25 -04:00
Robert Raposa
9475888392 fix: update file extension 2019-03-21 14:45:35 -04:00
Robert Raposa
c069f20716 Merge pull request #12 from edx/robrap/ARCH-460-add-empty-language
ARCH-460: fix: add empty language files
2019-03-20 17:14:10 -04:00
Robert Raposa
46772ecc0e fix: add empty language files
ARCH-460
2019-03-20 17:03:47 -04:00
edX Transifex Bot
ca09a07c62 fix(i18n): update translations 2019-03-20 16:36:53 -04:00
Robert Raposa
66f6832887 Merge pull request #9 from edx/robrap/ARCH-460-i18n
ARCH-460: feat: initial localization of footer
2019-03-20 13:16:42 -04:00
Robert Raposa
8f35487558 feat: initial localization of footer
BREAKING CHANGE: Now requires containing app to use `react-intl`. See
update to README for details.

ARCH-460
2019-03-20 12:37:11 -04:00
Adam Butterworth
349a458617 Merge pull request #8 from edx/abutterworth/unique-ids
fix: add unique ids to Icon components
2019-03-08 14:00:06 -05:00
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
21 changed files with 6554 additions and 5625 deletions

View File

@@ -1,43 +1,26 @@
{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "ie 11"]
}
}],
"babel-preset-react"
],
"plugins": [
"transform-object-rest-spread"
],
"env": {
"development": {
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "ie 11"]
}
}],
"babel-preset-react"
],
"plugins": [
"transform-object-rest-spread"
]
},
"test": {
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "ie 11"]
}
}],
"babel-preset-react"
],
"plugins": [
"rewire",
"transform-object-rest-spread"
"rewire"
]
},
"production": {
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "ie 11"]
}
}],
"babel-preset-react"
],
"i18n": {
"plugins": [
"transform-object-rest-spread"
["react-intl", {
"messagesDir": "./temp"
}]
]
}
}

3
.gitignore vendored
View File

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

View File

@@ -8,6 +8,7 @@ install:
- npm install
script:
- npm run lint
- npm run i18n_extract
- npm run test
- npm run build
after_success:

8
.tx/config Normal file
View File

@@ -0,0 +1,8 @@
[main]
host = https://www.transifex.com
[edx-platform.frontend-component-footer]
file_filter = src/i18n/messages/<lang>.json
source_file = src/i18n/transifex_input.json
source_lang = en
type = KEYVALUEJSON

36
Makefile Executable file
View File

@@ -0,0 +1,36 @@
extract_translations: ## no prerequisites so we can control order of operations
echo "We have to define this target due to tooling assumptions"
echo "Also we have to npm install using this hook b/c there's no other place for it in the current setup"
npm install
npm run-script i18n_extract
i18n.extract:
# Pulling display strings from .jsx files into .json files...
npm run-script i18n_extract
i18n.concat:
# Gathering JSON messages into one file...
./src/i18n/i18n-concat.js ./temp/src ./src/i18n/transifex_input.json
detect_changed_source_translations:
git diff --exit-code ./src/i18n/transifex_input.json
tx_url1 = https://www.transifex.com/api/2/project/edx-platform/resource/frontend-component-footer/translation/en/strings/
tx_url2 = https://www.transifex.com/api/2/project/edx-platform/resource/frontend-component-footer/source/
# push translations to Transifex, doing magic so we can include the translator comments
push_translations: | i18n.extract
# Adding translator comments...
# Fetching strings from Transifex...
./node_modules/reactifex/bash_scripts/get_hashed_strings.sh $(tx_url1)
# Writing out comments to file...
./src/i18n/i18n-concat.js ./temp/src --comments
# Adding comments to Transifex...
./node_modules/reactifex/bash_scripts/put_comments.sh $(tx_url2)
# pull translations from Transifex
pull_translations: ## must be exactly this name for edx tooling support, see ecommerce-scripts/transifex/pull.py
tx pull -f --mode reviewed --language="ar,fr,es_419,zh_CN"
validate-no-uncommitted-package-lock-changes:
git diff --exit-code package-lock.json

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
```

50
README.rst Normal file
View File

@@ -0,0 +1,50 @@
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 component is hard-coded to match the legacy LMS site footer, including all of its links. As implemented, this component should probably 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 <src/index.jsx>`__ for an example
of how the SiteFooter component can be specified.
Requirements
------------
This component uses ``react-intl``. Any containing app must provide ``react-intl`` as a peer dependency, and be wrapped inside an ``IntlProvider`` element, whether or not your consuming application is actually localized. For a basic default locale (English) version, follow the ``IntlProvider`` example in the sample application in `src/index.jsx <src/index.jsx>`__.
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

View File

@@ -13,6 +13,7 @@ module.exports = Merge.smart(commonConfig, {
path: path.resolve(__dirname, '../dist'),
library: 'frontend-component-footer',
libraryTarget: 'umd',
globalObject: 'typeof self !== \'undefined\' ? self : this',
},
resolve: {
extensions: ['.js', '.jsx'],

10757
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,7 @@
"gc": "commit",
"commitmsg": "commitlint -e $GIT_PARAMS",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"i18n_extract": "BABEL_ENV=i18n babel src --quiet > /dev/null",
"lint": "eslint --ext .js --ext .jsx .",
"precommit": "npm run lint",
"prepublishOnly": "npm run build",
@@ -19,7 +20,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",
@@ -36,9 +38,11 @@
"@commitlint/config-angular": "^6.0.2",
"@commitlint/prompt": "^6.0.2",
"@commitlint/prompt-cli": "^6.0.2",
"@edx/paragon": "^3.8.0",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-plugin-react-intl": "^3.0.1",
"babel-plugin-rewire": "^1.2.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.7.0",
@@ -46,28 +50,31 @@
"clean-webpack-plugin": "^0.1.19",
"coveralls": "^3.0.0",
"css-loader": "^0.28.9",
"@edx/paragon": "^3.8.0",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"eslint": "^5.2.0",
"eslint-config-edx": "^4.0.4",
"eslint-plugin-jsx-a11y": "^6.1.2",
"file-loader": "^1.1.9",
"glob": "^7.1.3",
"html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^4.2.0",
"husky": "^0.14.3",
"image-webpack-loader": "^4.2.0",
"jest": "23.6.0",
"node-sass": "^4.7.2",
"prop-types": "^15.5.10",
"react": "^16.4.2",
"react-dom": "^16.2.0",
"react-dev-utils": "^5.0.0",
"react-dom": "^16.2.0",
"react-intl": "^2.8.0",
"react-test-renderer": "^16.6.0",
"reactifex": "^1.1.1",
"sass-loader": "^6.0.6",
"semantic-release": "^15.1.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,11 +83,11 @@
"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",
"react-dom": "^16.2.0",
"react-intl": "2.x",
"webpack": "^4.19.1",
"webpack-merge": "^4.2.1"
},

65
src/i18n/i18n-concat.js Executable file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env node
/**
* See the Makefile for how the required hash file is downloaded from Transifex.
*/
// NOTE: This script is called from Jenkins using devDependencies, so eslint is being
// disabled so it doesn't force you to make these real dependencies.
const fs = require('fs'); // eslint-disable-line import/no-extraneous-dependencies
const glob = require('glob'); // eslint-disable-line import/no-extraneous-dependencies
const path = require('path'); // eslint-disable-line import/no-extraneous-dependencies
// Expected input: a directory, possibly containing subdirectories, with .json files. Each .json
// file is an array of translation triplets (id, description, defaultMessage).
function gatherJson(dir) {
const ret = [];
const files = glob.sync(`${dir}/**/*.json`);
files.forEach((filename) => {
const messages = JSON.parse(fs.readFileSync(filename));
ret.push(...messages);
});
return ret;
}
// the hash file returns ids whose periods are "escaped" (sort of), like this:
// "key": "profile\\.sociallinks\\.social\\.links"
// so our regular messageIds won't match them out of the box
function escapeDots(messageId) {
return messageId.replace(/\./g, '\\.');
}
const jsonDir = process.argv[2];
const messageObjects = gatherJson(jsonDir);
if (process.argv[3] === '--comments') { // prepare to handle the translator notes
const loggingPrefix = path.basename(`${__filename}`); // the name of this JS file
const bashScriptsPath = './node_modules/reactifex/bash_scripts';
const hashFile = `${bashScriptsPath}/hashmap.json`;
process.stdout.write(`${loggingPrefix}: reading hash file ${hashFile}\n`);
const messageInfo = JSON.parse(fs.readFileSync(hashFile));
const outputFile = `${bashScriptsPath}/hashed_data.txt`;
process.stdout.write(`${loggingPrefix}: writing to output file ${outputFile}\n`);
fs.writeFileSync(outputFile, '');
messageObjects.forEach((message) => {
const transifexFormatId = escapeDots(message.id);
const info = messageInfo.find(mi => mi.key === transifexFormatId);
if (info) {
fs.appendFileSync(outputFile, `${info.string_hash}|${message.description}\n`);
} else {
process.stdout.write(`${loggingPrefix}: string ${message.id} does not yet exist on transifex!\n`);
}
});
} else {
const output = {};
messageObjects.forEach((message) => {
output[message.id] = message.defaultMessage;
});
fs.writeFileSync(process.argv[3], JSON.stringify(output, null, 2));
}

39
src/i18n/messages/ar.json Normal file
View File

@@ -0,0 +1,39 @@
{
"footer.site-footer.link.about": "About",
"footer.site-footer.link.business": "{siteName} for Business",
"footer.site-footer.link.affiliates": "Affiliates",
"footer.site-footer.link.open-source": "Open {siteName}",
"footer.site-footer.link.careers": "Careers",
"footer.site-footer.link.news": "News",
"footer.site-footer.link.header.legal": "Legal",
"footer.site-footer.link.terms-of-service": "Terms of Service & Honor Code",
"footer.site-footer.link.privacy": "Privacy Policy",
"footer.site-footer.link.accessibility": "Accessibility Policy",
"footer.site-footer.link.trademark": "Trademark Policy",
"footer.site-footer.link.sitemap": "Sitemap",
"footer.site-footer.link.header.connect": "Connect",
"footer.site-footer.link.blog": "Blog",
"footer.site-footer.link.contact-us": "Contact Us",
"footer.site-footer.link.help-center": "Help Center",
"footer.site-footer.link.media-kit": "Media Kit",
"footer.site-footer.link.donate": "Donate",
"footer.site-footer.copyright-text": "{copyrightSymbol} {startDate}{endDate} {siteName} Inc.",
"footer.site-footer.trademark-text": "EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | {icpLicense}",
"footer.site-footer.site-logo.alt-text": "{siteName} logo",
"footer.site-footer.site-logo.aria-label": "{siteName} Home",
"footer.site-footer.facebook.title": "Facebook",
"footer.site-footer.facebook.screen-reader-text": "Like {siteName} on Facebook",
"footer.site-footer.twitter.title": "Twitter",
"footer.site-footer.twitter.screen-reader-text": "Follow {siteName} on Twitter",
"footer.site-footer.youtube.title": "Youtube",
"footer.site-footer.youtube.screen-reader-text": "Subscribe to the {siteName} YouTube channel",
"footer.site-footer.linkedin.title": "LinkedIn",
"footer.site-footer.linkedin.screen-reader-text": "Follow {siteName} on LinkedIn",
"footer.site-footer.google-plus.title": "Google+",
"footer.site-footer.google-plus.screen-reader-text": "Follow {siteName} on Google+",
"footer.site-footer.reddit.title": "Reddit",
"footer.site-footer.reddit.screen-reader-text": "Subscribe to the {siteName} subreddit",
"footer.site-footer.apple-app-store.alt-text": "Download the {siteName} mobile app from the Apple App Store",
"footer.site-footer.google-play.alt-text": "Download the {siteName} mobile app from Google Play",
"footer.site-footer.footer.aria-label": "Page Footer"
}

View File

@@ -0,0 +1,39 @@
{
"footer.site-footer.link.about": "About",
"footer.site-footer.link.business": "{siteName} for Business",
"footer.site-footer.link.affiliates": "Affiliates",
"footer.site-footer.link.open-source": "Open {siteName}",
"footer.site-footer.link.careers": "Careers",
"footer.site-footer.link.news": "News",
"footer.site-footer.link.header.legal": "Legal",
"footer.site-footer.link.terms-of-service": "Terms of Service & Honor Code",
"footer.site-footer.link.privacy": "Privacy Policy",
"footer.site-footer.link.accessibility": "Accessibility Policy",
"footer.site-footer.link.trademark": "Trademark Policy",
"footer.site-footer.link.sitemap": "Sitemap",
"footer.site-footer.link.header.connect": "Connect",
"footer.site-footer.link.blog": "Blog",
"footer.site-footer.link.contact-us": "Contact Us",
"footer.site-footer.link.help-center": "Help Center",
"footer.site-footer.link.media-kit": "Media Kit",
"footer.site-footer.link.donate": "Donate",
"footer.site-footer.copyright-text": "{copyrightSymbol} {startDate}{endDate} {siteName} Inc.",
"footer.site-footer.trademark-text": "EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | {icpLicense}",
"footer.site-footer.site-logo.alt-text": "{siteName} logo",
"footer.site-footer.site-logo.aria-label": "{siteName} Home",
"footer.site-footer.facebook.title": "Facebook",
"footer.site-footer.facebook.screen-reader-text": "Like {siteName} on Facebook",
"footer.site-footer.twitter.title": "Twitter",
"footer.site-footer.twitter.screen-reader-text": "Follow {siteName} on Twitter",
"footer.site-footer.youtube.title": "Youtube",
"footer.site-footer.youtube.screen-reader-text": "Subscribe to the {siteName} YouTube channel",
"footer.site-footer.linkedin.title": "LinkedIn",
"footer.site-footer.linkedin.screen-reader-text": "Follow {siteName} on LinkedIn",
"footer.site-footer.google-plus.title": "Google+",
"footer.site-footer.google-plus.screen-reader-text": "Follow {siteName} on Google+",
"footer.site-footer.reddit.title": "Reddit",
"footer.site-footer.reddit.screen-reader-text": "Subscribe to the {siteName} subreddit",
"footer.site-footer.apple-app-store.alt-text": "Download the {siteName} mobile app from the Apple App Store",
"footer.site-footer.google-play.alt-text": "Download the {siteName} mobile app from Google Play",
"footer.site-footer.footer.aria-label": "Page Footer"
}

39
src/i18n/messages/fr.json Normal file
View File

@@ -0,0 +1,39 @@
{
"footer.site-footer.link.about": "About",
"footer.site-footer.link.business": "{siteName} for Business",
"footer.site-footer.link.affiliates": "Affiliates",
"footer.site-footer.link.open-source": "Open {siteName}",
"footer.site-footer.link.careers": "Careers",
"footer.site-footer.link.news": "News",
"footer.site-footer.link.header.legal": "Legal",
"footer.site-footer.link.terms-of-service": "Terms of Service & Honor Code",
"footer.site-footer.link.privacy": "Privacy Policy",
"footer.site-footer.link.accessibility": "Accessibility Policy",
"footer.site-footer.link.trademark": "Trademark Policy",
"footer.site-footer.link.sitemap": "Sitemap",
"footer.site-footer.link.header.connect": "Connect",
"footer.site-footer.link.blog": "Blog",
"footer.site-footer.link.contact-us": "Contact Us",
"footer.site-footer.link.help-center": "Help Center",
"footer.site-footer.link.media-kit": "Media Kit",
"footer.site-footer.link.donate": "Donate",
"footer.site-footer.copyright-text": "{copyrightSymbol} {startDate}{endDate} {siteName} Inc.",
"footer.site-footer.trademark-text": "EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | {icpLicense}",
"footer.site-footer.site-logo.alt-text": "{siteName} logo",
"footer.site-footer.site-logo.aria-label": "{siteName} Home",
"footer.site-footer.facebook.title": "Facebook",
"footer.site-footer.facebook.screen-reader-text": "Like {siteName} on Facebook",
"footer.site-footer.twitter.title": "Twitter",
"footer.site-footer.twitter.screen-reader-text": "Follow {siteName} on Twitter",
"footer.site-footer.youtube.title": "Youtube",
"footer.site-footer.youtube.screen-reader-text": "Subscribe to the {siteName} YouTube channel",
"footer.site-footer.linkedin.title": "LinkedIn",
"footer.site-footer.linkedin.screen-reader-text": "Follow {siteName} on LinkedIn",
"footer.site-footer.google-plus.title": "Google+",
"footer.site-footer.google-plus.screen-reader-text": "Follow {siteName} on Google+",
"footer.site-footer.reddit.title": "Reddit",
"footer.site-footer.reddit.screen-reader-text": "Subscribe to the {siteName} subreddit",
"footer.site-footer.apple-app-store.alt-text": "Download the {siteName} mobile app from the Apple App Store",
"footer.site-footer.google-play.alt-text": "Download the {siteName} mobile app from Google Play",
"footer.site-footer.footer.aria-label": "Page Footer"
}

View File

@@ -0,0 +1,39 @@
{
"footer.site-footer.link.about": "About",
"footer.site-footer.link.business": "{siteName} for Business",
"footer.site-footer.link.affiliates": "Affiliates",
"footer.site-footer.link.open-source": "Open {siteName}",
"footer.site-footer.link.careers": "Careers",
"footer.site-footer.link.news": "News",
"footer.site-footer.link.header.legal": "Legal",
"footer.site-footer.link.terms-of-service": "Terms of Service & Honor Code",
"footer.site-footer.link.privacy": "Privacy Policy",
"footer.site-footer.link.accessibility": "Accessibility Policy",
"footer.site-footer.link.trademark": "Trademark Policy",
"footer.site-footer.link.sitemap": "Sitemap",
"footer.site-footer.link.header.connect": "Connect",
"footer.site-footer.link.blog": "Blog",
"footer.site-footer.link.contact-us": "Contact Us",
"footer.site-footer.link.help-center": "Help Center",
"footer.site-footer.link.media-kit": "Media Kit",
"footer.site-footer.link.donate": "Donate",
"footer.site-footer.copyright-text": "{copyrightSymbol} {startDate}{endDate} {siteName} Inc.",
"footer.site-footer.trademark-text": "EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | {icpLicense}",
"footer.site-footer.site-logo.alt-text": "{siteName} logo",
"footer.site-footer.site-logo.aria-label": "{siteName} Home",
"footer.site-footer.facebook.title": "Facebook",
"footer.site-footer.facebook.screen-reader-text": "Like {siteName} on Facebook",
"footer.site-footer.twitter.title": "Twitter",
"footer.site-footer.twitter.screen-reader-text": "Follow {siteName} on Twitter",
"footer.site-footer.youtube.title": "Youtube",
"footer.site-footer.youtube.screen-reader-text": "Subscribe to the {siteName} YouTube channel",
"footer.site-footer.linkedin.title": "LinkedIn",
"footer.site-footer.linkedin.screen-reader-text": "Follow {siteName} on LinkedIn",
"footer.site-footer.google-plus.title": "Google+",
"footer.site-footer.google-plus.screen-reader-text": "Follow {siteName} on Google+",
"footer.site-footer.reddit.title": "Reddit",
"footer.site-footer.reddit.screen-reader-text": "Subscribe to the {siteName} subreddit",
"footer.site-footer.apple-app-store.alt-text": "Download the {siteName} mobile app from the Apple App Store",
"footer.site-footer.google-play.alt-text": "Download the {siteName} mobile app from Google Play",
"footer.site-footer.footer.aria-label": "Page Footer"
}

View File

@@ -0,0 +1,39 @@
{
"footer.site-footer.link.about": "About",
"footer.site-footer.link.business": "{siteName} for Business",
"footer.site-footer.link.affiliates": "Affiliates",
"footer.site-footer.link.open-source": "Open {siteName}",
"footer.site-footer.link.careers": "Careers",
"footer.site-footer.link.news": "News",
"footer.site-footer.link.header.legal": "Legal",
"footer.site-footer.link.terms-of-service": "Terms of Service & Honor Code",
"footer.site-footer.link.privacy": "Privacy Policy",
"footer.site-footer.link.accessibility": "Accessibility Policy",
"footer.site-footer.link.trademark": "Trademark Policy",
"footer.site-footer.link.sitemap": "Sitemap",
"footer.site-footer.link.header.connect": "Connect",
"footer.site-footer.link.blog": "Blog",
"footer.site-footer.link.contact-us": "Contact Us",
"footer.site-footer.link.help-center": "Help Center",
"footer.site-footer.link.media-kit": "Media Kit",
"footer.site-footer.link.donate": "Donate",
"footer.site-footer.copyright-text": "{copyrightSymbol} {startDate}{endDate} {siteName} Inc.",
"footer.site-footer.trademark-text": "EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | {icpLicense}",
"footer.site-footer.site-logo.alt-text": "{siteName} logo",
"footer.site-footer.site-logo.aria-label": "{siteName} Home",
"footer.site-footer.facebook.title": "Facebook",
"footer.site-footer.facebook.screen-reader-text": "Like {siteName} on Facebook",
"footer.site-footer.twitter.title": "Twitter",
"footer.site-footer.twitter.screen-reader-text": "Follow {siteName} on Twitter",
"footer.site-footer.youtube.title": "Youtube",
"footer.site-footer.youtube.screen-reader-text": "Subscribe to the {siteName} YouTube channel",
"footer.site-footer.linkedin.title": "LinkedIn",
"footer.site-footer.linkedin.screen-reader-text": "Follow {siteName} on LinkedIn",
"footer.site-footer.google-plus.title": "Google+",
"footer.site-footer.google-plus.screen-reader-text": "Follow {siteName} on Google+",
"footer.site-footer.reddit.title": "Reddit",
"footer.site-footer.reddit.screen-reader-text": "Subscribe to the {siteName} subreddit",
"footer.site-footer.apple-app-store.alt-text": "Download the {siteName} mobile app from the Apple App Store",
"footer.site-footer.google-play.alt-text": "Download the {siteName} mobile app from Google Play",
"footer.site-footer.footer.aria-label": "Page Footer"
}

View File

@@ -1,29 +1,33 @@
import React from 'react';
import { render } from 'react-dom';
import { IntlProvider } from 'react-intl';
import SiteFooter from './lib';
import './index.scss';
import FooterLogo from './edx-footer.png';
const App = () => (
<SiteFooter
siteName="edX"
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"
/>
<IntlProvider locale="en">
<SiteFooter
siteName="edX"
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={() => {}}
/>
</IntlProvider>
);
render(<App />, document.getElementById('root'));

View File

@@ -0,0 +1,91 @@
import { defineMessages } from 'react-intl';
const messages = defineMessages({
'footer.site-footer.site-logo.alt-text': {
id: 'footer.site-footer.site-logo.alt-text',
defaultMessage: '{siteName} logo',
description: 'The alt description of the site logo',
},
'footer.site-footer.site-logo.aria-label': {
id: 'footer.site-footer.site-logo.aria-label',
defaultMessage: '{siteName} Home',
description: 'Aria label for the site logo which goes to the marketing site',
},
'footer.site-footer.facebook.title': {
id: 'footer.site-footer.facebook.title',
defaultMessage: 'Facebook',
description: 'Facebook button title',
},
'footer.site-footer.facebook.screen-reader-text': {
id: 'footer.site-footer.facebook.screen-reader-text',
defaultMessage: 'Like {siteName} on Facebook',
description: 'Facebook button screen reader text',
},
'footer.site-footer.twitter.title': {
id: 'footer.site-footer.twitter.title',
defaultMessage: 'Twitter',
description: 'Twitter button title',
},
'footer.site-footer.twitter.screen-reader-text': {
id: 'footer.site-footer.twitter.screen-reader-text',
defaultMessage: 'Follow {siteName} on Twitter',
description: 'Twitter button screen reader text',
},
'footer.site-footer.youtube.title': {
id: 'footer.site-footer.youtube.title',
defaultMessage: 'Youtube',
description: 'Youtube button title',
},
'footer.site-footer.youtube.screen-reader-text': {
id: 'footer.site-footer.youtube.screen-reader-text',
defaultMessage: 'Subscribe to the {siteName} YouTube channel',
description: 'Youtube button screen reader text',
},
'footer.site-footer.linkedin.title': {
id: 'footer.site-footer.linkedin.title',
defaultMessage: 'LinkedIn',
description: 'LinkedIn button title',
},
'footer.site-footer.linkedin.screen-reader-text': {
id: 'footer.site-footer.linkedin.screen-reader-text',
defaultMessage: 'Follow {siteName} on LinkedIn',
description: 'LinkedIn button screen reader text',
},
'footer.site-footer.google-plus.title': {
id: 'footer.site-footer.google-plus.title',
defaultMessage: 'Google+',
description: 'Google+ button title',
},
'footer.site-footer.google-plus.screen-reader-text': {
id: 'footer.site-footer.google-plus.screen-reader-text',
defaultMessage: 'Follow {siteName} on Google+',
description: 'Google+ button screen reader text',
},
'footer.site-footer.reddit.title': {
id: 'footer.site-footer.reddit.title',
defaultMessage: 'Reddit',
description: 'Reddit button title',
},
'footer.site-footer.reddit.screen-reader-text': {
id: 'footer.site-footer.reddit.screen-reader-text',
defaultMessage: 'Subscribe to the {siteName} subreddit',
description: 'Reddit button screen reader text',
},
'footer.site-footer.apple-app-store.alt-text': {
id: 'footer.site-footer.apple-app-store.alt-text',
defaultMessage: 'Download the {siteName} mobile app from the Apple App Store',
description: 'Apple App Store button alt description',
},
'footer.site-footer.google-play.alt-text': {
id: 'footer.site-footer.google-play.alt-text',
defaultMessage: 'Download the {siteName} mobile app from Google Play',
description: 'Google Play button alt description',
},
'footer.site-footer.footer.aria-label': {
id: 'footer.site-footer.footer.aria-label',
defaultMessage: 'Page Footer',
description: 'Aria label for the footer',
},
});
export default messages;

View File

@@ -1,81 +1,123 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { mount } from 'enzyme';
import { IntlProvider } from 'react-intl';
import FooterLogo from '../../../edx-footer.png';
import SiteFooter from '../../index';
import SiteFooter, { EVENT_NAMES } from './index';
const completeSiteFooterComponent = mockHandleAllTrackEvents =>
(
<IntlProvider locale="en">
<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"
redditUrl="https://reddit.com"
googlePlusUrl="https://plus.google.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
handleAllTrackEvents={mockHandleAllTrackEvents}
/>
</IntlProvider>
);
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((
<IntlProvider locale="en">
<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"
redditUrl="https://reddit.com"
googlePlusUrl="https://plus.google.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
handleAllTrackEvents={jest.fn()}
showSocialLinks={false}
/>
</IntlProvider>
)).toJSON();
expect(tree).toMatchSnapshot();
});
it('does not render mobile links', () => {
const tree = renderer
.create((
<IntlProvider locale="en">
<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"
redditUrl="https://reddit.com"
googlePlusUrl="https://plus.google.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
handleAllTrackEvents={jest.fn()}
showMobileLinks={false}
/>
</IntlProvider>
)).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"
@@ -37,44 +37,54 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<a
href="https://www.example.com/about-us"
>
About
<span>
About
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/enterprise"
>
example
for Business
<span>
example for Business
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/affiliate-program"
>
Affiliates
<span>
Affiliates
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/open"
>
Open
example
<span>
Open example
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/careers"
>
Careers
<span>
Careers
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/news-announcements"
>
News
<span>
News
</span>
</a>
</li>
</ul>
@@ -83,7 +93,9 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
className="area-3"
>
<h2>
Legal
<span>
Legal
</span>
</h2>
<ul
className="list-unstyled p-0 m-0"
@@ -92,35 +104,45 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<a
href="https://www.example.com/terms-of-service"
>
Terms of Service & Honor Code
<span>
Terms of Service & Honor Code
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/privacy-policy"
>
Privacy Policy
<span>
Privacy Policy
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/accessibility"
>
Accessibility Policy
<span>
Accessibility Policy
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/trademarks"
>
Trademark Policy
<span>
Trademark Policy
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/sitemap"
>
Sitemap
<span>
Sitemap
</span>
</a>
</li>
</ul>
@@ -129,7 +151,9 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
className="area-4"
>
<h2>
Connect
<span>
Connect
</span>
</h2>
<ul
className="list-unstyled p-0 m-0"
@@ -138,35 +162,45 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<a
href="https://www.example.com/blog"
>
Blog
<span>
Blog
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/contact"
>
Contact Us
<span>
Contact Us
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/support"
>
Help Center
<span>
Help Center
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/media-kit"
>
Media Kit
<span>
Media Kit
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/donate"
>
Donate
<span>
Donate
</span>
</a>
</li>
</ul>
@@ -180,6 +214,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 +222,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 +234,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 +242,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 +254,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 +262,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 +274,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 +282,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 +294,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 +302,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 +314,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<li>
<a
href="https://reddit.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Reddit"
@@ -282,7 +322,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-reddit-square fa-2x"
id="Icon1"
id="edx-footer-icon-reddit"
/>
<span
className="sr-only"
@@ -293,20 +333,20 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
</li>
</ul>
<p>
© 2012
2019
example
Inc.
<span>
© 20122019 example Inc.
</span>
<br />
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | 粤ICP备17044299号-2
<span>
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | 粤ICP备17044299号-2
</span>
</p>
</div>
</div>
</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"
@@ -343,44 +383,54 @@ exports[`<SiteFooter /> does not render social links 1`] = `
<a
href="https://www.example.com/about-us"
>
About
<span>
About
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/enterprise"
>
example
for Business
<span>
example for Business
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/affiliate-program"
>
Affiliates
<span>
Affiliates
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/open"
>
Open
example
<span>
Open example
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/careers"
>
Careers
<span>
Careers
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/news-announcements"
>
News
<span>
News
</span>
</a>
</li>
</ul>
@@ -389,7 +439,9 @@ exports[`<SiteFooter /> does not render social links 1`] = `
className="area-3"
>
<h2>
Legal
<span>
Legal
</span>
</h2>
<ul
className="list-unstyled p-0 m-0"
@@ -398,35 +450,45 @@ exports[`<SiteFooter /> does not render social links 1`] = `
<a
href="https://www.example.com/terms-of-service"
>
Terms of Service & Honor Code
<span>
Terms of Service & Honor Code
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/privacy-policy"
>
Privacy Policy
<span>
Privacy Policy
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/accessibility"
>
Accessibility Policy
<span>
Accessibility Policy
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/trademarks"
>
Trademark Policy
<span>
Trademark Policy
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/sitemap"
>
Sitemap
<span>
Sitemap
</span>
</a>
</li>
</ul>
@@ -435,7 +497,9 @@ exports[`<SiteFooter /> does not render social links 1`] = `
className="area-4"
>
<h2>
Connect
<span>
Connect
</span>
</h2>
<ul
className="list-unstyled p-0 m-0"
@@ -444,35 +508,45 @@ exports[`<SiteFooter /> does not render social links 1`] = `
<a
href="https://www.example.com/blog"
>
Blog
<span>
Blog
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/contact"
>
Contact Us
<span>
Contact Us
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/support"
>
Help Center
<span>
Help Center
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/media-kit"
>
Media Kit
<span>
Media Kit
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/donate"
>
Donate
<span>
Donate
</span>
</a>
</li>
</ul>
@@ -486,6 +560,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 +574,7 @@ exports[`<SiteFooter /> does not render social links 1`] = `
<li>
<a
href="https://play.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
@@ -511,20 +587,20 @@ exports[`<SiteFooter /> does not render social links 1`] = `
</li>
</ul>
<p>
© 2012
2019
example
Inc.
<span>
© 20122019 example Inc.
</span>
<br />
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | 粤ICP备17044299号-2
<span>
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | 粤ICP备17044299号-2
</span>
</p>
</div>
</div>
</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"
@@ -561,44 +637,54 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<a
href="https://www.example.com/about-us"
>
About
<span>
About
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/enterprise"
>
example
for Business
<span>
example for Business
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/affiliate-program"
>
Affiliates
<span>
Affiliates
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/open"
>
Open
example
<span>
Open example
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/careers"
>
Careers
<span>
Careers
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/news-announcements"
>
News
<span>
News
</span>
</a>
</li>
</ul>
@@ -607,7 +693,9 @@ exports[`<SiteFooter /> renders correctly 1`] = `
className="area-3"
>
<h2>
Legal
<span>
Legal
</span>
</h2>
<ul
className="list-unstyled p-0 m-0"
@@ -616,35 +704,45 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<a
href="https://www.example.com/terms-of-service"
>
Terms of Service & Honor Code
<span>
Terms of Service & Honor Code
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/privacy-policy"
>
Privacy Policy
<span>
Privacy Policy
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/accessibility"
>
Accessibility Policy
<span>
Accessibility Policy
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/trademarks"
>
Trademark Policy
<span>
Trademark Policy
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/sitemap"
>
Sitemap
<span>
Sitemap
</span>
</a>
</li>
</ul>
@@ -653,7 +751,9 @@ exports[`<SiteFooter /> renders correctly 1`] = `
className="area-4"
>
<h2>
Connect
<span>
Connect
</span>
</h2>
<ul
className="list-unstyled p-0 m-0"
@@ -662,35 +762,45 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<a
href="https://www.example.com/blog"
>
Blog
<span>
Blog
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/contact"
>
Contact Us
<span>
Contact Us
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/support"
>
Help Center
<span>
Help Center
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/media-kit"
>
Media Kit
<span>
Media Kit
</span>
</a>
</li>
<li>
<a
href="https://www.example.com/donate"
>
Donate
<span>
Donate
</span>
</a>
</li>
</ul>
@@ -704,6 +814,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://www.facebook.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Facebook"
@@ -711,7 +822,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 +834,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://www.twitter.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Twitter"
@@ -730,7 +842,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 +854,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://www.youtube.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Youtube"
@@ -749,7 +862,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 +874,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://www.linkedin.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="LinkedIn"
@@ -768,7 +882,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 +894,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://plus.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Google+"
@@ -787,7 +902,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 +914,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://reddit.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Reddit"
@@ -806,7 +922,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-reddit-square fa-2x"
id="Icon1"
id="edx-footer-icon-reddit"
/>
<span
className="sr-only"
@@ -822,6 +938,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://store.apple.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
@@ -835,6 +952,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://play.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
@@ -847,13 +965,13 @@ exports[`<SiteFooter /> renders correctly 1`] = `
</li>
</ul>
<p>
© 2012
2019
example
Inc.
<span>
© 20122019 example Inc.
</span>
<br />
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | 粤ICP备17044299号-2
<span>
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | 粤ICP备17044299号-2
</span>
</p>
</div>
</div>

View File

@@ -1,11 +1,38 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import { Hyperlink, Icon } from '@edx/paragon';
import messages from './SiteFooter.messages';
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`} />
<img
src={this.props.siteLogo}
alt={this.props.intl.formatMessage(
messages['footer.site-footer.site-logo.alt-text'],
{ siteName: this.props.siteName },
)}
/>
);
}
@@ -15,6 +42,7 @@ class SiteFooter extends React.Component {
renderSocialLinks() {
const {
intl,
siteName,
showSocialLinks,
facebookUrl,
@@ -33,33 +61,111 @@ 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={intl.formatMessage(messages['footer.site-footer.facebook.title'])}
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon
id="edx-footer-icon-facebook"
className={['fa', 'fa-facebook-square', 'fa-2x']}
screenReaderText={intl.formatMessage(
messages['footer.site-footer.facebook.screen-reader-text'],
{ siteName },
)}
/>
</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={twitterUrl}
title={intl.formatMessage(messages['footer.site-footer.twitter.title'])}
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon
id="edx-footer-icon-twitter"
className={['fa', 'fa-twitter-square', 'fa-2x']}
screenReaderText={intl.formatMessage(
messages['footer.site-footer.twitter.screen-reader-text'],
{ siteName },
)}
/>
</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={youTubeUrl}
title={intl.formatMessage(messages['footer.site-footer.youtube.title'])}
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon
id="edx-footer-icon-youtube"
className={['fa', 'fa-youtube-square', 'fa-2x']}
screenReaderText={intl.formatMessage(
messages['footer.site-footer.youtube.screen-reader-text'],
{ siteName },
)}
/>
</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={linkedInUrl}
title={intl.formatMessage(messages['footer.site-footer.linkedin.title'])}
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon
id="edx-footer-icon-linkedin"
className={['fa', 'fa-linkedin-square', 'fa-2x']}
screenReaderText={intl.formatMessage(
messages['footer.site-footer.linkedin.screen-reader-text'],
{ siteName },
)}
/>
</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
href={googlePlusUrl}
title={intl.formatMessage(messages['footer.site-footer.google-plus.title'])}
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon
id="edx-footer-icon-google"
className={['fa', 'fa-google-plus-square', 'fa-2x']}
screenReaderText={intl.formatMessage(
messages['footer.site-footer.google-plus.screen-reader-text'],
{ siteName },
)}
/>
</a>
</li>
<li>
<a href={redditUrl} title="Reddit" rel="noopener noreferrer" target="_blank">
<Icon className={['fa', 'fa-reddit-square', 'fa-2x']} screenReaderText={`Subscribe to the ${siteName} subreddit`} />
<a
href={redditUrl}
title={intl.formatMessage(messages['footer.site-footer.reddit.title'])}
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon
id="edx-footer-icon-reddit"
className={['fa', 'fa-reddit-square', 'fa-2x']}
screenReaderText={intl.formatMessage(
messages['footer.site-footer.reddit.screen-reader-text'],
{ siteName },
)}
/>
</a>
</li>
</ul>
@@ -70,6 +176,7 @@ class SiteFooter extends React.Component {
renderMobileLinks() {
const {
intl,
siteName,
showMobileLinks,
appleAppStoreUrl,
@@ -80,19 +187,25 @@ 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`}
alt={intl.formatMessage(
messages['footer.site-footer.apple-app-store.alt-text'],
{ siteName },
)}
src="https://prod-edxapp.edx-cdn.org/static/images/app/app_store_badge_135x40.d0558d910630.svg"
/>
</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`}
alt={intl.formatMessage(
messages['footer.site-footer.google-play.alt-text'],
{ siteName },
)}
src="https://prod-edxapp.edx-cdn.org/static/images/app/google_play_badge_45.6ea466e328da.png"
/>
</a>
@@ -105,6 +218,7 @@ class SiteFooter extends React.Component {
render() {
const {
intl,
siteName,
openSourceUrl,
termsOfServiceUrl,
@@ -115,52 +229,200 @@ class SiteFooter extends React.Component {
return (
<footer
role="contentinfo"
aria-label="Page Footer"
aria-label={intl.formatMessage(messages['footer.site-footer.footer.aria-label'])}
className="footer d-flex justify-content-center border-top py-3 px-4"
>
<div className="max-width-1180 d-grid">
<div className="area-1">
<Hyperlink destination={this.renderMarketingSiteUrl('/')} content={this.renderSiteLogo()} aria-label={`${siteName} Home`} />
<Hyperlink
destination={this.renderMarketingSiteUrl('/')}
content={this.renderSiteLogo()}
aria-label={intl.formatMessage(
messages['footer.site-footer.site-logo.aria-label'],
{ siteName },
)}
/>
</div>
<div className="area-2">
<h2>{siteName}</h2>
<ul className="list-unstyled p-0 m-0">
<li><a href={this.renderMarketingSiteUrl('/about-us')}>About</a></li>
<li><a href={this.renderMarketingSiteUrl('/enterprise')}>{siteName} for Business</a></li>
<li><a href={this.renderMarketingSiteUrl('/affiliate-program')}>Affiliates</a></li>
<li><a href={openSourceUrl}>Open {siteName}</a></li>
<li><a href={this.renderMarketingSiteUrl('/careers')}>Careers</a></li>
<li><a href={this.renderMarketingSiteUrl('/news-announcements')}>News</a></li>
<li>
<a href={this.renderMarketingSiteUrl('/about-us')}>
<FormattedMessage
id="footer.site-footer.link.about"
defaultMessage="About"
/>
</a>
</li>
<li>
<a href={this.renderMarketingSiteUrl('/enterprise')}>
<FormattedMessage
id="footer.site-footer.link.business"
defaultMessage="{siteName} for Business"
values={{ siteName }}
/>
</a>
</li>
<li>
<a href={this.renderMarketingSiteUrl('/affiliate-program')}>
<FormattedMessage
id="footer.site-footer.link.affiliates"
defaultMessage="Affiliates"
/>
</a>
</li>
<li>
<a href={openSourceUrl}>
<FormattedMessage
id="footer.site-footer.link.open-source"
defaultMessage="Open {siteName}"
values={{ siteName }}
description="Open Source link text"
/>
</a>
</li>
<li>
<a href={this.renderMarketingSiteUrl('/careers')}>
<FormattedMessage
id="footer.site-footer.link.careers"
defaultMessage="Careers"
/>
</a>
</li>
<li>
<a href={this.renderMarketingSiteUrl('/news-announcements')}>
<FormattedMessage
id="footer.site-footer.link.news"
defaultMessage="News"
/>
</a>
</li>
</ul>
</div>
<div className="area-3">
<h2>Legal</h2>
<h2>
<FormattedMessage
id="footer.site-footer.link.header.legal"
defaultMessage="Legal"
description="Header for legal links"
/>
</h2>
<ul className="list-unstyled p-0 m-0">
<li><a href={termsOfServiceUrl}>Terms of Service &amp; 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>
<li><a href={this.renderMarketingSiteUrl('/sitemap')}>Sitemap</a></li>
<li>
<a href={termsOfServiceUrl}>
<FormattedMessage
id="footer.site-footer.link.terms-of-service"
defaultMessage="Terms of Service & Honor Code"
/>
</a>
</li>
<li>
<a href={privacyPolicyUrl}>
<FormattedMessage
id="footer.site-footer.link.privacy"
defaultMessage="Privacy Policy"
/>
</a>
</li>
<li>
<a href={this.renderMarketingSiteUrl('/accessibility')}>
<FormattedMessage
id="footer.site-footer.link.accessibility"
defaultMessage="Accessibility Policy"
/>
</a>
</li>
<li>
<a href={this.renderMarketingSiteUrl('/trademarks')}>
<FormattedMessage
id="footer.site-footer.link.trademark"
defaultMessage="Trademark Policy"
/>
</a>
</li>
<li>
<a href={this.renderMarketingSiteUrl('/sitemap')}>
<FormattedMessage
id="footer.site-footer.link.sitemap"
defaultMessage="Sitemap"
/>
</a>
</li>
</ul>
</div>
<div className="area-4">
<h2>Connect</h2>
<h2>
<FormattedMessage
id="footer.site-footer.link.header.connect"
defaultMessage="Connect"
description="Header for connect links"
/>
</h2>
<ul className="list-unstyled p-0 m-0">
<li><a href={this.renderMarketingSiteUrl('/blog')}>Blog</a></li>
<li><a href={contactUrl}>Contact Us</a></li>
<li><a href={supportUrl}>Help Center</a></li>
<li><a href={this.renderMarketingSiteUrl('/media-kit')}>Media Kit</a></li>
<li><a href={this.renderMarketingSiteUrl('/donate')}>Donate</a></li>
<li>
<a href={this.renderMarketingSiteUrl('/blog')}>
<FormattedMessage
id="footer.site-footer.link.blog"
defaultMessage="Blog"
/>
</a>
</li>
<li>
<a href={contactUrl}>
<FormattedMessage
id="footer.site-footer.link.contact-us"
defaultMessage="Contact Us"
/>
</a>
</li>
<li>
<a href={supportUrl}>
<FormattedMessage
id="footer.site-footer.link.help-center"
defaultMessage="Help Center"
/>
</a>
</li>
<li>
<a href={this.renderMarketingSiteUrl('/media-kit')}>
<FormattedMessage
id="footer.site-footer.link.media-kit"
defaultMessage="Media Kit"
/>
</a>
</li>
<li>
<a href={this.renderMarketingSiteUrl('/donate')}>
<FormattedMessage
id="footer.site-footer.link.donate"
defaultMessage="Donate"
/>
</a>
</li>
</ul>
</div>
<div className="area-5">
{this.renderSocialLinks()}
{this.renderMobileLinks()}
<p>
© 2012{(new Date().getFullYear())} {siteName} Inc.
<FormattedMessage
id="footer.site-footer.copyright-text"
defaultMessage="{copyrightSymbol} {startDate}{endDate} {siteName} Inc."
values={{
copyrightSymbol: '©',
startDate: '2012',
endDate: `${new Date().getFullYear()}`,
siteName,
}}
description="Footer copyright text with copyright symbol and dates"
/>
<br />
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc.
| 粤ICP备17044299号-2
<FormattedMessage
id="footer.site-footer.trademark-text"
defaultMessage="EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | {icpLicense}"
values={{ icpLicense: '粤ICP备17044299号-2' }}
description="Footer trademark text"
/>
</p>
</div>
</div>
@@ -188,6 +450,8 @@ SiteFooter.propTypes = {
showMobileLinks: PropTypes.bool,
appleAppStoreUrl: PropTypes.string,
googlePlayUrl: PropTypes.string,
handleAllTrackEvents: PropTypes.func.isRequired,
intl: intlShape.isRequired,
};
SiteFooter.defaultProps = {
@@ -211,4 +475,5 @@ SiteFooter.defaultProps = {
googlePlayUrl: null,
};
export default SiteFooter;
export default injectIntl(SiteFooter);
export { EVENT_NAMES };