@openedx/frontend-app-authn 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/LICENSE +661 -0
  2. package/README.rst +204 -0
  3. package/package.json +79 -0
  4. package/src/Main.tsx +23 -0
  5. package/src/__mocks__/file.js +1 -0
  6. package/src/__mocks__/svg.js +1 -0
  7. package/src/app.scss +6 -0
  8. package/src/app.ts +43 -0
  9. package/src/base-container/components/default-layout/DefaultLayout.test.jsx +48 -0
  10. package/src/base-container/components/default-layout/LargeLayout.jsx +42 -0
  11. package/src/base-container/components/default-layout/MediumLayout.jsx +49 -0
  12. package/src/base-container/components/default-layout/SmallLayout.jsx +37 -0
  13. package/src/base-container/components/default-layout/index.jsx +3 -0
  14. package/src/base-container/components/default-layout/messages.js +16 -0
  15. package/src/base-container/components/image-layout/ExtraSmallLayout.jsx +31 -0
  16. package/src/base-container/components/image-layout/LargeLayout.jsx +32 -0
  17. package/src/base-container/components/image-layout/MediumLayout.jsx +32 -0
  18. package/src/base-container/components/image-layout/SmallLayout.jsx +31 -0
  19. package/src/base-container/components/image-layout/index.jsx +4 -0
  20. package/src/base-container/components/image-layout/index.scss +37 -0
  21. package/src/base-container/components/image-layout/messages.js +16 -0
  22. package/src/base-container/components/welcome-page-layout/LargeLayout.jsx +46 -0
  23. package/src/base-container/components/welcome-page-layout/MediumLayout.jsx +49 -0
  24. package/src/base-container/components/welcome-page-layout/SmallLayout.jsx +38 -0
  25. package/src/base-container/components/welcome-page-layout/index.jsx +3 -0
  26. package/src/base-container/components/welcome-page-layout/messages.js +21 -0
  27. package/src/base-container/index.jsx +70 -0
  28. package/src/base-container/tests/BaseContainer.test.jsx +44 -0
  29. package/src/common-components/EmbeddedRegistrationRoute.jsx +26 -0
  30. package/src/common-components/EnterpriseSSO.jsx +110 -0
  31. package/src/common-components/FormGroup.jsx +106 -0
  32. package/src/common-components/InstitutionLogistration.jsx +102 -0
  33. package/src/common-components/NotFoundPage.jsx +15 -0
  34. package/src/common-components/PasswordField.jsx +175 -0
  35. package/src/common-components/RedirectLogistration.jsx +94 -0
  36. package/src/common-components/RegisterFaIcons.jsx +8 -0
  37. package/src/common-components/SocialAuthProviders.jsx +75 -0
  38. package/src/common-components/ThirdPartyAuth.jsx +123 -0
  39. package/src/common-components/ThirdPartyAuthAlert.jsx +49 -0
  40. package/src/common-components/UnAuthOnlyRoute.jsx +41 -0
  41. package/src/common-components/data/actions.js +27 -0
  42. package/src/common-components/data/reducers.js +63 -0
  43. package/src/common-components/data/sagas.js +32 -0
  44. package/src/common-components/data/selectors.js +28 -0
  45. package/src/common-components/data/service.js +23 -0
  46. package/src/common-components/data/tests/reducer.test.js +82 -0
  47. package/src/common-components/data/tests/sagas.test.js +71 -0
  48. package/src/common-components/index.jsx +14 -0
  49. package/src/common-components/messages.jsx +127 -0
  50. package/src/common-components/tests/EmbeddedRegistrationRoute.test.jsx +76 -0
  51. package/src/common-components/tests/FormField.test.jsx +289 -0
  52. package/src/common-components/tests/SocialAuthProviders.test.jsx +75 -0
  53. package/src/common-components/tests/ThirdPartyAuthAlert.test.jsx +39 -0
  54. package/src/common-components/tests/UnAuthOnlyRoute.test.jsx +73 -0
  55. package/src/common-components/tests/__snapshots__/SocialAuthProviders.test.jsx.snap +156 -0
  56. package/src/common-components/tests/__snapshots__/ThirdPartyAuthAlert.test.jsx.snap +53 -0
  57. package/src/constants.ts +1 -0
  58. package/src/data/configureStore.js +33 -0
  59. package/src/data/constants.js +38 -0
  60. package/src/data/countries.ts +59 -0
  61. package/src/data/oneTrust.js +3 -0
  62. package/src/data/reducers.js +36 -0
  63. package/src/data/sagas.js +19 -0
  64. package/src/data/tests/cookies.test.js +42 -0
  65. package/src/data/tests/dataUtils.test.js +19 -0
  66. package/src/data/tests/reduxUtils.test.js +14 -0
  67. package/src/data/utils/cookies.js +12 -0
  68. package/src/data/utils/dataUtils.js +81 -0
  69. package/src/data/utils/index.js +11 -0
  70. package/src/data/utils/reduxUtils.js +34 -0
  71. package/src/data/utils/useMobileResponsive.js +24 -0
  72. package/src/field-renderer/FieldRenderer.jsx +156 -0
  73. package/src/field-renderer/index.jsx +2 -0
  74. package/src/field-renderer/tests/FieldRenderer.test.jsx +201 -0
  75. package/src/forgot-password/ForgotPasswordAlert.jsx +97 -0
  76. package/src/forgot-password/ForgotPasswordPage.jsx +193 -0
  77. package/src/forgot-password/data/actions.js +32 -0
  78. package/src/forgot-password/data/reducers.js +58 -0
  79. package/src/forgot-password/data/sagas.js +35 -0
  80. package/src/forgot-password/data/selectors.js +10 -0
  81. package/src/forgot-password/data/service.js +21 -0
  82. package/src/forgot-password/data/tests/reducers.test.js +34 -0
  83. package/src/forgot-password/data/tests/sagas.test.js +67 -0
  84. package/src/forgot-password/index.js +5 -0
  85. package/src/forgot-password/messages.js +128 -0
  86. package/src/forgot-password/tests/ForgotPasswordPage.test.jsx +269 -0
  87. package/src/i18n/index.js +25 -0
  88. package/src/index.ts +3 -0
  89. package/src/login/AccountActivationMessage.jsx +78 -0
  90. package/src/login/ChangePasswordPrompt.jsx +91 -0
  91. package/src/login/LoginFailure.jsx +231 -0
  92. package/src/login/LoginPage.jsx +368 -0
  93. package/src/login/data/actions.js +39 -0
  94. package/src/login/data/constants.js +20 -0
  95. package/src/login/data/reducers.js +76 -0
  96. package/src/login/data/sagas.js +45 -0
  97. package/src/login/data/service.js +24 -0
  98. package/src/login/data/tests/reducers.test.js +155 -0
  99. package/src/login/data/tests/sagas.test.js +110 -0
  100. package/src/login/index.js +5 -0
  101. package/src/login/messages.jsx +211 -0
  102. package/src/login/tests/AccountActivationMessage.test.jsx +122 -0
  103. package/src/login/tests/ChangePasswordPrompt.test.jsx +75 -0
  104. package/src/login/tests/LoginFailure.test.jsx +323 -0
  105. package/src/login/tests/LoginPage.test.jsx +839 -0
  106. package/src/logistration/Logistration.jsx +189 -0
  107. package/src/logistration/Logistration.test.jsx +275 -0
  108. package/src/progressive-profiling/ProgressiveProfiling.jsx +313 -0
  109. package/src/progressive-profiling/ProgressiveProfilingPageModal.jsx +56 -0
  110. package/src/progressive-profiling/data/actions.js +22 -0
  111. package/src/progressive-profiling/data/reducers.js +38 -0
  112. package/src/progressive-profiling/data/sagas.js +24 -0
  113. package/src/progressive-profiling/data/selectors.js +14 -0
  114. package/src/progressive-profiling/data/service.js +17 -0
  115. package/src/progressive-profiling/index.js +5 -0
  116. package/src/progressive-profiling/messages.jsx +57 -0
  117. package/src/progressive-profiling/tests/ProgressiveProfiling.test.jsx +322 -0
  118. package/src/register/RegistrationFields/CountryField/CountryField.jsx +164 -0
  119. package/src/register/RegistrationFields/CountryField/CountryField.test.jsx +204 -0
  120. package/src/register/RegistrationFields/CountryField/validator.js +32 -0
  121. package/src/register/RegistrationFields/EmailField/EmailField.jsx +140 -0
  122. package/src/register/RegistrationFields/EmailField/EmailField.test.jsx +236 -0
  123. package/src/register/RegistrationFields/EmailField/constants.js +131 -0
  124. package/src/register/RegistrationFields/EmailField/validator.js +126 -0
  125. package/src/register/RegistrationFields/EmailField/validator.test.js +39 -0
  126. package/src/register/RegistrationFields/HonorCodeField/HonorCode.jsx +104 -0
  127. package/src/register/RegistrationFields/HonorCodeField/HonorCode.test.jsx +70 -0
  128. package/src/register/RegistrationFields/NameField/NameField.jsx +68 -0
  129. package/src/register/RegistrationFields/NameField/NameField.test.jsx +146 -0
  130. package/src/register/RegistrationFields/NameField/validator.js +22 -0
  131. package/src/register/RegistrationFields/TermsOfServiceField/TermsOfService.jsx +58 -0
  132. package/src/register/RegistrationFields/TermsOfServiceField/TermsOfService.test.jsx +55 -0
  133. package/src/register/RegistrationFields/UsernameField/UsernameField.jsx +162 -0
  134. package/src/register/RegistrationFields/UsernameField/UsernameField.test.jsx +319 -0
  135. package/src/register/RegistrationFields/UsernameField/validator.js +16 -0
  136. package/src/register/RegistrationFields/index.js +6 -0
  137. package/src/register/RegistrationPage.jsx +428 -0
  138. package/src/register/RegistrationPage.test.jsx +854 -0
  139. package/src/register/components/ConfigurableRegistrationForm.jsx +244 -0
  140. package/src/register/components/RegistrationFailure.jsx +80 -0
  141. package/src/register/components/tests/ConfigurableRegistrationForm.test.jsx +401 -0
  142. package/src/register/components/tests/RegistrationFailure.test.jsx +212 -0
  143. package/src/register/components/tests/ThirdPartyAuth.test.jsx +439 -0
  144. package/src/register/data/actions.js +85 -0
  145. package/src/register/data/constants.js +13 -0
  146. package/src/register/data/reducers.js +140 -0
  147. package/src/register/data/sagas.js +58 -0
  148. package/src/register/data/selectors.js +34 -0
  149. package/src/register/data/service.js +45 -0
  150. package/src/register/data/tests/reducers.test.js +277 -0
  151. package/src/register/data/tests/sagas.test.js +239 -0
  152. package/src/register/data/tests/utils.test.js +98 -0
  153. package/src/register/data/utils.js +153 -0
  154. package/src/register/index.js +4 -0
  155. package/src/register/messages.jsx +206 -0
  156. package/src/reset-password/ResetPasswordFailure.jsx +55 -0
  157. package/src/reset-password/ResetPasswordPage.jsx +224 -0
  158. package/src/reset-password/ResetPasswordSuccess.jsx +19 -0
  159. package/src/reset-password/data/actions.js +50 -0
  160. package/src/reset-password/data/constants.js +16 -0
  161. package/src/reset-password/data/reducers.js +44 -0
  162. package/src/reset-password/data/sagas.js +67 -0
  163. package/src/reset-password/data/selectors.js +10 -0
  164. package/src/reset-password/data/service.js +61 -0
  165. package/src/reset-password/data/tests/sagas.test.js +185 -0
  166. package/src/reset-password/index.js +5 -0
  167. package/src/reset-password/messages.js +88 -0
  168. package/src/reset-password/tests/ResetPasswordPage.test.jsx +241 -0
  169. package/src/routes.jsx +79 -0
  170. package/src/sass/_base_component.scss +202 -0
  171. package/src/sass/_forgot_password.scss +3 -0
  172. package/src/sass/_login_page.scss +3 -0
  173. package/src/sass/_progressive_profiling_page.scss +30 -0
  174. package/src/sass/_registration.scss +123 -0
  175. package/src/sass/_reset_password.scss +3 -0
  176. package/src/sass/_style.scss +465 -0
  177. package/src/setupTest.js +68 -0
package/README.rst ADDED
@@ -0,0 +1,204 @@
1
+ ##################
2
+ frontend-app-authn
3
+ ##################
4
+
5
+ |Build Status| |ci-badge| |Codecov| |semantic-release|
6
+
7
+ ********
8
+ Purpose
9
+ ********
10
+
11
+ This is a micro-frontend application responsible for the login, registration and password reset functionality.
12
+
13
+ **What is the domain of this MFE?**
14
+
15
+ - Register page
16
+
17
+ - Login page
18
+
19
+ - Forgot password page
20
+
21
+ - Reset password page
22
+
23
+ - Progressive profiling page
24
+
25
+ ***************
26
+ Getting Started
27
+ ***************
28
+
29
+ Installation
30
+ ============
31
+
32
+ `Tutor`_ is currently recommended as a development environment for your new MFE. Please refer to the `relevant tutor-mfe documentation`_ to get started using it.
33
+
34
+ .. _Tutor: https://github.com/overhangio/tutor
35
+ .. _relevant tutor-mfe documentation: https://github.com/overhangio/tutor-mfe?tab=readme-ov-file#mfe-development
36
+
37
+ Environment Variables/Setup Notes
38
+ =================================
39
+
40
+ This MFE is configured via environment variables supplied at build time. All micro-frontends have a shared set of required environment variables, as documented in the Open edX Developer Guide under `Required Environment Variables <https://github.com/overhangio/tutor-mfe?tab=readme-ov-file#mfe-development>`__.
41
+
42
+ The authentication micro-frontend also requires the following additional variable:
43
+
44
+ .. list-table:: Environment Variables
45
+ :widths: 30 50 20
46
+ :header-rows: 1
47
+
48
+ * - Name
49
+ - Description / Usage
50
+ - Example
51
+
52
+ * - ``LOGIN_ISSUE_SUPPORT_LINK``
53
+ - The fully-qualified URL to the login issue support page in the target environment.
54
+ - ``https://support.example.com``
55
+
56
+ * - ``ACTIVATION_EMAIL_SUPPORT_LINK``
57
+ - The fully-qualified URL to the activation email support page in the target environment.
58
+ - ``https://support.example.com``
59
+
60
+ * - ``PASSWORD_RESET_SUPPORT_LINK``
61
+ - The fully-qualified URL to the password reset support page in the target environment.
62
+ - ``https://support.example.com``
63
+
64
+ * - ``AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK``
65
+ - The fully-qualified URL to the progressive profiling support page in the target environment.
66
+ - ``https://support.example.com``
67
+
68
+ * - ``TOS_AND_HONOR_CODE``
69
+ - The fully-qualified URL to the Honor code page in the target environment.
70
+ - ``https://example.com/honor``
71
+
72
+ * - ``TOS_LINK``
73
+ - The fully-qualified URL to the Terms of service page in the target environment.
74
+ - ``https://example.com/tos``
75
+
76
+ * - ``PRIVACY_POLICY``
77
+ - The fully-qualified URL to the Privacy policy page in the target environment.
78
+ - ``https://example.com/privacy``
79
+
80
+ * - ``INFO_EMAIL``
81
+ - The valid email address for information query regarding the target environment.
82
+ - ``info@example.com``
83
+
84
+ * - ``ENABLE_DYNAMIC_REGISTRATION_FIELDS``
85
+ - Enables support for configurable registration fields on the MFE. This flag must be enabled to show any required registration field besides the default fields (name, email, username, password).
86
+ - ``true`` | ``''`` (empty strings are falsy)
87
+
88
+ * - ``ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN``
89
+ - Enables support for progressive profiling. If enabled, users are redirected to a second page where data for optional registration fields can be collected.
90
+ - ``true`` | ``''`` (empty strings are falsy)
91
+
92
+ * - ``DISABLE_ENTERPRISE_LOGIN``
93
+ - Disables the enterprise login from Authn MFE.
94
+ - ``true`` | ``''`` (empty strings are falsy)
95
+
96
+ * - ``MFE_CONFIG_API_URL``
97
+ - Link of the API to get runtime mfe configuration variables from the site configuration or django settings.
98
+ - ``/api/v1/mfe_config`` | ``''`` (empty strings are falsy)
99
+
100
+ * - ``APP_ID``
101
+ - Name of MFE, this will be used by the API to get runtime configurations for the specific micro frontend. For a frontend repo `frontend-app-appName`, use `appName` as APP_ID.
102
+ - ``authn`` | ``''``
103
+
104
+ * - ``ENABLE_IMAGE_LAYOUT``
105
+ - Enables the image layout feature within the authn. When set to True, this feature allows the inclusion of images in the base container layout. For more details on configuring this feature, please refer to the `Modifying base container <docs/how_tos/modifying_base_container.rst>`_.
106
+ - ``true`` | ``''`` (empty strings are falsy)
107
+
108
+
109
+ edX-specific Environment Variables
110
+ ==================================
111
+
112
+ Furthermore, there are several edX-specific environment variables that enable integrations with closed-source services private to the edX organization, and might be unsupported in Open edX.
113
+
114
+ .. list-table:: edX-specific Environment Variables
115
+ :widths: 30 50 20
116
+ :header-rows: 1
117
+
118
+ * - Name
119
+ - Description / Usage
120
+ - Example
121
+
122
+ * - ``MARKETING_EMAILS_OPT_IN``
123
+ - Enables support for opting in marketing emails that helps us getting user consent for sending marketing emails.
124
+ - ``true`` | ``''`` (empty strings are falsy)
125
+
126
+ For more information see the document: `Micro-frontend applications in Open
127
+ edX <https://github.com/overhangio/tutor-mfe?tab=readme-ov-file#mfe-development>`__.
128
+
129
+ How To Contribute
130
+ =================
131
+
132
+ Contributions are very welcome, and strongly encouraged! We've
133
+ put together `some documentation that describes our contribution process <https://docs.openedx.org/en/latest/developers/references/developer_guide/process/index.html>`_.
134
+
135
+ Even though they were written with edx-platform in mind, the guidelines should be followed for Open edX code in general.
136
+
137
+ PR description template should be automatically applied if you are sending PR from github interface; otherwise you
138
+ can find it it at `PULL_REQUEST_TEMPLATE.md <https://github.com/openedx/frontend-app-authn/blob/master/.github/pull_request_template.md>`_
139
+
140
+ This project is currently accepting all types of contributions, bug fixes and security fixes.
141
+
142
+ Getting Help
143
+ ============
144
+
145
+ If you're having trouble, we have discussion forums at
146
+ https://discuss.openedx.org where you can connect with others in the community.
147
+
148
+ Our real-time conversations are on Slack. You can request a `Slack
149
+ invitation`_, then join our `community Slack workspace`_. Because this is a
150
+ frontend repository, the best place to discuss it would be in the `#wg-frontend
151
+ channel`_.
152
+
153
+ For anything non-trivial, the best path is to open an issue in this repository
154
+ with as many details about the issue you are facing as you can provide.
155
+
156
+ https://github.com/openedx/frontend-app-authn/issues
157
+
158
+ For more information about these options, see the `Getting Help`_ page.
159
+
160
+ .. _Slack invitation: https://openedx.org/slack
161
+ .. _community Slack workspace: https://openedx.slack.com/
162
+ .. _#wg-frontend channel: https://openedx.slack.com/archives/C04BM6YC7A6
163
+ .. _Getting Help: https://openedx.org/community/connect
164
+
165
+ The Open edX Code of Conduct
166
+ ============================
167
+ All community members are expected to follow the `Open edX Code of Conduct <https://openedx.org/code-of-conduct/>`_.
168
+
169
+ People
170
+ ======
171
+ The assigned maintainers for this component and other project details may be
172
+ found in `Backstage <https://backstage.openedx.org/catalog/default/group/2u-infinity>`_. Backstage pulls this data from the ``catalog-info.yaml``
173
+ file in this repo.
174
+
175
+ Reporting Security Issues
176
+ =========================
177
+
178
+ Please do not report security issues in public. Please email security@openedx.org.
179
+
180
+ Known Issues
181
+ ============
182
+
183
+ None
184
+
185
+ License
186
+ =======
187
+
188
+ The code in this repository is licensed under the GNU Affero General Public License v3.0, unless
189
+ otherwise noted.
190
+
191
+ Please see `LICENSE <https://github.com/openedx/frontend-app-authn/blob/master/LICENSE>`_ for details.
192
+
193
+
194
+ ==============================
195
+
196
+ .. |Build Status| image:: https://api.travis-ci.com/edx/frontend-app-authn.svg?branch=master
197
+ :target: https://travis-ci.com/edx/frontend-app-authn
198
+ .. |Codecov| image:: https://img.shields.io/codecov/c/github/edx/frontend-app-authn
199
+ :target: https://codecov.io/gh/edx/frontend-app-authn
200
+ .. |ci-badge| image:: https://github.com/openedx/edx-developer-docs/actions/workflows/ci.yml/badge.svg
201
+ :target: https://github.com/openedx/edx-developer-docs/actions/workflows/ci.yml
202
+ :alt: Continuous Integration
203
+ .. |semantic-release| image:: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
204
+ :target: https://github.com/semantic-release/semantic-release
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "@openedx/frontend-app-authn",
3
+ "version": "1.0.0-alpha.0",
4
+ "description": "Frontend authentication",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/openedx/frontend-app-authn.git"
8
+ },
9
+ "main": "src/index.ts",
10
+ "files": [
11
+ "/src"
12
+ ],
13
+ "browserslist": [
14
+ "extends @edx/browserslist-config"
15
+ ],
16
+ "sideEffects": [
17
+ "*.css",
18
+ "*.scss"
19
+ ],
20
+ "scripts": {
21
+ "dev": "PORT=1999 PUBLIC_PATH=/authn openedx dev",
22
+ "i18n_extract": "openedx formatjs extract",
23
+ "lint": "openedx lint .",
24
+ "lint:fix": "openedx lint --fix .",
25
+ "snapshot": "openedx test --updateSnapshot",
26
+ "test": "openedx test --coverage --passWithNoTests"
27
+ },
28
+ "author": "Open edX",
29
+ "license": "AGPL-3.0",
30
+ "homepage": "https://github.com/openedx/frontend-app-authn#readme",
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/openedx/frontend-app-authn/issues"
36
+ },
37
+ "dependencies": {
38
+ "@edx/brand": "npm:@openedx/brand-openedx@^1.2.3",
39
+ "@edx/openedx-atlas": "^0.7.0",
40
+ "@fortawesome/fontawesome-svg-core": "^6.7.2",
41
+ "@fortawesome/free-brands-svg-icons": "^6.7.2",
42
+ "@fortawesome/free-solid-svg-icons": "^6.7.2",
43
+ "@fortawesome/react-fontawesome": "^0.2.2",
44
+ "@redux-devtools/extension": "^3.3.0",
45
+ "classnames": "^2.5.1",
46
+ "fastest-levenshtein": "^1.0.16",
47
+ "form-urlencoded": "^6.1.5",
48
+ "i18n-iso-countries": "^7.13.0",
49
+ "prop-types": "^15.8.1",
50
+ "query-string": "^7.1.3",
51
+ "react-helmet": "^6.1.0",
52
+ "react-loading-skeleton": "^3.5.0",
53
+ "react-responsive": "^8.2.0",
54
+ "redux-logger": "^3.0.6",
55
+ "redux-mock-store": "^1.5.5",
56
+ "redux-saga": "^1.3.0",
57
+ "redux-thunk": "^2.4.2",
58
+ "reselect": "^5.1.1",
59
+ "universal-cookie": "^8.0.1"
60
+ },
61
+ "devDependencies": {
62
+ "@edx/browserslist-config": "^1.5.0",
63
+ "@testing-library/react": "^16.3.0",
64
+ "babel-plugin-formatjs": "10.5.38",
65
+ "eslint-plugin-import": "2.31.0",
66
+ "jest": "^29.7.0",
67
+ "react-test-renderer": "^18.3.1"
68
+ },
69
+ "peerDependencies": {
70
+ "@openedx/frontend-base": "^1.0.0-alpha.1",
71
+ "@openedx/paragon": "^22",
72
+ "react": "^18",
73
+ "react-dom": "^18",
74
+ "react-redux": "^8",
75
+ "react-router": "^6",
76
+ "react-router-dom": "^6",
77
+ "redux": "^4"
78
+ }
79
+ }
package/src/Main.tsx ADDED
@@ -0,0 +1,23 @@
1
+ import { Provider as ReduxProvider } from 'react-redux';
2
+ import { Outlet } from 'react-router-dom';
3
+ import { CurrentAppProvider } from '@openedx/frontend-base';
4
+
5
+ import { appId } from './constants';
6
+ import {
7
+ registerIcons,
8
+ } from './common-components';
9
+ import configureStore from './data/configureStore';
10
+
11
+ import './sass/_style.scss';
12
+
13
+ registerIcons();
14
+
15
+ const Main = () => (
16
+ <CurrentAppProvider appId={appId}>
17
+ <ReduxProvider store={configureStore()}>
18
+ <Outlet />
19
+ </ReduxProvider>
20
+ </CurrentAppProvider>
21
+ );
22
+
23
+ export default Main;
@@ -0,0 +1 @@
1
+ module.exports = 'FileMock';
@@ -0,0 +1 @@
1
+ module.exports = 'SvgURL';
package/src/app.scss ADDED
@@ -0,0 +1,6 @@
1
+ @use "@edx/brand/paragon/fonts";
2
+ @use "@edx/brand/paragon/variables";
3
+ @use "@openedx/paragon/scss/core/core";
4
+ @use "@edx/brand/paragon/overrides";
5
+
6
+ @use "sass/style";
package/src/app.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { App } from '@openedx/frontend-base';
2
+ import { appId } from './constants';
3
+ import routes from './routes';
4
+ import messages from './i18n';
5
+
6
+ const app: App = {
7
+ appId,
8
+ routes,
9
+ messages,
10
+ config: {
11
+ ACTIVATION_EMAIL_SUPPORT_LINK: null,
12
+ ALLOW_PUBLIC_ACCOUNT_CREATION: true,
13
+ AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: null,
14
+ BANNER_IMAGE_EXTRA_SMALL: '',
15
+ BANNER_IMAGE_LARGE: '',
16
+ BANNER_IMAGE_MEDIUM: '',
17
+ BANNER_IMAGE_SMALL: '',
18
+ DISABLE_ENTERPRISE_LOGIN: true,
19
+ ENABLE_AUTO_GENERATED_USERNAME: false,
20
+ ENABLE_DYNAMIC_REGISTRATION_FIELDS: false,
21
+ ENABLE_IMAGE_LAYOUT: false,
22
+ ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN: false,
23
+ FAVICON_URL: 'https://edx-cdn.org/v3/default/favicon.ico',
24
+ INFO_EMAIL: '',
25
+ LOGIN_ISSUE_SUPPORT_LINK: null,
26
+ LOGO_TRADEMARK_URL: 'https://edx-cdn.org/v3/default/logo-trademark.svg',
27
+ LOGO_URL: 'https://edx-cdn.org/v3/default/logo.svg',
28
+ LOGO_WHITE_URL: 'https://edx-cdn.org/v3/default/logo-white.svg',
29
+ MARKETING_EMAILS_OPT_IN: '',
30
+ MARKETING_SITE_BASE_URL: 'http://local.openedx.io',
31
+ PASSWORD_RESET_SUPPORT_LINK: null,
32
+ POST_REGISTRATION_REDIRECT_URL: '',
33
+ PRIVACY_POLICY: null,
34
+ SEARCH_CATALOG_URL: null,
35
+ SESSION_COOKIE_DOMAIN: 'local.openedx.io',
36
+ SHOW_REGISTRATION_LINKS: true,
37
+ TOS_AND_HONOR_CODE: null,
38
+ TOS_LINK: null,
39
+ USER_RETENTION_COOKIE_NAME: '',
40
+ },
41
+ };
42
+
43
+ export default app;
@@ -0,0 +1,48 @@
1
+ import { IntlProvider } from '@openedx/frontend-base';
2
+ import { render, screen } from '@testing-library/react';
3
+
4
+ import { DefaultLargeLayout, DefaultMediumLayout, DefaultSmallLayout } from './index';
5
+
6
+ describe('Default Layout tests', () => {
7
+ it('should display the form passed as a child in SmallScreenLayout', () => {
8
+ render(
9
+ <IntlProvider locale="en">
10
+ <div>
11
+ <DefaultSmallLayout />
12
+ <form aria-label="form">
13
+ <input type="text" />
14
+ </form>
15
+ </div>
16
+ </IntlProvider>,
17
+ );
18
+ expect(screen.getByRole('form')).toBeDefined();
19
+ });
20
+
21
+ it('should display the form passed as a child in MediumScreenLayout', () => {
22
+ render(
23
+ <IntlProvider locale="en">
24
+ <div>
25
+ <DefaultMediumLayout />
26
+ <form aria-label="form">
27
+ <input type="text" />
28
+ </form>
29
+ </div>
30
+ </IntlProvider>,
31
+ );
32
+ expect(screen.getByRole('form')).toBeDefined();
33
+ });
34
+
35
+ it('should display the form passed as a child in LargeScreenLayout', () => {
36
+ render(
37
+ <IntlProvider locale="en">
38
+ <div>
39
+ <DefaultLargeLayout />
40
+ <form aria-label="form">
41
+ <input type="text" />
42
+ </form>
43
+ </div>
44
+ </IntlProvider>,
45
+ );
46
+ expect(screen.getByRole('form')).toBeDefined();
47
+ });
48
+ });
@@ -0,0 +1,42 @@
1
+ import { useAppConfig, getSiteConfig, useIntl } from '@openedx/frontend-base';
2
+ import { Hyperlink, Image } from '@openedx/paragon';
3
+ import classNames from 'classnames';
4
+
5
+ import messages from './messages';
6
+
7
+ const LargeLayout = () => {
8
+ const { formatMessage } = useIntl();
9
+
10
+ return (
11
+ <div className="w-50 d-flex">
12
+ <div className="col-md-9 bg-primary-400">
13
+ <Hyperlink destination={useAppConfig().MARKETING_SITE_BASE_URL}>
14
+ <Image className="logo position-absolute" alt={getSiteConfig().siteName} src={useAppConfig().LOGO_WHITE_URL} />
15
+ </Hyperlink>
16
+ <div className="min-vh-100 d-flex align-items-center">
17
+ <div className={classNames({ 'large-yellow-line mr-n4.5': getSiteConfig().siteName === 'edX' })} />
18
+ <h1
19
+ className={classNames(
20
+ 'display-2 text-white mw-xs',
21
+ { 'ml-6': getSiteConfig().siteName !== 'edX' },
22
+ )}
23
+ >
24
+ {formatMessage(messages['start.learning'])}
25
+ <div className="text-accent-a">
26
+ {formatMessage(messages['with.site.name'], { siteName: getSiteConfig().siteName })}
27
+ </div>
28
+ </h1>
29
+ </div>
30
+ </div>
31
+ <div className="col-md-3 bg-white p-0">
32
+ <svg className="ml-n1 w-100 h-100 large-screen-svg-primary" preserveAspectRatio="xMaxYMin meet">
33
+ <g transform="skewX(171.6)">
34
+ <rect x="0" y="0" height="100%" width="100%" />
35
+ </g>
36
+ </svg>
37
+ </div>
38
+ </div>
39
+ );
40
+ };
41
+
42
+ export default LargeLayout;
@@ -0,0 +1,49 @@
1
+ import { useAppConfig, getSiteConfig, useIntl } from '@openedx/frontend-base';
2
+ import { Hyperlink, Image } from '@openedx/paragon';
3
+ import classNames from 'classnames';
4
+
5
+ import messages from './messages';
6
+
7
+ const MediumLayout = () => {
8
+ const { formatMessage } = useIntl();
9
+
10
+ return (
11
+ <>
12
+ <div className="w-100 medium-screen-top-stripe" />
13
+ <div className="w-100 p-0 mb-3 d-flex">
14
+ <div className="col-md-10 bg-primary-400">
15
+ <Hyperlink destination={useAppConfig().MARKETING_SITE_BASE_URL}>
16
+ <Image alt={getSiteConfig().siteName} className="logo" src={useAppConfig().LOGO_WHITE_URL} />
17
+ </Hyperlink>
18
+ <div className="d-flex align-items-center justify-content-center mb-4 ">
19
+ <div className={classNames({ 'mt-1 medium-yellow-line': getSiteConfig().siteName === 'edX' })} />
20
+ <div>
21
+ <h1
22
+ className={classNames(
23
+ 'display-1 text-white mt-5 mb-5 mr-2 main-heading',
24
+ { 'ml-4.5': getSiteConfig().siteName !== 'edX' },
25
+ )}
26
+ >
27
+ <span>
28
+ {formatMessage(messages['start.learning'])}{' '}
29
+ <span className="text-accent-a d-inline-block">
30
+ {formatMessage(messages['with.site.name'], { siteName: getSiteConfig().siteName })}
31
+ </span>
32
+ </span>
33
+ </h1>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ <div className="col-md-2 bg-white p-0">
38
+ <svg className="w-100 h-100 medium-screen-svg-primary" preserveAspectRatio="xMaxYMin meet">
39
+ <g transform="skewX(168)">
40
+ <rect x="0" y="0" height="100%" width="100%" />
41
+ </g>
42
+ </svg>
43
+ </div>
44
+ </div>
45
+ </>
46
+ );
47
+ };
48
+
49
+ export default MediumLayout;
@@ -0,0 +1,37 @@
1
+ import { useAppConfig, getSiteConfig, useIntl } from '@openedx/frontend-base';
2
+ import { Hyperlink, Image } from '@openedx/paragon';
3
+ import classNames from 'classnames';
4
+
5
+ import messages from './messages';
6
+
7
+ const SmallLayout = () => {
8
+ const { formatMessage } = useIntl();
9
+
10
+ return (
11
+ <span className="bg-primary-400 w-100">
12
+ <div className="col-md-12 small-screen-top-stripe" />
13
+ <div>
14
+ <Hyperlink destination={useAppConfig().MARKETING_SITE_BASE_URL}>
15
+ <Image className="logo-small" alt={getSiteConfig().siteName} src={useAppConfig().LOGO_WHITE_URL} />
16
+ </Hyperlink>
17
+ <div className="d-flex align-items-center m-3.5">
18
+ <div className={classNames({ 'small-yellow-line mr-n2.5': getSiteConfig().siteName === 'edX' })} />
19
+ <h1
20
+ className={classNames(
21
+ 'text-white mt-3.5 mb-3.5',
22
+ )}
23
+ >
24
+ <span>
25
+ {formatMessage(messages['start.learning'])}{' '}
26
+ <span className="text-accent-a d-inline-block">
27
+ {formatMessage(messages['with.site.name'], { siteName: getSiteConfig().siteName })}
28
+ </span>
29
+ </span>
30
+ </h1>
31
+ </div>
32
+ </div>
33
+ </span>
34
+ );
35
+ };
36
+
37
+ export default SmallLayout;
@@ -0,0 +1,3 @@
1
+ export { default as DefaultLargeLayout } from './LargeLayout';
2
+ export { default as DefaultMediumLayout } from './MediumLayout';
3
+ export { default as DefaultSmallLayout } from './SmallLayout';
@@ -0,0 +1,16 @@
1
+ import { defineMessages } from '@openedx/frontend-base';
2
+
3
+ const messages = defineMessages({
4
+ 'start.learning': {
5
+ id: 'start.learning',
6
+ defaultMessage: 'Start learning',
7
+ description: 'Header text for logistration MFE pages',
8
+ },
9
+ 'with.site.name': {
10
+ id: 'with.site.name',
11
+ defaultMessage: 'with {siteName}',
12
+ description: 'Header text with site name for logistration MFE pages',
13
+ },
14
+ });
15
+
16
+ export default messages;
@@ -0,0 +1,31 @@
1
+ import { useAppConfig, getSiteConfig, useIntl } from '@openedx/frontend-base';
2
+ import { Hyperlink, Image } from '@openedx/paragon';
3
+
4
+ import messages from './messages';
5
+
6
+ const ExtraSmallLayout = () => {
7
+ const { formatMessage } = useIntl();
8
+
9
+ return (
10
+ <span
11
+ className="w-100 bg-primary-500 banner__image extra-small-layout"
12
+ style={{ backgroundImage: `url(${useAppConfig().BANNER_IMAGE_EXTRA_SMALL})` }}
13
+ >
14
+ <Hyperlink destination={useAppConfig().MARKETING_SITE_BASE_URL}>
15
+ <Image className="company-logo" alt={getSiteConfig().siteName} src={useAppConfig().LOGO_WHITE_URL} />
16
+ </Hyperlink>
17
+ <div className="ml-4.5 mr-1 pb-3.5 pt-3.5">
18
+ <h1 className="banner__heading">
19
+ <span className="text-light-500">
20
+ {formatMessage(messages['your.career.turning.point'])}{' '}
21
+ </span>
22
+ <span className="text-warning-300">
23
+ {formatMessage(messages['is.here'])}
24
+ </span>
25
+ </h1>
26
+ </div>
27
+ </span>
28
+ );
29
+ };
30
+
31
+ export default ExtraSmallLayout;
@@ -0,0 +1,32 @@
1
+ import { useAppConfig, getSiteConfig, useIntl } from '@openedx/frontend-base';
2
+ import { Hyperlink, Image } from '@openedx/paragon';
3
+
4
+ import './index.scss';
5
+ import messages from './messages';
6
+
7
+ const LargeLayout = () => {
8
+ const { formatMessage } = useIntl();
9
+
10
+ return (
11
+ <div
12
+ className="w-50 bg-primary-500 banner__image large-layout"
13
+ style={{ backgroundImage: `url(${useAppConfig().BANNER_IMAGE_LARGE})` }}
14
+ >
15
+ <Hyperlink destination={useAppConfig().MARKETING_SITE_BASE_URL}>
16
+ <Image className="company-logo position-absolute" alt={getSiteConfig().siteName} src={useAppConfig().LOGO_WHITE_URL} />
17
+ </Hyperlink>
18
+ <div className="min-vh-100 p-5 d-flex align-items-end">
19
+ <h1 className="display-2 mw-sm mb-3 d-flex flex-column flex-shrink-0 justify-content-center">
20
+ <span className="text-light-500">
21
+ {formatMessage(messages['your.career.turning.point'])}
22
+ </span>
23
+ <span className="text-warning-300">
24
+ {formatMessage(messages['is.here'])}
25
+ </span>
26
+ </h1>
27
+ </div>
28
+ </div>
29
+ );
30
+ };
31
+
32
+ export default LargeLayout;
@@ -0,0 +1,32 @@
1
+ import { useAppConfig, getSiteConfig, useIntl } from '@openedx/frontend-base';
2
+ import { Hyperlink, Image } from '@openedx/paragon';
3
+
4
+ import './index.scss';
5
+ import messages from './messages';
6
+
7
+ const MediumLayout = () => {
8
+ const { formatMessage } = useIntl();
9
+
10
+ return (
11
+ <div
12
+ className="w-100 mb-3 bg-primary-500 banner__image medium-layout"
13
+ style={{ backgroundImage: `url(${useAppConfig().BANNER_IMAGE_MEDIUM})` }}
14
+ >
15
+ <Hyperlink destination={useAppConfig().MARKETING_SITE_BASE_URL}>
16
+ <Image className="company-logo" alt={getSiteConfig().siteName} src={useAppConfig().LOGO_WHITE_URL} />
17
+ </Hyperlink>
18
+ <div className="ml-5 pb-4 pt-4">
19
+ <h1 className="display-2 banner__heading">
20
+ <span className="text-light-500">
21
+ {formatMessage(messages['your.career.turning.point'])}{' '}
22
+ </span>
23
+ <span className="text-warning-300 d-inline-block">
24
+ {formatMessage(messages['is.here'])}
25
+ </span>
26
+ </h1>
27
+ </div>
28
+ </div>
29
+ );
30
+ };
31
+
32
+ export default MediumLayout;