diff --git a/package-lock.json b/package-lock.json index 4926a8f9c..a0a3f295c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", "@edx/browserslist-config": "^1.1.0", + "@edx/frontend-component-header": "^5.3.1", "@edx/frontend-enterprise-hotjar": "3.0.0", "@edx/frontend-platform": "^7.1.4", "@edx/openedx-atlas": "^0.6.0", @@ -2136,19 +2137,6 @@ "node": ">=6" } }, - "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/free-regular-svg-icons": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.2.tgz", - "integrity": "sha512-iabw/f5f8Uy2nTRtJ13XZTS1O5+t+anvlamJ3zJGLEVE2pKsAWhPv2lq01uQlfgCX7VaveT3EVs515cCN9jRbw==", - "hasInstallScript": true, - "peer": true, - "dependencies": { - "@fortawesome/fontawesome-common-types": "6.5.2" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/free-solid-svg-icons": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz", @@ -2815,6 +2803,491 @@ "node": ">=12" } }, + "node_modules/@edx/frontend-component-header": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-5.3.1.tgz", + "integrity": "sha512-hhraVbtmdaXSgaZZJOuEPeQNi5YXJwOfmoCdLsmh6WiTdGG5BusiFoF4SRyKKiTZuayhPFKGFFC8D0AwRxmKhg==", + "license": "AGPL-3.0", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "6.5.2", + "@fortawesome/free-brands-svg-icons": "6.5.2", + "@fortawesome/free-regular-svg-icons": "6.5.2", + "@fortawesome/free-solid-svg-icons": "6.5.2", + "@fortawesome/react-fontawesome": "^0.2.0", + "axios-mock-adapter": "1.22.0", + "babel-polyfill": "6.26.0", + "jest-environment-jsdom": "^29.7.0", + "react-responsive": "8.2.0", + "react-transition-group": "4.4.5" + }, + "peerDependencies": { + "@edx/frontend-platform": "^7.0.0 || ^8.0.0", + "@openedx/paragon": ">= 21.5.7 < 23.0.0", + "prop-types": "^15.5.10", + "react": "^16.9.0 || ^17.0.0", + "react-dom": "^16.9.0 || ^17.0.0" + } + }, + "node_modules/@edx/frontend-component-header/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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-header/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, + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.2.tgz", + "integrity": "sha512-zi5FNYdmKLnEc0jc0uuHH17kz/hfYTg4Uei0wMGzcoCL/4d3WM3u1VMc0iGGa31HuhV5i7ZK8ZlTCQrHqRHSGQ==", + "hasInstallScript": true, + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz", + "integrity": "sha512-QWFZYXFE7O1Gr1dTIp+D6UcFUF0qElOnZptpi7PBUMylJh+vFmIedVe1Ir6RM1t2tEQLLSV1k7bR4o92M+uqlw==", + "hasInstallScript": true, + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "license": "MIT", + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/@edx/frontend-component-header/node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "license": "MIT" + }, + "node_modules/@edx/frontend-component-header/node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/jest-environment-jsdom": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/@edx/frontend-component-header/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/@edx/frontend-component-header/node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@edx/frontend-component-header/node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, "node_modules/@edx/frontend-enterprise-hotjar": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@edx/frontend-enterprise-hotjar/-/frontend-enterprise-hotjar-3.0.0.tgz", @@ -3712,6 +4185,29 @@ "node": ">=6" } }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.2.tgz", + "integrity": "sha512-iabw/f5f8Uy2nTRtJ13XZTS1O5+t+anvlamJ3zJGLEVE2pKsAWhPv2lq01uQlfgCX7VaveT3EVs515cCN9jRbw==", + "hasInstallScript": true, + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-regular-svg-icons/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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/@fortawesome/free-solid-svg-icons": { "version": "5.15.4", "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz", @@ -8736,7 +9232,6 @@ "version": "20.0.1", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", - "peer": true, "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", @@ -8747,7 +9242,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "peer": true, "dependencies": { "entities": "^4.4.0" }, @@ -8929,8 +9423,7 @@ "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "peer": true + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==" }, "node_modules/@types/warning": { "version": "3.0.0", @@ -9380,9 +9873,10 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -9975,7 +10469,6 @@ "version": "1.22.0", "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.22.0.tgz", "integrity": "sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", "is-buffer": "^2.0.5" @@ -16786,7 +17279,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true, "funding": [ { "type": "github", diff --git a/package.json b/package.json index 6c4004783..a52ef237d 100755 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "dependencies": { "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", "@edx/browserslist-config": "^1.1.0", + "@edx/frontend-component-header": "^5.3.1", "@edx/frontend-enterprise-hotjar": "3.0.0", "@edx/frontend-platform": "^7.1.4", "@edx/openedx-atlas": "^0.6.0", diff --git a/src/App.scss b/src/App.scss index eed6b145a..9092d14c0 100755 --- a/src/App.scss +++ b/src/App.scss @@ -9,6 +9,7 @@ $fa-font-path: "~font-awesome/fonts"; $input-focus-box-shadow: $input-box-shadow; // hack to get upgrade to paragon 4.0.0 to work +@import "~@edx/frontend-component-header/dist/index"; @import "~@edx/frontend-component-footer/dist/_footer"; .text-ellipsis { @@ -36,19 +37,6 @@ $input-focus-box-shadow: $input-box-shadow; // hack to get upgrade to paragon 4. header { flex: 0 0 auto; - - .logo { - display: block; - box-sizing: content-box; - position: relative; - top: 0.1em; - height: 1.75rem; - margin-right: 1rem; - img { - display: block; - height: 100%; - } - } } footer { diff --git a/src/containers/LearnerDashboardHeader/CollapsedHeader/CollapseMenuBody.jsx b/src/containers/LearnerDashboardHeader/CollapsedHeader/CollapseMenuBody.jsx deleted file mode 100644 index 82de5aaf5..000000000 --- a/src/containers/LearnerDashboardHeader/CollapsedHeader/CollapseMenuBody.jsx +++ /dev/null @@ -1,104 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { getConfig } from '@edx/frontend-platform'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { AppContext } from '@edx/frontend-platform/react'; -import { Button, Badge } from '@openedx/paragon'; - -import urls from 'data/services/lms/urls'; -import { reduxHooks } from 'hooks'; - -import { findCoursesNavDropdownClicked } from '../hooks'; -import messages from '../messages'; - -export const CollapseMenuBody = ({ isOpen }) => { - const { formatMessage } = useIntl(); - const { authenticatedUser } = React.useContext(AppContext); - - const dashboard = reduxHooks.useEnterpriseDashboardData(); - const { courseSearchUrl } = reduxHooks.usePlatformSettingsData(); - - const exploreCoursesClick = findCoursesNavDropdownClicked( - urls.baseAppUrl(courseSearchUrl), - ); - - if (!isOpen) { - return null; - } - - return ( -
- - - - - {authenticatedUser && ( - <> - {!!dashboard && ( - - )} - {!dashboard && getConfig().CAREER_LINK_URL && ( - - )} - - - {getConfig().ORDER_HISTORY_URL && ( - - )} - - - )} -
- ); -}; - -CollapseMenuBody.propTypes = { - isOpen: PropTypes.bool.isRequired, -}; - -export default CollapseMenuBody; diff --git a/src/containers/LearnerDashboardHeader/CollapsedHeader/CollapseMenuBody.test.jsx b/src/containers/LearnerDashboardHeader/CollapsedHeader/CollapseMenuBody.test.jsx deleted file mode 100644 index 2af8ae7e6..000000000 --- a/src/containers/LearnerDashboardHeader/CollapsedHeader/CollapseMenuBody.test.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import { shallow } from '@edx/react-unit-test-utils'; -import { AppContext } from '@edx/frontend-platform/react'; - -import CollapseMenuBody from './CollapseMenuBody'; - -jest.mock('@edx/frontend-platform/react', () => ({ - AppContext: { - authenticatedUser: { - username: 'username', - }, - }, -})); - -jest.mock('hooks', () => ({ - reduxHooks: { - useEnterpriseDashboardData: () => ({ - url: 'url', - }), - usePlatformSettingsData: () => ({ - courseSearchUrl: '/courseSearchUrl', - }), - }, -})); - -jest.mock('../hooks', () => ({ - findCoursesNavDropdownClicked: (url) => jest.fn().mockName(`findCoursesNavDropdownClicked("${url}")`), -})); - -describe('CollapseMenuBody', () => { - test('render', () => { - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - }); - - test('render empty if not open', () => { - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - expect(wrapper.isEmptyRender()).toBe(true); - }); - - test('render unauthenticated', () => { - const { authenticatedUser } = AppContext; - AppContext.authenticatedUser = null; - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - AppContext.authenticatedUser = authenticatedUser; - }); -}); diff --git a/src/containers/LearnerDashboardHeader/CollapsedHeader/__snapshots__/CollapseMenuBody.test.jsx.snap b/src/containers/LearnerDashboardHeader/CollapsedHeader/__snapshots__/CollapseMenuBody.test.jsx.snap deleted file mode 100644 index c8cc4de83..000000000 --- a/src/containers/LearnerDashboardHeader/CollapsedHeader/__snapshots__/CollapseMenuBody.test.jsx.snap +++ /dev/null @@ -1,105 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CollapseMenuBody render 1`] = ` -
- - - - - - - - - - -
-`; - -exports[`CollapseMenuBody render empty if not open 1`] = `null`; - -exports[`CollapseMenuBody render unauthenticated 1`] = ` -
- - - - -
-`; diff --git a/src/containers/LearnerDashboardHeader/CollapsedHeader/__snapshots__/index.test.jsx.snap b/src/containers/LearnerDashboardHeader/CollapsedHeader/__snapshots__/index.test.jsx.snap deleted file mode 100644 index 2a1dc7bc4..000000000 --- a/src/containers/LearnerDashboardHeader/CollapsedHeader/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,48 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CollapsedHeader render nothing if not collapsed 1`] = `false`; - -exports[`CollapsedHeader renders 1`] = ` - -
- - -
- -
-`; - -exports[`CollapsedHeader renders with isOpen true 1`] = ` - -
- - -
- -
-`; diff --git a/src/containers/LearnerDashboardHeader/CollapsedHeader/index.jsx b/src/containers/LearnerDashboardHeader/CollapsedHeader/index.jsx deleted file mode 100644 index 5cf9762bc..000000000 --- a/src/containers/LearnerDashboardHeader/CollapsedHeader/index.jsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; - -import { useIntl } from '@edx/frontend-platform/i18n'; -import { MenuIcon, Close } from '@openedx/paragon/icons'; -import { IconButton, Icon } from '@openedx/paragon'; - -import { useLearnerDashboardHeaderData, useIsCollapsed } from '../hooks'; - -import CollapseMenuBody from './CollapseMenuBody'; -import BrandLogo from '../BrandLogo'; - -import messages from '../messages'; - -export const CollapsedHeader = () => { - const { formatMessage } = useIntl(); - const isCollapsed = useIsCollapsed(); - const { isOpen, toggleIsOpen } = useLearnerDashboardHeaderData(); - - return ( - isCollapsed && ( - <> -
- - -
- - - ) - ); -}; - -CollapsedHeader.propTypes = {}; - -export default CollapsedHeader; diff --git a/src/containers/LearnerDashboardHeader/CollapsedHeader/index.test.jsx b/src/containers/LearnerDashboardHeader/CollapsedHeader/index.test.jsx deleted file mode 100644 index c21e98ccd..000000000 --- a/src/containers/LearnerDashboardHeader/CollapsedHeader/index.test.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import { shallow } from '@edx/react-unit-test-utils'; - -import CollapsedHeader from '.'; - -import { useLearnerDashboardHeaderData, useIsCollapsed } from '../hooks'; - -jest.mock('../BrandLogo', () => jest.fn(() => 'BrandLogo')); -jest.mock('./CollapseMenuBody', () => jest.fn(() => 'CollapseMenuBody')); - -jest.mock('../hooks', () => ({ - useIsCollapsed: jest.fn(() => true), - useLearnerDashboardHeaderData: jest.fn(() => ({ - isOpen: false, - toggleIsOpen: jest.fn().mockName('toggleIsOpen'), - })), -})); - -describe('CollapsedHeader', () => { - it('renders', () => { - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - }); - - it('render nothing if not collapsed', () => { - useIsCollapsed.mockReturnValueOnce(false); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - }); - - it('renders with isOpen true', () => { - useLearnerDashboardHeaderData.mockReturnValueOnce({ - isOpen: true, - toggleIsOpen: jest.fn().mockName('toggleIsOpen'), - }); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - }); -}); diff --git a/src/containers/LearnerDashboardHeader/ExpandedHeader/AuthenticatedUserDropdown.jsx b/src/containers/LearnerDashboardHeader/ExpandedHeader/AuthenticatedUserDropdown.jsx deleted file mode 100644 index e0751bb38..000000000 --- a/src/containers/LearnerDashboardHeader/ExpandedHeader/AuthenticatedUserDropdown.jsx +++ /dev/null @@ -1,78 +0,0 @@ -import React from 'react'; - -import { getConfig } from '@edx/frontend-platform'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { AppContext } from '@edx/frontend-platform/react'; -import { AvatarButton, Dropdown, Badge } from '@openedx/paragon'; - -import { reduxHooks } from 'hooks'; - -import messages from '../messages'; - -export const AuthenticatedUserDropdown = () => { - const { formatMessage } = useIntl(); - const { authenticatedUser } = React.useContext(AppContext); - const dashboard = reduxHooks.useEnterpriseDashboardData(); - - return ( - authenticatedUser && ( - - - - {authenticatedUser.username} - - - - { getConfig().ENABLE_EDX_PERSONAL_DASHBOARD && ( - <> - {formatMessage(messages.dashboardSwitch)} - - {formatMessage(messages.dashboardPersonal)} - - {!!dashboard && ( - - {dashboard.label} {formatMessage(messages.dashboard)} - - )} - - - )} - - {!dashboard && getConfig().CAREER_LINK_URL && ( - - {formatMessage(messages.career)} - - {formatMessage(messages.newAlert)} - - - )} - - {formatMessage(messages.profile)} - - - {formatMessage(messages.account)} - - {getConfig().ORDER_HISTORY_URL && ( - - {formatMessage(messages.orderHistory)} - - )} - - - {formatMessage(messages.signOut)} - - - - ) - ); -}; - -AuthenticatedUserDropdown.propTypes = {}; - -export default AuthenticatedUserDropdown; diff --git a/src/containers/LearnerDashboardHeader/ExpandedHeader/AuthenticatedUserDropdown.test.jsx b/src/containers/LearnerDashboardHeader/ExpandedHeader/AuthenticatedUserDropdown.test.jsx deleted file mode 100644 index e7452d355..000000000 --- a/src/containers/LearnerDashboardHeader/ExpandedHeader/AuthenticatedUserDropdown.test.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import { shallow } from '@edx/react-unit-test-utils'; - -import { reduxHooks } from 'hooks'; -import { getConfig } from '@edx/frontend-platform'; -import { AppContext } from '@edx/frontend-platform/react'; -import { AuthenticatedUserDropdown } from './AuthenticatedUserDropdown'; -import { useIsCollapsed } from '../hooks'; - -jest.mock('@edx/frontend-platform', () => ({ - getConfig: jest.fn(), -})); - -jest.mock('@edx/frontend-platform/react', () => ({ - AppContext: { - authenticatedUser: { - profileImage: 'profileImage', - username: 'username', - }, - }, -})); -const COURSE_SEARCH_URL = 'test-course-search-url'; - -jest.mock('hooks', () => ({ - reduxHooks: { - useEnterpriseDashboardData: jest.fn(), - usePlatformSettingsData: jest.fn(() => ({ - courseSearchUrl: COURSE_SEARCH_URL, - })), - }, -})); -jest.mock('../hooks', () => ({ - useIsCollapsed: jest.fn(), - findCoursesNavDropdownClicked: (href) => jest.fn().mockName(`findCoursesNavDropdownClicked('${href}')`), -})); - -jest.mock('data/services/lms/urls', () => ({ - baseAppUrl: (url) => (url), - programsUrl: 'http://localhost:18000/dashboard/programs', -})); - -const config = { - ACCOUNT_PROFILE_URL: 'http://account-profile-url.test', - ACCOUNT_SETTINGS_URL: 'http://account-settings-url.test', - LOGOUT_URL: 'http://logout-url.test', - ORDER_HISTORY_URL: 'http://order-history-url.test', - SUPPORT_URL: 'http://localhost:18000/support', - CAREER_LINK_URL: 'http://localhost:18000/career', - LMS_BASE_URL: 'http:/localhost:18000', - ENABLE_EDX_PERSONAL_DASHBOARD: true, -}; -getConfig.mockReturnValue(config); - -describe('AuthenticatedUserDropdown', () => { - const defaultDashboardData = { - label: 'label', - url: 'url', - }; - - describe('snapshots', () => { - test('no auth render empty', () => { - const { authenticatedUser } = AppContext; - AppContext.authenticatedUser = null; - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - expect(wrapper.isEmptyRender()).toBe(true); - AppContext.authenticatedUser = authenticatedUser; - }); - test('with enterprise dashboard', () => { - reduxHooks.useEnterpriseDashboardData.mockReturnValueOnce(defaultDashboardData); - useIsCollapsed.mockReturnValueOnce(true); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - }); - test('without enterprise dashboard and expanded', () => { - reduxHooks.useEnterpriseDashboardData.mockReturnValueOnce(null); - useIsCollapsed.mockReturnValueOnce(false); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - }); - }); -}); diff --git a/src/containers/LearnerDashboardHeader/ExpandedHeader/__snapshots__/AuthenticatedUserDropdown.test.jsx.snap b/src/containers/LearnerDashboardHeader/ExpandedHeader/__snapshots__/AuthenticatedUserDropdown.test.jsx.snap deleted file mode 100644 index eafdef3ce..000000000 --- a/src/containers/LearnerDashboardHeader/ExpandedHeader/__snapshots__/AuthenticatedUserDropdown.test.jsx.snap +++ /dev/null @@ -1,139 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`AuthenticatedUserDropdown snapshots no auth render empty 1`] = `null`; - -exports[`AuthenticatedUserDropdown snapshots with enterprise dashboard 1`] = ` - - - - username - - - - - - SWITCH DASHBOARD - - - Personal - - - label - - Dashboard - - - - - Profile - - - Account - - - Order History - - - - Sign Out - - - -`; - -exports[`AuthenticatedUserDropdown snapshots without enterprise dashboard and expanded 1`] = ` - - - - username - - - - - - SWITCH DASHBOARD - - - Personal - - - - - Career - - New - - - - Profile - - - Account - - - Order History - - - - Sign Out - - - -`; diff --git a/src/containers/LearnerDashboardHeader/ExpandedHeader/__snapshots__/index.test.jsx.snap b/src/containers/LearnerDashboardHeader/ExpandedHeader/__snapshots__/index.test.jsx.snap deleted file mode 100644 index 44e08f166..000000000 --- a/src/containers/LearnerDashboardHeader/ExpandedHeader/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,52 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ExpandedHeader render 1`] = ` -
-
- - - - - - -
- -
-`; - -exports[`ExpandedHeader render empty if collapsed 1`] = `null`; diff --git a/src/containers/LearnerDashboardHeader/ExpandedHeader/index.jsx b/src/containers/LearnerDashboardHeader/ExpandedHeader/index.jsx deleted file mode 100644 index f257cbc57..000000000 --- a/src/containers/LearnerDashboardHeader/ExpandedHeader/index.jsx +++ /dev/null @@ -1,76 +0,0 @@ -import React from 'react'; - -import { getConfig } from '@edx/frontend-platform'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { Button } from '@openedx/paragon'; - -import urls from 'data/services/lms/urls'; -import { reduxHooks } from 'hooks'; - -import AuthenticatedUserDropdown from './AuthenticatedUserDropdown'; -import { useIsCollapsed, findCoursesNavClicked } from '../hooks'; -import messages from '../messages'; -import BrandLogo from '../BrandLogo'; - -export const ExpandedHeader = () => { - const { formatMessage } = useIntl(); - const { courseSearchUrl } = reduxHooks.usePlatformSettingsData(); - const isCollapsed = useIsCollapsed(); - - const exploreCoursesClick = findCoursesNavClicked( - urls.baseAppUrl(courseSearchUrl), - ); - - if (isCollapsed) { - return null; - } - - return ( -
-
- - - - - - - -
- - -
- ); -}; - -ExpandedHeader.propTypes = {}; - -export default ExpandedHeader; diff --git a/src/containers/LearnerDashboardHeader/ExpandedHeader/index.test.jsx b/src/containers/LearnerDashboardHeader/ExpandedHeader/index.test.jsx deleted file mode 100644 index 3b96a1dbf..000000000 --- a/src/containers/LearnerDashboardHeader/ExpandedHeader/index.test.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import { shallow } from '@edx/react-unit-test-utils'; - -import ExpandedHeader from '.'; - -import { useIsCollapsed } from '../hooks'; - -jest.mock('data/services/lms/urls', () => ({ - programsUrl: () => 'programsUrl', - baseAppUrl: url => (`http://localhost:18000${url}`), -})); - -jest.mock('hooks', () => ({ - reduxHooks: { - usePlatformSettingsData: () => ({ - courseSearchUrl: '/courseSearchUrl', - }), - }, -})); - -jest.mock('../hooks', () => ({ - useIsCollapsed: jest.fn(), - findCoursesNavClicked: (url) => jest.fn().mockName(`findCoursesNavClicked("${url}")`), -})); - -jest.mock('./AuthenticatedUserDropdown', () => 'AuthenticatedUserDropdown'); -jest.mock('../BrandLogo', () => 'BrandLogo'); - -describe('ExpandedHeader', () => { - test('render', () => { - useIsCollapsed.mockReturnValueOnce(false); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - }); - - test('render empty if collapsed', () => { - useIsCollapsed.mockReturnValueOnce(true); - const wrapper = shallow(); - expect(wrapper.snapshot).toMatchSnapshot(); - expect(wrapper.isEmptyRender()).toBe(true); - }); -}); diff --git a/src/containers/LearnerDashboardHeader/LearnerDashboardMenu.jsx b/src/containers/LearnerDashboardHeader/LearnerDashboardMenu.jsx new file mode 100644 index 000000000..9dcecc3a1 --- /dev/null +++ b/src/containers/LearnerDashboardHeader/LearnerDashboardMenu.jsx @@ -0,0 +1,75 @@ +import { getConfig } from '@edx/frontend-platform'; + +import urls from 'data/services/lms/urls'; + +import messages from './messages'; + +const getLearnerHeaderMenu = ( + formatMessage, + courseSearchUrl, + authenticatedUser, + exploreCoursesClick, +) => ({ + mainMenu: [ + { + type: 'item', + href: '/', + content: formatMessage(messages.course), + isActive: true, + }, + { + type: 'item', + href: `${urls.programsUrl()}`, + content: formatMessage(messages.program), + }, + { + type: 'item', + href: `${urls.baseAppUrl(courseSearchUrl)}`, + content: formatMessage(messages.discoverNew), + onClick: (e) => { + exploreCoursesClick(e); + }, + }, + ], + secondaryMenu: [ + { + type: 'item', + href: `${getConfig().SUPPORT_URL}`, + content: formatMessage(messages.help), + }, + ], + userMenu: [ + { + heading: '', + items: [ + { + type: 'item', + href: `${getConfig().ACCOUNT_PROFILE_URL}/u/${authenticatedUser?.username}`, + content: formatMessage(messages.profile), + }, + { + type: 'item', + href: `${getConfig().ACCOUNT_SETTINGS_URL}`, + content: formatMessage(messages.account), + }, + ...(getConfig().ORDER_HISTORY_URL ? [{ + type: 'item', + href: getConfig().ORDER_HISTORY_URL, + content: formatMessage(messages.orderHistory), + }] : []), + ], + }, + { + heading: '', + items: [ + { + type: 'item', + href: `${getConfig().LOGOUT_URL}`, + content: formatMessage(messages.signOut), + }, + ], + }, + ], +}); + +export default getLearnerHeaderMenu; diff --git a/src/containers/LearnerDashboardHeader/__snapshots__/index.test.jsx.snap b/src/containers/LearnerDashboardHeader/__snapshots__/index.test.jsx.snap index 87ec64c7d..2b7fed432 100644 --- a/src/containers/LearnerDashboardHeader/__snapshots__/index.test.jsx.snap +++ b/src/containers/LearnerDashboardHeader/__snapshots__/index.test.jsx.snap @@ -3,8 +3,72 @@ exports[`LearnerDashboardHeader render 1`] = ` - - +
`; diff --git a/src/containers/LearnerDashboardHeader/hooks.js b/src/containers/LearnerDashboardHeader/hooks.js index 7eee8437d..115322c1d 100644 --- a/src/containers/LearnerDashboardHeader/hooks.js +++ b/src/containers/LearnerDashboardHeader/hooks.js @@ -1,9 +1,12 @@ import React from 'react'; import { useWindowSize, breakpoints } from '@openedx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; import track from 'tracking'; import { StrictDict } from 'utils'; import { linkNames } from 'tracking/constants'; +import getLearnerHeaderMenu from './LearnerDashboardMenu'; + import * as module from './hooks'; export const state = StrictDict({ @@ -24,6 +27,13 @@ export const findCoursesNavDropdownClicked = (href) => track.findCourses.findCou linkName: linkNames.learnerHomeNavDropdownExplore, }); +export const useLearnerDashboardHeaderMenu = ({ + courseSearchUrl, authenticatedUser, exploreCoursesClick, +}) => { + const { formatMessage } = useIntl(); + return getLearnerHeaderMenu(formatMessage, courseSearchUrl, authenticatedUser, exploreCoursesClick); +}; + export const useLearnerDashboardHeaderData = () => { const [isOpen, setIsOpen] = module.state.isOpen(false); const toggleIsOpen = () => setIsOpen(!isOpen); @@ -39,4 +49,5 @@ export default { findCoursesNavClicked, findCoursesNavDropdownClicked, useLearnerDashboardHeaderData, + useLearnerDashboardHeaderMenu, }; diff --git a/src/containers/LearnerDashboardHeader/hooks.test.js b/src/containers/LearnerDashboardHeader/hooks.test.js index 72349f6e2..c9bac080a 100644 --- a/src/containers/LearnerDashboardHeader/hooks.test.js +++ b/src/containers/LearnerDashboardHeader/hooks.test.js @@ -13,6 +13,7 @@ const { findCoursesNavClicked, findCoursesNavDropdownClicked, useLearnerDashboardHeaderData, + useLearnerDashboardHeaderMenu, } = hooks; jest.mock('tracking', () => ({ @@ -48,6 +49,17 @@ describe('LearnerDashboardHeader hooks', () => { }); }); + describe('getLearnerDashboardHeaderMenu', () => { + test('calls header menu data hook', () => { + const courseSearchUrl = '/courses'; + const authenticatedUser = { + username: 'test', + }; + const learnerHomeHeaderMenu = useLearnerDashboardHeaderMenu({ courseSearchUrl, authenticatedUser }); + expect(learnerHomeHeaderMenu.mainMenu.length).toBe(3); + }); + }); + describe('findCoursesNavDropdownClicked', () => { test('calls tracking with dropdown link name', () => { findCoursesNavDropdownClicked(url); diff --git a/src/containers/LearnerDashboardHeader/index.jsx b/src/containers/LearnerDashboardHeader/index.jsx index dfa8dbfb0..84f79e5fb 100644 --- a/src/containers/LearnerDashboardHeader/index.jsx +++ b/src/containers/LearnerDashboardHeader/index.jsx @@ -1,21 +1,41 @@ import React from 'react'; import MasqueradeBar from 'containers/MasqueradeBar'; +import { AppContext } from '@edx/frontend-platform/react'; +import Header from '@edx/frontend-component-header'; +import { reduxHooks } from 'hooks'; +import urls from 'data/services/lms/urls'; + import ConfirmEmailBanner from './ConfirmEmailBanner'; -import CollapsedHeader from './CollapsedHeader'; -import ExpandedHeader from './ExpandedHeader'; +import { useLearnerDashboardHeaderMenu, findCoursesNavClicked } from './hooks'; + +export const LearnerDashboardHeader = () => { + const { authenticatedUser } = React.useContext(AppContext); + const { courseSearchUrl } = reduxHooks.usePlatformSettingsData(); + + const exploreCoursesClick = () => { + findCoursesNavClicked(urls.baseAppUrl(courseSearchUrl)); + }; -import './index.scss'; + const learnerHomeHeaderMenu = useLearnerDashboardHeaderMenu({ + courseSearchUrl, + authenticatedUser, + exploreCoursesClick, + }); -export const LearnerDashboardHeader = () => ( - <> - - - - - -); + return ( + <> + +
+ + + ); +}; LearnerDashboardHeader.propTypes = {}; diff --git a/src/containers/LearnerDashboardHeader/index.scss b/src/containers/LearnerDashboardHeader/index.scss deleted file mode 100644 index d8bd8da1b..000000000 --- a/src/containers/LearnerDashboardHeader/index.scss +++ /dev/null @@ -1,38 +0,0 @@ -.dropdown-menu-collapse { - width: 100vw; - position: absolute; - left: 0; -} - -.learner-variant-header { - a { - // needed to make the link not resize the header - border-bottom: 2px solid transparent; - } - .course-link { - border-bottom: 2px solid !important; - } - - .course-link:hover { - border-bottom: inherit !important; - } -} - -.nav-small-menu { - > * { - justify-content: flex-start !important; - - border-radius: 0 !important; - border-top: 1px solid #ddd !important; - - &::after { - content: '\00BB'; - padding-left: 10px; - } - } -} - -.logo { - // copy from legacy dashboard - height: 40px; -} diff --git a/src/containers/LearnerDashboardHeader/index.test.jsx b/src/containers/LearnerDashboardHeader/index.test.jsx index a7335565e..79b7549ef 100644 --- a/src/containers/LearnerDashboardHeader/index.test.jsx +++ b/src/containers/LearnerDashboardHeader/index.test.jsx @@ -1,18 +1,36 @@ +import { mergeConfig } from '@edx/frontend-platform'; import { shallow } from '@edx/react-unit-test-utils'; +import Header from '@edx/frontend-component-header'; + +import urls from 'data/services/lms/urls'; import LearnerDashboardHeader from '.'; +import { findCoursesNavClicked } from './hooks'; + +jest.mock('hooks', () => ({ + reduxHooks: { + usePlatformSettingsData: jest.fn(() => ({ + courseSearchUrl: '/course-search-url', + })), + }, +})); +jest.mock('./hooks', () => ({ + ...jest.requireActual('./hooks'), + findCoursesNavClicked: jest.fn(), +})); jest.mock('containers/MasqueradeBar', () => 'MasqueradeBar'); -jest.mock('./CollapsedHeader', () => 'CollapsedHeader'); jest.mock('./ConfirmEmailBanner', () => 'ConfirmEmailBanner'); -jest.mock('./ExpandedHeader', () => 'ExpandedHeader'); +jest.mock('@edx/frontend-component-header', () => 'Header'); describe('LearnerDashboardHeader', () => { test('render', () => { + mergeConfig({ ORDER_HISTORY_URL: 'test-url' }); const wrapper = shallow(); expect(wrapper.snapshot).toMatchSnapshot(); expect(wrapper.instance.findByType('ConfirmEmailBanner')).toHaveLength(1); expect(wrapper.instance.findByType('MasqueradeBar')).toHaveLength(1); - expect(wrapper.instance.findByType('CollapsedHeader')).toHaveLength(1); - expect(wrapper.instance.findByType('ExpandedHeader')).toHaveLength(1); + expect(wrapper.instance.findByType(Header)).toHaveLength(1); + wrapper.instance.findByType(Header)[0].props.mainMenuItems[2].onClick(); + expect(findCoursesNavClicked).toHaveBeenCalledWith(urls.baseAppUrl('/course-search-url')); }); }); diff --git a/src/containers/LearnerDashboardHeader/messages.js b/src/containers/LearnerDashboardHeader/messages.js index 08c71cd78..bed227f95 100644 --- a/src/containers/LearnerDashboardHeader/messages.js +++ b/src/containers/LearnerDashboardHeader/messages.js @@ -1,21 +1,6 @@ import { defineMessages } from '@edx/frontend-platform/i18n'; const messages = defineMessages({ - dashboard: { - id: 'learnerVariantDashboard.menu.dashboard.label', - defaultMessage: 'Dashboard', - description: 'The text for the user menu Dashboard navigation link.', - }, - dashboardPersonal: { - id: 'learnerVariantDashboard.menu.dashboardPersonal.label', - defaultMessage: 'Personal', - description: 'Link to personal dashboard in user menu', - }, - dashboardSwitch: { - id: 'learnerVariantDashboard.menu.dashboardSwitch.label', - defaultMessage: 'SWITCH DASHBOARD', - description: 'Switch Dashboard header in the user menu', - }, help: { id: 'learnerVariantDashboard.help.label', defaultMessage: 'Help', @@ -26,11 +11,6 @@ const messages = defineMessages({ defaultMessage: 'Profile', description: 'The text for the user menu Profile navigation link.', }, - viewPrograms: { - id: 'learnerVariantDashboard.menu.viewPrograms.label', - defaultMessage: 'View Programs', - description: 'The text for the user menu View Programs navigation link.', - }, account: { id: 'learnerVariantDashboard.menu.account.label', defaultMessage: 'Account', @@ -66,26 +46,6 @@ const messages = defineMessages({ defaultMessage: 'edX, Inc. Dashboard', description: 'Alt text for the edX logo.', }, - collapseMenuOpenAltText: { - id: 'learnerVariantDashboard.collapseMenuOpenAltText', - defaultMessage: 'Menu', - description: 'Alt text for the collapse menu icon when the menu is open.', - }, - collapseMenuClosedAltText: { - id: 'learnerVariantDashboard.collapseMenuClosedAltText', - defaultMessage: 'Close', - description: 'Alt text for the collapse menu icon when the menu is closed.', - }, - career: { - id: 'leanerDashboard.menu.career.label', - defaultMessage: 'Career', - description: 'The text for the user menu Career navigation link.', - }, - newAlert: { - id: 'header.menu.new.label', - defaultMessage: 'New', - description: 'The text announcing that an item in the user menu is New', - }, }); export default messages;