mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-03 12:41:45 +02:00
feat: impl user account deletion
This commit is contained in:
@@ -19,6 +19,7 @@ import { EV } from "notes-core/common";
|
||||
import useTablet from "./utils/use-tablet";
|
||||
import { showBuyDialog } from "./components/dialogs/buy-dialog";
|
||||
import Banner from "./components/banner";
|
||||
import { showAccountDeletedNotice } from "./components/dialogs/confirm";
|
||||
|
||||
function App() {
|
||||
const [show, setShow] = useState(true);
|
||||
@@ -58,6 +59,9 @@ function App() {
|
||||
return { type, result: false };
|
||||
}
|
||||
});
|
||||
EV.subscribe("user:deleted", async () => {
|
||||
await showAccountDeletedNotice();
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { Box, Text } from "rebass";
|
||||
import Dialog, { showDialog } from "./dialog";
|
||||
import * as Icon from "../icons";
|
||||
import Field from "../field";
|
||||
|
||||
function Confirm(props) {
|
||||
const [isButtonEnabled, setIsButtonEnabled] = useState(!props.confirmWith);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
isOpen={true}
|
||||
@@ -14,6 +17,7 @@ function Confirm(props) {
|
||||
positiveButton={{
|
||||
text: props.yesText,
|
||||
onClick: props.onYes,
|
||||
disabled: !isButtonEnabled,
|
||||
}}
|
||||
negativeButton={{ text: props.noText, onClick: props.onNo }}
|
||||
>
|
||||
@@ -21,12 +25,36 @@ function Confirm(props) {
|
||||
<Text as="span" variant="body">
|
||||
{props.message}
|
||||
</Text>
|
||||
{props.confirmWith && (
|
||||
<Field
|
||||
autoFocus
|
||||
sx={{ mt: 2 }}
|
||||
label={
|
||||
<>
|
||||
Please type
|
||||
<Text as="span" color="error" mx={1}>
|
||||
{`${props.confirmWith}`}
|
||||
</Text>
|
||||
to confirm
|
||||
</>
|
||||
}
|
||||
id="confirm"
|
||||
name="confirm"
|
||||
onChange={(e) => {
|
||||
if (e.target.value === props.confirmWith)
|
||||
setIsButtonEnabled(true);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export function confirm(icon, { title, subtitle, message, yesText, noText }) {
|
||||
export function confirm(
|
||||
icon,
|
||||
{ title, subtitle, message, yesText, noText, confirmWith }
|
||||
) {
|
||||
return showDialog((perform) => (
|
||||
<Confirm
|
||||
title={title}
|
||||
@@ -34,6 +62,7 @@ export function confirm(icon, { title, subtitle, message, yesText, noText }) {
|
||||
message={message}
|
||||
yesText={yesText}
|
||||
noText={noText}
|
||||
confirmWith={confirmWith}
|
||||
icon={icon}
|
||||
onNo={() => perform(false)}
|
||||
onYes={() => perform(true)}
|
||||
@@ -96,3 +125,28 @@ export function showLogoutConfirmation() {
|
||||
noText: "No",
|
||||
});
|
||||
}
|
||||
|
||||
export function showAccountDeleteConfirmation(username) {
|
||||
return confirm(Icon.Logout, {
|
||||
title: `Delete Account?`,
|
||||
message: (
|
||||
<>
|
||||
This action is <b>IRREVERSIBLE</b>. All your data (notes, notebooks,
|
||||
tags, pins, favorites) will be <b>permanently deleted</b> with no way of
|
||||
recovery.
|
||||
</>
|
||||
),
|
||||
confirmWith: username,
|
||||
yesText: `I understand, delete my account`,
|
||||
noText: "Cancel",
|
||||
});
|
||||
}
|
||||
|
||||
export function showAccountDeletedNotice() {
|
||||
return confirm(Icon.Logout, {
|
||||
title: `Your account was deleted.`,
|
||||
message:
|
||||
"You deleted your account from another device. You have been logged out.",
|
||||
yesText: `Okay`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ class AppStore extends BaseStore {
|
||||
menuPins = [];
|
||||
|
||||
refresh = async () => {
|
||||
await resetReminders();
|
||||
noteStore.refresh();
|
||||
notebookStore.refresh();
|
||||
trashStore.refresh();
|
||||
@@ -29,7 +30,6 @@ class AppStore extends BaseStore {
|
||||
editorStore.openLastSession();
|
||||
this.refreshColors();
|
||||
this.refreshMenuPins();
|
||||
await resetReminders();
|
||||
};
|
||||
|
||||
refreshColors = () => {
|
||||
|
||||
@@ -33,6 +33,13 @@ class UserStore extends BaseStore {
|
||||
});
|
||||
EV.subscribe("db:sync", () => this.sync(false));
|
||||
EV.subscribe("user:loggedOut", async () => {
|
||||
this.set((state) => {
|
||||
state.user = {};
|
||||
state.isLoggedIn = false;
|
||||
});
|
||||
config.clear();
|
||||
await appStore.refresh();
|
||||
|
||||
if (window.PasswordCredential) {
|
||||
await navigator.credentials.preventSilentAccess();
|
||||
if (navigator.credentials.requireUserMediation)
|
||||
@@ -95,17 +102,6 @@ class UserStore extends BaseStore {
|
||||
this.set((state) => (state.isSyncing = false));
|
||||
});
|
||||
};
|
||||
|
||||
logout = () => {
|
||||
return db.user.logout().then(async () => {
|
||||
this.set((state) => {
|
||||
state.user = {};
|
||||
state.isLoggedIn = false;
|
||||
});
|
||||
config.clear();
|
||||
await appStore.refresh();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,10 @@ import { useStore as useSettingStore } from "../stores/setting-store";
|
||||
import AccentItem from "../components/accent-item";
|
||||
import accents from "../theme/accents";
|
||||
import { showLogInDialog } from "../components/dialogs/logindialog";
|
||||
import { showLogoutConfirmation } from "../components/dialogs/confirm";
|
||||
import {
|
||||
showAccountDeleteConfirmation,
|
||||
showLogoutConfirmation,
|
||||
} from "../components/dialogs/confirm";
|
||||
import useSystemTheme from "../utils/use-system-theme";
|
||||
import {
|
||||
createBackup,
|
||||
@@ -67,7 +70,6 @@ function Settings(props) {
|
||||
);
|
||||
const user = useUserStore((store) => store.user);
|
||||
const isLoggedIn = useUserStore((store) => store.isLoggedIn);
|
||||
const logout = useUserStore((store) => store.logout);
|
||||
const [backupReminderOffset, setBackupReminderOffset] = usePersistentState(
|
||||
"backupReminderOffset",
|
||||
0
|
||||
@@ -191,7 +193,7 @@ function Settings(props) {
|
||||
variant="list"
|
||||
onClick={async () => {
|
||||
if (await showLogoutConfirmation()) {
|
||||
await logout();
|
||||
await db.user.logout();
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -200,6 +202,21 @@ function Settings(props) {
|
||||
tip="Log out of your account and clear all data."
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
sx={{ borderColor: "error" }}
|
||||
variant="list"
|
||||
onClick={async () => {
|
||||
if (await showAccountDeleteConfirmation(user.username)) {
|
||||
await db.user.delete();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TextWithTip
|
||||
color="error"
|
||||
text="Delete account"
|
||||
tip="Permanently delete account and logout from all devices."
|
||||
/>
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<Text
|
||||
@@ -376,11 +393,11 @@ function Settings(props) {
|
||||
|
||||
export default Settings;
|
||||
|
||||
function TextWithTip({ text, tip, sx }) {
|
||||
function TextWithTip({ text, tip, sx, color }) {
|
||||
return (
|
||||
<Text color="text" fontSize="body" sx={sx}>
|
||||
<Text color={color || "text"} fontSize="body" sx={sx}>
|
||||
{text}
|
||||
<Text color="fontTertiary" fontSize="subBody">
|
||||
<Text color={color || "fontTertiary"} fontSize="subBody">
|
||||
{tip}
|
||||
</Text>
|
||||
</Text>
|
||||
|
||||
@@ -8959,7 +8959,7 @@ normalize-url@^3.0.0, normalize-url@^3.0.1:
|
||||
|
||||
"notes-core@git+ssh://git@github.com:streetwriters/notesnook-core.git":
|
||||
version "4.3.1"
|
||||
resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#81188213c112d4ba421854bb4879f0527b4a814d"
|
||||
resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#1d1e86e59a3f149c97cf4dafb39ffe555981d528"
|
||||
dependencies:
|
||||
fast-sort "^2.0.1"
|
||||
fuzzysearch "^1.0.3"
|
||||
|
||||
Reference in New Issue
Block a user