diff --git a/.env b/.env index fd3b59f..c2fd5a2 100644 --- a/.env +++ b/.env @@ -55,6 +55,7 @@ MFE_CONFIG_API_URL='' DISABLE_DESKTOP_HEADER=false DISABLE_HEADER_LOGO=false +ENABLE_DASHBOARD_RETURN_LINK=false ACCESS_DENIED_PAGE_INSTRUCTIONS_LINK='' ACCESS_DENIED_PAGE_STUDENT_PORTAL_LINK='' ACCESS_DENIED_PAGE_STUDENT_PORTAL_LINK_TEXT='' diff --git a/.env.acaddev b/.env.acaddev index 7c7178a..011a3aa 100644 --- a/.env.acaddev +++ b/.env.acaddev @@ -58,9 +58,12 @@ PUBLIC_PATH='/wgulearning/' APP_ID='wgulearning' MFE_CONFIG_API_URL='https://devapp.learn.academy.test/api/mfe_config/v1' -DISABLE_APP_FOOTER=true -DISABLE_DESKTOP_HEADER=true -DISABLE_HEADER_LOGO=true +DISABLE_APP_FOOTER=false +DISABLE_DESKTOP_HEADER=false +DISABLE_HEADER_LOGO=false +FOOTER_LINK_MAP='[{"label": "Help Center", "url": "https://academy.test/help-center", "id": 1}]' +ENABLE_DASHBOARD_RETURN_LINK=true +DASHBOARD_BASE_URL='https://academy.test' ACCESS_DENIED_PAGE_INSTRUCTIONS_LINK='http://example.com' ACCESS_DENIED_PAGE_STUDENT_PORTAL_LINK='https://learn.academy.test/dashboard' ACCESS_DENIED_PAGE_STUDENT_PORTAL_LINK_TEXT='Student Dashboard' diff --git a/.env.development b/.env.development index 5c72a16..ddc1d75 100644 --- a/.env.development +++ b/.env.development @@ -61,6 +61,7 @@ MFE_CONFIG_API_URL='http://apps.local.overhang.io/api/mfe_config/v1' DISABLE_APP_FOOTER=false DISABLE_DESKTOP_HEADER=false DISABLE_HEADER_LOGO=false +ENABLE_DASHBOARD_RETURN_LINK=false ACCESS_DENIED_PAGE_INSTRUCTIONS_LINK='http://example.com' ACCESS_DENIED_PAGE_STUDENT_PORTAL_LINK='http://local.overhang.io/dashboard' ACCESS_DENIED_PAGE_STUDENT_PORTAL_LINK_TEXT='Student Portal' diff --git a/package-lock.json b/package-lock.json index d616c1f..7a9cbcd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "license": "AGPL-3.0", "dependencies": { "@edx/brand": "npm:@edx/brand-openedx@1.2.0", - "@edx/frontend-app-learning": "github:wgu-opensource/frontend-app-learning#0.5.5", + "@edx/frontend-app-learning": "github:wgu-opensource/frontend-app-learning#0.6.0", "@edx/frontend-component-footer": "12.1.2", "@edx/frontend-component-header": "4.2.3", "@edx/frontend-platform": "4.2.0", @@ -2012,36 +2012,43 @@ }, "node_modules/@edx/frontend-app-learning": { "version": "1.0.0-semantically-released", - "resolved": "git+ssh://git@github.com/wgu-opensource/frontend-app-learning.git#4e4f41abd188d0b1a164972756e8ab6f9b4b3a95", + "resolved": "git+ssh://git@github.com/wgu-opensource/frontend-app-learning.git#bed47cd9f52121a51fc5865d4048fe49b5fc74e1", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { - "@edx/brand": "npm:@edx/brand-openedx@1.1.0", + "@edx/brand": "npm:@edx/brand-openedx@1.2.0", "@edx/frontend-component-footer": "^12.0.0", "@edx/frontend-component-header": "^4.0.0", "@edx/frontend-lib-special-exams": "^2.16.1", "@edx/frontend-platform": "^4.2.0", + "@edx/paragon": "20.28.4", "@fortawesome/fontawesome-svg-core": "1.3.0", "@fortawesome/free-brands-svg-icons": "5.15.4", "@fortawesome/free-regular-svg-icons": "5.15.4", "@fortawesome/free-solid-svg-icons": "5.15.4", "@fortawesome/react-fontawesome": "0.1.18", - "@popperjs/core": "2.11.5", + "@popperjs/core": "2.11.6", "@reduxjs/toolkit": "1.8.1", - "classnames": "2.3.1", + "classnames": "2.3.2", "core-js": "3.22.2", - "history": "^5.3.0", + "history": "5.3.0", "js-cookie": "3.0.1", "lodash.camelcase": "4.3.0", "patch-package": "^8.0.0", - "query-string": "^7.1.1", + "prop-types": "15.8.1", + "query-string": "7.1.3", + "react": "16.14.0", + "react-dom": "16.14.0", "react-helmet": "6.1.0", + "react-redux": "7.2.9", "react-router": "5.2.1", - "react-share": "4.4.0", - "regenerator-runtime": "0.13.9", - "reselect": "4.1.5", + "react-router-dom": "5.3.0", + "react-share": "4.4.1", + "redux": "4.1.2", + "regenerator-runtime": "0.13.11", + "reselect": "4.1.7", "truncate-html": "1.0.4", - "util": "0.12.4" + "util": "0.12.5" }, "peerDependencies": { "@edx/frontend-build": ">= 8.1.0 || ^12.9.0-alpha.1", @@ -2054,11 +2061,62 @@ "redux": "^4.0.4" } }, - "node_modules/@edx/frontend-app-learning/node_modules/@edx/brand": { - "name": "@edx/brand-openedx", - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@edx/brand-openedx/-/brand-openedx-1.1.0.tgz", - "integrity": "sha512-ne2ZKF1r0akkt0rEzCAQAk4cTDTI2GiWCpc+T7ldQpw9X57OnUB16dKsFNe40C9uEjL5h3Ps/ZsFM5dm4cIkEQ==" + "node_modules/@edx/frontend-app-learning/node_modules/@edx/paragon": { + "version": "20.28.4", + "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.28.4.tgz", + "integrity": "sha512-JiEAUaEuOnHB/zC8h9d5f3AwchREiHFKbXFm7JpXNcvXpkTj0TTKTCS6zcfwZeDl77q/+Rx6Js7SpSE2EzAtDg==", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.1.1", + "@fortawesome/react-fontawesome": "^0.1.18", + "@popperjs/core": "^2.11.4", + "bootstrap": "^4.6.2", + "classnames": "^2.3.1", + "email-prop-type": "^3.0.0", + "file-selector": "^0.6.0", + "font-awesome": "^4.7.0", + "glob": "^8.0.3", + "lodash.uniqby": "^4.7.0", + "mailto-link": "^2.0.0", + "prop-types": "^15.8.1", + "react-bootstrap": "^1.6.5", + "react-dropzone": "^14.2.1", + "react-focus-on": "^3.5.4", + "react-loading-skeleton": "^3.1.0", + "react-popper": "^2.2.5", + "react-proptype-conditional-require": "^1.0.4", + "react-responsive": "^8.2.0", + "react-table": "^7.7.0", + "react-transition-group": "^4.4.2", + "tabbable": "^5.3.3", + "uncontrollable": "^7.2.1", + "uuid": "^9.0.0" + }, + "peerDependencies": { + "react": "^16.8.6 || ^17.0.0", + "react-dom": "^16.8.6 || ^17.0.0", + "react-intl": "^5.25.1" + } + }, + "node_modules/@edx/frontend-app-learning/node_modules/@edx/paragon/node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz", + "integrity": "sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-app-learning/node_modules/@edx/paragon/node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz", + "integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } }, "node_modules/@edx/frontend-app-learning/node_modules/@fortawesome/fontawesome-common-types": { "version": "0.3.0", @@ -2096,14 +2154,27 @@ } }, "node_modules/@edx/frontend-app-learning/node_modules/@popperjs/core": { - "version": "2.11.5", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", - "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==", + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, + "node_modules/@edx/frontend-app-learning/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@edx/frontend-app-learning/node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "node_modules/@edx/frontend-app-learning/node_modules/core-js": { "version": "3.22.2", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.2.tgz", @@ -2115,6 +2186,24 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/@edx/frontend-app-learning/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@edx/frontend-app-learning/node_modules/history": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", @@ -2123,6 +2212,17 @@ "@babel/runtime": "^7.7.6" } }, + "node_modules/@edx/frontend-app-learning/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@edx/frontend-app-learning/node_modules/query-string": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", @@ -2165,6 +2265,36 @@ "react": ">=15" } }, + "node_modules/@edx/frontend-app-learning/node_modules/react-router-dom": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", + "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.1", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/@edx/frontend-app-learning/node_modules/react-router-dom/node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, "node_modules/@edx/frontend-app-learning/node_modules/react-router/node_modules/history": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", @@ -2178,15 +2308,18 @@ "value-equal": "^1.0.1" } }, - "node_modules/@edx/frontend-app-learning/node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "node_modules/@edx/frontend-app-learning/node_modules/redux": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", + "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } }, "node_modules/@edx/frontend-app-learning/node_modules/reselect": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz", - "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==" + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" }, "node_modules/@edx/frontend-build": { "version": "12.9.2", @@ -20203,11 +20336,11 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-share": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/react-share/-/react-share-4.4.0.tgz", - "integrity": "sha512-POe8Ge/JT9Ew9iyW7CiYsCCWCb8uMJWqFl9S7W0fJ/oH5gBJNzukH0bL5vSr17KKG5h15d3GfKaoviI22BKeYA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-share/-/react-share-4.4.1.tgz", + "integrity": "sha512-AJ9m9RiJssqvYg7MoJUc9J0D7b/liWrsfQ99ndKc5vJ4oVHHd4Fy87jBlKEQPibT40oYA3AQ/a9/oQY6/yaigw==", "dependencies": { - "classnames": "^2.2.5", + "classnames": "^2.3.2", "jsonp": "^0.2.1" }, "engines": { @@ -20215,9 +20348,14 @@ "npm": ">=5.0.0" }, "peerDependencies": { - "react": "^16.3.0 || ^17" + "react": "^16.3.0 || ^17 || ^18" } }, + "node_modules/react-share/node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "node_modules/react-side-effect": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", @@ -22440,15 +22578,14 @@ } }, "node_modules/util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", "which-typed-array": "^1.1.2" } }, diff --git a/package.json b/package.json index d189474..a584205 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ }, "dependencies": { "@edx/brand": "npm:@edx/brand-openedx@1.2.0", - "@edx/frontend-app-learning": "github:wgu-opensource/frontend-app-learning#0.5.5", + "@edx/frontend-app-learning": "github:wgu-opensource/frontend-app-learning#0.6.0", "@edx/frontend-component-footer": "12.1.2", "@edx/frontend-component-header": "4.2.3", "@edx/frontend-platform": "4.2.0", diff --git a/src/features/course-player/sequence-container/SequenceContainer.test.jsx b/src/features/course-player/sequence-container/SequenceContainer.test.jsx index 9744e79..ec53551 100644 --- a/src/features/course-player/sequence-container/SequenceContainer.test.jsx +++ b/src/features/course-player/sequence-container/SequenceContainer.test.jsx @@ -22,11 +22,11 @@ describe('SequenceContainer', () => { unitId: unitBlocks[0].id, sequenceId: courseware.sequenceId, courseId: courseware.courseId, - unitNavigationHandler: () => {}, - nextSequenceHandler: () => {}, - previousSequenceHandler: () => {}, - toggleNotificationTray: () => {}, - setNotificationStatus: () => {}, + unitNavigationHandler: () => { }, + nextSequenceHandler: () => { }, + previousSequenceHandler: () => { }, + toggleNotificationTray: () => { }, + setNotificationStatus: () => { }, }; }); @@ -45,8 +45,8 @@ describe('SequenceContainer', () => { it('handles loading unit', async () => { render(); expect(await screen.findByText('Loading learning sequence...')).toBeInTheDocument(); - // Renders navigation buttons plus one button for each unit. - expect(screen.getAllByRole('button')).toHaveLength(3 + unitBlocks.length); + // Renders navigation buttons (4 prev, next, bookmark, notificaitons tray) plus one button for each unit. + expect(screen.getAllByRole('button')).toHaveLength(4 + unitBlocks.length); loadUnit(); await waitFor(() => expect(screen.queryByText('Loading learning sequence...')).not.toBeInTheDocument()); @@ -70,27 +70,6 @@ describe('SequenceContainer', () => { expect(nav).not.toBeVisible(); }); - it('has sidebar triggers button hidden', async () => { - // Sidebar triggers button is part of the Sequence component, shown only on sm screens, - // but we don't want to show it - - // Set width to less than small so the component is rendered - global.innerWidth = breakpoints.extraSmall.maxWidth; - - const { container } = render(); - appendStyles(container); - - let button; - await waitFor(() => { - button = container.querySelector('[aria-label="Show notification tray"]'); - if (!button) { - throw new Error('Sidebar triggers button not found in the DOM'); - } - }); - - expect(button).not.toBeVisible(); - }); - it('has bookmark button hidden', async () => { // Bookmark button is part of the Sequence component, but we don't want to show it const { container } = render(); diff --git a/src/features/footer/Footer.jsx b/src/features/footer/Footer.jsx index 6f59231..17350a2 100644 --- a/src/features/footer/Footer.jsx +++ b/src/features/footer/Footer.jsx @@ -17,18 +17,23 @@ ensureConfig([ 'SITE_NAME', ], 'Footer component'); -const Footer = ({ className }) => { +const Footer = ({ className, links }) => { const { config } = useContext(AppContext); const adaUrl = getConfig().ADA_URL; const copyRight = getConfig().COPYRIGHT_STRING; - const links = [ - { label: 'Privacy Policy', url: getConfig().PRIVACY_POLICY_URL, id: 1 }, - { label: 'Terms of Service', url: getConfig().TERMS_OF_SERVICE_URL, id: 2 }, - { label: 'Honor Code', url: getConfig().HONOR_CODE_URL, id: 3 }, - ]; const logo = getConfig().LOGO_TRADEMARK_URL; const logoAltText = `${getConfig().SITE_OPERATOR} logo`; + let footerlinks = []; + if (links == null) { + footerlinks = [ + { label: 'Privacy Policy', url: getConfig().PRIVACY_POLICY_URL, id: 1 }, + { label: 'Terms of Service', url: getConfig().TERMS_OF_SERVICE_URL, id: 2 }, + { label: 'Honor Code', url: getConfig().HONOR_CODE_URL, id: 3 }, + ]; + } else { + footerlinks = links; + } const externalLinkClickHandler = (event) => { const label = event.currentTarget.getAttribute('href'); @@ -76,7 +81,7 @@ const Footer = ({ className }) => {
- {links.map((link) => ( + {footerlinks.map((link) => ( { Footer.propTypes = { className: PropTypes.string, + links: PropTypes.arrayOf(PropTypes.objectOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))), }; Footer.defaultProps = { className: '', + links: null, }; export default Footer; diff --git a/src/features/footer/Footer.test.jsx b/src/features/footer/Footer.test.jsx index 635b5c7..9bfbd85 100644 --- a/src/features/footer/Footer.test.jsx +++ b/src/features/footer/Footer.test.jsx @@ -21,4 +21,15 @@ describe('Footer', () => { ), ).toBeInTheDocument()); }); + it('Renders Links', async () => { + render( +