Compare commits
3 Commits
alpha
...
abutterwor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a820357ee | ||
|
|
c99c06ba87 | ||
|
|
637282d20b |
@@ -1,24 +0,0 @@
|
|||||||
ACCESS_TOKEN_COOKIE_NAME=edx-jwt-cookie-header-payload
|
|
||||||
BASE_URL=localhost:8080
|
|
||||||
CREDENTIALS_BASE_URL=http://localhost:18150
|
|
||||||
CSRF_TOKEN_API_PATH=/csrf/api/v1/token
|
|
||||||
ECOMMERCE_BASE_URL=http://localhost:18130
|
|
||||||
LANGUAGE_PREFERENCE_COOKIE_NAME=openedx-language-preference
|
|
||||||
LMS_BASE_URL=http://localhost:18000
|
|
||||||
LOGIN_URL=http://localhost:18000/login
|
|
||||||
LOGOUT_URL=http://localhost:18000/login
|
|
||||||
MARKETING_SITE_BASE_URL=http://localhost:18000
|
|
||||||
TERMS_OF_SERVICE_URL=null
|
|
||||||
PRIVACY_POLICY_URL=null
|
|
||||||
SUPPORT_EMAIL=null
|
|
||||||
STUDIO_BASE_URL=http://localhost:18010
|
|
||||||
ENABLE_ACCESSIBILITY_PAGE=false
|
|
||||||
ORDER_HISTORY_URL=localhost:1996/orders
|
|
||||||
REFRESH_ACCESS_TOKEN_ENDPOINT=http://localhost:18000/login_refresh
|
|
||||||
SEGMENT_KEY=null
|
|
||||||
SITE_NAME=Open edX
|
|
||||||
USER_INFO_COOKIE_NAME=edx-user-info
|
|
||||||
LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
|
|
||||||
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
|
|
||||||
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
|
|
||||||
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
coverage
|
coverage
|
||||||
dist
|
dist
|
||||||
example
|
|
||||||
node_modules
|
node_modules
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
||||||
const { createConfig } = require('@openedx/frontend-build');
|
|
||||||
|
|
||||||
module.exports = createConfig('eslint');
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Run the workflow that adds new tickets that are either:
|
|
||||||
# - labelled "DEPR"
|
|
||||||
# - title starts with "[DEPR]"
|
|
||||||
# - body starts with "Proposal Date" (this is the first template field)
|
|
||||||
# to the org-wide DEPR project board
|
|
||||||
|
|
||||||
name: Add newly created DEPR issues to the DEPR project board
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
routeissue:
|
|
||||||
uses: openedx/.github/.github/workflows/add-depr-ticket-to-depr-board.yml@master
|
|
||||||
secrets:
|
|
||||||
GITHUB_APP_ID: ${{ secrets.GRAPHQL_AUTH_APP_ID }}
|
|
||||||
GITHUB_APP_PRIVATE_KEY: ${{ secrets.GRAPHQL_AUTH_APP_PEM }}
|
|
||||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_ISSUE_BOT_TOKEN }}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# This workflow runs when a comment is made on the ticket
|
|
||||||
# If the comment starts with "label: " it tries to apply
|
|
||||||
# the label indicated in rest of comment.
|
|
||||||
# If the comment starts with "remove label: ", it tries
|
|
||||||
# to remove the indicated label.
|
|
||||||
# Note: Labels are allowed to have spaces and this script does
|
|
||||||
# not parse spaces (as often a space is legitimate), so the command
|
|
||||||
# "label: really long lots of words label" will apply the
|
|
||||||
# label "really long lots of words label"
|
|
||||||
|
|
||||||
name: Allows for the adding and removing of labels via comment
|
|
||||||
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
add_remove_labels:
|
|
||||||
uses: openedx/.github/.github/workflows/add-remove-label-on-comment.yml@master
|
|
||||||
|
|
||||||
36
.github/workflows/ci.yml
vendored
36
.github/workflows/ci.yml
vendored
@@ -1,36 +0,0 @@
|
|||||||
name: Default CI
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
jobs:
|
|
||||||
tests:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup Nodejs Env
|
|
||||||
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
|
|
||||||
- name: Setup Nodejs
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VER }}
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
- name: Validate package-lock.json changes
|
|
||||||
run: make validate-no-uncommitted-package-lock-changes
|
|
||||||
- name: Lint
|
|
||||||
run: npm run lint
|
|
||||||
- name: Test
|
|
||||||
run: npm run test
|
|
||||||
- name: Build
|
|
||||||
run: npm run build
|
|
||||||
- name: i18n_extract
|
|
||||||
run: npm run i18n_extract
|
|
||||||
- name: Coverage
|
|
||||||
uses: codecov/codecov-action@v3
|
|
||||||
10
.github/workflows/commitlint.yml
vendored
10
.github/workflows/commitlint.yml
vendored
@@ -1,10 +0,0 @@
|
|||||||
# Run commitlint on the commit messages in a pull request.
|
|
||||||
|
|
||||||
name: Lint Commit Messages
|
|
||||||
|
|
||||||
on:
|
|
||||||
- pull_request
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
commitlint:
|
|
||||||
uses: openedx/.github/.github/workflows/commitlint.yml@master
|
|
||||||
13
.github/workflows/lockfileversion-check.yml
vendored
13
.github/workflows/lockfileversion-check.yml
vendored
@@ -1,13 +0,0 @@
|
|||||||
#check package-lock file version
|
|
||||||
|
|
||||||
name: Lockfile Version check
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
version-check:
|
|
||||||
uses: openedx/.github/.github/workflows/lockfile-check.yml@master
|
|
||||||
40
.github/workflows/release.yml
vendored
40
.github/workflows/release.yml
vendored
@@ -1,40 +0,0 @@
|
|||||||
name: Release CI
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- alpha
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
name: Release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup Nodejs Env
|
|
||||||
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VER }}
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
- name: Validate package-lock.json changes
|
|
||||||
run: make validate-no-uncommitted-package-lock-changes
|
|
||||||
- name: Lint
|
|
||||||
run: npm run lint
|
|
||||||
- name: Test
|
|
||||||
run: npm run test
|
|
||||||
- name: i18n_extract
|
|
||||||
run: npm run i18n_extract
|
|
||||||
- name: Coverage
|
|
||||||
uses: codecov/codecov-action@v3
|
|
||||||
- name: Build
|
|
||||||
run: npm run build
|
|
||||||
- name: Release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_GITHUB_TOKEN }}
|
|
||||||
NPM_TOKEN: ${{ secrets.SEMANTIC_RELEASE_NPM_TOKEN }}
|
|
||||||
run: npx semantic-release
|
|
||||||
12
.github/workflows/self-assign-issue.yml
vendored
12
.github/workflows/self-assign-issue.yml
vendored
@@ -1,12 +0,0 @@
|
|||||||
# This workflow runs when a comment is made on the ticket
|
|
||||||
# If the comment starts with "assign me" it assigns the author to the
|
|
||||||
# ticket (case insensitive)
|
|
||||||
|
|
||||||
name: Assign comment author to ticket if they say "assign me"
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
self_assign_by_comment:
|
|
||||||
uses: openedx/.github/.github/workflows/self-assign-issue.yml@master
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,5 +8,3 @@ temp
|
|||||||
|
|
||||||
src/i18n/transifex_input.json
|
src/i18n/transifex_input.json
|
||||||
temp/babel-plugin-react-intl
|
temp/babel-plugin-react-intl
|
||||||
/.vscode
|
|
||||||
module.config.js
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
{
|
{
|
||||||
"branches": [
|
"branch": "master",
|
||||||
"master",
|
|
||||||
{name: "alpha", prerelease: true}
|
|
||||||
],
|
|
||||||
"tagFormat": "v${version}",
|
"tagFormat": "v${version}",
|
||||||
"verifyConditions": [
|
"verifyConditions": [
|
||||||
"@semantic-release/npm",
|
"@semantic-release/npm",
|
||||||
|
|||||||
16
.travis.yml
Normal file
16
.travis.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
language: node_js
|
||||||
|
node_js: 12
|
||||||
|
install:
|
||||||
|
- npm install
|
||||||
|
script:
|
||||||
|
- npm run lint
|
||||||
|
- npm run i18n_extract
|
||||||
|
- npm run test
|
||||||
|
- npm run build
|
||||||
|
after_success:
|
||||||
|
- npx semantic-release
|
||||||
|
- npm run coveralls
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- secure: dxQadqP6tsoJzHcqs/Hs5AjE42z45q8ZeWKP5HcjbXoJURB4gc1uIxLky0FA6ZpulaTgRVTLcWQbx9yOODc9PQuFnFEDWlCg5EP8tONzeu7BVlJvV5eakgGUhl9w2pekBKsTGhK5dDg2y2D8bGfIL55UX81uiWeytp8s/y8QNs/FNXx9ScJnfhnC+2RfW52fB7iW12F1VYdQfVe43o5PsHze+YhB3FU/ztGe3iMaQiq9QplZWpvqQMpI7pTjyUAX8ITiiPS6UvLFObgpXpfjZdgd+yveFoi3z8o8F0NkmzBphFeSYFjFZE0qJ8bnGNIZldanMeuUgHmDeTwVmKQFhH2LqqnfcdGgW6UsKcHkSN1G51zzad2dEwAHrgxj1NkMp3JfEed2C7Kvntl6KRjVDmYZqHJvt+e+AHNbpjzblOW8tYMIrdz0TeJdk4D9pP3B3tRCtP6fvQ3GLzAMnaCrSsN6hZ9YVxWku8sg8WNEDHl14sZsdgk312MlHIdiUw97FHGrqx/NCix4IkUlCBDbKYbKzbZp20FfzZcwNRNH74+k6xpOnMGSfq8gByEhm9y02MBL76HiAI2VGct2La1ExaUfoikYGoNaZpFcZyOZKo6PYTYHpiUJmqrEnDyVQEOOXUaVsxWXwnYq/mU4nOEPKCRbNpPoksZdNxf6jlmMi8s=
|
||||||
|
- secure: lrlV0WQaXTRJ2lqDkFZ+1RkRb7YM/STOViOHUNboXb5+1ReVwY0wklFDVk/Qigp3jkbqWfzkBmEjSDVGDLD61QjpGY4BsxZ/Jn3+KUdo0n82Ym6cI/je1fH2gqDLi4U8bylmnkI5oEjV/1txDxkj4hF5w/Leo/oGue3xQohpi//ihhm/PxzExj+QiDqyZPZ5RQZeqLfPEU3Wff04vLE5bRmy1nDTZrgm5Wb1n5ItGsyrUyrCGuAM9kIEun65Snb8hxCuU9pSm1w/xF73iOGLiiC8KZhLu6SxSKoC872ai1GpUXNIqA8kpVeH0Erf5opMtqJT3jTTan/VOFQEoOeAKhR0ga+5rfK2jkhhN77B98dGVndNCfBpDlgQxVv42H6riFk3payZT262QiUqDejiBDtSPTokTGxf7xFtQkQQahhxVXzC2HRKEkDTXNSP8cvk2JJ4zCcUgxJpycudLMuC/Xv0upK+Q0caItBrHxfVNnRKkjKqlDxRhA8nXTY8d2n19FNi7wahCECbyweJJ76EaJaa/Ib6remUBrbGLoQ2PkaSMBHAcn3+7+H/6x11b2s1RHj5qyfIyrvZcDDyNuxdXwpOkhtrkwZsjgtOfXL6IuxW5FExgPPr8B9nNwJJKdTxyxgfqtwBR5+m9nrMixzT6AMe95torZ6eX40gKZ/O9EU=
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
[main]
|
[main]
|
||||||
host = https://www.transifex.com
|
host = https://www.transifex.com
|
||||||
|
|
||||||
[o:open-edx:p:edx-platform:r:frontend-component-footer]
|
[edx-platform.frontend-component-footer]
|
||||||
file_filter = src/i18n/messages/<lang>.json
|
file_filter = src/i18n/messages/<lang>.json
|
||||||
source_file = src/i18n/transifex_input.json
|
source_file = src/i18n/transifex_input.json
|
||||||
source_lang = en
|
source_lang = en
|
||||||
type = KEYVALUEJSON
|
type = KEYVALUEJSON
|
||||||
|
|
||||||
|
|||||||
18
Makefile
Normal file → Executable file
18
Makefile
Normal file → Executable file
@@ -1,12 +1,14 @@
|
|||||||
export TRANSIFEX_RESOURCE = frontend-component-footer
|
transifex_resource = frontend-component-footer
|
||||||
transifex_langs = "ar,fr,es_419,zh_CN,pt,it,de,uk,ru,hi,fr_CA,it_IT,pt_PT,de_DE"
|
transifex_langs = "ar,fr,es_419,zh_CN"
|
||||||
|
|
||||||
transifex_utils = ./node_modules/.bin/transifex-utils.js
|
transifex_utils = ./node_modules/.bin/transifex-utils.js
|
||||||
i18n = ./src/i18n
|
i18n = ./src/i18n
|
||||||
transifex_input = $(i18n)/transifex_input.json
|
transifex_input = $(i18n)/transifex_input.json
|
||||||
|
tx_url1 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/translation/en/strings/
|
||||||
|
tx_url2 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/source/
|
||||||
|
|
||||||
# This directory must match .babelrc .
|
# This directory must match .babelrc .
|
||||||
transifex_temp = ./temp/babel-plugin-formatjs
|
transifex_temp = ./temp/babel-plugin-react-intl
|
||||||
|
|
||||||
build:
|
build:
|
||||||
rm -rf ./dist
|
rm -rf ./dist
|
||||||
@@ -17,7 +19,7 @@ build:
|
|||||||
@rm -rf dist/__mocks__
|
@rm -rf dist/__mocks__
|
||||||
|
|
||||||
requirements:
|
requirements:
|
||||||
npm ci
|
npm install
|
||||||
|
|
||||||
i18n.extract:
|
i18n.extract:
|
||||||
# Pulling display strings from .jsx files into .json files...
|
# Pulling display strings from .jsx files into .json files...
|
||||||
@@ -40,15 +42,15 @@ push_translations:
|
|||||||
# Pushing strings to Transifex...
|
# Pushing strings to Transifex...
|
||||||
tx push -s
|
tx push -s
|
||||||
# Fetching hashes from Transifex...
|
# Fetching hashes from Transifex...
|
||||||
./node_modules/@edx/reactifex/bash_scripts/get_hashed_strings_v3.sh
|
./node_modules/reactifex/bash_scripts/get_hashed_strings.sh $(tx_url1)
|
||||||
# Writing out comments to file...
|
# Writing out comments to file...
|
||||||
$(transifex_utils) $(transifex_temp) --comments --v3-scripts-path
|
$(transifex_utils) $(transifex_temp) --comments
|
||||||
# Pushing comments to Transifex...
|
# Pushing comments to Transifex...
|
||||||
./node_modules/@edx/reactifex/bash_scripts/put_comments_v3.sh
|
./node_modules/reactifex/bash_scripts/put_comments.sh $(tx_url2)
|
||||||
|
|
||||||
# Pulls translations from Transifex.
|
# Pulls translations from Transifex.
|
||||||
pull_translations:
|
pull_translations:
|
||||||
tx pull -t -f --mode reviewed --languages=$(transifex_langs)
|
tx pull -f --mode reviewed --language=$(transifex_langs)
|
||||||
|
|
||||||
# This target is used by Travis.
|
# This target is used by Travis.
|
||||||
validate-no-uncommitted-package-lock-changes:
|
validate-no-uncommitted-package-lock-changes:
|
||||||
|
|||||||
244
README.rst
244
README.rst
@@ -1,194 +1,64 @@
|
|||||||
#########################
|
|
||||||
frontend-component-footer
|
frontend-component-footer
|
||||||
#########################
|
|
||||||
|
|
||||||
|Build Status| |Codecov| |npm_version| |npm_downloads| |license| |semantic-release|
|
|
||||||
|
|
||||||
********
|
|
||||||
Purpose
|
|
||||||
********
|
|
||||||
|
|
||||||
A generic footer for Open edX micro-frontend applications. It includes a logo and an optional language selector dropdown.
|
|
||||||
|
|
||||||
***************
|
|
||||||
Getting Started
|
|
||||||
***************
|
|
||||||
|
|
||||||
Prerequisites
|
|
||||||
=============
|
|
||||||
|
|
||||||
The `devstack`_ is currently recommended as a development environment for your
|
|
||||||
new MFE. If you start it with ``make dev.up.lms`` that should give you
|
|
||||||
everything you need as a companion to this frontend.
|
|
||||||
|
|
||||||
Note that it is also possible to use `Tutor`_ to develop an MFE. You can refer
|
|
||||||
to the `relevant tutor-mfe documentation`_ to get started using it.
|
|
||||||
|
|
||||||
.. _Devstack: https://github.com/openedx/devstack
|
|
||||||
|
|
||||||
.. _Tutor: https://github.com/overhangio/tutor
|
|
||||||
|
|
||||||
.. _relevant tutor-mfe documentation: https://github.com/overhangio/tutor-mfe#mfe-development
|
|
||||||
|
|
||||||
Requirements
|
|
||||||
============
|
|
||||||
|
|
||||||
This component uses ``@edx/frontend-platform`` services such as i18n, analytics, configuration, and the ``AppContext`` React component, and expects that it has been loaded into a micro-frontend that has been properly initialized via ``@edx/frontend-platform``'s ``initialize`` function. `Please visit the frontend template application to see an example. <https://github.com/openedx/frontend-template-application/blob/3355bb3a96232390e9056f35b06ffa8f105ed7ca/src/index.jsx>`_
|
|
||||||
|
|
||||||
Environment Variables
|
|
||||||
=====================
|
|
||||||
|
|
||||||
This component requires that the following environment variable be set by the consuming micro-frontend.
|
|
||||||
|
|
||||||
* ``LMS_BASE_URL`` - The URL of the LMS of your Open edX instance.
|
|
||||||
* ``LOGO_TRADEMARK_URL`` - This is a URL to a logo for use in the footer. This is a different environment variable than ``LOGO_URL`` (used in frontend-component-header) to accommodate sites that would like to have additional trademark information on a logo in the footer, such as a (tm) or (r) symbol.
|
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
To install this footer into your Open edX micro-frontend, run the following command in your MFE:
|
|
||||||
|
|
||||||
``npm i --save @edx/frontend-component-footer``
|
|
||||||
|
|
||||||
This will make the component available to be imported into your application.
|
|
||||||
|
|
||||||
Cloning and Startup
|
|
||||||
===================
|
|
||||||
|
|
||||||
.. code-block::
|
|
||||||
|
|
||||||
|
|
||||||
1. Clone your new repo:
|
|
||||||
|
|
||||||
``git clone https://github.com/openedx/frontend-component-footer.git``
|
|
||||||
|
|
||||||
2. Use node v18.x.
|
|
||||||
|
|
||||||
The current version of the micro-frontend build scripts support node 18.
|
|
||||||
Using other major versions of node *may* work, but this is unsupported. For
|
|
||||||
convenience, this repository includes an .nvmrc file to help in setting the
|
|
||||||
correct node version via `nvm <https://github.com/nvm-sh/nvm>`_.
|
|
||||||
|
|
||||||
3. Install npm dependencies:
|
|
||||||
|
|
||||||
``cd frontend-component-footer && npm ci``
|
|
||||||
|
|
||||||
4. Start the dev server:
|
|
||||||
|
|
||||||
``npm start``
|
|
||||||
|
|
||||||
Usage
|
|
||||||
=====
|
|
||||||
|
|
||||||
This library has the following exports:
|
|
||||||
|
|
||||||
* ``(default)``: The footer as a React component.
|
|
||||||
* ``messages``: Internationalization messages suitable for use with `@edx/frontend-platform/i18n <https://edx.github.io/frontend-platform/module-Internationalization.html>`_
|
|
||||||
* ``dist/footer.scss``: A SASS file which contains style information for the component. It should be imported into the micro-frontend's own SCSS file.
|
|
||||||
|
|
||||||
<Footer /> component props
|
|
||||||
==========================
|
|
||||||
|
|
||||||
* onLanguageSelected: Provides the footer with an event handler for when the user selects a
|
|
||||||
language from its dropdown.
|
|
||||||
* supportedLanguages: An array of objects representing available languages. See example below for object shape.
|
|
||||||
|
|
||||||
Examples
|
|
||||||
========
|
|
||||||
|
|
||||||
Component Usage Example::
|
|
||||||
|
|
||||||
import Footer, { messages } from '@edx/frontend-component-footer';
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
<Footer
|
|
||||||
onLanguageSelected={(languageCode) => {/* set language */}}
|
|
||||||
supportedLanguages={[
|
|
||||||
{ label: 'English', value: 'en'},
|
|
||||||
{ label: 'Español', value: 'es' },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
* `An example of minimal component and messages usage. <https://github.com/openedx/frontend-template-application/blob/3355bb3a96232390e9056f35b06ffa8f105ed7ca/src/index.jsx#L23>`_
|
|
||||||
* `An example of SCSS file usage. <https://github.com/openedx/frontend-template-application/blob/3cd5485bf387b8c479baf6b02bf59e3061dc3465/src/index.scss#L9>`_
|
|
||||||
|
|
||||||
Development
|
|
||||||
===========
|
|
||||||
|
|
||||||
Install dependencies::
|
|
||||||
|
|
||||||
npm i
|
|
||||||
|
|
||||||
Start the development server::
|
|
||||||
|
|
||||||
npm start
|
|
||||||
|
|
||||||
Build a production distribution::
|
|
||||||
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
License
|
|
||||||
=======
|
|
||||||
|
|
||||||
The code in this repository is licensed under the AGPLv3 unless otherwise
|
|
||||||
noted.
|
|
||||||
|
|
||||||
Please see `LICENSE <LICENSE>`_ for details.
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
============
|
|
||||||
|
|
||||||
Contributions are very welcome. Please read `How To Contribute`_ for details.
|
|
||||||
|
|
||||||
.. _How To Contribute: https://openedx.org/r/how-to-contribute
|
|
||||||
|
|
||||||
This project is currently accepting all types of contributions, bug fixes,
|
|
||||||
security fixes, maintenance work, or new features. However, please make sure
|
|
||||||
to have a discussion about your new feature idea with the maintainers prior to
|
|
||||||
beginning development to maximize the chances of your change being accepted.
|
|
||||||
You can start a conversation by creating a new issue on this repo summarizing
|
|
||||||
your idea.
|
|
||||||
|
|
||||||
Getting Help
|
|
||||||
===========
|
|
||||||
|
|
||||||
If you're having trouble, we have discussion forums at
|
|
||||||
https://discuss.openedx.org where you can connect with others in the community.
|
|
||||||
|
|
||||||
Our real-time conversations are on Slack. You can request a `Slack
|
|
||||||
invitation`_, then join our `community Slack workspace`_. Because this is a
|
|
||||||
frontend repository, the best place to discuss it would be in the `#wg-frontend
|
|
||||||
channel`_.
|
|
||||||
|
|
||||||
For anything non-trivial, the best path is to open an issue in this repository
|
|
||||||
with as many details about the issue you are facing as you can provide.
|
|
||||||
|
|
||||||
https://github.com/openedx/frontend-component-footer/issues
|
|
||||||
|
|
||||||
For more information about these options, see the `Getting Help`_ page.
|
|
||||||
|
|
||||||
.. _Slack invitation: https://openedx.org/slack
|
|
||||||
.. _community Slack workspace: https://openedx.slack.com/
|
|
||||||
.. _#wg-frontend channel: https://openedx.slack.com/archives/C04BM6YC7A6
|
|
||||||
.. _Getting Help: https://openedx.org/community/connect
|
|
||||||
|
|
||||||
The Open edX Code of Conduct
|
|
||||||
============================
|
|
||||||
|
|
||||||
All community members are expected to follow the `Open edX Code of Conduct`_.
|
|
||||||
|
|
||||||
.. _Open edX Code of Conduct: https://openedx.org/code-of-conduct/
|
|
||||||
|
|
||||||
Reporting Security Issues
|
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
Please do not report security issues in public. Please email security@openedx.org.
|
|Build Status| |Coveralls| |npm_version| |npm_downloads| |license|
|
||||||
|
|semantic-release|
|
||||||
|
|
||||||
.. |Build Status| image:: https://api.travis-ci.com/edx/frontend-component-footer.svg?branch=master
|
frontend-component-footer is a library containing a site footer
|
||||||
:target: https://travis-ci.com/edx/frontend-component-footer
|
component for use when building Open edX frontend applications.
|
||||||
.. |Codecov| image:: https://img.shields.io/codecov/c/github/edx/frontend-component-footer
|
|
||||||
:target: @edx/frontend-component-footer
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
To install frontend-component-footer into your project::
|
||||||
|
|
||||||
|
npm i --save @edx/frontend-component-footer
|
||||||
|
|
||||||
|
Component Usage::
|
||||||
|
|
||||||
|
import Footer from '@edx/frontend-component-footer';
|
||||||
|
import footerMessages from '@edx/frontend-component-footer/src/i18n/index';
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
<Footer
|
||||||
|
handleAllTrackEvents={(eventName, properties) => {/* track click event */}}
|
||||||
|
onLanguageSelected={(languageCode) => {/* set language */}}
|
||||||
|
supportedLanguages={[
|
||||||
|
{ label: 'English', value: 'en'},
|
||||||
|
{ label: 'Español', value: 'es' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
- handleAllTrackEvents (required)
|
||||||
|
- onLanguageSelected (optional)
|
||||||
|
- supportedLanguages (optional)
|
||||||
|
|
||||||
|
Styles (project.scss)::
|
||||||
|
|
||||||
|
@import '@edx/frontend-component-footer/src/footer.scss';
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
This component uses ``@edx/frontend-i18n``. Any containing app must provide ``@edx/frontend-i18n`` 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
|
.. |npm_version| image:: https://img.shields.io/npm/v/@edx/frontend-component-footer.svg
|
||||||
:target: @edx/frontend-component-footer
|
:target: @edx/frontend-component-footer
|
||||||
.. |npm_downloads| image:: https://img.shields.io/npm/dt/@edx/frontend-component-footer.svg
|
.. |npm_downloads| image:: https://img.shields.io/npm/dt/@edx/frontend-component-footer.svg
|
||||||
|
|||||||
@@ -1,3 +1,35 @@
|
|||||||
const { createConfig } = require('@openedx/frontend-build');
|
// These preset packages are included by frontend-build.
|
||||||
|
// TODO: Add to frontend-build and leverage that config.
|
||||||
module.exports = createConfig('babel-preserve-modules');
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'@babel/preset-env',
|
||||||
|
{
|
||||||
|
modules: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@babel/preset-react',
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
'@babel/plugin-proposal-object-rest-spread',
|
||||||
|
'@babel/plugin-proposal-class-properties',
|
||||||
|
],
|
||||||
|
env: {
|
||||||
|
i18n: {
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
'react-intl',
|
||||||
|
{
|
||||||
|
messagesDir: './temp/babel-plugin-react-intl',
|
||||||
|
moduleSourceName: '@edx/frontend-i18n',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
presets: [
|
||||||
|
'@babel/preset-env',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
3
commitlint.config.js
Normal file
3
commitlint.config.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['@commitlint/config-angular'],
|
||||||
|
};
|
||||||
@@ -1,33 +1,25 @@
|
|||||||
import 'babel-polyfill';
|
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { initialize, getConfig, subscribe, APP_READY } from '@edx/frontend-platform';
|
import { IntlProvider } from '@edx/frontend-i18n';
|
||||||
import { AppContext, AppProvider } from '@edx/frontend-platform/react';
|
|
||||||
import Footer from '@edx/frontend-component-footer';
|
|
||||||
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
import Footer from '../src';
|
||||||
|
|
||||||
subscribe(APP_READY, () => {
|
const App = () => (
|
||||||
ReactDOM.render(
|
<div>
|
||||||
<AppProvider>
|
<IntlProvider locale="en">
|
||||||
<AppContext.Provider value={{
|
<Footer
|
||||||
authenticatedUser: null,
|
/* eslint-disable-next-line no-unused-vars */
|
||||||
config: getConfig(),
|
handleAllTrackEvents={(eventName, properties) => {}}
|
||||||
}}>
|
/* eslint-disable-next-line no-unused-vars */
|
||||||
<Footer
|
onLanguageSelected={(languageCode) => {}}
|
||||||
onLanguageSelected={() => {}}
|
supportedLanguages={[
|
||||||
supportedLanguages={[
|
{ label: 'English', value: 'en' },
|
||||||
{ label: 'English', value: 'en' },
|
{ label: 'Español', value: 'es' },
|
||||||
{ label: 'Español', value: 'es' },
|
]}
|
||||||
]}
|
/>
|
||||||
/>
|
</IntlProvider>
|
||||||
</AppContext.Provider>
|
</div>
|
||||||
</AppProvider>,
|
);
|
||||||
document.getElementById('root'),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
initialize({
|
render(<App />, document.getElementById('root'));
|
||||||
messages: []
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,6 +1,2 @@
|
|||||||
@import "@edx/brand/paragon/fonts";
|
@import "~@edx/paragon/scss/core/core.scss";
|
||||||
@import "@edx/brand/paragon/variables";
|
@import "../src/footer";
|
||||||
@import "@openedx/paragon/scss/core/core";
|
|
||||||
@import "@edx/brand/paragon/overrides";
|
|
||||||
|
|
||||||
@import "@edx/frontend-component-footer/footer";
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const { createConfig } = require('@openedx/frontend-build');
|
const { createConfig } = require('@edx/frontend-build');
|
||||||
|
|
||||||
module.exports = createConfig('jest', {
|
module.exports = createConfig('jest', {
|
||||||
setupFiles: [
|
setupFiles: [
|
||||||
|
|||||||
49120
package-lock.json
generated
49120
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
82
package.json
82
package.json
@@ -1,70 +1,66 @@
|
|||||||
{
|
{
|
||||||
"name": "@edx/frontend-component-footer",
|
"name": "@edx/frontend-component-footer",
|
||||||
"version": "1.0.0-semantically-released",
|
"version": "1.0.0-semantically-released",
|
||||||
"description": "Footer component for use when building Open edX frontend applications",
|
"description": "Site footer component for use when building edX frontend applications",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "make build",
|
"build": "make build",
|
||||||
"i18n_extract": "fedx-scripts formatjs extract",
|
"gc": "commit",
|
||||||
|
"commitmsg": "commitlint -e $GIT_PARAMS",
|
||||||
|
"coveralls": "cat ./coverage/lcov.info | coveralls",
|
||||||
|
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
|
||||||
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
|
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
|
||||||
"snapshot": "fedx-scripts jest --updateSnapshot",
|
"precommit": "npm run lint",
|
||||||
|
"prepublishOnly": "npm run build",
|
||||||
"start": "fedx-scripts webpack-dev-server --progress",
|
"start": "fedx-scripts webpack-dev-server --progress",
|
||||||
"start:with-theme": "paragon install-theme && npm start && npm install",
|
"test": "fedx-scripts jest --coverage",
|
||||||
"test": "fedx-scripts jest"
|
"snapshot": "fedx-scripts jest --updateSnapshot"
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"/dist"
|
|
||||||
],
|
|
||||||
"husky": {
|
|
||||||
"hooks": {
|
|
||||||
"pre-commit": "npm run lint"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/openedx/frontend-component-footer.git"
|
"url": "git+https://github.com/edx/frontend-component-footer.git"
|
||||||
},
|
},
|
||||||
"author": "edX",
|
"author": "edX",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/openedx/frontend-component-footer/issues"
|
"url": "https://github.com/edx/frontend-component-footer/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/openedx/frontend-component-footer#readme",
|
"homepage": "https://github.com/edx/frontend-component-footer#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
"@commitlint/cli": "^7.1.2",
|
||||||
"@edx/browserslist-config": "^1.1.1",
|
"@commitlint/config-angular": "^6.0.2",
|
||||||
"@openedx/frontend-build": "^13.0.19",
|
"@commitlint/prompt": "^6.0.2",
|
||||||
"@openedx/paragon": "22.0.0",
|
"@commitlint/prompt-cli": "^6.0.2",
|
||||||
"@edx/frontend-platform": "6.2.0",
|
"@edx/frontend-build": "^1.0.1",
|
||||||
"@edx/reactifex": "^2.1.1",
|
"@edx/frontend-i18n": "^2.1.0",
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
"@edx/frontend-logging": "^2.0.2",
|
||||||
"@testing-library/react": "^12.1.1",
|
"@edx/paragon": "^7.1.3",
|
||||||
"husky": "8.0.3",
|
"coveralls": "^3.0.0",
|
||||||
"prop-types": "15.8.1",
|
"enzyme": "^3.3.0",
|
||||||
"react": "17.0.2",
|
"enzyme-adapter-react-16": "^1.1.1",
|
||||||
"react-dom": "17.0.2",
|
"husky": "^0.14.3",
|
||||||
"react-redux": "7.2.9",
|
"prop-types": "^15.5.10",
|
||||||
"react-router-dom": "6.21.3",
|
"react": "^16.4.2",
|
||||||
"react-test-renderer": "17.0.2",
|
"react-dom": "^16.2.0",
|
||||||
"redux": "4.2.1",
|
"react-test-renderer": "^16.6.0",
|
||||||
"semantic-release": "21.1.2"
|
"reactifex": "^1.1.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "6.5.1",
|
"@fortawesome/fontawesome-svg-core": "^1.2.17",
|
||||||
"@fortawesome/free-brands-svg-icons": "6.5.1",
|
"@fortawesome/free-brands-svg-icons": "^5.8.1",
|
||||||
"@fortawesome/free-regular-svg-icons": "6.5.1",
|
"@fortawesome/free-regular-svg-icons": "^5.8.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.5.1",
|
"@fortawesome/free-solid-svg-icons": "^5.8.1",
|
||||||
"@fortawesome/react-fontawesome": "0.2.0",
|
"@fortawesome/react-fontawesome": "^0.1.4"
|
||||||
"lodash": "^4.17.21"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@edx/frontend-platform": "^7.0.0",
|
"@edx/frontend-i18n": "^2.1.0",
|
||||||
"@openedx/paragon": ">= 21.11.3 < 23.0.0",
|
"@edx/frontend-logging": "^2.0.2",
|
||||||
|
"@edx/paragon": "^7.1.3",
|
||||||
"prop-types": "^15.5.10",
|
"prop-types": "^15.5.10",
|
||||||
"react": "^16.9.0 || ^17.0.0",
|
"react": "^16.4.2",
|
||||||
"react-dom": "^16.9.0 || ^17.0.0"
|
"react-dom": "^16.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": [
|
|
||||||
"config:base",
|
|
||||||
"schedule:weekly",
|
|
||||||
":automergeLinters",
|
|
||||||
":automergeMinor",
|
|
||||||
":automergeTesters",
|
|
||||||
":enableVulnerabilityAlerts",
|
|
||||||
":rebaseStalePrs",
|
|
||||||
":semanticCommits",
|
|
||||||
":updateNotScheduled"
|
|
||||||
],
|
|
||||||
"packageRules": [
|
|
||||||
{
|
|
||||||
"matchDepTypes": [
|
|
||||||
"devDependencies"
|
|
||||||
],
|
|
||||||
"matchUpdateTypes": [
|
|
||||||
"lockFileMaintenance",
|
|
||||||
"minor",
|
|
||||||
"patch",
|
|
||||||
"pin"
|
|
||||||
],
|
|
||||||
"automerge": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"matchPackagePatterns": ["@edx", "@openedx"],
|
|
||||||
"matchUpdateTypes": ["minor", "patch"],
|
|
||||||
"automerge": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"timezone": "America/New_York"
|
|
||||||
}
|
|
||||||
@@ -1,18 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
import { injectIntl, intlShape } from '@edx/frontend-i18n';
|
||||||
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
|
|
||||||
import { ensureConfig } from '@edx/frontend-platform';
|
|
||||||
import { AppContext } from '@edx/frontend-platform/react';
|
|
||||||
|
|
||||||
import messages from './Footer.messages';
|
import messages from './Footer.messages';
|
||||||
|
import FooterLogo from '../edx-openedx-logo-tag.png';
|
||||||
import LanguageSelector from './LanguageSelector';
|
import LanguageSelector from './LanguageSelector';
|
||||||
|
|
||||||
ensureConfig([
|
|
||||||
'LMS_BASE_URL',
|
|
||||||
'LOGO_TRADEMARK_URL',
|
|
||||||
], 'Footer component');
|
|
||||||
|
|
||||||
const EVENT_NAMES = {
|
const EVENT_NAMES = {
|
||||||
FOOTER_LINK: 'edx.bi.footer.link',
|
FOOTER_LINK: 'edx.bi.footer.link',
|
||||||
};
|
};
|
||||||
@@ -23,6 +16,14 @@ class SiteFooter extends React.Component {
|
|||||||
this.externalLinkClickHandler = this.externalLinkClickHandler.bind(this);
|
this.externalLinkClickHandler = this.externalLinkClickHandler.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLocalePrefix(locale) {
|
||||||
|
const twoLetterPrefix = locale.substring(0, 2).toLowerCase();
|
||||||
|
if (twoLetterPrefix === 'en') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return `/${twoLetterPrefix}`;
|
||||||
|
}
|
||||||
|
|
||||||
externalLinkClickHandler(event) {
|
externalLinkClickHandler(event) {
|
||||||
const label = event.currentTarget.getAttribute('href');
|
const label = event.currentTarget.getAttribute('href');
|
||||||
const eventName = EVENT_NAMES.FOOTER_LINK;
|
const eventName = EVENT_NAMES.FOOTER_LINK;
|
||||||
@@ -30,7 +31,7 @@ class SiteFooter extends React.Component {
|
|||||||
category: 'outbound_link',
|
category: 'outbound_link',
|
||||||
label,
|
label,
|
||||||
};
|
};
|
||||||
sendTrackEvent(eventName, properties);
|
this.props.handleAllTrackEvents(eventName, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -41,40 +42,38 @@ class SiteFooter extends React.Component {
|
|||||||
intl,
|
intl,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const showLanguageSelector = supportedLanguages.length > 0 && onLanguageSelected;
|
const showLanguageSelector = supportedLanguages.length > 0 && onLanguageSelected;
|
||||||
const { config } = this.context;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer
|
<footer
|
||||||
role="contentinfo"
|
role="contentinfo"
|
||||||
|
aria-label={intl.formatMessage(messages['footer.logo.ariaLabel'])}
|
||||||
className="footer d-flex border-top py-3 px-4"
|
className="footer d-flex border-top py-3 px-4"
|
||||||
>
|
>
|
||||||
<div className="container-fluid d-flex">
|
<div className="container d-flex">
|
||||||
<a
|
<a
|
||||||
className="d-block"
|
className="d-block mb-3"
|
||||||
href={config.LMS_BASE_URL}
|
href="https://open.edx.org"
|
||||||
aria-label={intl.formatMessage(messages['footer.logo.ariaLabel'])}
|
aria-label={intl.formatMessage(messages['footer.logo.ariaLabel'])}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
style={{ maxHeight: 45 }}
|
style={{ maxWidth: 150 }}
|
||||||
src={logo || config.LOGO_TRADEMARK_URL}
|
src={logo || FooterLogo}
|
||||||
alt={intl.formatMessage(messages['footer.logo.altText'])}
|
alt={intl.formatMessage(messages['footer.logo.altText'])}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<div className="flex-grow-1" />
|
<div className="flex-grow-1" />
|
||||||
{showLanguageSelector && (
|
{showLanguageSelector &&
|
||||||
<LanguageSelector
|
<LanguageSelector
|
||||||
options={supportedLanguages}
|
options={supportedLanguages}
|
||||||
onSubmit={onLanguageSelected}
|
onSubmit={onLanguageSelected}
|
||||||
/>
|
/>
|
||||||
)}
|
}
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SiteFooter.contextType = AppContext;
|
|
||||||
|
|
||||||
SiteFooter.propTypes = {
|
SiteFooter.propTypes = {
|
||||||
intl: intlShape.isRequired,
|
intl: intlShape.isRequired,
|
||||||
logo: PropTypes.string,
|
logo: PropTypes.string,
|
||||||
@@ -83,6 +82,7 @@ SiteFooter.propTypes = {
|
|||||||
label: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
})),
|
})),
|
||||||
|
handleAllTrackEvents: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
SiteFooter.defaultProps = {
|
SiteFooter.defaultProps = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
import { defineMessages } from '@edx/frontend-i18n';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
'footer.socialLinks.srText.facebook': {
|
'footer.socialLinks.srText.facebook': {
|
||||||
|
|||||||
@@ -1,75 +1,49 @@
|
|||||||
/* eslint-disable react/prop-types */
|
import React from 'react';
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
import { render, fireEvent, screen } from '@testing-library/react';
|
import { mount } from 'enzyme';
|
||||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-i18n';
|
||||||
import { AppContext } from '@edx/frontend-platform/react';
|
|
||||||
|
|
||||||
import Footer from './Footer';
|
import Footer from './Footer';
|
||||||
|
|
||||||
const FooterWithContext = ({ locale = 'es' }) => {
|
|
||||||
const contextValue = useMemo(() => ({
|
|
||||||
authenticatedUser: null,
|
|
||||||
config: {
|
|
||||||
LOGO_TRADEMARK_URL: process.env.LOGO_TRADEMARK_URL,
|
|
||||||
LMS_BASE_URL: process.env.LMS_BASE_URL,
|
|
||||||
},
|
|
||||||
}), []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IntlProvider locale={locale}>
|
|
||||||
<AppContext.Provider
|
|
||||||
value={contextValue}
|
|
||||||
>
|
|
||||||
<Footer />
|
|
||||||
</AppContext.Provider>
|
|
||||||
</IntlProvider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const FooterWithLanguageSelector = ({ languageSelected = () => {} }) => {
|
|
||||||
const contextValue = useMemo(() => ({
|
|
||||||
authenticatedUser: null,
|
|
||||||
config: {
|
|
||||||
LOGO_TRADEMARK_URL: process.env.LOGO_TRADEMARK_URL,
|
|
||||||
LMS_BASE_URL: process.env.LMS_BASE_URL,
|
|
||||||
},
|
|
||||||
}), []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IntlProvider locale="en">
|
|
||||||
<AppContext.Provider
|
|
||||||
value={contextValue}
|
|
||||||
>
|
|
||||||
<Footer
|
|
||||||
onLanguageSelected={languageSelected}
|
|
||||||
supportedLanguages={[
|
|
||||||
{ label: 'English', value: 'en' },
|
|
||||||
{ label: 'Español', value: 'es' },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</AppContext.Provider>
|
|
||||||
</IntlProvider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('<Footer />', () => {
|
describe('<Footer />', () => {
|
||||||
describe('renders correctly', () => {
|
describe('renders correctly', () => {
|
||||||
it('renders without a language selector', () => {
|
it('renders without a language selector', () => {
|
||||||
|
const mockHandleAllTrackEvents = jest.fn();
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(<FooterWithContext locale="en" />)
|
.create((
|
||||||
|
<IntlProvider locale="en">
|
||||||
|
<Footer handleAllTrackEvents={mockHandleAllTrackEvents} />
|
||||||
|
</IntlProvider>
|
||||||
|
))
|
||||||
.toJSON();
|
.toJSON();
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
it('renders without a language selector in es', () => {
|
it('renders without a language selector in es', () => {
|
||||||
|
const mockHandleAllTrackEvents = jest.fn();
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(<FooterWithContext locale="es" />)
|
.create((
|
||||||
|
<IntlProvider locale="es">
|
||||||
|
<Footer handleAllTrackEvents={mockHandleAllTrackEvents} />
|
||||||
|
</IntlProvider>
|
||||||
|
))
|
||||||
.toJSON();
|
.toJSON();
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
it('renders with a language selector', () => {
|
it('renders with a language selector', () => {
|
||||||
|
const mockHandleAllTrackEvents = jest.fn();
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(<FooterWithLanguageSelector />)
|
.create((
|
||||||
|
<IntlProvider locale="en">
|
||||||
|
<Footer
|
||||||
|
handleAllTrackEvents={mockHandleAllTrackEvents}
|
||||||
|
onLanguageSelected={() => {}}
|
||||||
|
supportedLanguages={[
|
||||||
|
{ label: 'English', value: 'en' },
|
||||||
|
{ label: 'Español', value: 'es' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</IntlProvider>
|
||||||
|
))
|
||||||
.toJSON();
|
.toJSON();
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
@@ -77,10 +51,22 @@ describe('<Footer />', () => {
|
|||||||
|
|
||||||
describe('handles language switching', () => {
|
describe('handles language switching', () => {
|
||||||
it('calls onLanguageSelected prop when a language is changed', () => {
|
it('calls onLanguageSelected prop when a language is changed', () => {
|
||||||
|
const mockHandleAllTrackEvents = jest.fn();
|
||||||
const mockHandleLanguageSelected = jest.fn();
|
const mockHandleLanguageSelected = jest.fn();
|
||||||
render(<FooterWithLanguageSelector languageSelected={mockHandleLanguageSelected} />);
|
const wrapper = mount((
|
||||||
|
<IntlProvider locale="en">
|
||||||
|
<Footer
|
||||||
|
handleAllTrackEvents={mockHandleAllTrackEvents}
|
||||||
|
onLanguageSelected={mockHandleLanguageSelected}
|
||||||
|
supportedLanguages={[
|
||||||
|
{ label: 'English', value: 'en' },
|
||||||
|
{ label: 'Español', value: 'es' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</IntlProvider>
|
||||||
|
));
|
||||||
|
|
||||||
fireEvent.submit(screen.getByTestId('site-footer-submit-btn'), {
|
wrapper.find('form').simulate('submit', {
|
||||||
target: {
|
target: {
|
||||||
elements: {
|
elements: {
|
||||||
'site-footer-language-select': {
|
'site-footer-language-select': {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-i18n';
|
||||||
|
|
||||||
const LanguageSelector = ({
|
const LanguageSelector = ({
|
||||||
intl, options, onSubmit, ...props
|
intl, options, onSubmit, ...props
|
||||||
@@ -17,8 +17,8 @@ const LanguageSelector = ({
|
|||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
{/* eslint-disable-next-line jsx-a11y/label-has-for */}
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
|
|
||||||
<label htmlFor="site-footer-language-select" className="d-inline-block m-0">
|
<label htmlFor="site-footer-language-select" className="d-inline-block m-0">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="footer.languageForm.select.label"
|
id="footer.languageForm.select.label"
|
||||||
@@ -32,9 +32,10 @@ const LanguageSelector = ({
|
|||||||
name="site-footer-language-select"
|
name="site-footer-language-select"
|
||||||
defaultValue={intl.locale}
|
defaultValue={intl.locale}
|
||||||
>
|
>
|
||||||
{options.map(({ value, label }) => <option key={value} value={value}>{label}</option>)}
|
{options.map(({ value, label }) =>
|
||||||
|
<option key={value} value={value}>{label}</option>)}
|
||||||
</select>
|
</select>
|
||||||
<button data-testid="site-footer-submit-btn" className="btn btn-outline-primary btn-sm" type="submit">
|
<button className="btn btn-outline-primary btn-sm" type="submit">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="footer.languageForm.submit.label"
|
id="footer.languageForm.submit.label"
|
||||||
defaultMessage="Apply"
|
defaultMessage="Apply"
|
||||||
|
|||||||
@@ -2,23 +2,24 @@
|
|||||||
|
|
||||||
exports[`<Footer /> renders correctly renders with a language selector 1`] = `
|
exports[`<Footer /> renders correctly renders with a language selector 1`] = `
|
||||||
<footer
|
<footer
|
||||||
|
aria-label="edX Home"
|
||||||
className="footer d-flex border-top py-3 px-4"
|
className="footer d-flex border-top py-3 px-4"
|
||||||
role="contentinfo"
|
role="contentinfo"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="container-fluid d-flex"
|
className="container d-flex"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
aria-label="edX Home"
|
aria-label="edX Home"
|
||||||
className="d-block"
|
className="d-block mb-3"
|
||||||
href="http://localhost:18000"
|
href="https://open.edx.org"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Powered by Open edX"
|
alt="Powered by Open edX"
|
||||||
src="https://edx-cdn.org/v3/default/logo-trademark.svg"
|
src="test-file-stub"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"maxHeight": 45,
|
"maxWidth": 150,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -37,7 +38,9 @@ exports[`<Footer /> renders correctly renders with a language selector 1`] = `
|
|||||||
className="d-inline-block m-0"
|
className="d-inline-block m-0"
|
||||||
htmlFor="site-footer-language-select"
|
htmlFor="site-footer-language-select"
|
||||||
>
|
>
|
||||||
Choose Language
|
<span>
|
||||||
|
Choose Language
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
className="form-control-sm mx-2"
|
className="form-control-sm mx-2"
|
||||||
@@ -58,10 +61,11 @@ exports[`<Footer /> renders correctly renders with a language selector 1`] = `
|
|||||||
</select>
|
</select>
|
||||||
<button
|
<button
|
||||||
className="btn btn-outline-primary btn-sm"
|
className="btn btn-outline-primary btn-sm"
|
||||||
data-testid="site-footer-submit-btn"
|
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
Apply
|
<span>
|
||||||
|
Apply
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -71,23 +75,24 @@ exports[`<Footer /> renders correctly renders with a language selector 1`] = `
|
|||||||
|
|
||||||
exports[`<Footer /> renders correctly renders without a language selector 1`] = `
|
exports[`<Footer /> renders correctly renders without a language selector 1`] = `
|
||||||
<footer
|
<footer
|
||||||
|
aria-label="edX Home"
|
||||||
className="footer d-flex border-top py-3 px-4"
|
className="footer d-flex border-top py-3 px-4"
|
||||||
role="contentinfo"
|
role="contentinfo"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="container-fluid d-flex"
|
className="container d-flex"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
aria-label="edX Home"
|
aria-label="edX Home"
|
||||||
className="d-block"
|
className="d-block mb-3"
|
||||||
href="http://localhost:18000"
|
href="https://open.edx.org"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Powered by Open edX"
|
alt="Powered by Open edX"
|
||||||
src="https://edx-cdn.org/v3/default/logo-trademark.svg"
|
src="test-file-stub"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"maxHeight": 45,
|
"maxWidth": 150,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -101,23 +106,24 @@ exports[`<Footer /> renders correctly renders without a language selector 1`] =
|
|||||||
|
|
||||||
exports[`<Footer /> renders correctly renders without a language selector in es 1`] = `
|
exports[`<Footer /> renders correctly renders without a language selector in es 1`] = `
|
||||||
<footer
|
<footer
|
||||||
|
aria-label="edX Home"
|
||||||
className="footer d-flex border-top py-3 px-4"
|
className="footer d-flex border-top py-3 px-4"
|
||||||
role="contentinfo"
|
role="contentinfo"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="container-fluid d-flex"
|
className="container d-flex"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
aria-label="edX Home"
|
aria-label="edX Home"
|
||||||
className="d-block"
|
className="d-block mb-3"
|
||||||
href="http://localhost:18000"
|
href="https://open.edx.org"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Powered by Open edX"
|
alt="Powered by Open edX"
|
||||||
src="https://edx-cdn.org/v3/default/logo-trademark.svg"
|
src="test-file-stub"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"maxHeight": 45,
|
"maxWidth": 150,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import { intlShape, injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n';
|
|
||||||
import { ensureConfig } from '@edx/frontend-platform';
|
|
||||||
import { AppContext } from '@edx/frontend-platform/react';
|
|
||||||
import {
|
|
||||||
ActionRow,
|
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Hyperlink,
|
|
||||||
Image,
|
|
||||||
TransitionReplace,
|
|
||||||
} from '@openedx/paragon';
|
|
||||||
import { ExpandLess, ExpandMore, Help } from '@openedx/paragon/icons';
|
|
||||||
import messages from './messages';
|
|
||||||
|
|
||||||
ensureConfig([
|
|
||||||
'LMS_BASE_URL',
|
|
||||||
'MARKETING_SITE_BASE_URL',
|
|
||||||
'TERMS_OF_SERVICE_URL',
|
|
||||||
'PRIVACY_POLICY_URL',
|
|
||||||
'SUPPORT_EMAIL',
|
|
||||||
'SITE_NAME',
|
|
||||||
'STUDIO_BASE_URL',
|
|
||||||
'ENABLE_ACCESSIBILITY_PAGE',
|
|
||||||
], 'Studio Footer component');
|
|
||||||
|
|
||||||
const StudioFooter = ({
|
|
||||||
// injected
|
|
||||||
intl,
|
|
||||||
}) => {
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const { config } = useContext(AppContext);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="m-0 mt-6 row align-items-center justify-content-center">
|
|
||||||
<div className="col border-top mr-2" />
|
|
||||||
<Button
|
|
||||||
data-testid="helpToggleButton"
|
|
||||||
variant="outline-primary"
|
|
||||||
onClick={() => setIsOpen(!isOpen)}
|
|
||||||
iconBefore={Help}
|
|
||||||
iconAfter={isOpen ? ExpandLess : ExpandMore}
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
{isOpen ? intl.formatMessage(messages.closeHelpButtonLabel)
|
|
||||||
: intl.formatMessage(messages.openHelpButtonLabel)}
|
|
||||||
</Button>
|
|
||||||
<div className="col border-top ml-2" />
|
|
||||||
</div>
|
|
||||||
<Container size="xl" className="px-4">
|
|
||||||
<TransitionReplace>
|
|
||||||
{isOpen ? (
|
|
||||||
<ActionRow key="help-link-button-row" className="py-4" data-testid="helpButtonRow">
|
|
||||||
<ActionRow.Spacer />
|
|
||||||
<Button as="a" href="https://docs.edx.org/" size="sm">
|
|
||||||
<FormattedMessage {...messages.edxDocumentationButtonLabel} />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
as="a"
|
|
||||||
href="https://open.edx.org/"
|
|
||||||
size="sm"
|
|
||||||
data-testid="openEdXPortalButton"
|
|
||||||
>
|
|
||||||
<FormattedMessage {...messages.openEdxPortalButtonLabel} />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
as="a"
|
|
||||||
href="https://www.edx.org/course/edx101-overview-of-creating-an-edx-course#.VO4eaLPF-n1"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
<FormattedMessage {...messages.edx101ButtonLabel} />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
as="a"
|
|
||||||
href="https://www.edx.org/course/studiox-creating-a-course-with-edx-studio"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
<FormattedMessage {...messages.studioXButtonLabel} />
|
|
||||||
</Button>
|
|
||||||
{!_.isEmpty(config.SUPPORT_EMAIL) && (
|
|
||||||
<Button
|
|
||||||
as="a"
|
|
||||||
href={`mailto:${config.SUPPORT_EMAIL}`}
|
|
||||||
size="sm"
|
|
||||||
data-testid="contactUsButton"
|
|
||||||
>
|
|
||||||
<FormattedMessage {...messages.contactUsButtonLabel} />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<ActionRow.Spacer />
|
|
||||||
</ActionRow>
|
|
||||||
) : null}
|
|
||||||
</TransitionReplace>
|
|
||||||
<ActionRow className="pt-3 m-0 x-small">
|
|
||||||
© {new Date().getFullYear()} <Hyperlink destination={config.MARKETING_SITE_BASE_URL} target="_blank" className="ml-2">{config.SITE_NAME}</Hyperlink>
|
|
||||||
<ActionRow.Spacer />
|
|
||||||
{!_.isEmpty(config.TERMS_OF_SERVICE_URL) && (
|
|
||||||
<Hyperlink destination={config.TERMS_OF_SERVICE_URL} data-testid="termsOfService">
|
|
||||||
{intl.formatMessage(messages.termsOfServiceLinkLabel)}
|
|
||||||
</Hyperlink>
|
|
||||||
)}{!_.isEmpty(config.PRIVACY_POLICY_URL) && (
|
|
||||||
<Hyperlink destination={config.PRIVACY_POLICY_URL} data-testid="privacyPolicy">
|
|
||||||
{intl.formatMessage(messages.privacyPolicyLinkLabel)}
|
|
||||||
</Hyperlink>
|
|
||||||
)}
|
|
||||||
{config.ENABLE_ACCESSIBILITY_PAGE === 'true' && (
|
|
||||||
<Hyperlink
|
|
||||||
destination={`${config.STUDIO_BASE_URL}/accessibility`}
|
|
||||||
data-testid="accessibilityRequest"
|
|
||||||
>
|
|
||||||
{intl.formatMessage(messages.accessibilityRequestLinkLabel)}
|
|
||||||
</Hyperlink>
|
|
||||||
)}
|
|
||||||
<Hyperlink destination={config.LMS_BASE_URL}>LMS</Hyperlink>
|
|
||||||
</ActionRow>
|
|
||||||
<ActionRow className="mt-3 pb-4 x-small">
|
|
||||||
{/*
|
|
||||||
Site operators: Please do not remove this paragraph! this attributes back to edX and
|
|
||||||
makes your acknowledgement of edX's trademarks clear.
|
|
||||||
Translators: 'edX' and 'Open edX' are trademarks of 'edX Inc.'. Please do not translate
|
|
||||||
any of these trademarks and company names.
|
|
||||||
*/}
|
|
||||||
<FormattedMessage {...messages.trademarkMessage} />
|
|
||||||
<Hyperlink className="ml-1" destination="https://www.edx.org">edX Inc</Hyperlink>.
|
|
||||||
<ActionRow.Spacer />
|
|
||||||
<Hyperlink destination="https://open.edx.org" className="float-right">
|
|
||||||
<Image
|
|
||||||
width="120px"
|
|
||||||
alt="Powered by Open edX"
|
|
||||||
src="https://logos.openedx.org/open-edx-logo-tag.png"
|
|
||||||
/>
|
|
||||||
</Hyperlink>
|
|
||||||
</ActionRow>
|
|
||||||
</Container>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
StudioFooter.propTypes = {
|
|
||||||
// injected
|
|
||||||
intl: intlShape.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default injectIntl(StudioFooter);
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
/* eslint-disable react/prop-types */
|
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import { fireEvent, render, screen } from '@testing-library/react';
|
|
||||||
import '@testing-library/jest-dom/extend-expect';
|
|
||||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
|
||||||
import { AppContext } from '@edx/frontend-platform/react';
|
|
||||||
import StudioFooter from './StudioFooter';
|
|
||||||
import messages from './messages';
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
LMS_BASE_URL: process.env.LMS_BASE_URL,
|
|
||||||
MARKETING_SITE_BASE_URL: process.env.MARKETING_SITE_BASE_URL,
|
|
||||||
TERMS_OF_SERVICE_URL: process.env.TERMS_OF_SERVICE_URL,
|
|
||||||
PRIVACY_POLICY_URL: process.env.PRIVACY_POLICY_URL,
|
|
||||||
SUPPORT_EMAIL: process.env.SUPPORT_EMAIL,
|
|
||||||
SITE_NAME: process.env.SITE_NAME,
|
|
||||||
STUDIO_BASE_URL: process.env.STUDIO_BASE_URL,
|
|
||||||
ENABLE_ACCESSIBILITY_PAGE: process.env.ENABLE_ACCESSIBILITY_PAGE,
|
|
||||||
};
|
|
||||||
|
|
||||||
let currentConfig = config;
|
|
||||||
const Component = ({ updateVariable }) => {
|
|
||||||
if (updateVariable) {
|
|
||||||
const [variable, value] = updateVariable;
|
|
||||||
currentConfig = {
|
|
||||||
...config,
|
|
||||||
[variable]: value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const contextValue = useMemo(() => ({
|
|
||||||
authenticatedUser: null,
|
|
||||||
config: currentConfig,
|
|
||||||
}), []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IntlProvider locale="en">
|
|
||||||
<AppContext.Provider value={contextValue}>
|
|
||||||
<StudioFooter />
|
|
||||||
</AppContext.Provider>
|
|
||||||
</IntlProvider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
jest.unmock('@openedx/paragon');
|
|
||||||
|
|
||||||
describe('Footer', () => {
|
|
||||||
describe('help section default view', () => {
|
|
||||||
it('help button should read Looking for help with Studio?', () => {
|
|
||||||
render(<Component />);
|
|
||||||
expect(screen.getByText(messages.openHelpButtonLabel.defaultMessage))
|
|
||||||
.toBeVisible();
|
|
||||||
});
|
|
||||||
it('help button link row should not be visible', () => {
|
|
||||||
render(<Component />);
|
|
||||||
expect(screen.queryByTestId('helpButtonRow')).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('help section expanded view', () => {
|
|
||||||
it('help button should read Hide Studio help', () => {
|
|
||||||
render(<Component />);
|
|
||||||
const helpToggleButton = screen.getByText(messages.openHelpButtonLabel.defaultMessage);
|
|
||||||
fireEvent.click(helpToggleButton);
|
|
||||||
expect(screen.getByText(messages.closeHelpButtonLabel.defaultMessage))
|
|
||||||
.toBeVisible();
|
|
||||||
});
|
|
||||||
it('help button link row should be visible', () => {
|
|
||||||
render(<Component />);
|
|
||||||
const helpToggleButton = screen.getByText(messages.openHelpButtonLabel.defaultMessage);
|
|
||||||
fireEvent.click(helpToggleButton);
|
|
||||||
expect(screen.getByTestId('helpButtonRow')).toBeVisible();
|
|
||||||
});
|
|
||||||
it('Open edX portal button should be visible', () => {
|
|
||||||
render(<Component />);
|
|
||||||
const helpToggleButton = screen.getByText(messages.openHelpButtonLabel.defaultMessage);
|
|
||||||
fireEvent.click(helpToggleButton);
|
|
||||||
expect(screen.getByTestId('openEdXPortalButton')).toBeVisible();
|
|
||||||
});
|
|
||||||
it('should not show contact us button', () => {
|
|
||||||
render(<Component />);
|
|
||||||
const helpToggleButton = screen.getByText(messages.openHelpButtonLabel.defaultMessage);
|
|
||||||
fireEvent.click(helpToggleButton);
|
|
||||||
expect(screen.queryByTestId('contactUsButton')).toBeNull();
|
|
||||||
});
|
|
||||||
it('should show contact us button', () => {
|
|
||||||
render(<Component updateVariable={['SUPPORT_EMAIL', 'support@email.com']} />);
|
|
||||||
const helpToggleButton = screen.getByText(messages.openHelpButtonLabel.defaultMessage);
|
|
||||||
fireEvent.click(helpToggleButton);
|
|
||||||
expect(screen.getByTestId('contactUsButton')).toBeVisible();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('policy link row', () => {
|
|
||||||
it('should only show LMS link', () => {
|
|
||||||
render(<Component />);
|
|
||||||
expect(screen.getByText('LMS')).toBeVisible();
|
|
||||||
expect(screen.queryByTestId('termsOfService')).toBeNull();
|
|
||||||
expect(screen.queryByTestId('privacyPolicy')).toBeNull();
|
|
||||||
expect(screen.queryByTestId('accessibilityRequest')).toBeNull();
|
|
||||||
});
|
|
||||||
it('should show terms of service link', () => {
|
|
||||||
render(<Component updateVariable={['TERMS_OF_SERVICE_URL', 'termsofserviceurl']} />);
|
|
||||||
expect(screen.getByText('LMS')).toBeVisible();
|
|
||||||
expect(screen.queryByTestId('termsOfService')).toBeVisible();
|
|
||||||
expect(screen.queryByTestId('privacyPolicy')).toBeNull();
|
|
||||||
expect(screen.queryByTestId('accessibilityRequest')).toBeNull();
|
|
||||||
});
|
|
||||||
it('should show privacy policy link', () => {
|
|
||||||
render(<Component updateVariable={['PRIVACY_POLICY_URL', 'privacypolicyurl']} />);
|
|
||||||
expect(screen.getByText('LMS')).toBeVisible();
|
|
||||||
expect(screen.queryByTestId('termsOfService')).toBeNull();
|
|
||||||
expect(screen.queryByTestId('privacyPolicy')).toBeVisible();
|
|
||||||
expect(screen.queryByTestId('accessibilityRequest')).toBeNull();
|
|
||||||
});
|
|
||||||
it('should show accessibilty request link', () => {
|
|
||||||
render(<Component updateVariable={['ENABLE_ACCESSIBILITY_PAGE', 'true']} />);
|
|
||||||
expect(screen.getByText('LMS')).toBeVisible();
|
|
||||||
expect(screen.queryByTestId('termsOfService')).toBeNull();
|
|
||||||
expect(screen.queryByTestId('privacyPolicy')).toBeNull();
|
|
||||||
expect(screen.queryByTestId('accessibilityRequest')).toBeVisible();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import StudioFooter from './StudioFooter';
|
|
||||||
|
|
||||||
export default StudioFooter;
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
openHelpButtonLabel: {
|
|
||||||
id: 'authoring.footer.help.openHelp.button.label',
|
|
||||||
defaultMessage: 'Looking for help with Studio?',
|
|
||||||
description: 'Label for button that opens the collapsed section with help buttons',
|
|
||||||
},
|
|
||||||
closeHelpButtonLabel: {
|
|
||||||
id: 'authoring.footer.help.closeHelp.button.label',
|
|
||||||
defaultMessage: 'Hide Studio help',
|
|
||||||
description: 'Label for button that closes the collapsed section with help buttons',
|
|
||||||
},
|
|
||||||
edxDocumentationButtonLabel: {
|
|
||||||
id: 'authoring.footer.help.edxDocumentation.button.label',
|
|
||||||
defaultMessage: 'edX documentation',
|
|
||||||
description: 'Label for button that links to the edX documentation site',
|
|
||||||
},
|
|
||||||
openEdxPortalButtonLabel: {
|
|
||||||
id: 'authoring.footer.help.openEdxPortal.button.label',
|
|
||||||
defaultMessage: 'Open edX portal',
|
|
||||||
description: 'Label for button that links to the Open edX portal',
|
|
||||||
},
|
|
||||||
edx101ButtonLabel: {
|
|
||||||
id: 'authoring.footer.help.edx101.button.label',
|
|
||||||
defaultMessage: 'Enroll in edX 101',
|
|
||||||
description: 'Label for button that links to the edX 101 course',
|
|
||||||
},
|
|
||||||
studioXButtonLabel: {
|
|
||||||
id: 'authoring.footer.help.studioX.button.label',
|
|
||||||
defaultMessage: 'Enroll in StudioX',
|
|
||||||
description: 'Label for button that links to the edX StudioX course',
|
|
||||||
},
|
|
||||||
contactUsButtonLabel: {
|
|
||||||
id: 'authoring.footer.help.contactUs.button.label',
|
|
||||||
defaultMessage: 'Contact us',
|
|
||||||
description: 'Label for button that links to the email for partner support',
|
|
||||||
},
|
|
||||||
termsOfServiceLinkLabel: {
|
|
||||||
id: 'authoring.footer.termsOfService.link.label',
|
|
||||||
defaultMessage: 'Terms of Service',
|
|
||||||
description: 'Label for button that links to the terms of service page',
|
|
||||||
},
|
|
||||||
privacyPolicyLinkLabel: {
|
|
||||||
id: 'authoring.footer.privacyPolicy.link.label',
|
|
||||||
defaultMessage: 'Privacy Policy',
|
|
||||||
description: 'Label for button that links to the privacy policy page',
|
|
||||||
},
|
|
||||||
accessibilityRequestLinkLabel: {
|
|
||||||
id: 'authoring.footer.accessibilityRequest.link.label',
|
|
||||||
defaultMessage: 'Accessibility Accomodation Request',
|
|
||||||
description: 'Label for button that links to the accessibility accomodation requests page',
|
|
||||||
},
|
|
||||||
trademarkMessage: {
|
|
||||||
id: 'authoring.footer.trademark.message',
|
|
||||||
defaultMessage: 'edX and Open edX, and the edX and Open edX logos are registered trademarks of',
|
|
||||||
description: 'Message about the use of logos and names edX and Open edX',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default messages;
|
|
||||||
BIN
src/edx-openedx-logo-tag.png
Normal file
BIN
src/edx-openedx-logo-tag.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -1,34 +1,32 @@
|
|||||||
import arMessages from './messages/ar.json';
|
import arMessages from './messages/ar.json';
|
||||||
import frMessages from './messages/fr.json';
|
import caMessages from './messages/ca.json';
|
||||||
import es419Messages from './messages/es_419.json';
|
|
||||||
import zhcnMessages from './messages/zh_CN.json';
|
|
||||||
import ptMessages from './messages/pt.json';
|
|
||||||
import itMessages from './messages/it.json';
|
|
||||||
import ukMessages from './messages/uk.json';
|
|
||||||
import deMessages from './messages/de.json';
|
|
||||||
import ruMessages from './messages/ru.json';
|
|
||||||
import hiMessages from './messages/hi.json';
|
|
||||||
import frCAMessages from './messages/fr_CA.json';
|
|
||||||
import dedeCAMessages from './messages/de_DE.json';
|
|
||||||
import ititCAMessages from './messages/it_IT.json';
|
|
||||||
import ptptCAMessages from './messages/pt_PT.json';
|
|
||||||
// no need to import en messages-- they are in the defaultMessage field
|
// no need to import en messages-- they are in the defaultMessage field
|
||||||
|
import es419Messages from './messages/es_419.json';
|
||||||
|
import frMessages from './messages/fr.json';
|
||||||
|
import zhcnMessages from './messages/zh_CN.json';
|
||||||
|
import heMessages from './messages/he.json';
|
||||||
|
import idMessages from './messages/id.json';
|
||||||
|
import kokrMessages from './messages/ko_kr.json';
|
||||||
|
import plMessages from './messages/pl.json';
|
||||||
|
import ptbrMessages from './messages/pt_br.json';
|
||||||
|
import ruMessages from './messages/ru.json';
|
||||||
|
import thMessages from './messages/th.json';
|
||||||
|
import ukMessages from './messages/uk.json';
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
ar: arMessages,
|
ar: arMessages,
|
||||||
'es-419': es419Messages,
|
'es-419': es419Messages,
|
||||||
fr: frMessages,
|
fr: frMessages,
|
||||||
'zh-cn': zhcnMessages,
|
'zh-cn': zhcnMessages,
|
||||||
pt: ptMessages,
|
ca: caMessages,
|
||||||
it: itMessages,
|
he: heMessages,
|
||||||
de: deMessages,
|
id: idMessages,
|
||||||
hi: hiMessages,
|
'ko-kr': kokrMessages,
|
||||||
'fr-ca': frCAMessages,
|
pl: plMessages,
|
||||||
|
'pt-br': ptbrMessages,
|
||||||
ru: ruMessages,
|
ru: ruMessages,
|
||||||
|
th: thMessages,
|
||||||
uk: ukMessages,
|
uk: ukMessages,
|
||||||
'de-de': dedeCAMessages,
|
|
||||||
'it-it': ititCAMessages,
|
|
||||||
'pt-pt': ptptCAMessages,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default messages;
|
export default messages;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import Footer, { EVENT_NAMES } from './components/Footer';
|
import Footer, { EVENT_NAMES } from './components/Footer';
|
||||||
import messages from './i18n/index';
|
import messages from './i18n/index';
|
||||||
import StudioFooter from './components/studio-footer';
|
|
||||||
|
|
||||||
export default Footer;
|
export default Footer;
|
||||||
export { messages, EVENT_NAMES, StudioFooter };
|
export { messages, EVENT_NAMES };
|
||||||
|
|||||||
@@ -1,22 +1,4 @@
|
|||||||
// These configuration values are usually set in webpack's EnvironmentPlugin however
|
import Enzyme from 'enzyme';
|
||||||
// Jest does not use webpack so we need to set these so for testing
|
import Adapter from 'enzyme-adapter-react-16';
|
||||||
process.env.ACCESS_TOKEN_COOKIE_NAME = 'edx-jwt-cookie-header-payload';
|
|
||||||
process.env.BASE_URL = 'localhost:1995';
|
Enzyme.configure({ adapter: new Adapter() });
|
||||||
process.env.CREDENTIALS_BASE_URL = 'http://localhost:18150';
|
|
||||||
process.env.CSRF_TOKEN_API_PATH = '/csrf/api/v1/token';
|
|
||||||
process.env.ECOMMERCE_BASE_URL = 'http://localhost:18130';
|
|
||||||
process.env.LANGUAGE_PREFERENCE_COOKIE_NAME = 'openedx-language-preference';
|
|
||||||
process.env.LMS_BASE_URL = 'http://localhost:18000';
|
|
||||||
process.env.LOGIN_URL = 'http://localhost:18000/login';
|
|
||||||
process.env.LOGOUT_URL = 'http://localhost:18000/login';
|
|
||||||
process.env.MARKETING_SITE_BASE_URL = 'http://localhost:18000';
|
|
||||||
process.env.ORDER_HISTORY_URL = 'localhost:1996/orders';
|
|
||||||
process.env.REFRESH_ACCESS_TOKEN_ENDPOINT = 'http://localhost:18000/login_refresh';
|
|
||||||
process.env.SEGMENT_KEY = 'segment_whoa';
|
|
||||||
process.env.SITE_NAME = 'edX';
|
|
||||||
process.env.USER_INFO_COOKIE_NAME = 'edx-user-info';
|
|
||||||
process.env.LOGO_URL = 'https://edx-cdn.org/v3/default/logo.svg';
|
|
||||||
process.env.LOGO_TRADEMARK_URL = 'https://edx-cdn.org/v3/default/logo-trademark.svg';
|
|
||||||
process.env.LOGO_WHITE_URL = 'https://edx-cdn.org/v3/default/logo-white.svg';
|
|
||||||
process.env.FAVICON_URL = 'https://edx-cdn.org/v3/default/favicon.ico';
|
|
||||||
process.env.ENABLE_ACCESSIBILITY_PAGE = 'false';
|
|
||||||
|
|||||||
1275
stats.json
Normal file
1275
stats.json
Normal file
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { createConfig } = require('@openedx/frontend-build');
|
const { createConfig } = require('@edx/frontend-build');
|
||||||
|
|
||||||
module.exports = createConfig('webpack-dev', {
|
module.exports = createConfig('webpack-dev', {
|
||||||
entry: path.resolve(__dirname, 'example'),
|
entry: path.resolve(__dirname, 'example'),
|
||||||
@@ -7,9 +7,4 @@ module.exports = createConfig('webpack-dev', {
|
|||||||
path: path.resolve(__dirname, 'example/dist'),
|
path: path.resolve(__dirname, 'example/dist'),
|
||||||
publicPath: '/',
|
publicPath: '/',
|
||||||
},
|
},
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'@edx/frontend-component-footer': path.resolve(__dirname, 'src'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user