fix session password dialog

This commit is contained in:
Audric Ackermann 2021-06-24 10:50:35 +10:00
parent a876c47fd1
commit f1ee7589a0
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4
8 changed files with 135 additions and 126 deletions

View File

@ -73,6 +73,7 @@ import { editProfileModal, onionPathModal } from '../../state/ducks/modalDialog'
import { SessionSeedModal } from './SessionSeedModal';
import { AdminLeaveClosedGroupDialog } from '../conversation/AdminLeaveClosedGroupDialog';
import { uploadOurAvatar } from '../../interactions/conversationInteractions';
import { ModalContainer } from './ModalContainer';
// tslint:disable-next-line: no-import-side-effect no-submodule-imports
@ -279,42 +280,6 @@ const doAppStartUp = () => {
SwarmPolling.getInstance().start();
};
const ModalContainer = () => {
const confirmModalState = useSelector(getConfirmModal);
const inviteModalState = useSelector(getInviteContactModal);
const addModeratorsModalState = useSelector(getAddModeratorsModal);
const removeModeratorsModalState = useSelector(getRemoveModeratorsModal);
const updateGroupMembersModalState = useSelector(getUpdateGroupMembersModal);
const updateGroupNameModalState = useSelector(getUpdateGroupNameModal);
const userDetailsModalState = useSelector(getUserDetailsModal);
const changeNicknameModal = useSelector(getChangeNickNameDialog);
const editProfileModalState = useSelector(getEditProfileDialog);
const onionPathModalState = useSelector(getOnionPathDialog);
const recoveryPhraseModalState = useSelector(getRecoveryPhraseDialog);
const adminLeaveClosedGroupModalState = useSelector(getAdminLeaveClosedGroupDialog);
return (
<>
{confirmModalState && <SessionConfirm {...confirmModalState} />}
{inviteModalState && <InviteContactsDialog {...inviteModalState} />}
{addModeratorsModalState && <AddModeratorsDialog {...addModeratorsModalState} />}
{removeModeratorsModalState && <RemoveModeratorsDialog {...removeModeratorsModalState} />}
{updateGroupMembersModalState && (
<UpdateGroupMembersDialog {...updateGroupMembersModalState} />
)}
{updateGroupNameModalState && <UpdateGroupNameDialog {...updateGroupNameModalState} />}
{userDetailsModalState && <UserDetailsDialog {...userDetailsModalState} />}
{changeNicknameModal && <SessionNicknameDialog {...changeNicknameModal} />}
{editProfileModalState && <EditProfileDialog {...editProfileModalState} />}
{onionPathModalState && <OnionPathModal {...onionPathModalState} />}
{recoveryPhraseModalState && <SessionSeedModal {...recoveryPhraseModalState} />}
{adminLeaveClosedGroupModalState && (
<AdminLeaveClosedGroupDialog {...adminLeaveClosedGroupModalState} />
)}
</>
);
};
/**
* ActionsPanel is the far left banner (not the left pane).
* The panel with buttons to switch between the message/contact/settings/theme views

View File

@ -0,0 +1,68 @@
import React from 'react';
import { useSelector } from 'react-redux';
import {
getAddModeratorsModal,
getAdminLeaveClosedGroupDialog,
getChangeNickNameDialog,
getConfirmModal,
getEditProfileDialog,
getInviteContactModal,
getOnionPathDialog,
getRecoveryPhraseDialog,
getRemoveModeratorsModal,
getSessionPasswordDialog,
getUpdateGroupMembersModal,
getUpdateGroupNameModal,
getUserDetailsModal,
} from '../../state/selectors/modal';
import { AdminLeaveClosedGroupDialog } from '../conversation/AdminLeaveClosedGroupDialog';
import { InviteContactsDialog } from '../conversation/InviteContactsDialog';
import { AddModeratorsDialog } from '../conversation/ModeratorsAddDialog';
import { RemoveModeratorsDialog } from '../conversation/ModeratorsRemoveDialog';
import { UpdateGroupMembersDialog } from '../conversation/UpdateGroupMembersDialog';
import { UpdateGroupNameDialog } from '../conversation/UpdateGroupNameDialog';
import { EditProfileDialog } from '../EditProfileDialog';
import { OnionPathModal } from '../OnionStatusDialog';
import { UserDetailsDialog } from '../UserDetailsDialog';
import { SessionConfirm } from './SessionConfirm';
import { SessionNicknameDialog } from './SessionNicknameDialog';
import { SessionPasswordModal } from './SessionPasswordModal';
import { SessionSeedModal } from './SessionSeedModal';
export const ModalContainer = () => {
const confirmModalState = useSelector(getConfirmModal);
const inviteModalState = useSelector(getInviteContactModal);
const addModeratorsModalState = useSelector(getAddModeratorsModal);
const removeModeratorsModalState = useSelector(getRemoveModeratorsModal);
const updateGroupMembersModalState = useSelector(getUpdateGroupMembersModal);
const updateGroupNameModalState = useSelector(getUpdateGroupNameModal);
const userDetailsModalState = useSelector(getUserDetailsModal);
const changeNicknameModal = useSelector(getChangeNickNameDialog);
const editProfileModalState = useSelector(getEditProfileDialog);
const onionPathModalState = useSelector(getOnionPathDialog);
const recoveryPhraseModalState = useSelector(getRecoveryPhraseDialog);
const adminLeaveClosedGroupModalState = useSelector(getAdminLeaveClosedGroupDialog);
const sessionPasswordModalState = useSelector(getSessionPasswordDialog);
return (
<>
{confirmModalState && <SessionConfirm {...confirmModalState} />}
{inviteModalState && <InviteContactsDialog {...inviteModalState} />}
{addModeratorsModalState && <AddModeratorsDialog {...addModeratorsModalState} />}
{removeModeratorsModalState && <RemoveModeratorsDialog {...removeModeratorsModalState} />}
{updateGroupMembersModalState && (
<UpdateGroupMembersDialog {...updateGroupMembersModalState} />
)}
{updateGroupNameModalState && <UpdateGroupNameDialog {...updateGroupNameModalState} />}
{userDetailsModalState && <UserDetailsDialog {...userDetailsModalState} />}
{changeNicknameModal && <SessionNicknameDialog {...changeNicknameModal} />}
{editProfileModalState && <EditProfileDialog {...editProfileModalState} />}
{onionPathModalState && <OnionPathModal {...onionPathModalState} />}
{recoveryPhraseModalState && <SessionSeedModal {...recoveryPhraseModalState} />}
{adminLeaveClosedGroupModalState && (
<AdminLeaveClosedGroupDialog {...adminLeaveClosedGroupModalState} />
)}
{sessionPasswordModalState && <SessionPasswordModal {...sessionPasswordModalState} />}
</>
);
};

View File

@ -1,25 +1,19 @@
import React from 'react';
import { SessionModal } from './SessionModal';
import { SessionButton, SessionButtonColor } from './SessionButton';
import { missingCaseError, PasswordUtil } from '../../util/';
import { ToastUtils } from '../../session/utils';
import { SessionIconType } from './icon';
import { DefaultTheme, withTheme } from 'styled-components';
import { getPasswordHash } from '../../data/data';
import { SessionWrapperModal } from './SessionWrapperModal';
import { SpacerLG, SpacerSM } from '../basic/Text';
export enum PasswordAction {
Set = 'set',
Change = 'change',
Remove = 'remove',
}
import autoBind from 'auto-bind';
import { sessionPassword } from '../../state/ducks/modalDialog';
export type PasswordAction = 'set' | 'change' | 'remove';
interface Props {
action: PasswordAction;
onOk: any;
onClose: any;
theme: DefaultTheme;
passwordAction: PasswordAction;
onOk: () => void;
}
interface State {
@ -29,7 +23,7 @@ interface State {
currentPasswordRetypeEntered: string | null;
}
class SessionPasswordModalInner extends React.Component<Props, State> {
export class SessionPasswordModal extends React.Component<Props, State> {
private passportInput: HTMLInputElement | null = null;
constructor(props: any) {
@ -42,14 +36,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
currentPasswordRetypeEntered: null,
};
this.showError = this.showError.bind(this);
this.setPassword = this.setPassword.bind(this);
this.closeDialog = this.closeDialog.bind(this);
this.onPasswordInput = this.onPasswordInput.bind(this);
this.onPasswordConfirmInput = this.onPasswordConfirmInput.bind(this);
this.onPasswordRetypeInput = this.onPasswordRetypeInput.bind(this);
autoBind(this);
}
public componentDidMount() {
@ -60,9 +47,9 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
}
public render() {
const { action, onOk } = this.props;
const { passwordAction } = this.props;
const placeholders =
action === PasswordAction.Change
passwordAction === 'change'
? [
window.i18n('typeInOldPassword'),
window.i18n('enterPassword'),
@ -71,10 +58,13 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
: [window.i18n('enterPassword'), window.i18n('confirmPassword')];
const confirmButtonColor =
action === PasswordAction.Remove ? SessionButtonColor.Danger : SessionButtonColor.Primary;
passwordAction === 'remove' ? SessionButtonColor.Danger : SessionButtonColor.Primary;
return (
<SessionWrapperModal title={window.i18n(`${action}Password`)} onClose={this.closeDialog}>
<SessionWrapperModal
title={window.i18n(`${passwordAction}Password`)}
onClose={this.closeDialog}
>
<SpacerSM />
<div className="session-modal__input-group">
@ -87,7 +77,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
placeholder={placeholders[0]}
onKeyUp={this.onPasswordInput}
/>
{action !== PasswordAction.Remove && (
{passwordAction !== 'remove' && (
<input
type="password"
id="password-modal-input-confirm"
@ -95,7 +85,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
onKeyUp={this.onPasswordConfirmInput}
/>
)}
{action === PasswordAction.Change && (
{passwordAction === 'change' && (
<input
type="password"
id="password-modal-input-reconfirm"
@ -183,7 +173,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
SessionIconType.Lock
);
this.props.onOk(this.props.action);
this.props.onOk();
this.closeDialog();
}
@ -222,7 +212,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
SessionIconType.Lock
);
this.props.onOk(this.props.action);
this.props.onOk();
this.closeDialog();
}
@ -243,31 +233,30 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
window.i18n('removePasswordToastDescription')
);
this.props.onOk(this.props.action);
this.props.onOk();
this.closeDialog();
}
// tslint:disable-next-line: cyclomatic-complexity
private async setPassword() {
const { action } = this.props;
const { passwordAction } = this.props;
const {
currentPasswordEntered,
currentPasswordConfirmEntered,
currentPasswordRetypeEntered,
} = this.state;
const { Set, Remove, Change } = PasswordAction;
// Trim leading / trailing whitespace for UX
const firstPasswordEntered = (currentPasswordEntered || '').trim();
const secondPasswordEntered = (currentPasswordConfirmEntered || '').trim();
const thirdPasswordEntered = (currentPasswordRetypeEntered || '').trim();
switch (action) {
case Set: {
switch (passwordAction) {
case 'set': {
await this.handleActionSet(firstPasswordEntered, secondPasswordEntered);
return;
}
case Change: {
case 'change': {
await this.handleActionChange(
firstPasswordEntered,
secondPasswordEntered,
@ -275,19 +264,17 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
);
return;
}
case Remove: {
case 'remove': {
await this.handleActionRemove(firstPasswordEntered);
return;
}
default:
throw missingCaseError(action);
throw missingCaseError(passwordAction);
}
}
private closeDialog() {
if (this.props.onClose) {
this.props.onClose();
}
window.inboxStore?.dispatch(sessionPassword(null));
}
private async onPasswordInput(event: any) {
@ -317,5 +304,3 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
this.setState({ currentPasswordRetypeEntered });
}
}
export const SessionPasswordModal = withTheme(SessionPasswordModalInner);

View File

@ -33,15 +33,9 @@ import { SessionMemberListItem } from '../SessionMemberListItem';
import autoBind from 'auto-bind';
import { SectionType } from '../ActionsPanel';
import { SessionSettingCategory } from '../settings/SessionSettings';
import {
defaultMentionsInputReducer,
updateMentionsMembers,
} from '../../../state/ducks/mentionsInput';
import { getMentionsInput } from '../../../state/selectors/mentionsInput';
import { useDispatch } from 'react-redux';
import { updateConfirmModal } from '../../../state/ducks/modalDialog';
import { SessionButtonColor } from '../SessionButton';
import { any } from 'underscore';
import { SessionConfirmDialogProps } from '../SessionConfirm';
export interface ReplyingToMessageProps {
@ -93,7 +87,6 @@ interface Props {
showLeftPaneSection: (section: SectionType) => void;
showSettingsSection: (category: SessionSettingCategory) => void;
theme: DefaultTheme;
updateConfirmModal: (props: SessionConfirmDialogProps) => any;
}
interface State {
@ -247,15 +240,17 @@ export class SessionCompositionBox extends React.Component<Props, State> {
private showLinkSharingConfirmationModalDialog(e: any) {
const pastedText = e.clipboardData.getData('text');
if (this.isURL(pastedText)) {
this.props.updateConfirmModal({
shouldShowConfirm: () => !window.getSettingValue('link-preview-setting'),
title: window.i18n('linkPreviewsTitle'),
message: window.i18n('linkPreviewsConfirmMessage'),
okTheme: SessionButtonColor.Danger,
onClickOk: () => {
window.setSettingValue('link-preview-setting', true);
},
});
window.inboxStore?.dispatch(
updateConfirmModal({
shouldShowConfirm: () => !window.getSettingValue('link-preview-setting'),
title: window.i18n('linkPreviewsTitle'),
message: window.i18n('linkPreviewsConfirmMessage'),
okTheme: SessionButtonColor.Danger,
onClickOk: () => {
window.setSettingValue('link-preview-setting', true);
},
})
);
}
}

View File

@ -304,7 +304,6 @@ export class SessionConversation extends React.Component<Props, State> {
removeAttachment={this.removeAttachment}
onChoseAttachments={this.onChoseAttachments}
theme={this.props.theme}
updateConfirmModal={actions.updateConfirmModal}
/>
</div>

View File

@ -13,10 +13,11 @@ import { connect } from 'react-redux';
import { getPasswordHash } from '../../../../ts/data/data';
import { SpacerLG, SpacerXS } from '../../basic/Text';
import { shell } from 'electron';
import { PasswordAction, SessionPasswordModal } from '../SessionPasswordModal';
import { SessionConfirmDialogProps } from '../SessionConfirm';
import { mapDispatchToProps } from '../../../state/actions';
import { unblockConvoById } from '../../../interactions/conversationInteractions';
import { sessionPassword } from '../../../state/ducks/modalDialog';
import { PasswordAction } from '../SessionPasswordModal';
export enum SessionSettingCategory {
Appearance = 'appearance',
@ -47,7 +48,6 @@ interface State {
pwdLockError: string | null;
mediaSetting: boolean | null;
shouldLockSettings: boolean | null;
modal: JSX.Element | null;
}
interface ConfirmationDialogParams extends SessionConfirmDialogProps {
@ -80,7 +80,6 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
pwdLockError: null,
mediaSetting: null,
shouldLockSettings: true,
modal: null,
};
this.settingsViewRef = React.createRef();
@ -174,12 +173,8 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
<h3>{window.i18n('password')}</h3>
<input type="password" id="password-lock-input" defaultValue="" placeholder="Password" />
<SpacerXS />
{this.state.pwdLockError && (
<>
<div className="session-label warning">{this.state.pwdLockError}</div>
<SpacerLG />
</>
<div className="session-label warning">{this.state.pwdLockError}</div>
)}
<SessionButton
@ -234,8 +229,6 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
categoryTitle={window.i18n(`${category}SettingsTitle`)}
/>
{this.state.modal ? this.state.modal : null}
<div className="session-settings-view">
{shouldRenderPasswordLock ? (
this.renderPasswordLock()
@ -512,7 +505,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
buttonColor: SessionButtonColor.Primary,
},
onClick: () => {
this.displayPasswordModal(PasswordAction.Set);
this.displayPasswordModal('set');
},
confirmationDialogParams: undefined,
},
@ -530,7 +523,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
buttonColor: SessionButtonColor.Primary,
},
onClick: () => {
this.displayPasswordModal(PasswordAction.Change);
this.displayPasswordModal('change');
},
confirmationDialogParams: undefined,
},
@ -548,7 +541,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
buttonColor: SessionButtonColor.Danger,
},
onClick: () => {
this.displayPasswordModal(PasswordAction.Remove);
this.displayPasswordModal('remove');
},
confirmationDialogParams: undefined,
},
@ -556,25 +549,14 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
}
private displayPasswordModal(passwordAction: PasswordAction) {
this.setState({
...this.state,
modal: (
<SessionPasswordModal
onClose={() => {
this.clearModal();
}}
onOk={this.onPasswordUpdated}
action={passwordAction}
/>
),
});
}
private clearModal(): void {
this.setState({
...this.state,
modal: null,
});
window.inboxStore?.dispatch(
sessionPassword({
passwordAction,
onOk: () => {
this.onPasswordUpdated(passwordAction);
},
})
);
}
private getBlockedUserSettings(): Array<LocalSettingType> {

View File

@ -1,5 +1,6 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { SessionConfirmDialogProps } from '../../components/session/SessionConfirm';
import { PasswordAction } from '../../components/session/SessionPasswordModal';
export type ConfirmModalState = SessionConfirmDialogProps | null;
export type InviteContactModalState = { conversationId: string } | null;
@ -13,6 +14,8 @@ export type EditProfileModalState = {} | null;
export type OnionPathModalState = EditProfileModalState;
export type RecoveryPhraseModalState = EditProfileModalState;
export type SessionPasswordModalState = { passwordAction: PasswordAction; onOk: () => void } | null;
export type UserDetailsModalState = {
conversationId: string;
authorAvatarPath?: string;
@ -32,6 +35,7 @@ export type ModalState = {
onionPathModal: OnionPathModalState;
recoveryPhraseModal: RecoveryPhraseModalState;
adminLeaveClosedGroup: AdminLeaveClosedGroupModalState;
sessionPasswordModal: SessionPasswordModalState;
};
export const initialModalState: ModalState = {
@ -47,6 +51,7 @@ export const initialModalState: ModalState = {
onionPathModal: null,
recoveryPhraseModal: null,
adminLeaveClosedGroup: null,
sessionPasswordModal: null,
};
const ModalSlice = createSlice({
@ -89,6 +94,9 @@ const ModalSlice = createSlice({
adminLeaveClosedGroup(state, action: PayloadAction<AdminLeaveClosedGroupModalState | null>) {
return { ...state, adminLeaveClosedGroup: action.payload };
},
sessionPassword(state, action: PayloadAction<SessionPasswordModalState>) {
return { ...state, sessionPasswordModal: action.payload };
},
},
});
@ -106,5 +114,6 @@ export const {
onionPathModal,
recoveryPhraseModal,
adminLeaveClosedGroup,
sessionPassword,
} = actions;
export const modalReducer = reducer;

View File

@ -12,6 +12,7 @@ import {
OnionPathModalState,
RecoveryPhraseModalState,
RemoveModeratorsModalState,
SessionPasswordModalState,
UpdateGroupMembersModalState,
UpdateGroupNameModalState,
UserDetailsModalState,
@ -80,3 +81,8 @@ export const getAdminLeaveClosedGroupDialog = createSelector(
getModal,
(state: ModalState): AdminLeaveClosedGroupModalState => state.adminLeaveClosedGroup
);
export const getSessionPasswordDialog = createSelector(
getModal,
(state: ModalState): SessionPasswordModalState => state.sessionPasswordModal
);