Merge pull request #1354 from open-craft/kshitij/plugin-slot
feat: Add plugin slot for login page
This commit is contained in:
181
package-lock.json
generated
181
package-lock.json
generated
@@ -16,6 +16,7 @@
|
|||||||
"@fortawesome/free-brands-svg-icons": "6.7.2",
|
"@fortawesome/free-brands-svg-icons": "6.7.2",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.7.2",
|
"@fortawesome/free-solid-svg-icons": "6.7.2",
|
||||||
"@fortawesome/react-fontawesome": "0.2.6",
|
"@fortawesome/react-fontawesome": "0.2.6",
|
||||||
|
"@openedx/frontend-plugin-framework": "^1.7.0",
|
||||||
"@openedx/paragon": "^23.4.2",
|
"@openedx/paragon": "^23.4.2",
|
||||||
"@optimizely/react-sdk": "^2.9.1",
|
"@optimizely/react-sdk": "^2.9.1",
|
||||||
"@redux-devtools/extension": "3.3.0",
|
"@redux-devtools/extension": "3.3.0",
|
||||||
@@ -286,7 +287,6 @@
|
|||||||
"integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==",
|
"integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ampproject/remapping": "^2.2.0",
|
"@ampproject/remapping": "^2.2.0",
|
||||||
"@babel/code-frame": "^7.24.7",
|
"@babel/code-frame": "^7.24.7",
|
||||||
@@ -2443,7 +2443,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^14 || ^16 || >=18"
|
"node": "^14 || ^16 || >=18"
|
||||||
},
|
},
|
||||||
@@ -2466,7 +2465,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^14 || ^16 || >=18"
|
"node": "^14 || ^16 || >=18"
|
||||||
}
|
}
|
||||||
@@ -3166,7 +3164,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
|
||||||
"integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
|
"integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-common-types": "6.7.2"
|
"@fortawesome/fontawesome-common-types": "6.7.2"
|
||||||
},
|
},
|
||||||
@@ -5978,7 +5975,6 @@
|
|||||||
"integrity": "sha512-Iu4/GPq90Xr/MSWnonn2qX8VDhI89HN7KOYBZ0/sxmAQgvXXNc7OYNC7kumvzbYzKueJQTyZoUYS7UjKB/n1WA==",
|
"integrity": "sha512-Iu4/GPq90Xr/MSWnonn2qX8VDhI89HN7KOYBZ0/sxmAQgvXXNc7OYNC7kumvzbYzKueJQTyZoUYS7UjKB/n1WA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/cli": "7.24.8",
|
"@babel/cli": "7.24.8",
|
||||||
"@babel/core": "7.24.9",
|
"@babel/core": "7.24.9",
|
||||||
@@ -6497,7 +6493,6 @@
|
|||||||
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
|
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jest/core": "^29.7.0",
|
"@jest/core": "^29.7.0",
|
||||||
"@jest/types": "^29.6.3",
|
"@jest/types": "^29.6.3",
|
||||||
@@ -7060,12 +7055,88 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@openedx/frontend-plugin-framework": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@openedx/frontend-plugin-framework/-/frontend-plugin-framework-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-8tGkuHvtzhbqb9dU4sXUtR0K44+Hjh1uGR6DvhZAt9wSKQC1v4RBk34ef8DFzQhoNQa/Jtn6BJuta4Un6MmHmw==",
|
||||||
|
"license": "AGPL-3.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||||
|
"classnames": "^2.3.2",
|
||||||
|
"core-js": "3.37.1",
|
||||||
|
"react-redux": "8.1.1",
|
||||||
|
"redux": "4.2.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@edx/frontend-platform": "^7.0.0 || ^8.0.0",
|
||||||
|
"@openedx/paragon": "^21.0.0 || ^22.0.0 || ^23.0.0",
|
||||||
|
"prop-types": "^15.8.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^17.0.0 || ^18.0.0",
|
||||||
|
"react-error-boundary": "^4.0.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@openedx/frontend-plugin-framework/node_modules/core-js": {
|
||||||
|
"version": "3.37.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz",
|
||||||
|
"integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/core-js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@openedx/frontend-plugin-framework/node_modules/react-is": {
|
||||||
|
"version": "18.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
||||||
|
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@openedx/frontend-plugin-framework/node_modules/react-redux": {
|
||||||
|
"version": "8.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.1.tgz",
|
||||||
|
"integrity": "sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.12.1",
|
||||||
|
"@types/hoist-non-react-statics": "^3.3.1",
|
||||||
|
"@types/use-sync-external-store": "^0.0.3",
|
||||||
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
|
"react-is": "^18.0.0",
|
||||||
|
"use-sync-external-store": "^1.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"@types/react-dom": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-native": ">=0.59",
|
||||||
|
"redux": "^4 || ^5.0.0-beta.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-native": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"redux": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@openedx/paragon": {
|
"node_modules/@openedx/paragon": {
|
||||||
"version": "23.15.0",
|
"version": "23.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-23.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-23.15.0.tgz",
|
||||||
"integrity": "sha512-wmsO0tOcLGLsinIHWi2PvGIQ0PGlfB8c789NTPCUiY1AGfkpboOEpZc+7f3m1imCdJ3OvBula5lYV9BpuQ0CSQ==",
|
"integrity": "sha512-wmsO0tOcLGLsinIHWi2PvGIQ0PGlfB8c789NTPCUiY1AGfkpboOEpZc+7f3m1imCdJ3OvBula5lYV9BpuQ0CSQ==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"example",
|
"example",
|
||||||
"component-generator",
|
"component-generator",
|
||||||
@@ -7755,7 +7826,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
@@ -8063,7 +8133,6 @@
|
|||||||
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
|
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.21.3",
|
"@babel/core": "^7.21.3",
|
||||||
"@svgr/babel-preset": "8.1.0",
|
"@svgr/babel-preset": "8.1.0",
|
||||||
@@ -8274,7 +8343,8 @@
|
|||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
@@ -8636,7 +8706,6 @@
|
|||||||
"integrity": "sha512-gUuVEAK4/u6F9wRLznPUU4WGUacSEBDPoC2TrBkw3GAnOLHBL45QdfHOXp1kJ4ypBGLxTOB+t7NJLpKoC3gznQ==",
|
"integrity": "sha512-gUuVEAK4/u6F9wRLznPUU4WGUacSEBDPoC2TrBkw3GAnOLHBL45QdfHOXp1kJ4ypBGLxTOB+t7NJLpKoC3gznQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.11.0"
|
"undici-types": "~7.11.0"
|
||||||
}
|
}
|
||||||
@@ -8686,12 +8755,12 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "19.1.13",
|
"version": "18.3.26",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
|
||||||
"integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==",
|
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/prop-types": "*",
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -8787,6 +8856,12 @@
|
|||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/use-sync-external-store": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/warning": {
|
"node_modules/@types/warning": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
|
||||||
@@ -8826,7 +8901,6 @@
|
|||||||
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.4.0",
|
"@eslint-community/regexpp": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "5.62.0",
|
"@typescript-eslint/scope-manager": "5.62.0",
|
||||||
@@ -8875,7 +8949,6 @@
|
|||||||
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "5.62.0",
|
"@typescript-eslint/scope-manager": "5.62.0",
|
||||||
"@typescript-eslint/types": "5.62.0",
|
"@typescript-eslint/types": "5.62.0",
|
||||||
@@ -9613,7 +9686,6 @@
|
|||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -9711,7 +9783,6 @@
|
|||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
@@ -9780,7 +9851,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.25.2.tgz",
|
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.25.2.tgz",
|
||||||
"integrity": "sha512-lYx98L6kb1VvXypbPI7Z54C4BJB2VT5QvOYthvPq6/POufZj+YdyeZSKjoLBKHJgGmYWQTHOKtcCTdKf98WOCA==",
|
"integrity": "sha512-lYx98L6kb1VvXypbPI7Z54C4BJB2VT5QvOYthvPq6/POufZj+YdyeZSKjoLBKHJgGmYWQTHOKtcCTdKf98WOCA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@algolia/cache-browser-local-storage": "4.25.2",
|
"@algolia/cache-browser-local-storage": "4.25.2",
|
||||||
"@algolia/cache-common": "4.25.2",
|
"@algolia/cache-common": "4.25.2",
|
||||||
@@ -10256,7 +10326,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz",
|
||||||
"integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==",
|
"integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
"form-data": "^4.0.4",
|
"form-data": "^4.0.4",
|
||||||
@@ -10778,7 +10847,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.8.2",
|
"baseline-browser-mapping": "^2.8.2",
|
||||||
"caniuse-lite": "^1.0.30001741",
|
"caniuse-lite": "^1.0.30001741",
|
||||||
@@ -12986,7 +13054,8 @@
|
|||||||
"version": "0.5.16",
|
"version": "0.5.16",
|
||||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
||||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/dom-converter": {
|
"node_modules/dom-converter": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
@@ -13556,7 +13625,6 @@
|
|||||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.4.0",
|
"@eslint-community/regexpp": "^4.4.0",
|
||||||
@@ -13614,7 +13682,6 @@
|
|||||||
"integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==",
|
"integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"object.assign": "^4.1.2",
|
"object.assign": "^4.1.2",
|
||||||
@@ -13657,7 +13724,6 @@
|
|||||||
"integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==",
|
"integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eslint-config-airbnb-base": "^15.0.0"
|
"eslint-config-airbnb-base": "^15.0.0"
|
||||||
},
|
},
|
||||||
@@ -14060,7 +14126,6 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@@ -14118,7 +14183,6 @@
|
|||||||
"integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==",
|
"integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.7",
|
"@babel/runtime": "^7.20.7",
|
||||||
"aria-query": "^5.1.3",
|
"aria-query": "^5.1.3",
|
||||||
@@ -14157,7 +14221,6 @@
|
|||||||
"integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==",
|
"integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"array-includes": "^3.1.6",
|
"array-includes": "^3.1.6",
|
||||||
"array.prototype.flatmap": "^1.3.1",
|
"array.prototype.flatmap": "^1.3.1",
|
||||||
@@ -14189,7 +14252,6 @@
|
|||||||
"integrity": "sha512-Ck77j8hF7l9N4S/rzSLOWEKpn994YH6iwUK8fr9mXIaQvGpQYmOnQLbiue1u5kI5T1y+gdgqosnEAO9NCz0DBg==",
|
"integrity": "sha512-Ck77j8hF7l9N4S/rzSLOWEKpn994YH6iwUK8fr9mXIaQvGpQYmOnQLbiue1u5kI5T1y+gdgqosnEAO9NCz0DBg==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -17822,7 +17884,6 @@
|
|||||||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.3",
|
"@babel/generator": "^7.28.3",
|
||||||
@@ -22576,7 +22637,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.7",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -23361,6 +23421,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^5.0.1",
|
"ansi-regex": "^5.0.1",
|
||||||
"ansi-styles": "^5.0.0",
|
"ansi-styles": "^5.0.0",
|
||||||
@@ -23375,6 +23436,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
||||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -23386,7 +23448,8 @@
|
|||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/process": {
|
"node_modules/process": {
|
||||||
"version": "0.11.10",
|
"version": "0.11.10",
|
||||||
@@ -23423,7 +23486,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
@@ -23681,7 +23743,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
},
|
},
|
||||||
@@ -23840,7 +23901,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"scheduler": "^0.23.2"
|
"scheduler": "^0.23.2"
|
||||||
@@ -23878,6 +23938,19 @@
|
|||||||
"node": ">= 12"
|
"node": ">= 12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-error-boundary": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.12.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-error-overlay": {
|
"node_modules/react-error-overlay": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.1.0.tgz",
|
||||||
@@ -24039,16 +24112,6 @@
|
|||||||
"tslib": "2"
|
"tslib": "2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-intl/node_modules/@types/react": {
|
|
||||||
"version": "18.3.24",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.24.tgz",
|
|
||||||
"integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/prop-types": "*",
|
|
||||||
"csstype": "^3.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
@@ -24116,7 +24179,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz",
|
||||||
"integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==",
|
"integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.15.4",
|
"@babel/runtime": "^7.15.4",
|
||||||
"@types/react-redux": "^7.1.20",
|
"@types/react-redux": "^7.1.20",
|
||||||
@@ -24149,7 +24211,6 @@
|
|||||||
"integrity": "sha512-FPvF2XxTSikpJxcr+bHut2H4gJ17+18Uy20D5/F+SKzFap62R3cM5wH6b8WN3LyGSYeQilLEcJcR1fjBSI2S1A==",
|
"integrity": "sha512-FPvF2XxTSikpJxcr+bHut2H4gJ17+18Uy20D5/F+SKzFap62R3cM5wH6b8WN3LyGSYeQilLEcJcR1fjBSI2S1A==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -24239,7 +24300,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz",
|
||||||
"integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==",
|
"integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remix-run/router": "1.23.0",
|
"@remix-run/router": "1.23.0",
|
||||||
"react-router": "6.30.1"
|
"react-router": "6.30.1"
|
||||||
@@ -24442,7 +24502,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
|
||||||
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
|
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.9.2"
|
"@babel/runtime": "^7.9.2"
|
||||||
}
|
}
|
||||||
@@ -25102,7 +25161,6 @@
|
|||||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"fast-uri": "^3.0.1",
|
"fast-uri": "^3.0.1",
|
||||||
@@ -26104,7 +26162,6 @@
|
|||||||
"integrity": "sha512-+xU0IA1StzqAqFs/QtXkK+XJa7wpS4X5H+JQccRKsRCElgeLGocFU1U/UMvMUylKFw6vwGV+Y/a2wb2pm5rFFQ==",
|
"integrity": "sha512-+xU0IA1StzqAqFs/QtXkK+XJa7wpS4X5H+JQccRKsRCElgeLGocFU1U/UMvMUylKFw6vwGV+Y/a2wb2pm5rFFQ==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bundled-es-modules/deepmerge": "^4.3.1",
|
"@bundled-es-modules/deepmerge": "^4.3.1",
|
||||||
"@bundled-es-modules/glob": "^10.4.2",
|
"@bundled-es-modules/glob": "^10.4.2",
|
||||||
@@ -26622,7 +26679,6 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -26755,7 +26811,6 @@
|
|||||||
"integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==",
|
"integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bs-logger": "^0.2.6",
|
"bs-logger": "^0.2.6",
|
||||||
"fast-json-stable-stringify": "^2.1.0",
|
"fast-json-stable-stringify": "^2.1.0",
|
||||||
@@ -26910,8 +26965,7 @@
|
|||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
"license": "0BSD",
|
"license": "0BSD"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/tsutils": {
|
"node_modules/tsutils": {
|
||||||
"version": "3.21.0",
|
"version": "3.21.0",
|
||||||
@@ -26965,7 +27019,6 @@
|
|||||||
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
|
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "(MIT OR CC0-1.0)",
|
"license": "(MIT OR CC0-1.0)",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -27071,7 +27124,6 @@
|
|||||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -27258,7 +27310,6 @@
|
|||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"napi-postinstall": "^0.3.0"
|
"napi-postinstall": "^0.3.0"
|
||||||
},
|
},
|
||||||
@@ -27448,6 +27499,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/use-sync-external-store": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/util": {
|
"node_modules/util": {
|
||||||
"version": "0.12.5",
|
"version": "0.12.5",
|
||||||
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
|
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
|
||||||
@@ -27618,7 +27678,6 @@
|
|||||||
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
|
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/eslint-scope": "^3.7.7",
|
"@types/eslint-scope": "^3.7.7",
|
||||||
"@types/estree": "^1.0.8",
|
"@types/estree": "^1.0.8",
|
||||||
@@ -27727,7 +27786,6 @@
|
|||||||
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
|
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discoveryjs/json-ext": "^0.5.0",
|
"@discoveryjs/json-ext": "^0.5.0",
|
||||||
"@webpack-cli/configtest": "^2.1.1",
|
"@webpack-cli/configtest": "^2.1.1",
|
||||||
@@ -27808,7 +27866,6 @@
|
|||||||
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
|
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/bonjour": "^3.5.9",
|
"@types/bonjour": "^3.5.9",
|
||||||
"@types/connect-history-api-fallback": "^1.3.5",
|
"@types/connect-history-api-fallback": "^1.3.5",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"@fortawesome/free-brands-svg-icons": "6.7.2",
|
"@fortawesome/free-brands-svg-icons": "6.7.2",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.7.2",
|
"@fortawesome/free-solid-svg-icons": "6.7.2",
|
||||||
"@fortawesome/react-fontawesome": "0.2.6",
|
"@fortawesome/react-fontawesome": "0.2.6",
|
||||||
|
"@openedx/frontend-plugin-framework": "^1.7.0",
|
||||||
"@openedx/paragon": "^23.4.2",
|
"@openedx/paragon": "^23.4.2",
|
||||||
"@optimizely/react-sdk": "^2.9.1",
|
"@optimizely/react-sdk": "^2.9.1",
|
||||||
"@redux-devtools/extension": "3.3.0",
|
"@redux-devtools/extension": "3.3.0",
|
||||||
|
|||||||
@@ -1,26 +1,17 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import {
|
||||||
import { connect } from 'react-redux';
|
useCallback, useEffect, useMemo, useState,
|
||||||
|
} from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||||
import {
|
import { Form, StatefulButton } from '@openedx/paragon';
|
||||||
Form, StatefulButton,
|
|
||||||
} from '@openedx/paragon';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import Skeleton from 'react-loading-skeleton';
|
import Skeleton from 'react-loading-skeleton';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import AccountActivationMessage from './AccountActivationMessage';
|
|
||||||
import {
|
|
||||||
backupLoginFormBegin,
|
|
||||||
dismissPasswordResetBanner,
|
|
||||||
loginRequest,
|
|
||||||
} from './data/actions';
|
|
||||||
import { INVALID_FORM, TPA_AUTHENTICATION_FAILURE } from './data/constants';
|
|
||||||
import LoginFailureMessage from './LoginFailure';
|
|
||||||
import messages from './messages';
|
|
||||||
import {
|
import {
|
||||||
FormGroup,
|
FormGroup,
|
||||||
InstitutionLogistration,
|
InstitutionLogistration,
|
||||||
@@ -28,13 +19,12 @@ import {
|
|||||||
RedirectLogistration,
|
RedirectLogistration,
|
||||||
ThirdPartyAuthAlert,
|
ThirdPartyAuthAlert,
|
||||||
} from '../common-components';
|
} from '../common-components';
|
||||||
|
import AccountActivationMessage from './AccountActivationMessage';
|
||||||
import { getThirdPartyAuthContext } from '../common-components/data/actions';
|
import { getThirdPartyAuthContext } from '../common-components/data/actions';
|
||||||
import { thirdPartyAuthContextSelector } from '../common-components/data/selectors';
|
import { thirdPartyAuthContextSelector } from '../common-components/data/selectors';
|
||||||
import EnterpriseSSO from '../common-components/EnterpriseSSO';
|
import EnterpriseSSO from '../common-components/EnterpriseSSO';
|
||||||
import ThirdPartyAuth from '../common-components/ThirdPartyAuth';
|
import ThirdPartyAuth from '../common-components/ThirdPartyAuth';
|
||||||
import {
|
import { PENDING_STATE, RESET_PAGE } from '../data/constants';
|
||||||
DEFAULT_STATE, PENDING_STATE, RESET_PAGE,
|
|
||||||
} from '../data/constants';
|
|
||||||
import {
|
import {
|
||||||
getActivationStatus,
|
getActivationStatus,
|
||||||
getAllPossibleQueryParams,
|
getAllPossibleQueryParams,
|
||||||
@@ -43,37 +33,57 @@ import {
|
|||||||
updatePathWithQueryParams,
|
updatePathWithQueryParams,
|
||||||
} from '../data/utils';
|
} from '../data/utils';
|
||||||
import ResetPasswordSuccess from '../reset-password/ResetPasswordSuccess';
|
import ResetPasswordSuccess from '../reset-password/ResetPasswordSuccess';
|
||||||
|
import { backupLoginFormBegin, dismissPasswordResetBanner, loginRequest } from './data/actions';
|
||||||
|
import { INVALID_FORM, TPA_AUTHENTICATION_FAILURE } from './data/constants';
|
||||||
|
import LoginFailureMessage from './LoginFailure';
|
||||||
|
import messages from './messages';
|
||||||
|
|
||||||
const LoginPage = (props) => {
|
const LoginPage = ({
|
||||||
|
institutionLogin,
|
||||||
|
handleInstitutionLogin,
|
||||||
|
}) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const backupFormState = useCallback((data) => dispatch(backupLoginFormBegin(data)), [dispatch]);
|
||||||
|
const getTPADataFromBackend = useCallback(() => dispatch(getThirdPartyAuthContext()), [dispatch]);
|
||||||
const {
|
const {
|
||||||
backedUpFormData,
|
backedUpFormData,
|
||||||
loginErrorCode,
|
loginErrorCode,
|
||||||
loginErrorContext,
|
loginErrorContext,
|
||||||
loginResult,
|
loginResult,
|
||||||
shouldBackupState,
|
shouldBackupState,
|
||||||
thirdPartyAuthContext: {
|
|
||||||
providers,
|
|
||||||
currentProvider,
|
|
||||||
secondaryProviders,
|
|
||||||
finishAuthUrl,
|
|
||||||
platformName,
|
|
||||||
errorMessage: thirdPartyErrorMessage,
|
|
||||||
},
|
|
||||||
thirdPartyAuthApiStatus,
|
|
||||||
institutionLogin,
|
|
||||||
showResetPasswordSuccessBanner,
|
showResetPasswordSuccessBanner,
|
||||||
submitState,
|
submitState,
|
||||||
// Actions
|
thirdPartyAuthContext,
|
||||||
backupFormState,
|
thirdPartyAuthApiStatus,
|
||||||
handleInstitutionLogin,
|
} = useSelector((state) => ({
|
||||||
getTPADataFromBackend,
|
backedUpFormData: state.login.loginFormData,
|
||||||
} = props;
|
loginErrorCode: state.login.loginErrorCode,
|
||||||
|
loginErrorContext: state.login.loginErrorContext,
|
||||||
|
loginResult: state.login.loginResult,
|
||||||
|
shouldBackupState: state.login.shouldBackupState,
|
||||||
|
showResetPasswordSuccessBanner: state.login.showResetPasswordSuccessBanner,
|
||||||
|
submitState: state.login.submitState,
|
||||||
|
thirdPartyAuthContext: thirdPartyAuthContextSelector(state),
|
||||||
|
thirdPartyAuthApiStatus: state.commonComponents.thirdPartyAuthApiStatus,
|
||||||
|
}));
|
||||||
|
const {
|
||||||
|
providers,
|
||||||
|
currentProvider,
|
||||||
|
secondaryProviders,
|
||||||
|
finishAuthUrl,
|
||||||
|
platformName,
|
||||||
|
errorMessage: thirdPartyErrorMessage,
|
||||||
|
} = thirdPartyAuthContext;
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const activationMsgType = getActivationStatus();
|
const activationMsgType = getActivationStatus();
|
||||||
const queryParams = useMemo(() => getAllPossibleQueryParams(), []);
|
const queryParams = useMemo(() => getAllPossibleQueryParams(), []);
|
||||||
|
|
||||||
const [formFields, setFormFields] = useState({ ...backedUpFormData.formFields });
|
const [formFields, setFormFields] = useState({ ...backedUpFormData.formFields });
|
||||||
const [errorCode, setErrorCode] = useState({ type: '', count: 0, context: {} });
|
const [errorCode, setErrorCode] = useState({
|
||||||
|
type: '',
|
||||||
|
count: 0,
|
||||||
|
context: {},
|
||||||
|
});
|
||||||
const [errors, setErrors] = useState({ ...backedUpFormData.errors });
|
const [errors, setErrors] = useState({ ...backedUpFormData.errors });
|
||||||
const tpaHint = getTpaHint();
|
const tpaHint = getTpaHint();
|
||||||
|
|
||||||
@@ -87,7 +97,7 @@ const LoginPage = (props) => {
|
|||||||
payload.tpa_hint = tpaHint;
|
payload.tpa_hint = tpaHint;
|
||||||
}
|
}
|
||||||
getTPADataFromBackend(payload);
|
getTPADataFromBackend(payload);
|
||||||
}, [getTPADataFromBackend, queryParams, tpaHint]);
|
}, [queryParams, tpaHint, getTPADataFromBackend]);
|
||||||
/**
|
/**
|
||||||
* Backup the login form in redux when login page is toggled.
|
* Backup the login form in redux when login page is toggled.
|
||||||
*/
|
*/
|
||||||
@@ -98,7 +108,7 @@ const LoginPage = (props) => {
|
|||||||
errors: { ...errors },
|
errors: { ...errors },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [shouldBackupState, formFields, errors, backupFormState]);
|
}, [backupFormState, shouldBackupState, formFields, errors]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loginErrorCode) {
|
if (loginErrorCode) {
|
||||||
@@ -123,7 +133,10 @@ const LoginPage = (props) => {
|
|||||||
}, [thirdPartyErrorMessage]);
|
}, [thirdPartyErrorMessage]);
|
||||||
|
|
||||||
const validateFormFields = (payload) => {
|
const validateFormFields = (payload) => {
|
||||||
const { emailOrUsername, password } = payload;
|
const {
|
||||||
|
emailOrUsername,
|
||||||
|
password,
|
||||||
|
} = payload;
|
||||||
const fieldErrors = { ...errors };
|
const fieldErrors = { ...errors };
|
||||||
|
|
||||||
if (emailOrUsername === '') {
|
if (emailOrUsername === '') {
|
||||||
@@ -141,14 +154,18 @@ const LoginPage = (props) => {
|
|||||||
const handleSubmit = (event) => {
|
const handleSubmit = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (showResetPasswordSuccessBanner) {
|
if (showResetPasswordSuccessBanner) {
|
||||||
props.dismissPasswordResetBanner();
|
dispatch(dismissPasswordResetBanner());
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = { ...formFields };
|
const formData = { ...formFields };
|
||||||
const validationErrors = validateFormFields(formData);
|
const validationErrors = validateFormFields(formData);
|
||||||
if (validationErrors.emailOrUsername || validationErrors.password) {
|
if (validationErrors.emailOrUsername || validationErrors.password) {
|
||||||
setErrors({ ...validationErrors });
|
setErrors({ ...validationErrors });
|
||||||
setErrorCode(prevState => ({ type: INVALID_FORM, count: prevState.count + 1, context: {} }));
|
setErrorCode(prevState => ({
|
||||||
|
type: INVALID_FORM,
|
||||||
|
count: prevState.count + 1,
|
||||||
|
context: {},
|
||||||
|
}));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,23 +175,35 @@ const LoginPage = (props) => {
|
|||||||
password: formData.password,
|
password: formData.password,
|
||||||
...queryParams,
|
...queryParams,
|
||||||
};
|
};
|
||||||
props.loginRequest(payload);
|
dispatch(loginRequest(payload));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnChange = (event) => {
|
const handleOnChange = (event) => {
|
||||||
const { name, value } = event.target;
|
const {
|
||||||
setFormFields(prevState => ({ ...prevState, [name]: value }));
|
name,
|
||||||
|
value,
|
||||||
|
} = event.target;
|
||||||
|
setFormFields(prevState => ({
|
||||||
|
...prevState,
|
||||||
|
[name]: value,
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnFocus = (event) => {
|
const handleOnFocus = (event) => {
|
||||||
const { name } = event.target;
|
const { name } = event.target;
|
||||||
setErrors(prevErrors => ({ ...prevErrors, [name]: '' }));
|
setErrors(prevErrors => ({
|
||||||
|
...prevErrors,
|
||||||
|
[name]: '',
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
const trackForgotPasswordLinkClick = () => {
|
const trackForgotPasswordLinkClick = () => {
|
||||||
sendTrackEvent('edx.bi.password-reset_form.toggled', { category: 'user-engagement' });
|
sendTrackEvent('edx.bi.password-reset_form.toggled', { category: 'user-engagement' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const { provider, skipHintedLogin } = getTpaProvider(tpaHint, providers, secondaryProviders);
|
const {
|
||||||
|
provider,
|
||||||
|
skipHintedLogin,
|
||||||
|
} = getTpaProvider(tpaHint, providers, secondaryProviders);
|
||||||
|
|
||||||
if (tpaHint) {
|
if (tpaHint) {
|
||||||
if (thirdPartyAuthApiStatus === PENDING_STATE) {
|
if (thirdPartyAuthApiStatus === PENDING_STATE) {
|
||||||
@@ -281,88 +310,9 @@ const LoginPage = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const loginPageState = state.login;
|
|
||||||
return {
|
|
||||||
backedUpFormData: loginPageState.loginFormData,
|
|
||||||
loginErrorCode: loginPageState.loginErrorCode,
|
|
||||||
loginErrorContext: loginPageState.loginErrorContext,
|
|
||||||
loginResult: loginPageState.loginResult,
|
|
||||||
shouldBackupState: loginPageState.shouldBackupState,
|
|
||||||
showResetPasswordSuccessBanner: loginPageState.showResetPasswordSuccessBanner,
|
|
||||||
submitState: loginPageState.submitState,
|
|
||||||
thirdPartyAuthContext: thirdPartyAuthContextSelector(state),
|
|
||||||
thirdPartyAuthApiStatus: state.commonComponents.thirdPartyAuthApiStatus,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
LoginPage.propTypes = {
|
LoginPage.propTypes = {
|
||||||
backedUpFormData: PropTypes.shape({
|
|
||||||
formFields: PropTypes.shape({}),
|
|
||||||
errors: PropTypes.shape({}),
|
|
||||||
}),
|
|
||||||
loginErrorCode: PropTypes.string,
|
|
||||||
loginErrorContext: PropTypes.shape({
|
|
||||||
email: PropTypes.string,
|
|
||||||
redirectUrl: PropTypes.string,
|
|
||||||
context: PropTypes.shape({}),
|
|
||||||
}),
|
|
||||||
loginResult: PropTypes.shape({
|
|
||||||
redirectUrl: PropTypes.string,
|
|
||||||
success: PropTypes.bool,
|
|
||||||
}),
|
|
||||||
shouldBackupState: PropTypes.bool,
|
|
||||||
showResetPasswordSuccessBanner: PropTypes.bool,
|
|
||||||
submitState: PropTypes.string,
|
|
||||||
thirdPartyAuthApiStatus: PropTypes.string,
|
|
||||||
institutionLogin: PropTypes.bool.isRequired,
|
institutionLogin: PropTypes.bool.isRequired,
|
||||||
thirdPartyAuthContext: PropTypes.shape({
|
|
||||||
currentProvider: PropTypes.string,
|
|
||||||
errorMessage: PropTypes.string,
|
|
||||||
platformName: PropTypes.string,
|
|
||||||
providers: PropTypes.arrayOf(PropTypes.shape({})),
|
|
||||||
secondaryProviders: PropTypes.arrayOf(PropTypes.shape({})),
|
|
||||||
finishAuthUrl: PropTypes.string,
|
|
||||||
}),
|
|
||||||
// Actions
|
|
||||||
backupFormState: PropTypes.func.isRequired,
|
|
||||||
dismissPasswordResetBanner: PropTypes.func.isRequired,
|
|
||||||
loginRequest: PropTypes.func.isRequired,
|
|
||||||
getTPADataFromBackend: PropTypes.func.isRequired,
|
|
||||||
handleInstitutionLogin: PropTypes.func.isRequired,
|
handleInstitutionLogin: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
LoginPage.defaultProps = {
|
export default LoginPage;
|
||||||
backedUpFormData: {
|
|
||||||
formFields: {
|
|
||||||
emailOrUsername: '', password: '',
|
|
||||||
},
|
|
||||||
errors: {
|
|
||||||
emailOrUsername: '', password: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
loginErrorCode: null,
|
|
||||||
loginErrorContext: {},
|
|
||||||
loginResult: {},
|
|
||||||
shouldBackupState: false,
|
|
||||||
showResetPasswordSuccessBanner: false,
|
|
||||||
submitState: DEFAULT_STATE,
|
|
||||||
thirdPartyAuthApiStatus: PENDING_STATE,
|
|
||||||
thirdPartyAuthContext: {
|
|
||||||
currentProvider: null,
|
|
||||||
errorMessage: null,
|
|
||||||
finishAuthUrl: null,
|
|
||||||
providers: [],
|
|
||||||
secondaryProviders: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
{
|
|
||||||
backupFormState: backupLoginFormBegin,
|
|
||||||
dismissPasswordResetBanner,
|
|
||||||
loginRequest,
|
|
||||||
getTPADataFromBackend: getThirdPartyAuthContext,
|
|
||||||
},
|
|
||||||
)(LoginPage);
|
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ describe('LoginPage', () => {
|
|||||||
const initialState = {
|
const initialState = {
|
||||||
login: {
|
login: {
|
||||||
loginResult: { success: false, redirectUrl: '' },
|
loginResult: { success: false, redirectUrl: '' },
|
||||||
|
loginFormData: {
|
||||||
|
formFields: {
|
||||||
|
emailOrUsername: '', password: '',
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
emailOrUsername: '', password: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
commonComponents: {
|
commonComponents: {
|
||||||
thirdPartyAuthApiStatus: null,
|
thirdPartyAuthApiStatus: null,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||||
@@ -24,16 +24,20 @@ import { LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
|
|||||||
import {
|
import {
|
||||||
getTpaHint, getTpaProvider, updatePathWithQueryParams,
|
getTpaHint, getTpaProvider, updatePathWithQueryParams,
|
||||||
} from '../data/utils';
|
} from '../data/utils';
|
||||||
import { LoginPage } from '../login';
|
|
||||||
import { backupLoginForm } from '../login/data/actions';
|
import { backupLoginForm } from '../login/data/actions';
|
||||||
|
import LoginComponentSlot from '../plugin-slots/LoginComponentSlot';
|
||||||
import { RegistrationPage } from '../register';
|
import { RegistrationPage } from '../register';
|
||||||
import { backupRegistrationForm } from '../register/data/actions';
|
import { backupRegistrationForm } from '../register/data/actions';
|
||||||
|
|
||||||
const Logistration = (props) => {
|
const Logistration = ({
|
||||||
const { selectedPage, tpaProviders } = props;
|
selectedPage,
|
||||||
|
}) => {
|
||||||
const tpaHint = getTpaHint();
|
const tpaHint = getTpaHint();
|
||||||
|
const tpaProviders = useSelector(tpaProvidersSelector);
|
||||||
|
const dispatch = useDispatch();
|
||||||
const {
|
const {
|
||||||
providers, secondaryProviders,
|
providers,
|
||||||
|
secondaryProviders,
|
||||||
} = tpaProviders;
|
} = tpaProviders;
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const [institutionLogin, setInstitutionLogin] = useState(false);
|
const [institutionLogin, setInstitutionLogin] = useState(false);
|
||||||
@@ -45,7 +49,8 @@ const Logistration = (props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const authService = getAuthService();
|
const authService = getAuthService();
|
||||||
if (authService) {
|
if (authService) {
|
||||||
authService.getCsrfTokenService().getCsrfToken(getConfig().LMS_BASE_URL);
|
authService.getCsrfTokenService()
|
||||||
|
.getCsrfToken(getConfig().LMS_BASE_URL);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -71,11 +76,11 @@ const Logistration = (props) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendTrackEvent(`edx.bi.${tabKey.replace('/', '')}_form.toggled`, { category: 'user-engagement' });
|
sendTrackEvent(`edx.bi.${tabKey.replace('/', '')}_form.toggled`, { category: 'user-engagement' });
|
||||||
props.clearThirdPartyAuthContextErrorMessage();
|
dispatch(clearThirdPartyAuthContextErrorMessage());
|
||||||
if (tabKey === LOGIN_PAGE) {
|
if (tabKey === LOGIN_PAGE) {
|
||||||
props.backupRegistrationForm();
|
dispatch(backupRegistrationForm());
|
||||||
} else if (tabKey === REGISTER_PAGE) {
|
} else if (tabKey === REGISTER_PAGE) {
|
||||||
props.backupLoginForm();
|
dispatch(backupLoginForm());
|
||||||
}
|
}
|
||||||
setKey(tabKey);
|
setKey(tabKey);
|
||||||
};
|
};
|
||||||
@@ -111,7 +116,10 @@ const Logistration = (props) => {
|
|||||||
{!institutionLogin && (
|
{!institutionLogin && (
|
||||||
<h3 className="mb-4.5">{formatMessage(messages['logistration.sign.in'])}</h3>
|
<h3 className="mb-4.5">{formatMessage(messages['logistration.sign.in'])}</h3>
|
||||||
)}
|
)}
|
||||||
<LoginPage institutionLogin={institutionLogin} handleInstitutionLogin={handleInstitutionLogin} />
|
<LoginComponentSlot
|
||||||
|
institutionLogin={institutionLogin}
|
||||||
|
handleInstitutionLogin={handleInstitutionLogin}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
@@ -124,12 +132,16 @@ const Logistration = (props) => {
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
)
|
)
|
||||||
: (!isValidTpaHint() && !hideRegistrationLink && (
|
: (!isValidTpaHint() && !hideRegistrationLink && (
|
||||||
<Tabs defaultActiveKey={selectedPage} id="controlled-tab" onSelect={(tabKey) => handleOnSelect(tabKey, selectedPage)}>
|
<Tabs
|
||||||
|
defaultActiveKey={selectedPage}
|
||||||
|
id="controlled-tab"
|
||||||
|
onSelect={(tabKey) => handleOnSelect(tabKey, selectedPage)}
|
||||||
|
>
|
||||||
<Tab title={formatMessage(messages['logistration.register'])} eventKey={REGISTER_PAGE} />
|
<Tab title={formatMessage(messages['logistration.register'])} eventKey={REGISTER_PAGE} />
|
||||||
<Tab title={formatMessage(messages['logistration.sign.in'])} eventKey={LOGIN_PAGE} />
|
<Tab title={formatMessage(messages['logistration.sign.in'])} eventKey={LOGIN_PAGE} />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
))}
|
))}
|
||||||
{ key && (
|
{key && (
|
||||||
<Navigate to={updatePathWithQueryParams(key)} replace />
|
<Navigate to={updatePathWithQueryParams(key)} replace />
|
||||||
)}
|
)}
|
||||||
<div id="main-content" className="main-content">
|
<div id="main-content" className="main-content">
|
||||||
@@ -139,7 +151,12 @@ const Logistration = (props) => {
|
|||||||
</h3>
|
</h3>
|
||||||
)}
|
)}
|
||||||
{selectedPage === LOGIN_PAGE
|
{selectedPage === LOGIN_PAGE
|
||||||
? <LoginPage institutionLogin={institutionLogin} handleInstitutionLogin={handleInstitutionLogin} />
|
? (
|
||||||
|
<LoginComponentSlot
|
||||||
|
institutionLogin={institutionLogin}
|
||||||
|
handleInstitutionLogin={handleInstitutionLogin}
|
||||||
|
/>
|
||||||
|
)
|
||||||
: (
|
: (
|
||||||
<RegistrationPage
|
<RegistrationPage
|
||||||
institutionLogin={institutionLogin}
|
institutionLogin={institutionLogin}
|
||||||
@@ -156,35 +173,10 @@ const Logistration = (props) => {
|
|||||||
|
|
||||||
Logistration.propTypes = {
|
Logistration.propTypes = {
|
||||||
selectedPage: PropTypes.string,
|
selectedPage: PropTypes.string,
|
||||||
backupLoginForm: PropTypes.func.isRequired,
|
|
||||||
backupRegistrationForm: PropTypes.func.isRequired,
|
|
||||||
clearThirdPartyAuthContextErrorMessage: PropTypes.func.isRequired,
|
|
||||||
tpaProviders: PropTypes.shape({
|
|
||||||
providers: PropTypes.arrayOf(PropTypes.shape({})),
|
|
||||||
secondaryProviders: PropTypes.arrayOf(PropTypes.shape({})),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
Logistration.defaultProps = {
|
|
||||||
tpaProviders: {
|
|
||||||
providers: [],
|
|
||||||
secondaryProviders: [],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Logistration.defaultProps = {
|
Logistration.defaultProps = {
|
||||||
selectedPage: REGISTER_PAGE,
|
selectedPage: REGISTER_PAGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
export default Logistration;
|
||||||
tpaProviders: tpaProvidersSelector(state),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
{
|
|
||||||
backupLoginForm,
|
|
||||||
backupRegistrationForm,
|
|
||||||
clearThirdPartyAuthContextErrorMessage,
|
|
||||||
},
|
|
||||||
)(Logistration);
|
|
||||||
|
|||||||
@@ -48,16 +48,26 @@ describe('Logistration', () => {
|
|||||||
marketingEmailsOptIn: true,
|
marketingEmailsOptIn: true,
|
||||||
},
|
},
|
||||||
formFields: {
|
formFields: {
|
||||||
name: '', email: '', username: '', password: '',
|
name: '',
|
||||||
|
email: '',
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
},
|
},
|
||||||
emailSuggestion: {
|
emailSuggestion: {
|
||||||
suggestion: '', type: '',
|
suggestion: '',
|
||||||
|
type: '',
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
name: '', email: '', username: '', password: '',
|
name: '',
|
||||||
|
email: '',
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
registrationResult: { success: false, redirectUrl: '' },
|
registrationResult: {
|
||||||
|
success: false,
|
||||||
|
redirectUrl: '',
|
||||||
|
},
|
||||||
registrationError: {},
|
registrationError: {},
|
||||||
usernameSuggestions: [],
|
usernameSuggestions: [],
|
||||||
validationApiRateLimited: false,
|
validationApiRateLimited: false,
|
||||||
@@ -69,7 +79,18 @@ describe('Logistration', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
login: {
|
login: {
|
||||||
loginResult: { success: false, redirectUrl: '' },
|
loginResult: {
|
||||||
|
success: false,
|
||||||
|
redirectUrl: '',
|
||||||
|
},
|
||||||
|
loginFormData: {
|
||||||
|
formFields: {
|
||||||
|
emailOrUsername: '', password: '',
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
emailOrUsername: '', password: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
47
src/plugin-slots/LoginComponentSlot/README.md
Normal file
47
src/plugin-slots/LoginComponentSlot/README.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Login Component Slot
|
||||||
|
|
||||||
|
### Slot ID: `org.openedx.frontend.authn.login_component.v1`
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This slot is used to replace/modify/hide the login component.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
### Default content
|
||||||
|

|
||||||
|
|
||||||
|
### With a prepended message
|
||||||
|

|
||||||
|
|
||||||
|
The following `env.config.jsx` will add a message before the login component.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
|
||||||
|
|
||||||
|
// Load environment variables from .env file
|
||||||
|
const config = {
|
||||||
|
...process.env,
|
||||||
|
pluginSlots: {
|
||||||
|
'org.openedx.frontend.authn.login_component.v1': {
|
||||||
|
keepDefault: true,
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
op: PLUGIN_OPERATIONS.Insert,
|
||||||
|
widget: {
|
||||||
|
id: 'test_plugin',
|
||||||
|
type: DIRECT_PLUGIN,
|
||||||
|
priority: 1,
|
||||||
|
RenderWidget: () => (
|
||||||
|
<h2>You're logging into TEST Instance.</h2>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
|
||||||
|
```
|
||||||
BIN
src/plugin-slots/LoginComponentSlot/component_with_prefix.png
Normal file
BIN
src/plugin-slots/LoginComponentSlot/component_with_prefix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
src/plugin-slots/LoginComponentSlot/default_component.png
Normal file
BIN
src/plugin-slots/LoginComponentSlot/default_component.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
31
src/plugin-slots/LoginComponentSlot/index.jsx
Normal file
31
src/plugin-slots/LoginComponentSlot/index.jsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { PluginSlot } from '@openedx/frontend-plugin-framework';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import LoginPage from '../../login/LoginPage';
|
||||||
|
|
||||||
|
const LoginComponentSlot = ({
|
||||||
|
institutionLogin,
|
||||||
|
handleInstitutionLogin,
|
||||||
|
}) => (
|
||||||
|
<PluginSlot
|
||||||
|
id="org.openedx.frontend.authn.login_component.v1"
|
||||||
|
pluginProps={{
|
||||||
|
isInstitutionLogin: institutionLogin,
|
||||||
|
setInstitutionLogin: handleInstitutionLogin,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LoginPage
|
||||||
|
institutionLogin={institutionLogin}
|
||||||
|
handleInstitutionLogin={handleInstitutionLogin}
|
||||||
|
/>
|
||||||
|
</PluginSlot>
|
||||||
|
);
|
||||||
|
|
||||||
|
LoginComponentSlot.propTypes = {
|
||||||
|
institutionLogin: PropTypes.bool,
|
||||||
|
handleInstitutionLogin: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoginComponentSlot;
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import { renderHook } from '@testing-library/react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
import algoliasearchHelper from 'algoliasearch-helper';
|
import algoliasearchHelper from 'algoliasearch-helper';
|
||||||
|
|
||||||
import mockedRecommendedProducts from './mockedData';
|
import mockedRecommendedProducts from './mockedData';
|
||||||
import CreateAlgoliaSearchHelperMock from './test_utils/test_utils';
|
|
||||||
import isOneTrustFunctionalCookieEnabled from '../../../data/oneTrust';
|
import isOneTrustFunctionalCookieEnabled from '../../../data/oneTrust';
|
||||||
import useAlgoliaRecommendations from '../hooks/useAlgoliaRecommendations';
|
import useAlgoliaRecommendations from '../hooks/useAlgoliaRecommendations';
|
||||||
|
import CreateAlgoliaSearchHelperMock from './test_utils/test_utils';
|
||||||
|
|
||||||
jest.mock('algoliasearch-helper');
|
jest.mock('algoliasearch-helper');
|
||||||
|
|
||||||
@@ -17,6 +19,23 @@ jest.mock('../../../data/algolia', () => ({
|
|||||||
|
|
||||||
jest.mock('../algoliaResultsParser', () => jest.fn((course) => course));
|
jest.mock('../algoliaResultsParser', () => jest.fn((course) => course));
|
||||||
|
|
||||||
|
const renderHook = (hookCallback) => {
|
||||||
|
const result = {
|
||||||
|
current: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Component = () => {
|
||||||
|
const val = hookCallback();
|
||||||
|
React.useEffect(() => {
|
||||||
|
result.current = val;
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<Component />);
|
||||||
|
return { result };
|
||||||
|
};
|
||||||
|
|
||||||
describe('useAlgoliaRecommendations Tests', () => {
|
describe('useAlgoliaRecommendations Tests', () => {
|
||||||
const MockSearchHelperWithData = new CreateAlgoliaSearchHelperMock(mockedRecommendedProducts);
|
const MockSearchHelperWithData = new CreateAlgoliaSearchHelperMock(mockedRecommendedProducts);
|
||||||
const MockSearchHelperWithoutData = new CreateAlgoliaSearchHelperMock();
|
const MockSearchHelperWithoutData = new CreateAlgoliaSearchHelperMock();
|
||||||
@@ -28,8 +47,10 @@ describe('useAlgoliaRecommendations Tests', () => {
|
|||||||
() => useAlgoliaRecommendations('PK', 'Introductory'),
|
() => useAlgoliaRecommendations('PK', 'Introductory'),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.current.recommendations).toEqual(mockedRecommendedProducts);
|
expect(result.current.recommendations)
|
||||||
expect(result.current.isLoading).toBe(false);
|
.toEqual(mockedRecommendedProducts);
|
||||||
|
expect(result.current.isLoading)
|
||||||
|
.toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not fetch recommendations if functional cookies are not set', async () => {
|
it('should not fetch recommendations if functional cookies are not set', async () => {
|
||||||
@@ -39,8 +60,10 @@ describe('useAlgoliaRecommendations Tests', () => {
|
|||||||
() => useAlgoliaRecommendations('PK', 'Introductory'),
|
() => useAlgoliaRecommendations('PK', 'Introductory'),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.current.recommendations).toEqual([]);
|
expect(result.current.recommendations)
|
||||||
expect(result.current.isLoading).toBe(false);
|
.toEqual([]);
|
||||||
|
expect(result.current.isLoading)
|
||||||
|
.toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty list if no recommendations returned from Algolia', async () => {
|
it('should return empty list if no recommendations returned from Algolia', async () => {
|
||||||
@@ -50,7 +73,9 @@ describe('useAlgoliaRecommendations Tests', () => {
|
|||||||
() => useAlgoliaRecommendations('PK', 'Introductory'),
|
() => useAlgoliaRecommendations('PK', 'Introductory'),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.current.recommendations).toEqual([]);
|
expect(result.current.recommendations)
|
||||||
expect(result.current.isLoading).toBe(false);
|
.toEqual([]);
|
||||||
|
expect(result.current.isLoading)
|
||||||
|
.toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user