@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
@@ -0,0 +1,98 @@
1
+ import { isFormValid } from '../utils';
2
+
3
+ describe('Payload validation', () => {
4
+ let formatMessage;
5
+ let configurableFormFields;
6
+ let fieldDescriptions;
7
+
8
+ beforeEach(() => {
9
+ formatMessage = jest.fn(msg => msg);
10
+ configurableFormFields = {
11
+ confirm_email: true,
12
+ };
13
+ fieldDescriptions = {};
14
+ });
15
+
16
+ test('validates name field correctly', () => {
17
+ const payload = { name: ' ' };
18
+ const errors = {};
19
+ const { isValid, fieldErrors } = isFormValid(
20
+ payload,
21
+ errors,
22
+ configurableFormFields,
23
+ fieldDescriptions,
24
+ formatMessage
25
+ );
26
+
27
+ expect(fieldErrors.name).toBeDefined();
28
+ expect(isValid).toBe(false);
29
+ });
30
+
31
+ test('validates email field correctly', () => {
32
+ const payload = { email: 'invalid-email' };
33
+ const errors = {};
34
+ const { isValid, fieldErrors } = isFormValid(
35
+ payload,
36
+ errors,
37
+ configurableFormFields,
38
+ fieldDescriptions,
39
+ formatMessage
40
+ );
41
+
42
+ expect(fieldErrors.email).toBeDefined();
43
+ expect(isValid).toBe(false);
44
+ });
45
+
46
+ test('validates username field correctly', () => {
47
+ const payload = { username: 'invalid username' };
48
+ const errors = {};
49
+ const { isValid, fieldErrors } = isFormValid(
50
+ payload,
51
+ errors,
52
+ configurableFormFields,
53
+ fieldDescriptions,
54
+ formatMessage
55
+ );
56
+
57
+ expect(fieldErrors.username).toBeDefined();
58
+ expect(isValid).toBe(false);
59
+ });
60
+
61
+ test('validates password field correctly', () => {
62
+ const payload = { password: 'short' };
63
+ const errors = {};
64
+ const { isValid, fieldErrors } = isFormValid(
65
+ payload,
66
+ errors,
67
+ configurableFormFields,
68
+ fieldDescriptions,
69
+ formatMessage
70
+ );
71
+
72
+ expect(fieldErrors.password).toBeDefined();
73
+ expect(isValid).toBe(false);
74
+ });
75
+
76
+ test('validates multiple fields correctly', () => {
77
+ const payload = {
78
+ name: 'InvalidName!',
79
+ email: 'invalid-email',
80
+ username: 'invalid username',
81
+ password: 'short',
82
+ };
83
+ const errors = {};
84
+ const { isValid, fieldErrors } = isFormValid(
85
+ payload,
86
+ errors,
87
+ configurableFormFields,
88
+ fieldDescriptions,
89
+ formatMessage
90
+ );
91
+
92
+ expect(fieldErrors.name).toBeDefined();
93
+ expect(fieldErrors.email).toBeDefined();
94
+ expect(fieldErrors.username).toBeDefined();
95
+ expect(fieldErrors.password).toBeDefined();
96
+ expect(isValid).toBe(false);
97
+ });
98
+ });
@@ -0,0 +1,153 @@
1
+ import { snakeCaseObject } from '@openedx/frontend-base';
2
+
3
+ import { LETTER_REGEX, NUMBER_REGEX } from '../../data/constants';
4
+ import messages from '../messages';
5
+ import validateEmail from '../RegistrationFields/EmailField/validator';
6
+ import validateName from '../RegistrationFields/NameField/validator';
7
+ import validateUsername from '../RegistrationFields/UsernameField/validator';
8
+
9
+ /**
10
+ * It validates the password field value
11
+ * @param value
12
+ * @param formatMessage
13
+ * @returns {string}
14
+ */
15
+ export const validatePasswordField = (value, formatMessage) => {
16
+ let fieldError = '';
17
+ if (!value || !LETTER_REGEX.test(value) || !NUMBER_REGEX.test(value) || value.length < 8) {
18
+ fieldError = formatMessage(messages['password.validation.message']);
19
+ }
20
+ return fieldError;
21
+ };
22
+
23
+ /**
24
+ * It accepts complete registration data as payload and checks if the form is valid.
25
+ * @param payload
26
+ * @param errors
27
+ * @param configurableFormFields
28
+ * @param fieldDescriptions
29
+ * @param formatMessage
30
+ * @returns {{fieldErrors, isValid: boolean}}
31
+ */
32
+ export const isFormValid = (
33
+ payload,
34
+ errors,
35
+ configurableFormFields,
36
+ fieldDescriptions,
37
+ formatMessage,
38
+ ) => {
39
+ const fieldErrors = { ...errors };
40
+ let isValid = true;
41
+ let emailSuggestion = { suggestion: '', type: '' };
42
+
43
+ Object.keys(payload).forEach(key => {
44
+ switch (key) {
45
+ case 'name':
46
+ if (!fieldErrors.name) {
47
+ fieldErrors.name = validateName(payload.name, formatMessage);
48
+ }
49
+ if (fieldErrors.name) {
50
+ isValid = false;
51
+ }
52
+ break;
53
+ case 'email': {
54
+ if (!fieldErrors.email) {
55
+ const {
56
+ fieldError, confirmEmailError, suggestion,
57
+ } = validateEmail(payload.email, configurableFormFields?.confirm_email, formatMessage);
58
+ if (fieldError) {
59
+ fieldErrors.email = fieldError;
60
+ isValid = false;
61
+ }
62
+ if (confirmEmailError) {
63
+ fieldErrors.confirm_email = confirmEmailError;
64
+ isValid = false;
65
+ }
66
+ emailSuggestion = suggestion;
67
+ }
68
+ if (fieldErrors.email) {
69
+ isValid = false;
70
+ }
71
+ break;
72
+ }
73
+ case 'username':
74
+ if (!fieldErrors.username) {
75
+ fieldErrors.username = validateUsername(payload.username, formatMessage);
76
+ }
77
+ if (fieldErrors.username) {
78
+ isValid = false;
79
+ }
80
+ break;
81
+ case 'password':
82
+ if (!fieldErrors.password) {
83
+ fieldErrors.password = validatePasswordField(payload.password, formatMessage);
84
+ }
85
+ if (fieldErrors.password) {
86
+ isValid = false;
87
+ }
88
+ break;
89
+ default:
90
+ break;
91
+ }
92
+ });
93
+
94
+ // Don't validate when country field is optional or hidden and not present on registration form
95
+ if (configurableFormFields?.country && !configurableFormFields.country?.displayValue) {
96
+ fieldErrors.country = formatMessage(messages['empty.country.field.error']);
97
+ isValid = false;
98
+ } else if (configurableFormFields?.country && !configurableFormFields.country?.countryCode) {
99
+ fieldErrors.country = formatMessage(messages['invalid.country.field.error']);
100
+ isValid = false;
101
+ }
102
+
103
+ Object.keys(fieldDescriptions).forEach(key => {
104
+ if (key === 'country' && !configurableFormFields?.country?.displayValue) {
105
+ fieldErrors[key] = formatMessage(messages['empty.country.field.error']);
106
+ } else if (!configurableFormFields[key]) {
107
+ fieldErrors[key] = fieldDescriptions[key].error_message;
108
+ }
109
+ if (fieldErrors[key]) {
110
+ isValid = false;
111
+ }
112
+ });
113
+
114
+ return { isValid, fieldErrors, emailSuggestion };
115
+ };
116
+
117
+ /**
118
+ * It prepares a payload for registration data that can be passed to registration API endpoint.
119
+ * @param initPayload
120
+ * @param configurableFormFields
121
+ * @param showMarketingEmailOptInCheckbox
122
+ * @param totalRegistrationTime
123
+ * @param queryParams
124
+ * @returns {*}
125
+ */
126
+ export const prepareRegistrationPayload = (
127
+ initPayload,
128
+ configurableFormFields,
129
+ showMarketingEmailOptInCheckbox,
130
+ totalRegistrationTime,
131
+ queryParams,
132
+ ) => {
133
+ let payload = { ...initPayload };
134
+ Object.keys(configurableFormFields).forEach((fieldName) => {
135
+ if (fieldName === 'country') {
136
+ payload[fieldName] = configurableFormFields[fieldName].countryCode;
137
+ } else {
138
+ payload[fieldName] = configurableFormFields[fieldName];
139
+ }
140
+ });
141
+
142
+ // Don't send the marketing email opt-in value if the flag is turned off
143
+ if (!showMarketingEmailOptInCheckbox) {
144
+ delete payload.marketingEmailsOptIn;
145
+ }
146
+
147
+ payload.totalRegistrationTime = totalRegistrationTime;
148
+ payload = snakeCaseObject(payload);
149
+
150
+ // add query params to the payload
151
+ payload = { ...payload, ...queryParams };
152
+ return payload;
153
+ };
@@ -0,0 +1,4 @@
1
+ export { default as RegistrationPage } from './RegistrationPage';
2
+ export { default as reducer } from './data/reducers';
3
+ export { default as saga } from './data/sagas';
4
+ export { storeName } from './data/reducers';
@@ -0,0 +1,206 @@
1
+ import { defineMessages } from '@openedx/frontend-base';
2
+
3
+ const messages = defineMessages({
4
+ 'register.page.title': {
5
+ id: 'register.page.title',
6
+ defaultMessage: 'Register | {siteName}',
7
+ description: 'register page title',
8
+ },
9
+ // Field labels
10
+ 'registration.fullname.label': {
11
+ id: 'registration.fullname.label',
12
+ defaultMessage: 'Full name',
13
+ description: 'Label that appears above fullname field',
14
+ },
15
+ 'registration.email.label': {
16
+ id: 'registration.email.label',
17
+ defaultMessage: 'Email',
18
+ description: 'Label that appears above email field on register page',
19
+ },
20
+ 'registration.username.label': {
21
+ id: 'registration.username.label',
22
+ defaultMessage: 'Public username',
23
+ description: 'Label that appears above username field',
24
+ },
25
+ 'registration.password.label': {
26
+ id: 'registration.password.label',
27
+ defaultMessage: 'Password',
28
+ description: 'Label that appears above password field',
29
+ },
30
+ 'registration.country.label': {
31
+ id: 'registration.country.label',
32
+ defaultMessage: 'Country/Region',
33
+ description: 'Placeholder for the country options dropdown.',
34
+ },
35
+ 'registration.opt.in.label': {
36
+ id: 'registration.opt.in.label',
37
+ defaultMessage: 'I agree that {siteName} may send me marketing messages.',
38
+ description: 'Text for opt in option on register page.',
39
+ },
40
+ // Help text
41
+ 'help.text.name': {
42
+ id: 'help.text.name',
43
+ defaultMessage: 'This name will be used by any certificates that you earn.',
44
+ description: 'Help text for fullname field on registration page',
45
+ },
46
+ 'help.text.username.1': {
47
+ id: 'help.text.username.1',
48
+ defaultMessage: 'The name that will identify you in your courses.',
49
+ description: 'Part of help text for username field on registration page',
50
+ },
51
+ 'help.text.username.2': {
52
+ id: 'help.text.username.2',
53
+ defaultMessage: 'This can not be changed later.',
54
+ description: 'Part of help text for username field on registration page',
55
+ },
56
+ 'help.text.email': {
57
+ id: 'help.text.email',
58
+ defaultMessage: 'For account activation and important updates',
59
+ description: 'Help text for email field on registration page',
60
+ },
61
+ // Form buttons
62
+ 'create.account.for.free.button': {
63
+ id: 'create.account.for.free.button',
64
+ defaultMessage: 'Create an account for free',
65
+ description: 'Label text for registration form submission button',
66
+ },
67
+ 'create.account.cta.button': {
68
+ id: 'create.account.cta.button',
69
+ defaultMessage: '{label}',
70
+ description: 'Label text for registration form submission button for those users who are landing through redirections',
71
+ },
72
+ // Institution login
73
+ 'register.institution.login.page.title': {
74
+ id: 'register.institution.login.page.title',
75
+ defaultMessage: 'Register with institution/campus credentials',
76
+ description: 'Heading of institution page',
77
+ },
78
+ // Validation messages
79
+ 'empty.name.field.error': {
80
+ id: 'empty.name.field.error',
81
+ defaultMessage: 'Enter your full name',
82
+ description: 'Error message for empty fullname field',
83
+ },
84
+ 'empty.email.field.error': {
85
+ id: 'empty.email.field.error',
86
+ defaultMessage: 'Enter your email',
87
+ description: 'Error message for empty email field',
88
+ },
89
+ 'empty.username.field.error': {
90
+ id: 'empty.username.field.error',
91
+ defaultMessage: 'Username must be between 2 and 30 characters',
92
+ description: 'Error message for empty username field',
93
+ },
94
+ 'empty.password.field.error': {
95
+ id: 'empty.password.field.error',
96
+ defaultMessage: 'Password criteria has not been met',
97
+ description: 'Error message for empty password field',
98
+ },
99
+ 'empty.country.field.error': {
100
+ id: 'empty.country.field.error',
101
+ defaultMessage: 'Select your country or region of residence',
102
+ description: 'Error message when no country/region is selected',
103
+ },
104
+ 'invalid.country.field.error': {
105
+ id: 'invalid.country.field.error',
106
+ defaultMessage: 'Country must match with an option available in the dropdown.',
107
+ description: 'Error message when country is invalid',
108
+ },
109
+ 'email.do.not.match': {
110
+ id: 'email.do.not.match',
111
+ defaultMessage: 'The email addresses do not match.',
112
+ description: 'Email not match to confirm email',
113
+ },
114
+ 'email.invalid.format.error': {
115
+ id: 'email.invalid.format.error',
116
+ defaultMessage: 'Enter a valid email address',
117
+ description: 'Validation error for invalid email address',
118
+ },
119
+ 'username.validation.message': {
120
+ id: 'username.validation.message',
121
+ defaultMessage: 'Username must be between 2 and 30 characters',
122
+ description: 'Error message for empty username field',
123
+ },
124
+ 'name.validation.message': {
125
+ id: 'name.validation.message',
126
+ defaultMessage: 'Enter a valid name',
127
+ description: 'Validation message that appears when fullname contain URL',
128
+ },
129
+ 'password.validation.message': {
130
+ id: 'password.validation.message',
131
+ defaultMessage: 'Password criteria has not been met',
132
+ description: 'Error message for empty or invalid password',
133
+ },
134
+ 'username.format.validation.message': {
135
+ id: 'username.format.validation.message',
136
+ defaultMessage: 'Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-). Usernames cannot contain spaces',
137
+ description: 'Validation message that appears when username format is invalid',
138
+ },
139
+ // Error messages
140
+ 'registration.request.failure.header': {
141
+ id: 'registration.request.failure.header',
142
+ defaultMessage: 'We couldn\'t create your account.',
143
+ description: 'error message when registration failure.',
144
+ },
145
+ 'registration.empty.form.submission.error': {
146
+ id: 'registration.empty.form.submission.error',
147
+ defaultMessage: 'Please check your responses and try again.',
148
+ description: 'Error message that appears on top of the form when empty form is submitted',
149
+ },
150
+ 'registration.request.server.error': {
151
+ id: 'registration.request.server.error',
152
+ defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.',
153
+ description: 'Error message for internal server error.',
154
+ },
155
+ 'registration.rate.limit.error': {
156
+ id: 'registration.rate.limit.error',
157
+ defaultMessage: 'Too many failed registration attempts. Try again later.',
158
+ description: 'Error message that appears when an anonymous user has made too many failed registration attempts',
159
+ },
160
+ 'registration.tpa.session.expired': {
161
+ id: 'registration.tpa.session.expired',
162
+ defaultMessage: 'Registration using {provider} has timed out.',
163
+ description: 'Error message that appears when a user has not registered in the required timeframe for the registration method they chose.',
164
+ },
165
+ 'registration.tpa.authentication.failure': {
166
+ id: 'registration.tpa.authentication.failure',
167
+ defaultMessage: 'We are sorry, you are not authorized to access {platform_name} via this channel. '
168
+ + 'Please contact your learning administrator or manager in order to access {platform_name}.'
169
+ + '{lineBreak}{lineBreak}Error Details:{lineBreak}{errorMessage}',
170
+ description: 'Error message third party authentication pipeline fails',
171
+ },
172
+ // Terms of Service and Honor Code
173
+ 'terms.of.service.and.honor.code': {
174
+ id: 'terms.of.service.and.honor.code',
175
+ defaultMessage: 'Terms of Service and Honor Code',
176
+ description: 'Text for the hyperlink that redirects user to terms of service and honor code',
177
+ },
178
+ 'privacy.policy': {
179
+ id: 'privacy.policy',
180
+ defaultMessage: 'Privacy Policy',
181
+ description: 'Text for the hyperlink that redirects user to privacy policy',
182
+ },
183
+ 'honor.code': {
184
+ id: 'honor.code',
185
+ defaultMessage: 'Honor Code',
186
+ description: 'Text for the hyperlink that redirects user to the honor code',
187
+ },
188
+ 'terms.of.service': {
189
+ id: 'terms.of.service',
190
+ defaultMessage: 'Terms of Service',
191
+ description: 'Text for the hyperlink that redirects user to the terms of service',
192
+ },
193
+ // miscellaneous strings
194
+ 'registration.username.suggestion.label': {
195
+ id: 'registration.username.suggestion.label',
196
+ defaultMessage: 'Suggested:',
197
+ description: 'Suggested usernames label text.',
198
+ },
199
+ 'did.you.mean.alert.text': {
200
+ id: 'did.you.mean.alert.text',
201
+ defaultMessage: 'Did you mean',
202
+ description: 'Did you mean alert suggestion',
203
+ },
204
+ });
205
+
206
+ export default messages;
@@ -0,0 +1,55 @@
1
+ import { useIntl } from '@openedx/frontend-base';
2
+ import { Alert } from '@openedx/paragon';
3
+ import { Error } from '@openedx/paragon/icons';
4
+ import PropTypes from 'prop-types';
5
+
6
+ import { FORM_SUBMISSION_ERROR, PASSWORD_RESET, PASSWORD_VALIDATION_ERROR } from './data/constants';
7
+ import messages from './messages';
8
+
9
+ const ResetPasswordFailure = (props) => {
10
+ const { formatMessage } = useIntl();
11
+ const { errorCode, errorMsg } = props;
12
+
13
+ let errorMessage = null;
14
+ let heading = formatMessage(messages['reset.password.failure.heading']);
15
+ switch (errorCode) {
16
+ case PASSWORD_RESET.FORBIDDEN_REQUEST:
17
+ heading = formatMessage(messages['reset.server.rate.limit.error']);
18
+ errorMessage = formatMessage(messages['rate.limit.error']);
19
+ break;
20
+ case PASSWORD_RESET.INTERNAL_SERVER_ERROR:
21
+ errorMessage = formatMessage(messages['internal.server.error']);
22
+ break;
23
+ case PASSWORD_VALIDATION_ERROR:
24
+ errorMessage = errorMsg;
25
+ break;
26
+ case FORM_SUBMISSION_ERROR:
27
+ errorMessage = formatMessage(messages['reset.password.form.submission.error']);
28
+ break;
29
+ default:
30
+ break;
31
+ }
32
+
33
+ if (errorMessage) {
34
+ return (
35
+ <Alert id="validation-errors" className="mb-5" variant="danger" icon={Error}>
36
+ <Alert.Heading>{heading}</Alert.Heading>
37
+ <p>{errorMessage}</p>
38
+ </Alert>
39
+ );
40
+ }
41
+
42
+ return null;
43
+ };
44
+
45
+ ResetPasswordFailure.defaultProps = {
46
+ errorCode: null,
47
+ errorMsg: null,
48
+ };
49
+
50
+ ResetPasswordFailure.propTypes = {
51
+ errorCode: PropTypes.string,
52
+ errorMsg: PropTypes.string,
53
+ };
54
+
55
+ export default ResetPasswordFailure;