diff --git a/web/settings/account-settings.css b/web/settings/account-settings.css
index 47adf83f4..28daa7bbf 100644
--- a/web/settings/account-settings.css
+++ b/web/settings/account-settings.css
@@ -1,81 +1,67 @@
.container {
flex: 1;
background-color: var(--frame-background-primary-default);
overflow: auto;
}
.contentContainer {
padding: 40px;
width: 456px;
overflow-y: auto;
}
.header {
color: var(--text-background-primary-default);
font-weight: var(--semi-bold);
line-height: var(--line-height-display);
padding-bottom: 55px;
}
.content {
margin-top: 32px;
}
.content ul {
list-style-type: none;
}
.content li {
color: var(--text-background-tertiary-default);
padding: 24px 16px 16px;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.content li:not(:last-child) {
border-bottom: 1px solid var(--separator-background-primary-default);
}
.logoutContainer {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.logoutLabel {
color: var(--text-background-tertiary-default);
}
.username {
color: var(--text-background-primary-default);
}
.buttonText {
color: var(--link-background-primary-default);
line-height: var(--line-height-text);
}
-.passwordContainer {
- display: flex;
-}
-
-.password {
- align-items: center;
- padding-right: 16px;
-}
-
-.editPasswordLink {
- color: var(--text-background-tertiary-default);
- cursor: pointer;
-}
-
.preferencesContainer {
padding-top: 24px;
}
.preferencesHeader {
color: var(--text-background-primary-default);
font-weight: var(--semi-bold);
line-height: var(--line-height-display);
}
diff --git a/web/settings/account-settings.react.js b/web/settings/account-settings.react.js
index 28abe8225..c9539f9b5 100644
--- a/web/settings/account-settings.react.js
+++ b/web/settings/account-settings.react.js
@@ -1,365 +1,338 @@
// @flow
import invariant from 'invariant';
import * as React from 'react';
import uuid from 'uuid';
import {
useLogOut,
logOutActionTypes,
useSecondaryDeviceLogOut,
} from 'lib/actions/user-actions.js';
import { useModalContext } from 'lib/components/modal-provider.react.js';
import SWMansionIcon from 'lib/components/swmansion-icon.react.js';
import { useStringForUser } from 'lib/hooks/ens-cache.js';
-import { accountHasPassword } from 'lib/shared/account-utils.js';
import {
dmOperationSpecificationTypes,
type OutboundDMOperationSpecification,
} from 'lib/shared/dm-ops/dm-op-utils.js';
import { useProcessAndSendDMOperation } from 'lib/shared/dm-ops/process-dm-ops.js';
import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js';
import type { DMCreateThreadOperation } from 'lib/types/dm-ops.js';
import { thickThreadTypes } from 'lib/types/thread-types-enum.js';
import {
createOlmSessionsWithOwnDevices,
getContentSigningKey,
} from 'lib/utils/crypto-utils.js';
import { isDev } from 'lib/utils/dev-utils.js';
import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
import css from './account-settings.css';
import AppearanceChangeModal from './appearance-change-modal.react.js';
import BackupTestRestoreModal from './backup-test-restore-modal.react.js';
-import PasswordChangeModal from './password-change-modal.js';
import BlockListModal from './relationship/block-list-modal.react.js';
import FriendListModal from './relationship/friend-list-modal.react.js';
import TunnelbrokerMessagesScreen from './tunnelbroker-message-list.react.js';
import TunnelbrokerTestScreen from './tunnelbroker-test.react.js';
import EditUserAvatar from '../avatars/edit-user-avatar.react.js';
import Button from '../components/button.react.js';
import VersionUnsupportedModal from '../modals/version-unsupported-modal.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { useStaffCanSee } from '../utils/staff-utils.js';
function AccountSettings(): React.Node {
const { pushModal, popModal } = useModalContext();
const logOutOptions = React.useMemo(() => {
const showVersionUnsupportedModal = () => {
pushModal();
};
return { handleUseNewFlowResponse: showVersionUnsupportedModal };
}, [pushModal]);
const sendLogoutRequest = useLogOut(logOutOptions);
const sendSecondaryDeviceLogoutRequest = useSecondaryDeviceLogOut();
const dispatchActionPromise = useDispatchActionPromise();
const logOutUser = React.useCallback(
() => dispatchActionPromise(logOutActionTypes, sendLogoutRequest()),
[dispatchActionPromise, sendLogoutRequest],
);
const logOutSecondaryDevice = React.useCallback(
() =>
dispatchActionPromise(
logOutActionTypes,
sendSecondaryDeviceLogoutRequest(),
),
[dispatchActionPromise, sendSecondaryDeviceLogoutRequest],
);
const identityContext = React.useContext(IdentityClientContext);
const userID = useSelector(state => state.currentUserInfo?.id);
const [deviceID, setDeviceID] = React.useState();
React.useEffect(() => {
void (async () => {
const contentSigningKey = await getContentSigningKey();
setDeviceID(contentSigningKey);
})();
}, []);
- const showPasswordChangeModal = React.useCallback(
- () => pushModal(),
- [pushModal],
- );
-
const openFriendList = React.useCallback(
() => pushModal(),
[pushModal],
);
const openBlockList = React.useCallback(
() => pushModal(),
[pushModal],
);
- const isAccountWithPassword = useSelector(state =>
- accountHasPassword(state.currentUserInfo),
- );
-
const currentUserInfo = useSelector(state => state.currentUserInfo);
const stringForUser = useStringForUser(currentUserInfo);
const staffCanSee = useStaffCanSee();
const { sendMessageToDevice, socketState, addListener, removeListener } =
useTunnelbroker();
const openTunnelbrokerModal = React.useCallback(
() =>
pushModal(
,
),
[popModal, pushModal, sendMessageToDevice],
);
const openTunnelbrokerMessagesModal = React.useCallback(
() =>
pushModal(
,
),
[addListener, popModal, pushModal, removeListener],
);
const onCreateOlmSessions = React.useCallback(async () => {
if (!identityContext) {
return;
}
const authMetadata = await identityContext.getAuthMetadata();
try {
await createOlmSessionsWithOwnDevices(
authMetadata,
identityContext.identityClient,
sendMessageToDevice,
);
} catch (e) {
console.log(`Error creating olm sessions with own devices: ${e.message}`);
}
}, [identityContext, sendMessageToDevice]);
const openBackupTestRestoreModal = React.useCallback(
() => pushModal(),
[popModal, pushModal],
);
const processAndSendDMOperation = useProcessAndSendDMOperation();
const onCreateDMThread = React.useCallback(async () => {
invariant(userID, 'userID should be set');
const op: DMCreateThreadOperation = {
type: 'create_thread',
threadID: uuid.v4(),
creatorID: userID,
time: Date.now(),
threadType: thickThreadTypes.LOCAL,
memberIDs: [],
roleID: uuid.v4(),
newMessageID: uuid.v4(),
};
const specification: OutboundDMOperationSpecification = {
type: dmOperationSpecificationTypes.OUTBOUND,
op,
recipients: {
type: 'self_devices',
},
};
await processAndSendDMOperation(specification);
}, [processAndSendDMOperation, userID]);
const showAppearanceModal = React.useCallback(
() => pushModal(),
[pushModal],
);
if (!currentUserInfo || currentUserInfo.anonymous) {
return null;
}
- let changePasswordSection;
- if (isAccountWithPassword) {
- changePasswordSection = (
-
- Password
-
- ******
-
-
-
-
-
- );
- }
-
let experimentalLogOutSection;
if (isDev) {
experimentalLogOutSection = (
Log out secondary device
);
}
let preferences;
if (staffCanSee) {
preferences = (
);
}
let tunnelbroker;
if (staffCanSee) {
tunnelbroker = (
Tunnelbroker menu
-
Connected
{socketState.connected.toString()}
-
Send message to device
-
Trace received messages
-
Create session with own devices
);
}
let backup;
if (staffCanSee) {
backup = (
Backup menu
-
Test backup restore
);
}
let deviceData;
if (staffCanSee) {
deviceData = (
);
}
let dms;
if (staffCanSee) {
dms = (
DMs menu
-
Create a new local DM thread
);
}
return (
My Account
{preferences}
{tunnelbroker}
{backup}
{deviceData}
{dms}
);
}
export default AccountSettings;
diff --git a/web/settings/password-change-modal.css b/web/settings/password-change-modal.css
deleted file mode 100644
index bcdd0fb55..000000000
--- a/web/settings/password-change-modal.css
+++ /dev/null
@@ -1,38 +0,0 @@
-.modalFormError {
- font-size: var(--xs-font-12);
- color: var(--text-background-danger-default);
- font-style: italic;
- height: 24px;
- display: flex;
- justify-content: center;
- align-items: flex-end;
-}
-
-.errorPlaceholder {
- height: 24px;
-}
-
-.formContent {
- display: flex;
- flex-direction: column;
-}
-.formContent input:not(:last-child) {
- margin-bottom: 16px;
-}
-
-.formContent input[type='password'] {
- width: auto;
-}
-
-.usernameContainer {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- margin-bottom: 16px;
-}
-.usernameLabel {
- color: var(--text-background-tertiary-default);
-}
-.username {
- color: var(--text-background-primary-default);
-}
diff --git a/web/settings/password-change-modal.js b/web/settings/password-change-modal.js
deleted file mode 100644
index 59a041416..000000000
--- a/web/settings/password-change-modal.js
+++ /dev/null
@@ -1,296 +0,0 @@
-// @flow
-
-import invariant from 'invariant';
-import * as React from 'react';
-
-import {
- changeKeyserverUserPasswordActionTypes,
- changeKeyserverUserPassword,
- useChangeIdentityUserPassword,
- changeIdentityUserPasswordActionTypes,
-} from 'lib/actions/user-actions.js';
-import { useModalContext } from 'lib/components/modal-provider.react.js';
-import { useStringForUser } from 'lib/hooks/ens-cache.js';
-import { useLegacyAshoatKeyserverCall } from 'lib/keyserver-conn/legacy-keyserver-call.js';
-import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
-import { type PasswordUpdate } from 'lib/types/user-types.js';
-import { getMessageForException } from 'lib/utils/errors.js';
-import {
- useDispatchActionPromise,
- type DispatchActionPromise,
-} from 'lib/utils/redux-promise-utils.js';
-import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js';
-
-import css from './password-change-modal.css';
-import Button from '../components/button.react.js';
-import Input from '../modals/input.react.js';
-import Modal from '../modals/modal.react.js';
-import { useSelector } from '../redux/redux-utils.js';
-
-type Props = {
- +inputDisabled: boolean,
- +dispatchActionPromise: DispatchActionPromise,
- +changeKeyserverUserPassword: (
- passwordUpdate: PasswordUpdate,
- ) => Promise,
- +changeIdentityUserPassword: (
- oldPassword: string,
- newPassword: string,
- ) => Promise,
- +popModal: () => void,
- +stringForUser: ?string,
-};
-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();
- }
-
- render(): React.Node {
- const { inputDisabled } = this.props;
-
- let errorMsg = ;
- if (this.state.errorMessage) {
- errorMsg = (
- {this.state.errorMessage}
- );
- }
-
- const buttonIsDisabled =
- inputDisabled ||
- this.state.currentPassword.length === 0 ||
- this.state.newPassword.length === 0 ||
- this.state.confirmNewPassword.length === 0;
-
- const changePasswordButton = (
-
- );
-
- return (
-
-
-
- );
- }
-
- 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;
- }
-
- if (usingCommServicesAccessToken) {
- void this.props.dispatchActionPromise(
- changeIdentityUserPasswordActionTypes,
- this.changeUserSettingsAction(),
- );
- } else {
- void this.props.dispatchActionPromise(
- changeKeyserverUserPasswordActionTypes,
- this.changeUserSettingsAction(),
- );
- }
- };
-
- async changeUserSettingsAction(): Promise {
- try {
- if (usingCommServicesAccessToken) {
- await this.props.changeIdentityUserPassword(
- this.state.currentPassword,
- this.state.newPassword,
- );
- } else {
- await this.props.changeKeyserverUserPassword({
- updatedFields: {
- password: this.state.newPassword,
- },
- currentPassword: this.state.currentPassword,
- });
- }
- this.props.popModal();
- } catch (e) {
- const messageForException = getMessageForException(e);
- if (
- messageForException === 'invalid_credentials' ||
- messageForException === 'login_failed'
- ) {
- 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 = usingCommServicesAccessToken
- ? createLoadingStatusSelector(changeIdentityUserPasswordActionTypes)
- : createLoadingStatusSelector(changeKeyserverUserPasswordActionTypes);
-const ConnectedPasswordChangeModal: React.ComponentType<{}> = React.memo<{}>(
- function ConnectedPasswordChangeModal(): React.Node {
- const inputDisabled = useSelector(
- state => changeUserPasswordLoadingStatusSelector(state) === 'loading',
- );
- const callChangeKeyserverUserPassword = useLegacyAshoatKeyserverCall(
- changeKeyserverUserPassword,
- );
- const callChangeIdentityUserPassword = useChangeIdentityUserPassword();
- const dispatchActionPromise = useDispatchActionPromise();
-
- const modalContext = useModalContext();
-
- const currentUserInfo = useSelector(state => state.currentUserInfo);
- const stringForUser = useStringForUser(currentUserInfo);
-
- return (
-
- );
- },
-);
-
-export default ConnectedPasswordChangeModal;