diff --git a/package-lock.json b/package-lock.json index d8e4e95..0062fb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1009,9 +1009,9 @@ "integrity": "sha512-APBpZvdQrC1MJWMzk33V7FR2RhBRtnH2QPLqZzS+qia7PixwgWNlnX7UfHjhx+YWkM53GdsZKs40EBkSwADuMA==" }, "@edx/edx-bootstrap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@edx/edx-bootstrap/-/edx-bootstrap-2.0.1.tgz", - "integrity": "sha512-tq9ScRJBkUYw+0ypTshd+9+9Hnow00FkS6Rvh0RfK4xZ+rh8wNAUIVkG3TMclaW5qxvXSIE7Qo7YO7i7JrqV6A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@edx/edx-bootstrap/-/edx-bootstrap-2.1.0.tgz", + "integrity": "sha512-9/CkIP1IsldKvOAS/T2OYeBnyuNWwX+u5GVR1kxw1YUCQbFw0W2M/Nz0HbIhG82H4O64uQqfdxnd1QpRJn07LA==", "requires": { "bootstrap": "^4.3.1" } diff --git a/package.json b/package.json index 286ad28..e1948a3 100755 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@cospired/i18n-iso-languages": "^2.0.2", - "@edx/edx-bootstrap": "^2.0.1", + "@edx/edx-bootstrap": "^2.1.0", "@edx/frontend-analytics": "^1.0.0", "@edx/frontend-auth": "^5.2.0", "@edx/frontend-component-footer": "^2.0.3", diff --git a/src/account-settings/AccountSettingsPage.jsx b/src/account-settings/AccountSettingsPage.jsx index f0b5cc6..fd0ed70 100644 --- a/src/account-settings/AccountSettingsPage.jsx +++ b/src/account-settings/AccountSettingsPage.jsx @@ -68,7 +68,9 @@ class AccountSettingsPage extends React.Component {
-

{this.props.intl.formatMessage(messages['account.settings.section.account.information'])}

+ + +

{this.props.intl.formatMessage(messages['account.settings.section.account.information'])}

{this.props.intl.formatMessage(messages['account.settings.section.account.information.description'])}

@@ -84,6 +87,7 @@ class AccountSettingsPage extends React.Component { type="text" value={this.props.formValues.name} label={this.props.intl.formatMessage(messages['account.settings.field.full.name'])} + helpText={this.props.intl.formatMessage(messages['account.settings.field.full.name.help.text'])} {...editableFieldProps} /> + - - + + +

{this.props.intl.formatMessage(messages['account.settings.section.profile.information'])}

+ - -

{this.props.intl.formatMessage(messages['account.settings.section.social.media'])}

+ +

{this.props.intl.formatMessage(messages['account.settings.section.social.media'])}

{this.props.intl.formatMessage(messages['account.settings.section.social.media.description'])}

+ + + +

{this.props.intl.formatMessage(messages['account.settings.section.site.preferences'])}

+ + + + +

{this.props.intl.formatMessage(messages['account.settings.section.linked.accounts'])}

+

{this.props.intl.formatMessage(messages['account.settings.section.linked.accounts.description'])}

+ +
diff --git a/src/account-settings/AccountSettingsPage.messages.jsx b/src/account-settings/AccountSettingsPage.messages.jsx index e756e67..e951bc2 100644 --- a/src/account-settings/AccountSettingsPage.messages.jsx +++ b/src/account-settings/AccountSettingsPage.messages.jsx @@ -26,16 +26,46 @@ const messages = defineMessages({ defaultMessage: 'These settings include basic information about your account.', description: 'The basic account information section heading description.', }, + 'account.settings.section.profile.information': { + id: 'account.settings.section.profile.information', + defaultMessage: 'Profile Information', + description: 'The profile information section heading.', + }, + 'account.settings.section.site.preferences': { + id: 'account.settings.section.site.preferences', + defaultMessage: 'Site Preferences', + description: 'The site preferences section heading.', + }, + 'account.settings.section.linked.accounts': { + id: 'account.settings.section.linked.accounts', + defaultMessage: 'Linked Accounts', + description: 'The linked accounts section heading.', + }, + 'account.settings.section.linked.accounts.description': { + id: 'account.settings.section.linked.accounts.description', + defaultMessage: 'You can link your identity accounts to simplify signing in to edX.', + description: 'The linked accounts section heading description.', + }, 'account.settings.field.username': { id: 'account.settings.field.username', defaultMessage: 'Username', description: 'Label for account settings username field.', }, + 'account.settings.field.username.help.text': { + id: 'account.settings.field.username.help.text', + defaultMessage: 'The name that identifies you on edX. You cannot change your username.', + description: 'Help text for the account settings username field.', + }, 'account.settings.field.full.name': { id: 'account.settings.field.full.name', defaultMessage: 'Full name', description: 'Label for account settings name field.', }, + 'account.settings.field.full.name.help.text': { + id: 'account.settings.field.full.name.help.text', + defaultMessage: 'The name that is used for ID verification and that appears on your certificates.', + description: 'Help text for the account settings name field.', + }, 'account.settings.field.email': { id: 'account.settings.field.email', defaultMessage: 'Email address (Sign in)', @@ -46,6 +76,11 @@ const messages = defineMessages({ defaultMessage: 'We’ve sent a confirmation message to {value}. Click the link in the message to update your email address.', description: 'Confirmation message for saving the account settings email field.', }, + 'account.settings.field.email.help.text': { + id: 'account.settings.field.email.help.text', + defaultMessage: 'You receive messages from edX and course teams at this address.', + description: 'Help text for the account settings email field.', + }, 'account.settings.email.field.confirmation.header': { id: 'account.settings.email.field.confirmation.header', defaultMessage: 'One more step!', diff --git a/src/account-settings/actions.js b/src/account-settings/actions.js index dabd517..4fa8c82 100644 --- a/src/account-settings/actions.js +++ b/src/account-settings/actions.js @@ -89,8 +89,9 @@ export const saveSettingsFailure = ({ fieldErrors, message }) => ({ // RESET PASSWORD ACTIONS -export const resetPassword = () => ({ +export const resetPassword = email => ({ type: RESET_PASSWORD.BASE, + payload: { email }, }); export const resetPasswordBegin = () => ({ diff --git a/src/account-settings/components/PasswordReset.jsx b/src/account-settings/components/PasswordReset.jsx index 75fb511..5606a00 100644 --- a/src/account-settings/components/PasswordReset.jsx +++ b/src/account-settings/components/PasswordReset.jsx @@ -54,7 +54,17 @@ function PasswordReset({ email, intl, ...props }) { { + // Swallow clicks if the state is pending. + // We do this instead of disabling the button to prevent + // it from losing focus (disabled elements cannot have focus). + // Disabling it would causes upstream issues in focus management. + // Swallowing the onSubmit event on the form would be better, but + // we would have to add that logic for every field given our + // current structure of the application. + if (props.resetPasswordState === 'pending') e.preventDefault(); + props.resetPassword(email); + }} disabledStates={[]} labels={{ default: intl.formatMessage(messages['account.settings.editable.field.password.reset.button']), diff --git a/src/account-settings/components/ThirdPartyAuth.jsx b/src/account-settings/components/ThirdPartyAuth.jsx index 303b392..42ea7b6 100644 --- a/src/account-settings/components/ThirdPartyAuth.jsx +++ b/src/account-settings/components/ThirdPartyAuth.jsx @@ -72,7 +72,7 @@ class ThirdPartyAuth extends React.Component { ); } - renderProviders() { + render() { if (this.props.providers === undefined) return null; if (this.props.providers.length === 0) { @@ -81,28 +81,6 @@ class ThirdPartyAuth extends React.Component { return this.props.providers.map(this.renderProvider, this); } - - render() { - return ( -
-

- -

-

- -

- {this.renderProviders()} -
- ); - } } diff --git a/src/account-settings/sagas.js b/src/account-settings/sagas.js index 812e2a0..ee35bdf 100644 --- a/src/account-settings/sagas.js +++ b/src/account-settings/sagas.js @@ -73,10 +73,10 @@ export function* handleSaveSettings(action) { } } -export function* handleResetPassword() { +export function* handleResetPassword(action) { try { yield put(resetPasswordBegin()); - const response = yield call(ApiService.postResetPassword); + const response = yield call(ApiService.postResetPassword, action.payload.email); yield put(resetPasswordSuccess(response)); } catch (e) { logAPIErrorResponse(e); diff --git a/src/account-settings/service.js b/src/account-settings/service.js index 283cb95..5a437e3 100644 --- a/src/account-settings/service.js +++ b/src/account-settings/service.js @@ -173,9 +173,9 @@ export async function patchSettings(username, commitValues) { return combinedResults; } -export async function postResetPassword() { +export async function postResetPassword(email) { const { data } = await apiClient - .post(config.PASSWORD_RESET_URL) + .post(config.PASSWORD_RESET_URL, { email }) .catch(handleRequestError); return data;