diff --git a/src/components/views/settings/encryption/DeleteKeyStoragePanel.tsx b/src/components/views/settings/encryption/DeleteKeyStoragePanel.tsx new file mode 100644 index 0000000000..fa54862e41 --- /dev/null +++ b/src/components/views/settings/encryption/DeleteKeyStoragePanel.tsx @@ -0,0 +1,74 @@ +/* + * Copyright 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 { Breadcrumb, Button, VisualList, VisualListItem } from "@vector-im/compound-web"; +import CrossIcon from "@vector-im/compound-design-tokens/assets/web/icons/close"; +import ErrorIcon from "@vector-im/compound-design-tokens/assets/web/icons/error"; +import React, { useCallback, useState } from "react"; + +import { _t } from "../../../../languageHandler"; +import { EncryptionCard } from "./EncryptionCard"; +import { useKeyStoragePanelViewModel } from "../../../viewmodels/settings/encryption/KeyStoragePanelViewModel"; + +interface ResetIdentityPanelProps { + onFinish: () => void; +} + +/** + * Confirms that the user really wants to turn off and delete their key storage + */ +export function DeleteKeyStoragePanel({ onFinish }: ResetIdentityPanelProps): JSX.Element { + const { setEnabled } = useKeyStoragePanelViewModel(); + const [busy, setBusy] = useState(false); + + const onDeleteClick = useCallback(async () => { + setBusy(true); + try { + await setEnabled(false); + } finally { + setBusy(false); + } + onFinish(); + }, [setEnabled, onFinish]); + + return ( + <> + + +
+ {_t("settings|encryption|delete_key_storage|description")} + + + {_t("settings|encryption|delete_key_storage|list_first")} + + + {_t("settings|encryption|delete_key_storage|list_second")} + + +
+
+ + +
+
+ + ); +} diff --git a/src/components/views/settings/encryption/KeyStoragePanel.tsx b/src/components/views/settings/encryption/KeyStoragePanel.tsx index 448025f672..09c6ac0974 100644 --- a/src/components/views/settings/encryption/KeyStoragePanel.tsx +++ b/src/components/views/settings/encryption/KeyStoragePanel.tsx @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -import React, { FormEvent, JSX, useCallback } from "react"; +import React, { FormEvent, useCallback } from "react"; import { InlineField, InlineSpinner, Label, Root, ToggleControl } from "@vector-im/compound-web"; import { SettingsSection } from "../shared/SettingsSection"; @@ -13,17 +13,25 @@ import { _t } from "../../../../languageHandler"; import { SettingsHeader } from "../SettingsHeader"; import { useKeyStoragePanelViewModel } from "../../../viewmodels/settings/encryption/KeyStoragePanelViewModel"; +interface Props { + onKeyStorageDisableClick: () => void; +} + /** * This component allows the user to set up or change their recovery key. */ -export function KeyBackupPanel(): JSX.Element { +export const KeyStoragePanel: React.FC = ({ onKeyStorageDisableClick }) => { const { isEnabled, setEnabled, loading, busy } = useKeyStoragePanelViewModel(); const onKeyBackupChange = useCallback( (e: FormEvent) => { - setEnabled(e.currentTarget.checked); + if (e.currentTarget.checked) { + setEnabled(true); + } else { + onKeyStorageDisableClick(); + } }, - [setEnabled], + [setEnabled, onKeyStorageDisableClick], ); if (loading) { @@ -58,4 +66,4 @@ export function KeyBackupPanel(): JSX.Element { ); -} +}; diff --git a/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx b/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx index a0e2dbc08d..df9e611e96 100644 --- a/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/EncryptionUserSettingsTab.tsx @@ -24,7 +24,8 @@ import { ResetIdentityPanel } from "../../encryption/ResetIdentityPanel"; import { RecoveryPanelOutOfSync } from "../../encryption/RecoveryPanelOutOfSync"; import Spinner from "../../../elements/Spinner"; import { useEventEmitter } from "../../../../../hooks/useEventEmitter"; -import { KeyBackupPanel } from "../../encryption/KeyStoragePanel"; +import { KeyStoragePanel } from "../../encryption/KeyStoragePanel"; +import { DeleteKeyStoragePanel } from "../../encryption/DeleteKeyStoragePanel"; /** * The state in the encryption settings tab. @@ -49,7 +50,8 @@ export type State = | "set_recovery_key" | "reset_identity_compromised" | "reset_identity_forgot" - | "secrets_not_cached"; + | "secrets_not_cached" + | "key_storage_delete"; interface EncryptionUserSettingsTabProps { /** @@ -113,7 +115,7 @@ export function EncryptionUserSettingsTab({ initialState = "loading" }: Encrypti case "main": content = ( <> - + setState("key_storage_delete")} /> {keyBackupIsEnabled && ( <> ); break; + case "key_storage_delete": + content = setState("main")} />; + break; } } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d2d977c934..d53c44ede3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2482,6 +2482,14 @@ "session_key": "Session key:", "title": "Advanced" }, + "delete_key_storage": { + "breadcrumb_page": "Delete key storage", + "confirm": "Delete key storage", + "description": "Deleting key storage will remove your cryptographic identity and message keys from the server and turn off the following security features:", + "list_first": "You will not have encrypted message history on new devices", + "list_second": "You will lose access to your encrypted messages if you are signed out of Element everywhere", + "title": "Are you sure you want to turn off key storage and delete it?" + }, "device_not_verified_button": "Verify this device", "device_not_verified_description": "You need to verify this device in order to view your encryption settings.", "device_not_verified_title": "Device not verified",