diff --git a/web/settings/password-change-modal.css b/web/settings/password-change-modal.css index 64009b444..014237efe 100644 --- a/web/settings/password-change-modal.css +++ b/web/settings/password-change-modal.css @@ -1,92 +1,41 @@ -div.modal-body { - padding: 6px 6px; - width: 100%; - box-sizing: border-box; - background-color: var(--modal-bg); - border-bottom-left-radius: 15px; - border-bottom-right-radius: 15px; - flex: 1; - display: flex; - flex-direction: column; -} -div.modal-body p { - padding: 1px 3px 4px 3px; - font-size: 14px; - text-align: center; -} -div.modal-body p.confirm-account-password { - color: #777777; - margin-bottom: 4px; +.modal-body { + padding: 24px 40px 32px; color: var(--fg); } -div.modal-body div.form-footer { +.form-footer { display: flex; flex-direction: row-reverse; justify-content: space-between; padding-top: 8px; } -div.modal-body div.form-footer div.modal-form-error { - font-size: 12px; - color: red; +.modal-form-error { + font-size: var(--xs-font-12); + color: var(--error); font-style: italic; padding-left: 6px; align-self: center; } -div.modal-body div.form-title { - display: inline-block; - text-align: right; - padding-right: 5px; - padding-top: 5px; - font-size: 14px; - font-weight: 600; - vertical-align: top; - width: 110px; - color: var(--fg); -} -div.large-modal-container div.modal-body div.form-title { - width: 140px; -} -div.modal-body div.form-content { - display: inline-block; - font-family: var(--font-stack); - color: var(--fg); -} -div.modal-body div.form-content input { - margin-bottom: 4px; -} - -div.form-text { +.form-content { display: flex; - align-items: baseline; + flex-direction: column; } -div.form-text > div.form-title { - vertical-align: initial; - flex-shrink: 0; +.form-content input { + margin-bottom: 16px; } -div.form-text > div.form-content { - margin-left: 3px; - margin-bottom: 3px; - word-break: break-word; +.form-content input[type='password'] { + width: auto; } -div.form-text > div.form-float-title { - float: left; - text-align: right; - padding-right: 5px; - font-size: 14px; - font-weight: 600; - width: 110px; -} -div.form-text > div.form-float-content { +.username-container { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - font-size: 14px; - padding: 1px 20px 3px 4px; - margin-top: 5px; + color: var(--fg); + margin-bottom: 16px; } - -div.user-settings-current-password { - padding-top: 4px; - margin-top: 5px; +.username-label { + color: var(--account-settings-label); +} +.username { + color: var(--fg); } diff --git a/web/settings/password-change-modal.js b/web/settings/password-change-modal.js index 1ccca9033..57cac0fac 100644 --- a/web/settings/password-change-modal.js +++ b/web/settings/password-change-modal.js @@ -1,278 +1,265 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { changeUserPasswordActionTypes, changeUserPassword, } from 'lib/actions/user-actions'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors'; import { type PasswordUpdate, type CurrentUserInfo, } from 'lib/types/user-types'; import { type DispatchActionPromise, useDispatchActionPromise, useServerCall, } from 'lib/utils/action-utils'; import Button from '../components/button.react'; import Input from '../modals/input.react'; import { useModalContext } from '../modals/modal-provider.react'; import Modal from '../modals/modal.react'; import { useSelector } from '../redux/redux-utils'; import css from './password-change-modal.css'; type Props = { +currentUserInfo: ?CurrentUserInfo, +inputDisabled: boolean, +dispatchActionPromise: DispatchActionPromise, +changeUserPassword: (passwordUpdate: PasswordUpdate) => Promise, +clearModal: () => void, }; type State = { +newPassword: string, +confirmNewPassword: string, +currentPassword: string, +errorMessage: string, }; class PasswordChangeModal extends React.PureComponent { newPasswordInput: ?HTMLInputElement; currentPasswordInput: ?HTMLInputElement; constructor(props: Props) { super(props); this.state = { newPassword: '', confirmNewPassword: '', currentPassword: '', errorMessage: '', }; } componentDidMount() { invariant(this.newPasswordInput, 'newPasswordInput ref unset'); this.newPasswordInput.focus(); } get username() { return this.props.currentUserInfo && !this.props.currentUserInfo.anonymous ? this.props.currentUserInfo.username : undefined; } render() { let errorMsg; if (this.state.errorMessage) { errorMsg = (
{this.state.errorMessage}
); } const { inputDisabled } = this.props; return (
-
-
-
Username
-
{this.username}
-
-
-
New password
-
-
- -
-
- -
-
-
-
-

- Please enter your current password to confirm your identity -

-
Current password
-
- -
-
-
- - {errorMsg} -
+
+

+ {'Logged in as '} + {this.username} +

+ + +
+
+ +
+
+ + {errorMsg}
); } newPasswordInputRef = (newPasswordInput: ?HTMLInputElement) => { this.newPasswordInput = newPasswordInput; }; currentPasswordInputRef = (currentPasswordInput: ?HTMLInputElement) => { this.currentPasswordInput = currentPasswordInput; }; onChangeNewPassword = (event: SyntheticEvent) => { const target = event.target; invariant(target instanceof HTMLInputElement, 'target not input'); this.setState({ newPassword: target.value }); }; onChangeConfirmNewPassword = (event: SyntheticEvent) => { const target = event.target; invariant(target instanceof HTMLInputElement, 'target not input'); this.setState({ confirmNewPassword: target.value }); }; onChangeCurrentPassword = (event: SyntheticEvent) => { const target = event.target; invariant(target instanceof HTMLInputElement, 'target not input'); this.setState({ currentPassword: target.value }); }; onSubmit = (event: SyntheticEvent) => { event.preventDefault(); if (this.state.newPassword === '') { this.setState( { newPassword: '', confirmNewPassword: '', errorMessage: 'empty password', }, () => { invariant(this.newPasswordInput, 'newPasswordInput ref unset'); this.newPasswordInput.focus(); }, ); } else if (this.state.newPassword !== this.state.confirmNewPassword) { this.setState( { newPassword: '', confirmNewPassword: '', errorMessage: "passwords don't match", }, () => { invariant(this.newPasswordInput, 'newPasswordInput ref unset'); this.newPasswordInput.focus(); }, ); return; } this.props.dispatchActionPromise( changeUserPasswordActionTypes, this.changeUserSettingsAction(), ); }; async changeUserSettingsAction() { try { await this.props.changeUserPassword({ updatedFields: { password: this.state.newPassword, }, currentPassword: this.state.currentPassword, }); this.props.clearModal(); } catch (e) { if (e.message === 'invalid_credentials') { this.setState( { currentPassword: '', errorMessage: 'wrong current password', }, () => { invariant( this.currentPasswordInput, 'currentPasswordInput ref unset', ); this.currentPasswordInput.focus(); }, ); } else { this.setState( { newPassword: '', confirmNewPassword: '', currentPassword: '', errorMessage: 'unknown error', }, () => { invariant(this.newPasswordInput, 'newPasswordInput ref unset'); this.newPasswordInput.focus(); }, ); } throw e; } } } const changeUserPasswordLoadingStatusSelector = createLoadingStatusSelector( changeUserPasswordActionTypes, ); const ConnectedPasswordChangeModal: React.ComponentType<{}> = React.memo<{}>( function ConnectedPasswordChangeModal(): React.Node { const currentUserInfo = useSelector(state => state.currentUserInfo); const inputDisabled = useSelector( state => changeUserPasswordLoadingStatusSelector(state) === 'loading', ); const callChangeUserPassword = useServerCall(changeUserPassword); const dispatchActionPromise = useDispatchActionPromise(); const modalContext = useModalContext(); return ( ); }, ); export default ConnectedPasswordChangeModal;