diff --git a/src/components/views/settings/encryption/ResetIdentityBody.tsx b/src/components/views/settings/encryption/ResetIdentityBody.tsx new file mode 100644 index 0000000000..f2c339ca4d --- /dev/null +++ b/src/components/views/settings/encryption/ResetIdentityBody.tsx @@ -0,0 +1,124 @@ +/* + * Copyright 2024-2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import { Button, InlineSpinner, VisualList, VisualListItem } from "@vector-im/compound-web"; +import CheckIcon from "@vector-im/compound-design-tokens/assets/web/icons/check"; +import InfoIcon from "@vector-im/compound-design-tokens/assets/web/icons/info"; +import ErrorIcon from "@vector-im/compound-design-tokens/assets/web/icons/error-solid"; +import React, { type JSX, useState, type MouseEventHandler } from "react"; + +import { _t } from "../../../../languageHandler"; +import { EncryptionCard } from "./EncryptionCard"; +import { uiAuthCallback } from "../../../../CreateCrossSigning"; +import { EncryptionCardButtons } from "./EncryptionCardButtons"; +import { EncryptionCardEmphasisedContent } from "./EncryptionCardEmphasisedContent"; +import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext"; + +interface ResetIdentityBodyProps { + /** + * Called when the identity is reset. + */ + onFinish: MouseEventHandler; + /** + * Called when the cancel button is clicked. + */ + onCancelClick: () => void; + + /** + * The variant of the panel to show. We show more warnings in the 'compromised' variant (no use in showing a user + * this warning if they have to reset because they no longer have their key) + */ + variant: ResetIdentityBodyVariant; +} + +/** + * "compromised" is shown when the user chooses 'reset' explicitly in settings, usually because they believe their + * identity has been compromised. + * + * "sync_failed" is shown when the user tried to recover their identity but the process failed, probably because + * the required information is missing from recovery. + * + * "forgot" is shown when the user has just forgotten their passphrase. + */ +export type ResetIdentityBodyVariant = "compromised" | "forgot" | "sync_failed"; + +/** + * User interface component allowing the user to reset their cryptographic identity. + * + * Used by {@link ResetIdentityPanel}. + */ +export function ResetIdentityBody({ onCancelClick, onFinish, variant }: ResetIdentityBodyProps): JSX.Element { + const matrixClient = useMatrixClientContext(); + + // After the user clicks "Continue", we disable the button so it can't be + // clicked again, and warn the user not to close the window. + const [inProgress, setInProgress] = useState(false); + + return ( + + + + + {_t("settings|encryption|advanced|breadcrumb_first_description")} + + + {_t("settings|encryption|advanced|breadcrumb_second_description")} + + + {_t("settings|encryption|advanced|breadcrumb_third_description")} + + + {variant === "compromised" && {_t("settings|encryption|advanced|breadcrumb_warning")}} + + + + {inProgress ? ( + + + {_t("settings|encryption|advanced|do_not_close_warning")} + + + ) : ( + + )} + + + ); +} + +function titleForVariant(variant: ResetIdentityBodyVariant): string { + switch (variant) { + case "compromised": + return _t("settings|encryption|advanced|breadcrumb_title"); + case "sync_failed": + return _t("settings|encryption|advanced|breadcrumb_title_sync_failed"); + + default: + case "forgot": + return _t("settings|encryption|advanced|breadcrumb_title_forgot"); + } +} diff --git a/src/components/views/settings/encryption/ResetIdentityPanel.tsx b/src/components/views/settings/encryption/ResetIdentityPanel.tsx index f77b6d1138..dc733a1967 100644 --- a/src/components/views/settings/encryption/ResetIdentityPanel.tsx +++ b/src/components/views/settings/encryption/ResetIdentityPanel.tsx @@ -5,18 +5,11 @@ * Please see LICENSE files in the repository root for full details. */ -import { Breadcrumb, Button, InlineSpinner, VisualList, VisualListItem } from "@vector-im/compound-web"; -import CheckIcon from "@vector-im/compound-design-tokens/assets/web/icons/check"; -import InfoIcon from "@vector-im/compound-design-tokens/assets/web/icons/info"; -import ErrorIcon from "@vector-im/compound-design-tokens/assets/web/icons/error-solid"; -import React, { type JSX, useState, type MouseEventHandler } from "react"; +import { Breadcrumb } from "@vector-im/compound-web"; +import React, { type JSX, type MouseEventHandler } from "react"; import { _t } from "../../../../languageHandler"; -import { EncryptionCard } from "./EncryptionCard"; -import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext"; -import { uiAuthCallback } from "../../../../CreateCrossSigning"; -import { EncryptionCardButtons } from "./EncryptionCardButtons"; -import { EncryptionCardEmphasisedContent } from "./EncryptionCardEmphasisedContent"; +import { ResetIdentityBody, type ResetIdentityBodyVariant } from "./ResetIdentityBody"; interface ResetIdentityPanelProps { /** @@ -29,33 +22,17 @@ interface ResetIdentityPanelProps { onCancelClick: () => void; /** - * The variant of the panel to show. We show more warnings in the 'compromised' variant (no use in showing a user - * this warning if they have to reset because they no longer have their key) + * Which variant of this panel to show. */ - variant: ResetIdentityPanelVariant; + variant: ResetIdentityBodyVariant; } /** - * "compromised" is shown when the user chooses 'reset' explicitly in settings, usually because they believe their - * identity has been compromised. + * The Encryption Settings panel for resetting the identity of the current user. * - * "sync_failed" is shown when the user tried to recover their identity but the process failed, probably because - * the required information is missing from recovery. - * - * "forgot" is shown when the user has just forgotten their passphrase. - */ -export type ResetIdentityPanelVariant = "compromised" | "forgot" | "sync_failed"; - -/** - * The panel for resetting the identity of the current user. + * A thin wrapper around {@link ResetIdentityBody}, just adding breadcrumbs. */ export function ResetIdentityPanel({ onCancelClick, onFinish, variant }: ResetIdentityPanelProps): JSX.Element { - const matrixClient = useMatrixClientContext(); - - // After the user clicks "Continue", we disable the button so it can't be - // clicked again, and warn the user not to close the window. - const [inProgress, setInProgress] = useState(false); - return ( <> - - - - - {_t("settings|encryption|advanced|breadcrumb_first_description")} - - - {_t("settings|encryption|advanced|breadcrumb_second_description")} - - - {_t("settings|encryption|advanced|breadcrumb_third_description")} - - - {variant === "compromised" && {_t("settings|encryption|advanced|breadcrumb_warning")}} - - - - {inProgress ? ( - - - {_t("settings|encryption|advanced|do_not_close_warning")} - - - ) : ( - - )} - - + ); } - -function titleForVariant(variant: ResetIdentityPanelVariant): string { - switch (variant) { - case "compromised": - return _t("settings|encryption|advanced|breadcrumb_title"); - case "sync_failed": - return _t("settings|encryption|advanced|breadcrumb_title_sync_failed"); - - default: - case "forgot": - return _t("settings|encryption|advanced|breadcrumb_title_forgot"); - } -} diff --git a/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx b/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx index e2c9f443ca..7cd0c1d7b5 100644 --- a/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx @@ -20,7 +20,8 @@ import SetupEncryptionDialog from "../../../dialogs/security/SetupEncryptionDial import { SettingsSection } from "../../shared/SettingsSection"; import { SettingsSubheader } from "../../SettingsSubheader"; import { AdvancedPanel } from "../../encryption/AdvancedPanel"; -import { ResetIdentityPanel, type ResetIdentityPanelVariant } from "../../encryption/ResetIdentityPanel"; +import { ResetIdentityPanel } from "../../encryption/ResetIdentityPanel"; +import { type ResetIdentityBodyVariant } from "../../encryption/ResetIdentityBody"; import { RecoveryPanelOutOfSync } from "../../encryption/RecoveryPanelOutOfSync"; import { useTypedEventEmitter } from "../../../../../hooks/useEventEmitter"; import { KeyStoragePanel } from "../../encryption/KeyStoragePanel"; @@ -147,7 +148,7 @@ export function EncryptionUserSettingsTab({ initialState = "loading" }: Props): * Given what state we want the tab to be in, what variant of the * ResetIdentityPanel do we need? */ -function findResetVariant(state: State): ResetIdentityPanelVariant { +function findResetVariant(state: State): ResetIdentityBodyVariant { switch (state) { case "reset_identity_compromised": return "compromised";