diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 466779485..0c7928003 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -426,6 +426,8 @@
"recoveryPasswordErrorMessageIncorrect": "Some of the words in your Recovery Password are incorrect. Please check and try again.",
"recoveryPasswordErrorMessageShort": "The Recovery Password you entered is not long enough. Please check and try again.",
"recoveryPasswordHidePermanently": "Hide Recovery Password Permanently",
+ "recoveryPasswordHidePermanentlyDescription1": "Without your recovery password, you cannot load your account on new devices.
We strongly recommend you save your recovery password in a safe and secure place before continuing.",
+ "recoveryPasswordHidePermanentlyDescription2": "Are you sure you want to permanently hide your recovery password on this device? This cannot be undone.",
"recoveryPasswordHideRecoveryPasswordDescription": "Permanently hide your recover password on this device.",
"recoveryPasswordWarningSendDescription": "This is your recovery password. If you send it to someone they'll have full access to your account.",
"recoveryPhraseSavePromptMain": "Your recovery password is the master key to your Account ID — you can use it to restore your Account ID if you lose access to your device. Store your recovery password in a safe place, and don't give it to anyone.",
@@ -585,6 +587,7 @@
"windowMenuClose": "Close Window",
"windowMenuMinimize": "Minimize",
"windowMenuZoom": "Zoom",
+ "yes": "Yes",
"yesterday": "Yesterday",
"you": "You",
"youChangedTheTimer": "You have set messages to disappear $time$ after they have been $mode$",
diff --git a/ts/components/dialog/HideRecoveryPasswordDialog.tsx b/ts/components/dialog/HideRecoveryPasswordDialog.tsx
new file mode 100644
index 000000000..77b93d16c
--- /dev/null
+++ b/ts/components/dialog/HideRecoveryPasswordDialog.tsx
@@ -0,0 +1,109 @@
+import { isEmpty } from 'lodash';
+import { useDispatch } from 'react-redux';
+import styled from 'styled-components';
+import { SettingsKey } from '../../data/settings-key';
+import { updateHideRecoveryPasswordModel } from '../../state/ducks/modalDialog';
+import { showSettingsSection } from '../../state/ducks/section';
+import { SessionWrapperModal } from '../SessionWrapperModal';
+import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
+import { SessionHtmlRenderer } from '../basic/SessionHTMLRenderer';
+import { SpacerMD } from '../basic/Text';
+import { ModalConfirmButtonContainer } from '../buttons/ModalConfirmButtonContainer';
+
+const StyledDescriptionContainer = styled.div`
+ width: 280px;
+ line-height: 120%;
+`;
+
+export type HideRecoveryPasswordDialogProps = {
+ state: 'firstWarning' | 'secondWarning';
+};
+
+export function HideRecoveryPasswordDialog(props: HideRecoveryPasswordDialogProps) {
+ const { state } = props;
+
+ const dispatch = useDispatch();
+
+ const onClose = () => {
+ dispatch(updateHideRecoveryPasswordModel(null));
+ };
+
+ const onConfirmation = async () => {
+ await window.setSettingValue(SettingsKey.hideRecoveryPassword, true);
+ onClose();
+ dispatch(showSettingsSection('privacy'));
+ };
+
+ if (isEmpty(state)) {
+ return null;
+ }
+
+ const leftButtonProps =
+ state === 'firstWarning'
+ ? {
+ text: window.i18n('continue'),
+ buttonColor: SessionButtonColor.Danger,
+ onClick: () => {
+ dispatch(updateHideRecoveryPasswordModel({ state: 'secondWarning' }));
+ },
+ dataTestId: 'session-confirm-ok-button',
+ }
+ : {
+ text: window.i18n('cancel'),
+ onClick: onClose,
+ dataTestId: 'session-confirm-cancel-button',
+ };
+
+ const rightButtonProps =
+ state === 'firstWarning'
+ ? {
+ text: window.i18n('cancel'),
+ onClick: onClose,
+ dataTestId: 'session-confirm-cancel-button',
+ }
+ : {
+ text: window.i18n('yes'),
+ buttonColor: SessionButtonColor.Danger,
+ onClick: () => {
+ void onConfirmation();
+ },
+ dataTestId: 'session-confirm-ok-button',
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx
index 8d61f51fa..4293d4305 100644
--- a/ts/components/dialog/ModalContainer.tsx
+++ b/ts/components/dialog/ModalContainer.tsx
@@ -8,6 +8,7 @@ import {
getEditProfileDialog,
getEditProfilePictureModalState,
getEnterPasswordModalState,
+ getHideRecoveryPasswordModalState,
getInviteContactModal,
getOnionPathDialog,
getReactClearAllDialog,
@@ -24,6 +25,7 @@ import { DeleteAccountModal } from './DeleteAccountModal';
import { EditProfileDialog } from './EditProfileDialog';
import { EditProfilePictureModal } from './EditProfilePictureModal';
import { EnterPasswordModal } from './EnterPasswordModal';
+import { HideRecoveryPasswordDialog } from './HideRecoveryPasswordDialog';
import { InviteContactsDialog } from './InviteContactsDialog';
import { AddModeratorsDialog } from './ModeratorsAddDialog';
import { RemoveModeratorsDialog } from './ModeratorsRemoveDialog';
@@ -57,6 +59,7 @@ export const ModalContainer = () => {
const reactListModalState = useSelector(getReactListDialog);
const reactClearAllModalState = useSelector(getReactClearAllDialog);
const editProfilePictureModalState = useSelector(getEditProfilePictureModalState);
+ const hideRecoveryPasswordModalState = useSelector(getHideRecoveryPasswordModalState);
return (
<>
@@ -82,6 +85,9 @@ export const ModalContainer = () => {
{editProfilePictureModalState && (
)}
+ {hideRecoveryPasswordModalState && (
+
+ )}
>
);
};
diff --git a/ts/components/leftpane/LeftPaneSectionHeader.tsx b/ts/components/leftpane/LeftPaneSectionHeader.tsx
index fd58f7d71..3cdf18de0 100644
--- a/ts/components/leftpane/LeftPaneSectionHeader.tsx
+++ b/ts/components/leftpane/LeftPaneSectionHeader.tsx
@@ -4,6 +4,7 @@ import { recoveryPhraseModal } from '../../state/ducks/modalDialog';
import { SectionType, setLeftOverlayMode } from '../../state/ducks/section';
import { disableRecoveryPhrasePrompt } from '../../state/ducks/userConfig';
import { getFocusedSection, getLeftOverlayMode } from '../../state/selectors/section';
+import { useHideRecoveryPasswordEnabled } from '../../state/selectors/settings';
import { getShowRecoveryPhrasePrompt } from '../../state/selectors/userConfig';
import { isSignWithRecoveryPhrase } from '../../util/storage';
import { Flex } from '../basic/Flex';
@@ -75,6 +76,7 @@ const StyledLeftPaneBanner = styled.div`
export const LeftPaneBanner = () => {
const section = useSelector(getFocusedSection);
const isSignInWithRecoveryPhrase = isSignWithRecoveryPhrase();
+ const hideRecoveryPassword = useHideRecoveryPasswordEnabled();
const dispatch = useDispatch();
@@ -83,7 +85,7 @@ export const LeftPaneBanner = () => {
dispatch(recoveryPhraseModal({}));
};
- if (section !== SectionType.Message || isSignInWithRecoveryPhrase) {
+ if (section !== SectionType.Message || isSignInWithRecoveryPhrase || hideRecoveryPassword) {
return null;
}
diff --git a/ts/components/leftpane/LeftPaneSettingSection.tsx b/ts/components/leftpane/LeftPaneSettingSection.tsx
index 672fc303f..285806080 100644
--- a/ts/components/leftpane/LeftPaneSettingSection.tsx
+++ b/ts/components/leftpane/LeftPaneSettingSection.tsx
@@ -10,6 +10,7 @@ import {
showSettingsSection,
} from '../../state/ducks/section';
import { getFocusedSettingsSection } from '../../state/selectors/section';
+import { useHideRecoveryPasswordEnabled } from '../../state/selectors/settings';
import type { SessionSettingCategory } from '../../types/ReduxTypes';
import { Flex } from '../basic/Flex';
import { SessionIcon, SessionIconSize, SessionIconType } from '../icon';
@@ -164,7 +165,12 @@ const LeftPaneSettingsCategoryRow = (props: { item: Categories }) => {
};
const LeftPaneSettingsCategories = () => {
- const categories = getCategories();
+ let categories = getCategories();
+ const hideRecoveryPassword = useHideRecoveryPasswordEnabled();
+
+ if (hideRecoveryPassword) {
+ categories = categories.filter(category => category.id !== 'recoveryPassword');
+ }
return (
<>
diff --git a/ts/components/settings/section/CategoryRecoveryPassword.tsx b/ts/components/settings/section/CategoryRecoveryPassword.tsx
index 454a28bce..5f6eba6b9 100644
--- a/ts/components/settings/section/CategoryRecoveryPassword.tsx
+++ b/ts/components/settings/section/CategoryRecoveryPassword.tsx
@@ -6,7 +6,9 @@ import styled from 'styled-components';
import { usePasswordModal } from '../../../hooks/usePasswordModal';
import { mnDecode } from '../../../session/crypto/mnemonic';
import { ToastUtils } from '../../../session/utils';
+import { updateHideRecoveryPasswordModel } from '../../../state/ducks/modalDialog';
import { showSettingsSection } from '../../../state/ducks/section';
+import { useHideRecoveryPasswordEnabled } from '../../../state/selectors/settings';
import { getTheme } from '../../../state/selectors/theme';
import { THEME_GLOBALS, getThemeValue } from '../../../themes/globals';
import { getCurrentRecoveryPhrase } from '../../../util/storage';
@@ -49,6 +51,8 @@ export const SettingsCategoryRecoveryPassword = () => {
const [hexEncodedSeed, setHexEncodedSeed] = useState('');
const [isQRVisible, setIsQRVisible] = useState(false);
+ const hideRecoveryPassword = useHideRecoveryPasswordEnabled();
+
const dispatch = useDispatch();
const { hasPassword, passwordValid } = usePasswordModal({
@@ -79,7 +83,7 @@ export const SettingsCategoryRecoveryPassword = () => {
}
});
- if ((hasPassword && !passwordValid) || loadingSeed) {
+ if ((hasPassword && !passwordValid) || loadingSeed || hideRecoveryPassword) {
return null;
}
@@ -166,16 +170,18 @@ export const SettingsCategoryRecoveryPassword = () => {
{isQRVisible ? 'View as Password' : 'View QR'}
- {
- // TODO
- }}
- buttonText={window.i18n('hide')}
- buttonColor={SessionButtonColor.Danger}
- dataTestId={'hide-recovery-password-button'}
- />
+ {!hideRecoveryPassword ? (
+ {
+ dispatch(updateHideRecoveryPasswordModel({ state: 'firstWarning' }));
+ }}
+ buttonText={window.i18n('hide')}
+ buttonColor={SessionButtonColor.Danger}
+ dataTestId={'hide-recovery-password-button'}
+ />
+ ) : null}
);
};
diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx
index d72cbe257..c4fbffa1c 100644
--- a/ts/state/ducks/modalDialog.tsx
+++ b/ts/state/ducks/modalDialog.tsx
@@ -1,5 +1,6 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { EnterPasswordModalProps } from '../../components/dialog/EnterPasswordModal';
+import { HideRecoveryPasswordDialogProps } from '../../components/dialog/HideRecoveryPasswordDialog';
import { SessionConfirmDialogProps } from '../../components/dialog/SessionConfirm';
import type { EditProfilePictureModalProps, PasswordAction } from '../../types/ReduxTypes';
@@ -38,6 +39,8 @@ export type ReactModalsState = {
export type EditProfilePictureModalState = EditProfilePictureModalProps | null;
+export type HideRecoveryPasswordModalState = HideRecoveryPasswordDialogProps | null;
+
export type ModalState = {
confirmModal: ConfirmModalState;
inviteContactModal: InviteContactModalState;
@@ -57,6 +60,7 @@ export type ModalState = {
reactListModalState: ReactModalsState;
reactClearAllModalState: ReactModalsState;
editProfilePictureModalState: EditProfilePictureModalState;
+ hideRecoveryPasswordModalState: HideRecoveryPasswordModalState;
};
export const initialModalState: ModalState = {
@@ -78,6 +82,7 @@ export const initialModalState: ModalState = {
reactListModalState: null,
reactClearAllModalState: null,
editProfilePictureModalState: null,
+ hideRecoveryPasswordModalState: null,
};
const ModalSlice = createSlice({
@@ -138,6 +143,9 @@ const ModalSlice = createSlice({
updateEditProfilePictureModel(state, action: PayloadAction) {
return { ...state, editProfilePictureModalState: action.payload };
},
+ updateHideRecoveryPasswordModel(state, action: PayloadAction) {
+ return { ...state, hideRecoveryPasswordModalState: action.payload };
+ },
},
});
@@ -161,5 +169,6 @@ export const {
updateReactListModal,
updateReactClearAllModal,
updateEditProfilePictureModel,
+ updateHideRecoveryPasswordModel,
} = actions;
export const modalReducer = reducer;
diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts
index d682048fb..c09681a12 100644
--- a/ts/state/selectors/modal.ts
+++ b/ts/state/selectors/modal.ts
@@ -9,6 +9,7 @@ import {
EditProfileModalState,
EditProfilePictureModalState,
EnterPasswordModalState,
+ HideRecoveryPasswordModalState,
InviteContactModalState,
ModalState,
OnionPathModalState,
@@ -115,3 +116,8 @@ export const getEditProfilePictureModalState = createSelector(
getModal,
(state: ModalState): EditProfilePictureModalState => state.editProfilePictureModalState
);
+
+export const getHideRecoveryPasswordModalState = createSelector(
+ getModal,
+ (state: ModalState): HideRecoveryPasswordModalState => state.hideRecoveryPasswordModalState
+);
diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts
index 40add78f4..e2ccdbc4e 100644
--- a/ts/types/LocalizerKeys.ts
+++ b/ts/types/LocalizerKeys.ts
@@ -426,6 +426,8 @@ export type LocalizerKeys =
| 'recoveryPasswordErrorMessageIncorrect'
| 'recoveryPasswordErrorMessageShort'
| 'recoveryPasswordHidePermanently'
+ | 'recoveryPasswordHidePermanentlyDescription1'
+ | 'recoveryPasswordHidePermanentlyDescription2'
| 'recoveryPasswordHideRecoveryPasswordDescription'
| 'recoveryPasswordWarningSendDescription'
| 'recoveryPhraseSavePromptMain'
@@ -585,6 +587,7 @@ export type LocalizerKeys =
| 'windowMenuClose'
| 'windowMenuMinimize'
| 'windowMenuZoom'
+ | 'yes'
| 'yesterday'
| 'you'
| 'youChangedTheTimer'