Compare commits
1 Commits
open-relea
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a853f8ce0c |
1
Makefile
1
Makefile
@@ -55,7 +55,6 @@ validate:
|
||||
make validate-no-uncommitted-package-lock-changes
|
||||
npm run i18n_extract
|
||||
npm run lint -- --max-warnings 0
|
||||
npm run types
|
||||
npm run test
|
||||
npm run build
|
||||
npm run bundlewatch
|
||||
|
||||
386
package-lock.json
generated
386
package-lock.json
generated
@@ -12,7 +12,7 @@
|
||||
"dependencies": {
|
||||
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||
"@edx/browserslist-config": "1.2.0",
|
||||
"@edx/frontend-component-header": "^5.8.0",
|
||||
"@edx/frontend-component-header": "^5.3.3",
|
||||
"@edx/frontend-lib-learning-assistant": "^2.2.4",
|
||||
"@edx/frontend-lib-special-exams": "^3.1.3",
|
||||
"@edx/frontend-platform": "^8.0.0",
|
||||
@@ -52,7 +52,7 @@
|
||||
"sass": "^1.79.3",
|
||||
"sass-loader": "^16.0.2",
|
||||
"source-map-loader": "^5.0.0",
|
||||
"truncate-html": "1.0.4"
|
||||
"truncate-html": "1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@edx/reactifex": "2.2.0",
|
||||
@@ -2323,19 +2323,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header": {
|
||||
"version": "5.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-5.8.0.tgz",
|
||||
"integrity": "sha512-AgLgt1y5vrqx6cU3IDr7HKngJImTN48gCIaXdCQ4YhR4PpX3p+ZS9R5Ih0dapWtvnX0Oo2hT2ggUKORV0h90rw==",
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-5.3.4.tgz",
|
||||
"integrity": "sha512-niuaXu0+qWPHud9Bs1pqmNXvZc9jpf8WS270/2YEH5owokd+BiDwQ6MWkvS9qbuQIVGPGTSZFFTttUKmQO5O0A==",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "6.6.0",
|
||||
"@fortawesome/free-brands-svg-icons": "6.6.0",
|
||||
"@fortawesome/free-regular-svg-icons": "6.6.0",
|
||||
"@fortawesome/free-solid-svg-icons": "6.6.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@openedx/frontend-plugin-framework": "^1.3.0",
|
||||
"axios-mock-adapter": "1.22.0",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"classnames": "^2.5.1",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"react-responsive": "8.2.0",
|
||||
"react-transition-group": "4.4.5"
|
||||
@@ -2345,8 +2344,7 @@
|
||||
"@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",
|
||||
"react-router-dom": "^6.14.2"
|
||||
"react-dom": "^16.9.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/@fortawesome/free-brands-svg-icons": {
|
||||
@@ -5173,14 +5171,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cheerio": {
|
||||
"version": "0.22.31",
|
||||
"resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.31.tgz",
|
||||
"integrity": "sha512-Kt7Cdjjdi2XWSfrZ53v4Of0wG3ZcmaegFXjMmz9tfNrZSkzzo36G0AL1YqSdcIA78Etjt6E609pt5h1xnQkPUw==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/connect": {
|
||||
"version": "3.4.35",
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
|
||||
@@ -7276,9 +7266,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001669",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz",
|
||||
"integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==",
|
||||
"version": "1.0.30001664",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz",
|
||||
"integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -7351,118 +7341,164 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cheerio": {
|
||||
"version": "0.22.0",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
|
||||
"integrity": "sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==",
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz",
|
||||
"integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==",
|
||||
"dependencies": {
|
||||
"css-select": "~1.2.0",
|
||||
"dom-serializer": "~0.1.0",
|
||||
"entities": "~1.1.1",
|
||||
"htmlparser2": "^3.9.1",
|
||||
"lodash.assignin": "^4.0.9",
|
||||
"lodash.bind": "^4.1.4",
|
||||
"lodash.defaults": "^4.0.1",
|
||||
"lodash.filter": "^4.4.0",
|
||||
"lodash.flatten": "^4.2.0",
|
||||
"lodash.foreach": "^4.3.0",
|
||||
"lodash.map": "^4.4.0",
|
||||
"lodash.merge": "^4.4.0",
|
||||
"lodash.pick": "^4.2.1",
|
||||
"lodash.reduce": "^4.4.0",
|
||||
"lodash.reject": "^4.4.0",
|
||||
"lodash.some": "^4.4.0"
|
||||
"cheerio-select": "^2.1.0",
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.1.0",
|
||||
"encoding-sniffer": "^0.2.0",
|
||||
"htmlparser2": "^9.1.0",
|
||||
"parse5": "^7.1.2",
|
||||
"parse5-htmlparser2-tree-adapter": "^7.0.0",
|
||||
"parse5-parser-stream": "^7.1.2",
|
||||
"undici": "^6.19.5",
|
||||
"whatwg-mimetype": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
"node": ">=18.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/cheerio?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio/node_modules/css-select": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||
"integrity": "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==",
|
||||
"node_modules/cheerio-select": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
|
||||
"integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
|
||||
"dependencies": {
|
||||
"boolbase": "~1.0.0",
|
||||
"css-what": "2.1",
|
||||
"domutils": "1.5.1",
|
||||
"nth-check": "~1.0.1"
|
||||
"boolbase": "^1.0.0",
|
||||
"css-select": "^5.1.0",
|
||||
"css-what": "^6.1.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio/node_modules/css-what": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
|
||||
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
|
||||
"node_modules/cheerio-select/node_modules/css-select": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
||||
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^6.1.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"domutils": "^3.0.1",
|
||||
"nth-check": "^2.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio-select/node_modules/dom-serializer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio-select/node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio-select/node_modules/domutils": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio/node_modules/dom-serializer": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
|
||||
"integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^1.3.0",
|
||||
"entities": "^1.1.1"
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio/node_modules/domelementtype": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
|
||||
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
|
||||
},
|
||||
"node_modules/cheerio/node_modules/domhandler": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
|
||||
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "1"
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio/node_modules/domutils": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
|
||||
"integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||
"dependencies": {
|
||||
"dom-serializer": "0",
|
||||
"domelementtype": "1"
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio/node_modules/entities": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
|
||||
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
|
||||
},
|
||||
"node_modules/cheerio/node_modules/htmlparser2": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
|
||||
"integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==",
|
||||
"funding": [
|
||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"domelementtype": "^1.3.1",
|
||||
"domhandler": "^2.3.0",
|
||||
"domutils": "^1.5.1",
|
||||
"entities": "^1.1.1",
|
||||
"inherits": "^2.0.1",
|
||||
"readable-stream": "^3.1.1"
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.1.0",
|
||||
"entities": "^4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio/node_modules/nth-check": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
|
||||
"integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
|
||||
"dependencies": {
|
||||
"boolbase": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"node_modules/cheerio/node_modules/whatwg-mimetype": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
|
||||
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/child_process": {
|
||||
@@ -9002,6 +9038,40 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/encoding-sniffer": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
|
||||
"integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==",
|
||||
"dependencies": {
|
||||
"iconv-lite": "^0.6.3",
|
||||
"whatwg-encoding": "^3.1.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/encoding-sniffer/node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/encoding-sniffer/node_modules/whatwg-encoding": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
|
||||
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
|
||||
"dependencies": {
|
||||
"iconv-lite": "0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
@@ -14024,16 +14094,6 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.assignin": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
|
||||
"integrity": "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg=="
|
||||
},
|
||||
"node_modules/lodash.bind": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz",
|
||||
"integrity": "sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA=="
|
||||
},
|
||||
"node_modules/lodash.camelcase": {
|
||||
"version": "4.3.0",
|
||||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
|
||||
@@ -14043,26 +14103,6 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
||||
},
|
||||
"node_modules/lodash.defaults": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
||||
},
|
||||
"node_modules/lodash.filter": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz",
|
||||
"integrity": "sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ=="
|
||||
},
|
||||
"node_modules/lodash.flatten": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
|
||||
"integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="
|
||||
},
|
||||
"node_modules/lodash.foreach": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
|
||||
"integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ=="
|
||||
},
|
||||
"node_modules/lodash.isfunction": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.8.tgz",
|
||||
@@ -14081,11 +14121,6 @@
|
||||
"integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.map": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
|
||||
"integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q=="
|
||||
},
|
||||
"node_modules/lodash.memoize": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||
@@ -14102,31 +14137,11 @@
|
||||
"integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.pick": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
|
||||
"integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q=="
|
||||
},
|
||||
"node_modules/lodash.reduce": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
|
||||
"integrity": "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw=="
|
||||
},
|
||||
"node_modules/lodash.reject": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz",
|
||||
"integrity": "sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ=="
|
||||
},
|
||||
"node_modules/lodash.snakecase": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
|
||||
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="
|
||||
},
|
||||
"node_modules/lodash.some": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz",
|
||||
"integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ=="
|
||||
},
|
||||
"node_modules/lodash.uniq": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
|
||||
@@ -15598,6 +15613,43 @@
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/parse5-htmlparser2-tree-adapter": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
|
||||
"integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
|
||||
"dependencies": {
|
||||
"domhandler": "^5.0.2",
|
||||
"parse5": "^7.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/parse5-htmlparser2-tree-adapter/node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/parse5-parser-stream": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
|
||||
"integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
|
||||
"dependencies": {
|
||||
"parse5": "^7.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
@@ -19783,11 +19835,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/truncate-html": {
|
||||
"version": "1.0.4",
|
||||
"integrity": "sha512-FpDAlPzpJ3jlZiNEahRs584FS3jOSQafgj4cC9DmAYPct6uMZDLY625+eErRd43G35vGDrNq3i7b4aYUQ/Bxqw==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/truncate-html/-/truncate-html-1.1.1.tgz",
|
||||
"integrity": "sha512-8U5jgta8uapbnTId/h95a5EVFGld94V7pZ2iLH18lRppjx8+r/Zx0VdFYThRQEVjBhbG7W2Goiv+b1+kceeb7A==",
|
||||
"dependencies": {
|
||||
"@types/cheerio": "^0.22.8",
|
||||
"cheerio": "0.22.0"
|
||||
"cheerio": "^1.0.0-rc.12"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
@@ -20087,6 +20139,14 @@
|
||||
"integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz",
|
||||
"integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-canonical-property-names-ecmascript": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
|
||||
|
||||
11
package.json
11
package.json
@@ -13,15 +13,14 @@
|
||||
"build": "fedx-scripts webpack",
|
||||
"bundlewatch": "bundlewatch",
|
||||
"i18n_extract": "fedx-scripts formatjs extract",
|
||||
"lint": "fedx-scripts eslint --ext .js --ext .jsx --ext .ts --ext .tsx .",
|
||||
"lint:fix": "fedx-scripts eslint --fix --ext .js --ext .jsx --ext .ts --ext .tsx .",
|
||||
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
|
||||
"lint:fix": "fedx-scripts eslint --fix --ext .js --ext .jsx .",
|
||||
"prepare": "husky install",
|
||||
"postinstall": "patch-package",
|
||||
"snapshot": "fedx-scripts jest --updateSnapshot",
|
||||
"start": "fedx-scripts webpack-dev-server --progress",
|
||||
"dev": "PUBLIC_PATH=/learning/ MFE_CONFIG_API_URL='http://localhost:8000/api/mfe_config/v1' fedx-scripts webpack-dev-server --progress --host apps.local.openedx.io",
|
||||
"test": "fedx-scripts jest --coverage --passWithNoTests",
|
||||
"types": "tsc --noEmit"
|
||||
"test": "fedx-scripts jest --coverage --passWithNoTests"
|
||||
},
|
||||
"author": "edX",
|
||||
"license": "AGPL-3.0",
|
||||
@@ -35,7 +34,7 @@
|
||||
"dependencies": {
|
||||
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||
"@edx/browserslist-config": "1.2.0",
|
||||
"@edx/frontend-component-header": "^5.8.0",
|
||||
"@edx/frontend-component-header": "^5.3.3",
|
||||
"@edx/frontend-lib-learning-assistant": "^2.2.4",
|
||||
"@edx/frontend-lib-special-exams": "^3.1.3",
|
||||
"@edx/frontend-platform": "^8.0.0",
|
||||
@@ -75,7 +74,7 @@
|
||||
"sass": "^1.79.3",
|
||||
"sass-loader": "^16.0.2",
|
||||
"source-map-loader": "^5.0.0",
|
||||
"truncate-html": "1.0.4"
|
||||
"truncate-html": "1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@edx/reactifex": "2.2.0",
|
||||
|
||||
@@ -16,7 +16,7 @@ export const DECODE_ROUTES = {
|
||||
],
|
||||
REDIRECT_HOME: 'home/:courseId',
|
||||
REDIRECT_SURVEY: 'survey/:courseId',
|
||||
} as const satisfies Readonly<{ [k: string]: string | readonly string[] }>;
|
||||
};
|
||||
|
||||
export const ROUTES = {
|
||||
UNSUBSCRIBE: '/goal-unsubscribe/:token',
|
||||
@@ -25,7 +25,7 @@ export const ROUTES = {
|
||||
DASHBOARD: 'dashboard',
|
||||
ENTERPRISE_LEARNER_DASHBOARD: 'enterprise-learner-dashboard',
|
||||
CONSENT: 'consent',
|
||||
} as const satisfies Readonly<{ [k: string]: string }>;
|
||||
};
|
||||
|
||||
export const REDIRECT_MODES = {
|
||||
DASHBOARD_REDIRECT: 'dashboard-redirect',
|
||||
@@ -33,7 +33,7 @@ export const REDIRECT_MODES = {
|
||||
CONSENT_REDIRECT: 'consent-redirect',
|
||||
HOME_REDIRECT: 'home-redirect',
|
||||
SURVEY_REDIRECT: 'survey-redirect',
|
||||
} as const satisfies Readonly<{ [k: string]: string }>;
|
||||
};
|
||||
|
||||
export const VERIFIED_MODES = [
|
||||
'professional',
|
||||
@@ -44,15 +44,14 @@ export const VERIFIED_MODES = [
|
||||
'executive-education',
|
||||
'paid-executive-education',
|
||||
'paid-bootcamp',
|
||||
] as const satisfies readonly string[];
|
||||
];
|
||||
|
||||
export const WIDGETS = {
|
||||
DISCUSSIONS: 'DISCUSSIONS',
|
||||
NOTIFICATIONS: 'NOTIFICATIONS',
|
||||
} as const satisfies Readonly<{ [k: string]: string }>;
|
||||
};
|
||||
|
||||
export const LOADING = 'loading';
|
||||
export const LOADED = 'loaded';
|
||||
export const FAILED = 'failed';
|
||||
export const DENIED = 'denied';
|
||||
export type StatusValue = typeof LOADING | typeof LOADED | typeof FAILED | typeof DENIED;
|
||||
@@ -1,12 +1,10 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
import {
|
||||
LOADING,
|
||||
LOADED,
|
||||
FAILED,
|
||||
DENIED,
|
||||
} from '@src/constants';
|
||||
export const LOADING = 'loading';
|
||||
export const LOADED = 'loaded';
|
||||
export const FAILED = 'failed';
|
||||
export const DENIED = 'denied';
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'course-home',
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useParams } from 'react-router-dom';
|
||||
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import HeaderSlot from '../../plugin-slots/HeaderSlot';
|
||||
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
||||
import PageLoading from '../../generic/PageLoading';
|
||||
import { unsubscribeFromCourseGoal } from '../data/api';
|
||||
|
||||
@@ -38,7 +38,7 @@ const GoalUnsubscribe = ({ intl }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeaderSlot showUserDropdown={false} />
|
||||
<Header showUserDropdown={false} />
|
||||
<main id="main-content" className="container my-5 text-center">
|
||||
{isLoading && (
|
||||
<PageLoading srMessage={`${intl.formatMessage(messages.loading)}`} />
|
||||
|
||||
@@ -197,10 +197,7 @@ const OutlineTab = ({ intl }) => {
|
||||
<CourseTools />
|
||||
<PluginSlot
|
||||
id="outline_tab_notifications_slot"
|
||||
pluginProps={{
|
||||
courseId,
|
||||
model: 'outline',
|
||||
}}
|
||||
pluginProps={{ courseId }}
|
||||
>
|
||||
<UpgradeNotification
|
||||
offer={offer}
|
||||
|
||||
@@ -12,9 +12,9 @@ import {
|
||||
} from '@openedx/paragon';
|
||||
import PropTypes from 'prop-types';
|
||||
import truncate from 'truncate-html';
|
||||
import { FAILED, LOADED, LOADING } from '@src/constants';
|
||||
import { useModel } from '../../../generic/model-store';
|
||||
import fetchCourseRecommendations from './data/thunks';
|
||||
import { FAILED, LOADED, LOADING } from './data/slice';
|
||||
import CatalogSuggestion from './CatalogSuggestion';
|
||||
import PageLoading from '../../../generic/PageLoading';
|
||||
import { logClick } from './utils';
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import {
|
||||
LOADING,
|
||||
LOADED,
|
||||
FAILED,
|
||||
} from '@src/constants';
|
||||
|
||||
export const LOADING = 'loading';
|
||||
export const LOADED = 'loaded';
|
||||
export const FAILED = 'failed';
|
||||
|
||||
const slice = createSlice({
|
||||
courseId: null,
|
||||
|
||||
5
src/courseware/course/new-sidebar/SidebarContext.js
Normal file
5
src/courseware/course/new-sidebar/SidebarContext.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const SidebarContext = React.createContext({});
|
||||
|
||||
export default SidebarContext;
|
||||
@@ -1,37 +0,0 @@
|
||||
import React from 'react';
|
||||
import type { WIDGETS } from '@src/constants';
|
||||
import type { SIDEBARS } from './sidebars';
|
||||
|
||||
export type SidebarId = keyof typeof SIDEBARS;
|
||||
export type WidgetId = keyof typeof WIDGETS;
|
||||
export type UpgradeNotificationState = (
|
||||
| 'accessLastHour'
|
||||
| 'accessHoursLeft'
|
||||
| 'accessDaysLeft'
|
||||
| 'FPDdaysLeft'
|
||||
| 'FPDLastHour'
|
||||
| 'accessDateView'
|
||||
| 'PastExpirationDate'
|
||||
);
|
||||
|
||||
export interface SidebarContextData {
|
||||
toggleSidebar: (sidebarId?: SidebarId | null, widgetId?: WidgetId | null) => void;
|
||||
onNotificationSeen: () => void;
|
||||
setNotificationStatus: React.Dispatch<'active' | 'inactive'>;
|
||||
currentSidebar: SidebarId | null;
|
||||
notificationStatus: 'active' | 'inactive';
|
||||
upgradeNotificationCurrentState: UpgradeNotificationState;
|
||||
setUpgradeNotificationCurrentState: React.Dispatch<UpgradeNotificationState>;
|
||||
shouldDisplaySidebarOpen: boolean;
|
||||
shouldDisplayFullScreen: boolean;
|
||||
courseId: string;
|
||||
unitId: string;
|
||||
hideDiscussionbar: boolean;
|
||||
hideNotificationbar: boolean;
|
||||
isNotificationbarAvailable: boolean;
|
||||
isDiscussionbarAvailable: boolean;
|
||||
}
|
||||
|
||||
const SidebarContext = React.createContext<SidebarContextData>({} as SidebarContextData);
|
||||
|
||||
export default SidebarContext;
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, {
|
||||
useCallback, useEffect, useMemo, useState,
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
@@ -12,13 +13,7 @@ import { WIDGETS } from '../../../constants';
|
||||
import SidebarContext from './SidebarContext';
|
||||
import { SIDEBARS } from './sidebars';
|
||||
|
||||
interface Props {
|
||||
courseId: string;
|
||||
unitId: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const SidebarProvider: React.FC<Props> = ({
|
||||
const SidebarProvider = ({
|
||||
courseId,
|
||||
unitId,
|
||||
children,
|
||||
@@ -127,4 +122,14 @@ const SidebarProvider: React.FC<Props> = ({
|
||||
);
|
||||
};
|
||||
|
||||
SidebarProvider.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
unitId: PropTypes.string.isRequired,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
SidebarProvider.defaultProps = {
|
||||
children: null,
|
||||
};
|
||||
|
||||
export default SidebarProvider;
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useCallback, useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
@@ -9,30 +10,18 @@ import { ArrowBackIos, Close } from '@openedx/paragon/icons';
|
||||
import { useEventListener } from '../../../../generic/hooks';
|
||||
import { WIDGETS } from '../../../../constants';
|
||||
import messages from '../messages';
|
||||
import SidebarContext, { type SidebarId } from '../SidebarContext';
|
||||
import SidebarContext from '../SidebarContext';
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
ariaLabel: string;
|
||||
sidebarId: SidebarId;
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
showTitleBar?: boolean;
|
||||
width?: string;
|
||||
allowFullHeight?: boolean;
|
||||
showBorder?: boolean;
|
||||
}
|
||||
|
||||
const SidebarBase: React.FC<Props> = ({
|
||||
title = '',
|
||||
const SidebarBase = ({
|
||||
title,
|
||||
ariaLabel,
|
||||
sidebarId,
|
||||
className,
|
||||
children,
|
||||
showTitleBar = true,
|
||||
width = '45rem',
|
||||
allowFullHeight = false,
|
||||
showBorder = true,
|
||||
showTitleBar,
|
||||
width,
|
||||
allowFullHeight,
|
||||
showBorder,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
@@ -69,7 +58,8 @@ const SidebarBase: React.FC<Props> = ({
|
||||
onClick={() => toggleSidebar(null)}
|
||||
onKeyDown={() => toggleSidebar(null)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
tabIndex="0"
|
||||
alt={intl.formatMessage(messages.responsiveCloseSidebarTray)}
|
||||
>
|
||||
<Icon src={ArrowBackIos} />
|
||||
<span className="font-weight-bold m-2 d-inline-block">
|
||||
@@ -100,4 +90,25 @@ const SidebarBase: React.FC<Props> = ({
|
||||
);
|
||||
};
|
||||
|
||||
SidebarBase.propTypes = {
|
||||
title: PropTypes.string,
|
||||
ariaLabel: PropTypes.string.isRequired,
|
||||
sidebarId: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.element.isRequired,
|
||||
showTitleBar: PropTypes.bool,
|
||||
width: PropTypes.string,
|
||||
allowFullHeight: PropTypes.bool,
|
||||
showBorder: PropTypes.bool,
|
||||
};
|
||||
|
||||
SidebarBase.defaultProps = {
|
||||
title: '',
|
||||
width: '45rem',
|
||||
allowFullHeight: false,
|
||||
showTitleBar: true,
|
||||
className: '',
|
||||
showBorder: true,
|
||||
};
|
||||
|
||||
export default SidebarBase;
|
||||
@@ -1,3 +1,5 @@
|
||||
import * as React from 'react';
|
||||
|
||||
const RightSidebarFilled = (props) => (
|
||||
<svg
|
||||
width={24}
|
||||
@@ -1,3 +1,5 @@
|
||||
import * as React from 'react';
|
||||
|
||||
const RightSidebarOutlined = (props) => (
|
||||
<svg
|
||||
width={24}
|
||||
@@ -31,7 +31,7 @@ describe('DiscussionsWidget', () => {
|
||||
excludeFetchSequence: false,
|
||||
});
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
const state = store.getState() as any; // TODO: remove 'any' once redux state gets types
|
||||
const state = store.getState();
|
||||
courseId = state.courseware.courseId;
|
||||
[unitId] = Object.keys(state.models.units);
|
||||
|
||||
@@ -65,7 +65,6 @@ const NotificationsWidget = () => {
|
||||
|
||||
// After three seconds, update notificationSeen (to hide red dot)
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||
setTimeout(onNotificationSeen, 3000);
|
||||
sendTrackEvent('edx.ui.course.upgrade.new_sidebar.notifications', notificationTrayEventProperties);
|
||||
}, []);
|
||||
@@ -78,7 +77,6 @@ const NotificationsWidget = () => {
|
||||
id="notification_widget_slot"
|
||||
pluginProps={{
|
||||
courseId,
|
||||
model: 'coursewareMeta',
|
||||
notificationCurrentState: upgradeNotificationCurrentState,
|
||||
setNotificationCurrentState: setUpgradeNotificationCurrentState,
|
||||
toggleSidebar: onToggleSidebar,
|
||||
@@ -96,6 +94,7 @@ const NotificationsWidget = () => {
|
||||
timeOffsetMillis={timeOffsetMillis}
|
||||
courseId={courseId}
|
||||
org={org}
|
||||
upgradeNotificationCurrentState={upgradeNotificationCurrentState}
|
||||
setupgradeNotificationCurrentState={setUpgradeNotificationCurrentState}
|
||||
toggleSidebar={onToggleSidebar}
|
||||
/>
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
import initializeStore from '../../../../../../store';
|
||||
import { appendBrowserTimezoneToUrl, executeThunk } from '../../../../../../utils';
|
||||
import { fetchCourse } from '../../../../../data';
|
||||
import SidebarContext, { SidebarContextData } from '../../../SidebarContext';
|
||||
import SidebarContext from '../../../SidebarContext';
|
||||
import NotificationsWidget from './NotificationsWidget';
|
||||
import setupDiscussionSidebar from '../../../../test-utils';
|
||||
|
||||
@@ -24,7 +24,7 @@ jest.mock('@edx/frontend-platform/analytics');
|
||||
describe('NotificationsWidget', () => {
|
||||
let axiosMock;
|
||||
let store;
|
||||
const ID = 'DISCUSSIONS_NOTIFICATIONS';
|
||||
const ID = 'NEWSIDEBAR';
|
||||
const defaultMetadata = Factory.build('courseMetadata');
|
||||
const courseId = defaultMetadata.id;
|
||||
let courseMetadataUrl = `${getConfig().LMS_BASE_URL}/api/courseware/course/${defaultMetadata.id}`;
|
||||
@@ -33,7 +33,7 @@ describe('NotificationsWidget', () => {
|
||||
const courseHomeMetadata = Factory.build('courseHomeMetadata');
|
||||
const courseHomeMetadataUrl = appendBrowserTimezoneToUrl(`${getConfig().LMS_BASE_URL}/api/course_home/course_metadata/${courseId}`);
|
||||
|
||||
function setMetadata(attributes, options = undefined) {
|
||||
function setMetadata(attributes, options) {
|
||||
const updatedCourseHomeMetadata = Factory.build('courseHomeMetadata', attributes, options);
|
||||
axiosMock.onGet(courseHomeMetadataUrl).reply(200, updatedCourseHomeMetadata);
|
||||
}
|
||||
@@ -85,7 +85,7 @@ describe('NotificationsWidget', () => {
|
||||
courseId,
|
||||
hideNotificationbar: false,
|
||||
isNotificationbarAvailable: true,
|
||||
} as SidebarContextData}
|
||||
}}
|
||||
>
|
||||
<NotificationsWidget />
|
||||
</SidebarContext.Provider>,
|
||||
@@ -94,14 +94,14 @@ describe('NotificationsWidget', () => {
|
||||
});
|
||||
|
||||
it('renders upgrade card', async () => {
|
||||
const contextData: Partial<SidebarContextData> = {
|
||||
currentSidebar: ID,
|
||||
courseId,
|
||||
hideNotificationbar: false,
|
||||
isNotificationbarAvailable: true,
|
||||
};
|
||||
await fetchAndRender(
|
||||
<SidebarContext.Provider value={contextData as SidebarContextData}>
|
||||
<SidebarContext.Provider value={{
|
||||
currentSidebar: ID,
|
||||
courseId,
|
||||
hideNotificationbar: false,
|
||||
isNotificationbarAvailable: true,
|
||||
}}
|
||||
>
|
||||
<NotificationsWidget />
|
||||
</SidebarContext.Provider>,
|
||||
);
|
||||
@@ -116,14 +116,14 @@ describe('NotificationsWidget', () => {
|
||||
|
||||
it('renders no notifications bar if no verified mode', async () => {
|
||||
setMetadata({ verified_mode: null });
|
||||
const contextData: Partial<SidebarContextData> = {
|
||||
currentSidebar: ID,
|
||||
courseId,
|
||||
hideNotificationbar: true,
|
||||
isNotificationbarAvailable: false,
|
||||
};
|
||||
await fetchAndRender(
|
||||
<SidebarContext.Provider value={contextData as SidebarContextData}>
|
||||
<SidebarContext.Provider value={{
|
||||
currentSidebar: ID,
|
||||
courseId,
|
||||
hideNotificationbar: true,
|
||||
isNotificationbarAvailable: false,
|
||||
}}
|
||||
>
|
||||
<NotificationsWidget />
|
||||
</SidebarContext.Provider>,
|
||||
);
|
||||
@@ -170,15 +170,15 @@ describe('NotificationsWidget', () => {
|
||||
|
||||
it('marks notification as seen 3 seconds later', async () => {
|
||||
const onNotificationSeen = jest.fn();
|
||||
const contextData: Partial<SidebarContextData> = {
|
||||
currentSidebar: ID,
|
||||
courseId,
|
||||
onNotificationSeen,
|
||||
hideNotificationbar: false,
|
||||
isNotificationbarAvailable: true,
|
||||
};
|
||||
await fetchAndRender(
|
||||
<SidebarContext.Provider value={contextData as SidebarContextData}>
|
||||
<SidebarContext.Provider value={{
|
||||
currentSidebar: ID,
|
||||
courseId,
|
||||
onNotificationSeen,
|
||||
hideNotificationbar: false,
|
||||
isNotificationbarAvailable: true,
|
||||
}}
|
||||
>
|
||||
<NotificationsWidget />
|
||||
</SidebarContext.Provider>,
|
||||
);
|
||||
@@ -6,8 +6,8 @@ export const SIDEBARS = {
|
||||
Sidebar: discussionsNotifications.Sidebar,
|
||||
Trigger: discussionsNotifications.Trigger,
|
||||
},
|
||||
} as const;
|
||||
};
|
||||
|
||||
export const SIDEBAR_ORDER = [
|
||||
discussionsNotifications.ID,
|
||||
] as const;
|
||||
];
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-use-before-define */
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@ import {
|
||||
import { PluginSlot } from '@openedx/frontend-plugin-framework';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { LOADED } from '@src/constants';
|
||||
import { GetCourseExitNavigation } from '../../course-exit';
|
||||
import UnitButton from './UnitButton';
|
||||
import SequenceNavigationTabs from './SequenceNavigationTabs';
|
||||
import { useSequenceNavigationMetadata } from './hooks';
|
||||
import { useModel } from '../../../../generic/model-store';
|
||||
import { LOADED } from '../../../data/slice';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from '@openedx/paragon/icons';
|
||||
|
||||
import { useModel } from '@src/generic/model-store';
|
||||
import { LOADING, LOADED } from '@src/constants';
|
||||
import { LOADING, LOADED } from '@src/course-home/data/slice';
|
||||
import PageLoading from '@src/generic/PageLoading';
|
||||
import {
|
||||
getSequenceId,
|
||||
|
||||
@@ -64,7 +64,6 @@ const NotificationTray = ({ intl }) => {
|
||||
};
|
||||
// After three seconds, update notificationSeen (to hide red dot)
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||
setTimeout(onNotificationSeen, 3000);
|
||||
sendTrackEvent('edx.ui.course.upgrade.old_sidebar.notifications', notificationTrayEventProperties);
|
||||
}, []);
|
||||
@@ -86,7 +85,6 @@ const NotificationTray = ({ intl }) => {
|
||||
id="notification_tray_slot"
|
||||
pluginProps={{
|
||||
courseId,
|
||||
model: 'coursewareMeta',
|
||||
notificationCurrentState: upgradeNotificationCurrentState,
|
||||
setNotificationCurrentState: setUpgradeNotificationCurrentState,
|
||||
}}
|
||||
|
||||
@@ -4,8 +4,8 @@ import MockAdapter from 'axios-mock-adapter';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
import { FAILED, LOADING } from '@src/constants';
|
||||
import * as thunks from './thunks';
|
||||
import { FAILED, LOADING } from './slice';
|
||||
|
||||
import { appendBrowserTimezoneToUrl, executeThunk } from '../../utils';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LOADED } from '@src/constants';
|
||||
import { LOADED } from './slice';
|
||||
|
||||
export function sequenceIdsSelector(state) {
|
||||
if (state.courseware.courseStatus !== LOADED) {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
import {
|
||||
LOADING,
|
||||
LOADED,
|
||||
FAILED,
|
||||
DENIED,
|
||||
} from '@src/constants';
|
||||
export const LOADING = 'loading';
|
||||
export const LOADED = 'loaded';
|
||||
export const FAILED = 'failed';
|
||||
export const DENIED = 'denied';
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'courseware',
|
||||
|
||||
41
src/frontend-platform.d.ts
vendored
41
src/frontend-platform.d.ts
vendored
@@ -1,41 +0,0 @@
|
||||
// frontend-platform currently doesn't provide types... do it ourselves for i18n module at least.
|
||||
// We can remove this in the future when we migrate to frontend-shell, or when frontend-platform gets types
|
||||
// (whichever comes first).
|
||||
|
||||
declare module '@edx/frontend-platform/i18n' {
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { injectIntl as _injectIntl } from 'react-intl';
|
||||
/** @deprecated Use useIntl() hook instead. */
|
||||
export const injectIntl: typeof _injectIntl;
|
||||
/** @deprecated Use useIntl() hook instead. */
|
||||
export const intlShape: any;
|
||||
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
export {
|
||||
createIntl,
|
||||
FormattedDate,
|
||||
FormattedTime,
|
||||
FormattedRelativeTime,
|
||||
FormattedNumber,
|
||||
FormattedPlural,
|
||||
FormattedMessage,
|
||||
defineMessages,
|
||||
IntlProvider,
|
||||
useIntl,
|
||||
} from 'react-intl';
|
||||
|
||||
// Other exports from the i18n module:
|
||||
export const configure: any;
|
||||
export const getPrimaryLanguageSubtag: (code: string) => string;
|
||||
export const getLocale: (locale?: string) => string;
|
||||
export const getMessages: any;
|
||||
export const isRtl: (locale?: string) => boolean;
|
||||
export const handleRtl: any;
|
||||
export const mergeMessages: any;
|
||||
export const LOCALE_CHANGED: any;
|
||||
export const LOCALE_TOPIC: any;
|
||||
export const getCountryList: any;
|
||||
export const getCountryMessages: any;
|
||||
export const getLanguageList: any;
|
||||
export const getLanguageMessages: any;
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
||||
import { useParams, Navigate } from 'react-router-dom';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import FooterSlot from '@openedx/frontend-slot-footer';
|
||||
import { LOADED, LOADING } from '@src/constants';
|
||||
import HeaderSlot from '../plugin-slots/HeaderSlot';
|
||||
import useActiveEnterpriseAlert from '../alerts/active-enteprise-alert';
|
||||
import { AlertList } from './user-messages';
|
||||
import { fetchDiscussionTab } from '../course-home/data/thunks';
|
||||
import { LOADED, LOADING } from '../course-home/data/slice';
|
||||
import PageLoading from './PageLoading';
|
||||
import messages from '../tab-page/messages';
|
||||
|
||||
@@ -28,7 +28,7 @@ const CourseAccessErrorPage = ({ intl }) => {
|
||||
if (courseStatus === LOADING) {
|
||||
return (
|
||||
<>
|
||||
<HeaderSlot />
|
||||
<Header />
|
||||
<PageLoading
|
||||
srMessage={intl.formatMessage(messages.loading)}
|
||||
/>
|
||||
@@ -41,7 +41,7 @@ const CourseAccessErrorPage = ({ intl }) => {
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<HeaderSlot />
|
||||
<Header />
|
||||
<main id="main-content" className="container my-5 text-center" data-testid="access-denied-main">
|
||||
<AlertList
|
||||
topic="outline"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { useIntl, FormattedDate, FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
useIntl, FormattedDate, FormattedMessage, injectIntl,
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
import { sendTrackEvent, sendTrackingLogEvent } from '@edx/frontend-platform/analytics';
|
||||
import { Button, Icon, IconButton } from '@openedx/paragon';
|
||||
import { Close } from '@openedx/paragon/icons';
|
||||
@@ -559,4 +561,4 @@ UpgradeNotification.defaultProps = {
|
||||
toggleSidebar: null,
|
||||
};
|
||||
|
||||
export default UpgradeNotification;
|
||||
export default injectIntl(UpgradeNotification);
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# Header Slot
|
||||
|
||||
### Slot ID: `header_slot`
|
||||
### Props:
|
||||
* `courseOrg`
|
||||
* `courseNumber`
|
||||
* `courseTitle`
|
||||
* `showUserDropdown`
|
||||
|
||||
## Description
|
||||
|
||||
This slot is used to replace/modify/hide the entire learning header.
|
||||
|
||||
## Example
|
||||
|
||||
The following `env.config.jsx` will replace the learning header entirely.
|
||||
|
||||

|
||||
|
||||
```js
|
||||
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
|
||||
|
||||
const config = {
|
||||
pluginSlots: {
|
||||
header_slot: {
|
||||
keepDefault: false,
|
||||
plugins: [
|
||||
{
|
||||
op: PLUGIN_OPERATIONS.Insert,
|
||||
widget: {
|
||||
id: 'custom_header_component',
|
||||
type: DIRECT_PLUGIN,
|
||||
RenderWidget: ({courseOrg, courseNumber, courseTitle, showUserDropdown}) => (
|
||||
<>
|
||||
<h1 style={{textAlign: 'center'}}>🌞</h1>
|
||||
<p style={{textAlign: 'center'}}>courseOrg: {courseOrg}</p>
|
||||
<p style={{textAlign: 'center'}}>courseNumber: {courseNumber}</p>
|
||||
<p style={{textAlign: 'center'}}>courseTitle: {courseTitle}</p>
|
||||
<p style={{textAlign: 'center'}}>showUserDropdown: {showUserDropdown ? '👍' : '👎'}</p>
|
||||
<h1 style={{textAlign: 'center'}}>🌚</h1>
|
||||
</>
|
||||
),
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default config;
|
||||
```
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB |
@@ -1,44 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PluginSlot } from '@openedx/frontend-plugin-framework';
|
||||
|
||||
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
||||
|
||||
const HeaderSlot = ({
|
||||
courseOrg, courseNumber, courseTitle, showUserDropdown,
|
||||
}) => (
|
||||
<PluginSlot
|
||||
id="header_slot"
|
||||
slotOptions={{
|
||||
mergeProps: true,
|
||||
}}
|
||||
pluginProps={{
|
||||
courseOrg,
|
||||
courseNumber,
|
||||
courseTitle,
|
||||
showUserDropdown,
|
||||
}}
|
||||
>
|
||||
<Header
|
||||
courseOrg={courseOrg}
|
||||
courseNumber={courseNumber}
|
||||
courseTitle={courseTitle}
|
||||
showUserDropdown={showUserDropdown}
|
||||
/>
|
||||
</PluginSlot>
|
||||
);
|
||||
|
||||
HeaderSlot.propTypes = {
|
||||
courseOrg: PropTypes.string,
|
||||
courseNumber: PropTypes.string,
|
||||
courseTitle: PropTypes.string,
|
||||
showUserDropdown: PropTypes.bool,
|
||||
};
|
||||
|
||||
HeaderSlot.defaultProps = {
|
||||
courseOrg: null,
|
||||
courseNumber: null,
|
||||
courseTitle: null,
|
||||
showUserDropdown: true,
|
||||
};
|
||||
|
||||
export default HeaderSlot;
|
||||
@@ -1,6 +1,5 @@
|
||||
# `frontend-app-learning` Plugin Slots
|
||||
|
||||
* [`header_slot`](./HeaderSlot/)
|
||||
* [`footer_slot`](./FooterSlot/)
|
||||
* [`sequence_container_slot`](./SequenceContainerSlot/)
|
||||
* [`unit_title_slot`](./UnitTitleSlot/)
|
||||
|
||||
@@ -10,7 +10,7 @@ import { sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { logError } from '@edx/frontend-platform/logging';
|
||||
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { LOADED, LOADING, FAILED } from '@src/constants';
|
||||
import { LOADED, LOADING, FAILED } from '../constants';
|
||||
import PageLoading from '../generic/PageLoading';
|
||||
import { unsubscribeNotificationPreferences } from './data/api';
|
||||
import messages from './messages';
|
||||
|
||||
@@ -193,10 +193,10 @@ export async function initializeTestStore(options = {}, overrideStore = true) {
|
||||
|
||||
logUnhandledRequests(axiosMock);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
!options.excludeFetchCourse && await executeThunk(fetchCourse(courseMetadata.id), store.dispatch);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
!options.excludeFetchOutlineSidebar && await executeThunk(
|
||||
getCourseOutlineStructure(courseMetadata.id),
|
||||
store.dispatch,
|
||||
|
||||
@@ -64,7 +64,7 @@ const StreakModal = ({
|
||||
}) => {
|
||||
const { org, celebrations, username } = useModel('courseHomeMeta', courseId);
|
||||
const factoid = getRandomFactoid(intl, streakLengthToCelebrate);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const [randomFactoid, setRandomFactoid] = useState(factoid); // Don't change factoid on re-render
|
||||
|
||||
// Open edX Folks: if you create a voucher with this code, the MFE will notice and show the discount
|
||||
|
||||
@@ -5,8 +5,8 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
|
||||
import { Toast } from '@openedx/paragon';
|
||||
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
||||
import FooterSlot from '@openedx/frontend-slot-footer';
|
||||
import HeaderSlot from '../plugin-slots/HeaderSlot';
|
||||
import PageLoading from '../generic/PageLoading';
|
||||
import { getAccessDeniedRedirectUrl } from '../shared/access';
|
||||
import { useModel } from '../generic/model-store';
|
||||
@@ -64,7 +64,7 @@ const TabPage = ({ intl, ...props }) => {
|
||||
</>
|
||||
)}
|
||||
|
||||
<HeaderSlot courseOrg={org} courseNumber={number} courseTitle={title} />
|
||||
<Header courseOrg={org} courseNumber={number} courseTitle={title} />
|
||||
|
||||
{courseStatus === 'loading' && (
|
||||
<PageLoading srMessage={intl.formatMessage(messages.loading)} />
|
||||
|
||||
17
src/utils.js
Normal file
17
src/utils.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Helper, that is used to forcibly finalize all promises
|
||||
// in thunk before running matcher against state.
|
||||
export const executeThunk = async (thunk, dispatch, getState) => {
|
||||
await thunk(dispatch, getState);
|
||||
await new Promise(setImmediate);
|
||||
};
|
||||
|
||||
// Utility function for appending the browser timezone to the url
|
||||
// Can be used on the backend when the user timezone is not set in the user account
|
||||
export const appendBrowserTimezoneToUrl = (url) => {
|
||||
const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
const urlObject = new URL(url);
|
||||
if (browserTimezone) {
|
||||
urlObject.searchParams.append('browser_timezone', browserTimezone);
|
||||
}
|
||||
return urlObject.href;
|
||||
};
|
||||
23
src/utils.ts
23
src/utils.ts
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Helper, that is used to forcibly finalize all promises
|
||||
* in thunk before running matcher against state.
|
||||
*
|
||||
* TODO: move this to setupTest or testUtils - it's only used in tests.
|
||||
*/
|
||||
export const executeThunk = async (thunk, dispatch, getState = undefined) => {
|
||||
await thunk(dispatch, getState);
|
||||
await new Promise(setImmediate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility function for appending the browser timezone to the url
|
||||
* Can be used on the backend when the user timezone is not set in the user account
|
||||
*/
|
||||
export const appendBrowserTimezoneToUrl = (url: string) => {
|
||||
const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
const urlObject = new URL(url);
|
||||
if (browserTimezone) {
|
||||
urlObject.searchParams.append('browser_timezone', browserTimezone);
|
||||
}
|
||||
return urlObject.href;
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"extends": "@edx/typescript-config",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"*": ["*"],
|
||||
"@src/*": ["*"]
|
||||
}
|
||||
},
|
||||
"include": ["*.js", ".eslintrc.js", "src/**/*", "plugins/**/*"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user