diff --git a/web/modals/account/user-settings-modal.css b/web/modals/account/user-settings-modal.css deleted file mode 100644 index eae24cd1e..000000000 --- a/web/modals/account/user-settings-modal.css +++ /dev/null @@ -1,143 +0,0 @@ -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.resized-modal-body { - min-height: 250px; -} -div.modal-body p { - padding: 1px 3px 4px 3px; - font-size: 14px; - text-align: center; -} -div.modal-body p.form-pre-footer { - padding-top: 5px; - font-size: 12px; - font-style: italic; -} -div.modal-body textarea { - margin: 3px; -} -div.modal-body textarea { - font-size: 14px; - padding: 1px; - width: 175px; -} -div.large-modal-container div.modal-body textarea { - width: 275px; -} -div.modal-body p.confirm-account-password { - margin-bottom: 4px; - color: var(--fg); -} -div.modal-body div.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; - font-style: italic; - padding-left: 6px; - align-self: center; -} -div.modal-body div.form-footer div.modal-form-error ol { - padding-left: 20px; -} -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.modal-body div.form-subtitle { - font-size: 12px; - padding-left: 4px; - font-style: italic; -} - -div.form-text { - display: flex; - align-items: baseline; -} -div.form-text > div.form-title { - vertical-align: initial; - flex-shrink: 0; -} -div.form-text > div.form-content { - margin-left: 3px; - margin-bottom: 3px; - word-break: break-word; -} - -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 { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - font-size: 14px; - padding: 1px 20px 3px 4px; - margin-top: 5px; -} - -.italic { - font-style: italic; - color: var(--fg); -} - -ul.tab-panel { - background-color: var(--modal-bg); - padding-left: 10px; - padding-top: 5px; -} -ul.tab-panel > li { - display: inline-block; - list-style-type: none; - font-size: 13px; - font-weight: 600; - cursor: pointer; - padding: 3px 10px 3px 10px; -} -ul.tab-panel > li > a { - color: #555555; -} -ul.tab-panel > li.delete-tab > a { - color: #ff0000 !important; -} - -div.user-settings-current-password { - padding-top: 4px; - margin-top: 5px; -} diff --git a/web/modals/account/user-settings-modal.react.js b/web/modals/account/user-settings-modal.react.js deleted file mode 100644 index 049011e9e..000000000 --- a/web/modals/account/user-settings-modal.react.js +++ /dev/null @@ -1,440 +0,0 @@ -// @flow - -import classNames from 'classnames'; -import invariant from 'invariant'; -import * as React from 'react'; - -import { - deleteAccountActionTypes, - deleteAccount, - changeUserPasswordActionTypes, - changeUserPassword, - logOut, - logOutActionTypes, -} from 'lib/actions/user-actions'; -import { preRequestUserStateSelector } from 'lib/selectors/account-selectors'; -import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors'; -import type { LogOutResult } from 'lib/types/account-types'; -import { type PreRequestUserState } from 'lib/types/session-types'; -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 { useSelector } from '../../redux/redux-utils'; -import Input from '../input.react'; -import { useModalContext } from '../modal-provider.react'; -import Modal from '../modal.react'; -import css from './user-settings-modal.css'; - -type TabType = 'general' | 'delete'; -type TabProps = { - +name: string, - +tabType: TabType, - +selected: boolean, - +onClick: (tabType: TabType) => void, -}; -class Tab extends React.PureComponent { - render() { - const { selected, name, tabType } = this.props; - const classNamesForTab = classNames({ - [css['current-tab']]: selected, - [css['delete-tab']]: selected && tabType === 'delete', - }); - return ( -
  • - {name} -
  • - ); - } - - onClick = () => { - return this.props.onClick(this.props.tabType); - }; -} - -type Props = { - +currentUserInfo: ?CurrentUserInfo, - +preRequestUserState: PreRequestUserState, - +inputDisabled: boolean, - +dispatchActionPromise: DispatchActionPromise, - +deleteAccount: ( - password: string, - preRequestUserState: PreRequestUserState, - ) => Promise, - +changeUserPassword: (passwordUpdate: PasswordUpdate) => Promise, - +logOut: (preRequestUserState: PreRequestUserState) => Promise, - +popModal: () => void, -}; -type State = { - +newPassword: string, - +confirmNewPassword: string, - +currentPassword: string, - +errorMessage: string, - +currentTabType: TabType, -}; - -class UserSettingsModal extends React.PureComponent { - newPasswordInput: ?HTMLInputElement; - currentPasswordInput: ?HTMLInputElement; - - constructor(props: Props) { - super(props); - this.state = { - newPassword: '', - confirmNewPassword: '', - currentPassword: '', - errorMessage: '', - currentTabType: 'general', - }; - } - - 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; - } - - onLogOut = (event: SyntheticEvent) => { - event.preventDefault(); - this.props.dispatchActionPromise(logOutActionTypes, this.logOut()); - }; - - logOut = async () => { - await this.props.logOut(this.props.preRequestUserState); - this.props.popModal(); - }; - - render() { - const { inputDisabled } = this.props; - let mainContent = null; - if (this.state.currentTabType === 'general') { - mainContent = ( -
    -
    -
    Username
    -
    {this.username}
    -
    -
    -
    New password
    -
    -
    - -
    -
    - -
    -
    -
    -
    - ); - } else if (this.state.currentTabType === 'delete') { - mainContent = ( -

    - Your account will be permanently deleted. There is no way to reverse - this. -

    - ); - } - - let buttons = null; - if (this.state.currentTabType === 'delete') { - buttons = ( - - ); - } else { - buttons = ( - <> - - - - ); - } - - let errorMsg; - if (this.state.errorMessage) { - errorMsg = ( -
    {this.state.errorMessage}
    - ); - } - - return ( - -
      - - -
    -
    -
    - {mainContent} -
    -

    - Please enter your current password to confirm your identity -

    -
    Current password
    -
    - -
    -
    -
    - {buttons} - {errorMsg} -
    -
    -
    -
    - ); - } - - newPasswordInputRef = (newPasswordInput: ?HTMLInputElement) => { - this.newPasswordInput = newPasswordInput; - }; - - currentPasswordInputRef = (currentPasswordInput: ?HTMLInputElement) => { - this.currentPasswordInput = currentPasswordInput; - }; - - setTab = (tabType: TabType) => { - this.setState({ currentTabType: tabType }); - }; - - 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', - currentTabType: 'general', - }, - () => { - 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", - currentTabType: 'general', - }, - () => { - 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.popModal(); - } 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', - currentTabType: 'general', - }, - () => { - invariant(this.newPasswordInput, 'newPasswordInput ref unset'); - this.newPasswordInput.focus(); - }, - ); - } - throw e; - } - } - - onDelete = (event: SyntheticEvent) => { - event.preventDefault(); - this.props.dispatchActionPromise( - deleteAccountActionTypes, - this.deleteAction(), - ); - }; - - async deleteAction() { - try { - const response = await this.props.deleteAccount( - this.state.currentPassword, - this.props.preRequestUserState, - ); - this.props.popModal(); - return response; - } catch (e) { - const errorMessage = - e.message === 'invalid_credentials' - ? 'wrong password' - : 'unknown error'; - this.setState( - { - currentPassword: '', - errorMessage: errorMessage, - }, - () => { - invariant( - this.currentPasswordInput, - 'currentPasswordInput ref unset', - ); - this.currentPasswordInput.focus(); - }, - ); - throw e; - } - } -} - -const deleteAccountLoadingStatusSelector = createLoadingStatusSelector( - deleteAccountActionTypes, -); -const changeUserPasswordLoadingStatusSelector = createLoadingStatusSelector( - changeUserPasswordActionTypes, -); -const ConnectedUserSettingsModal: React.ComponentType<{}> = React.memo<{}>( - function ConnectedUserSettingsModal(): React.Node { - const currentUserInfo = useSelector(state => state.currentUserInfo); - const preRequestUserState = useSelector(preRequestUserStateSelector); - const inputDisabled = useSelector( - state => - deleteAccountLoadingStatusSelector(state) === 'loading' || - changeUserPasswordLoadingStatusSelector(state) === 'loading', - ); - const callDeleteAccount = useServerCall(deleteAccount); - const callChangeUserPassword = useServerCall(changeUserPassword); - const dispatchActionPromise = useDispatchActionPromise(); - const boundLogOut = useServerCall(logOut); - - const modalContext = useModalContext(); - - return ( - - ); - }, -); - -export default ConnectedUserSettingsModal;