mirror of
https://github.com/haveno-dex/haveno-ui.git
synced 2024-12-25 23:49:38 -05:00
feat: account backup
--- Co-authored-by: @schowdhuri Reviewed-by: @schowdhuri
This commit is contained in:
parent
ad493f5147
commit
500be9a7fd
@ -18,6 +18,7 @@ import { app } from "electron";
|
|||||||
import "./security-restrictions";
|
import "./security-restrictions";
|
||||||
import { restoreOrCreateWindow } from "@src/mainWindow";
|
import { restoreOrCreateWindow } from "@src/mainWindow";
|
||||||
import { registerStoreHandlers } from "@src/services/store";
|
import { registerStoreHandlers } from "@src/services/store";
|
||||||
|
import { registerHavenoHandlers } from "./services/haveno";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent multiple instances
|
* Prevent multiple instances
|
||||||
@ -61,6 +62,11 @@ app
|
|||||||
.then(registerStoreHandlers)
|
.then(registerStoreHandlers)
|
||||||
.catch((e) => console.error("Failed to register store handlers:", e));
|
.catch((e) => console.error("Failed to register store handlers:", e));
|
||||||
|
|
||||||
|
app
|
||||||
|
.whenReady()
|
||||||
|
.then(registerHavenoHandlers)
|
||||||
|
.catch((e) => console.error("Failed to register haveno handlers:", e));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install devtools in development mode only
|
* Install devtools in development mode only
|
||||||
*/
|
*/
|
||||||
|
59
packages/main/src/services/haveno.ts
Normal file
59
packages/main/src/services/haveno.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import fsPromises from "fs/promises";
|
||||||
|
import { ipcMain, dialog } from "electron";
|
||||||
|
import type { DownloadBackupInput } from "@src/types";
|
||||||
|
import { IpcChannels } from "@src/types";
|
||||||
|
|
||||||
|
export function registerHavenoHandlers() {
|
||||||
|
ipcMain.handle(
|
||||||
|
IpcChannels.DownloadBackup,
|
||||||
|
async (_, data: DownloadBackupInput) => {
|
||||||
|
const file = await dialog.showSaveDialog({
|
||||||
|
defaultPath: "haveno-backup",
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
extensions: ["zip"],
|
||||||
|
name: "*",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: ["createDirectory", "dontAddToRecent"],
|
||||||
|
});
|
||||||
|
if (!file?.filePath) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
await fsPromises.writeFile(file.filePath, new Uint8Array(data.bytes));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
ipcMain.handle(IpcChannels.RestoreBackup, async (): Promise<Uint8Array> => {
|
||||||
|
const files = await dialog.showOpenDialog({
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
extensions: ["zip"],
|
||||||
|
name: "*",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: ["openFile", "dontAddToRecent"],
|
||||||
|
});
|
||||||
|
if (!files?.filePaths[0]) {
|
||||||
|
return new Uint8Array();
|
||||||
|
}
|
||||||
|
const zipFile = files.filePaths[0];
|
||||||
|
return new Uint8Array(await fsPromises.readFile(zipFile));
|
||||||
|
});
|
||||||
|
}
|
@ -14,12 +14,6 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
import { AccountLayout } from "@templates/AccountLayout";
|
export interface DownloadBackupInput {
|
||||||
|
bytes: ArrayBuffer;
|
||||||
export function Backup() {
|
|
||||||
return (
|
|
||||||
<AccountLayout>
|
|
||||||
<h1>Account Backup</h1>
|
|
||||||
</AccountLayout>
|
|
||||||
);
|
|
||||||
}
|
}
|
@ -16,3 +16,4 @@
|
|||||||
|
|
||||||
export * from "./ipc";
|
export * from "./ipc";
|
||||||
export * from "./store";
|
export * from "./store";
|
||||||
|
export * from "./haveno";
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
export enum IpcChannels {
|
export enum IpcChannels {
|
||||||
|
// store
|
||||||
GetAccountInfo = "store:accountInfo",
|
GetAccountInfo = "store:accountInfo",
|
||||||
SetPassword = "store:accountinfo.setPassword",
|
SetPassword = "store:accountinfo.setPassword",
|
||||||
ChangePassword = "store:accountinfo.changePassword",
|
ChangePassword = "store:accountinfo.changePassword",
|
||||||
@ -23,5 +24,10 @@ export enum IpcChannels {
|
|||||||
GetPreferences = "store:preferences",
|
GetPreferences = "store:preferences",
|
||||||
SetMoneroNode = "store:preferences.setMoneroNode",
|
SetMoneroNode = "store:preferences.setMoneroNode",
|
||||||
|
|
||||||
|
// haveno
|
||||||
|
DownloadBackup = "haveno:downloadBackup",
|
||||||
|
RestoreBackup = "haveno:restoreBackup",
|
||||||
|
|
||||||
|
// others
|
||||||
VerifyAuthToken = "verifyAuthToken",
|
VerifyAuthToken = "verifyAuthToken",
|
||||||
}
|
}
|
||||||
|
1
packages/preload/contracts.d.ts
vendored
1
packages/preload/contracts.d.ts
vendored
@ -20,6 +20,7 @@ interface Exposed {
|
|||||||
readonly nodeCrypto: Readonly<typeof import("./src/nodeCrypto").nodeCrypto>;
|
readonly nodeCrypto: Readonly<typeof import("./src/nodeCrypto").nodeCrypto>;
|
||||||
readonly versions: Readonly<typeof import("./src/versions").versions>;
|
readonly versions: Readonly<typeof import("./src/versions").versions>;
|
||||||
readonly electronStore: Readonly<typeof import("./src/store").store>;
|
readonly electronStore: Readonly<typeof import("./src/store").store>;
|
||||||
|
readonly haveno: Readonly<typeof import("./src/haveno").store>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||||
|
31
packages/preload/src/haveno.ts
Normal file
31
packages/preload/src/haveno.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { ipcRenderer } from "electron";
|
||||||
|
import { exposeInMainWorld } from "./exposeInMainWorld";
|
||||||
|
import type { DownloadBackupInput } from "./types";
|
||||||
|
import { IpcChannels } from "./types";
|
||||||
|
|
||||||
|
// Export for types in contracts.d.ts
|
||||||
|
export const haveno = {
|
||||||
|
downloadBackup: async (data: DownloadBackupInput): Promise<void> =>
|
||||||
|
ipcRenderer.invoke(IpcChannels.DownloadBackup, data),
|
||||||
|
|
||||||
|
getBackupData: async (): Promise<Uint8Array> =>
|
||||||
|
ipcRenderer.invoke(IpcChannels.RestoreBackup),
|
||||||
|
};
|
||||||
|
|
||||||
|
exposeInMainWorld("haveno", haveno);
|
@ -21,3 +21,4 @@
|
|||||||
import "./nodeCrypto";
|
import "./nodeCrypto";
|
||||||
import "./versions";
|
import "./versions";
|
||||||
import "./store";
|
import "./store";
|
||||||
|
import "./haveno";
|
||||||
|
@ -21,7 +21,7 @@ import { Home } from "@pages/Home";
|
|||||||
import { Login } from "@pages/Login";
|
import { Login } from "@pages/Login";
|
||||||
import { CreateAccount, Welcome } from "@pages/Onboarding";
|
import { CreateAccount, Welcome } from "@pages/Onboarding";
|
||||||
import {
|
import {
|
||||||
Backup,
|
AccountBackup,
|
||||||
Settings,
|
Settings,
|
||||||
PaymentAccounts,
|
PaymentAccounts,
|
||||||
Security,
|
Security,
|
||||||
@ -57,7 +57,7 @@ export function AppRoutes() {
|
|||||||
path={ROUTES.Backup}
|
path={ROUTES.Backup}
|
||||||
element={
|
element={
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
<Backup />
|
<AccountBackup />
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -53,4 +53,12 @@ export enum LangKeys {
|
|||||||
AccountWalletTitle = "account.wallet.title",
|
AccountWalletTitle = "account.wallet.title",
|
||||||
AccountWalletDesc = "account.wallet.desc",
|
AccountWalletDesc = "account.wallet.desc",
|
||||||
AccountWalletPassword = "account.wallet.field.password",
|
AccountWalletPassword = "account.wallet.field.password",
|
||||||
|
AccountBackupDownloadTitle = "account.backup.download.title",
|
||||||
|
AccountBackupDownloadDesc = "account.backup.download.desc",
|
||||||
|
AccountBackupDownloadBtn = "account.backup.download.btn",
|
||||||
|
AccountBackupRestoreTitle = "account.backup.restore.title",
|
||||||
|
AccountBackupRestoreDesc = "account.backup.restore.desc",
|
||||||
|
AccountBackupRestoreBtn = "account.backup.restore.btn",
|
||||||
|
AccountBackupDownloadSuccessNotif = "account.backup.download.successNotification",
|
||||||
|
AccountBackupRestoreSuccessNotif = "account.backup.restore.successNotification",
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,18 @@ const LangPackEN: { [key in LangKeys]: string } = {
|
|||||||
[LangKeys.AccountWalletDesc]:
|
[LangKeys.AccountWalletDesc]:
|
||||||
"The Haveno wallet is permanently connected to your account. Solely saving your seed phrase is not enough to recover your account, you need to download a backup of your account, which you can download via the backup section.",
|
"The Haveno wallet is permanently connected to your account. Solely saving your seed phrase is not enough to recover your account, you need to download a backup of your account, which you can download via the backup section.",
|
||||||
[LangKeys.AccountWalletPassword]: "Password",
|
[LangKeys.AccountWalletPassword]: "Password",
|
||||||
|
[LangKeys.AccountBackupDownloadTitle]: "Download your backup file",
|
||||||
|
[LangKeys.AccountBackupDownloadDesc]:
|
||||||
|
"To be able to restore your Haveno account you need to create a backup file of your account. Keep it somewhere safe.",
|
||||||
|
[LangKeys.AccountBackupDownloadBtn]: "Download backup file",
|
||||||
|
[LangKeys.AccountBackupRestoreTitle]: "Restore an existing backup file",
|
||||||
|
[LangKeys.AccountBackupRestoreDesc]:
|
||||||
|
"When you restore an existing backup file of your Haveno account, you will lose the account you’re using currently. Please use with caution.",
|
||||||
|
[LangKeys.AccountBackupRestoreBtn]: "Restore backup",
|
||||||
|
[LangKeys.AccountBackupDownloadSuccessNotif]:
|
||||||
|
"The backup has been downloaded successfully.",
|
||||||
|
[LangKeys.AccountBackupRestoreSuccessNotif]:
|
||||||
|
"The backup has been restored successfully.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LangPackEN;
|
export default LangPackEN;
|
||||||
|
@ -63,6 +63,21 @@ const LangPackES: { [key in LangKeys]: string } = {
|
|||||||
[LangKeys.AccountWalletDesc]:
|
[LangKeys.AccountWalletDesc]:
|
||||||
"La billetera Haveno está permanentemente conectada a su cuenta. Solo guardar su frase inicial no es suficiente para recuperar su cuenta, necesita descargar una copia de seguridad de su cuenta, que puede descargar a través de la sección de copia de seguridad.",
|
"La billetera Haveno está permanentemente conectada a su cuenta. Solo guardar su frase inicial no es suficiente para recuperar su cuenta, necesita descargar una copia de seguridad de su cuenta, que puede descargar a través de la sección de copia de seguridad.",
|
||||||
[LangKeys.AccountWalletPassword]: "contraseña",
|
[LangKeys.AccountWalletPassword]: "contraseña",
|
||||||
|
[LangKeys.AccountBackupDownloadTitle]:
|
||||||
|
"Descarga tu archivo de copia de seguridad",
|
||||||
|
[LangKeys.AccountBackupDownloadDesc]:
|
||||||
|
"Para poder restore your Haveno account you need to create a backup file of your account. Keep it somewhere safe.",
|
||||||
|
[LangKeys.AccountBackupDownloadBtn]:
|
||||||
|
"Descargar archivo de copia de seguridad",
|
||||||
|
[LangKeys.AccountBackupRestoreTitle]:
|
||||||
|
"Restaurar un archivo de copia de seguridad existente",
|
||||||
|
[LangKeys.AccountBackupRestoreDesc]:
|
||||||
|
"Cuando restaure un archivo de respaldo existente de su cuenta de Haveno, perderá la cuenta que está usando actualmente. Úselo con precaución.",
|
||||||
|
[LangKeys.AccountBackupRestoreBtn]: "Restaurar copia de seguridad",
|
||||||
|
[LangKeys.AccountBackupDownloadSuccessNotif]:
|
||||||
|
"La copia de seguridad se ha descargado correctamente.",
|
||||||
|
[LangKeys.AccountBackupRestoreSuccessNotif]:
|
||||||
|
"La copia de seguridad se ha restaurado correctamente.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LangPackES;
|
export default LangPackES;
|
||||||
|
20
packages/renderer/src/constants/notifications.ts
Normal file
20
packages/renderer/src/constants/notifications.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
export enum Notifications {
|
||||||
|
AccountRestoring = "AccountRestoring",
|
||||||
|
MoneroRestartAfterRestoring = "MoneroRestartAfterRestoring",
|
||||||
|
}
|
61
packages/renderer/src/hooks/haveno/useDownloadBackup.ts
Normal file
61
packages/renderer/src/hooks/haveno/useDownloadBackup.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { useMutation } from "react-query";
|
||||||
|
import type { HavenoClient } from "haveno-ts";
|
||||||
|
import { useHavenoClient } from "./useHavenoClient";
|
||||||
|
|
||||||
|
export function useDownloadBackup() {
|
||||||
|
const client = useHavenoClient();
|
||||||
|
return useMutation(async () => {
|
||||||
|
const bytes = await getBackupData(client);
|
||||||
|
return window.haveno.downloadBackup({
|
||||||
|
bytes,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getBackupData(client: HavenoClient) {
|
||||||
|
const SIZE_INCREMENT = 4096;
|
||||||
|
let size = SIZE_INCREMENT;
|
||||||
|
let result = new ArrayBuffer(size);
|
||||||
|
let numBytes = 0;
|
||||||
|
|
||||||
|
const writableStream = new WritableStream({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
write(chunk: Array<any>) {
|
||||||
|
const len = chunk.length;
|
||||||
|
if (numBytes + len > size) {
|
||||||
|
while (numBytes + len > size) {
|
||||||
|
size += SIZE_INCREMENT;
|
||||||
|
}
|
||||||
|
const largerBuffer = new ArrayBuffer(size);
|
||||||
|
new Uint8Array(largerBuffer).set(new Uint8Array(result));
|
||||||
|
result = largerBuffer;
|
||||||
|
}
|
||||||
|
const view = new Uint8Array(result);
|
||||||
|
chunk.forEach((byte, index) => {
|
||||||
|
view[numBytes + index] = byte;
|
||||||
|
});
|
||||||
|
numBytes += len;
|
||||||
|
},
|
||||||
|
abort(err) {
|
||||||
|
console.log("Sink error:", err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await client.backupAccount(writableStream.getWriter());
|
||||||
|
return result.slice(0, numBytes);
|
||||||
|
}
|
82
packages/renderer/src/hooks/haveno/useRestoreBackup.ts
Normal file
82
packages/renderer/src/hooks/haveno/useRestoreBackup.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { hideNotification, showNotification } from "@mantine/notifications";
|
||||||
|
import { useMutation } from "react-query";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { MoneroNodeSettings } from "haveno-ts";
|
||||||
|
import { useHavenoClient } from "./useHavenoClient";
|
||||||
|
import { Notifications } from "@constants/notifications";
|
||||||
|
import { deleteSession } from "@utils/session";
|
||||||
|
import { ROUTES } from "@constants/routes";
|
||||||
|
|
||||||
|
export function useRestoreBackup() {
|
||||||
|
const client = useHavenoClient();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
return useMutation(
|
||||||
|
async () => {
|
||||||
|
const bytes = await window.haveno.getBackupData();
|
||||||
|
|
||||||
|
if (!bytes.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showNotification({
|
||||||
|
id: Notifications.AccountRestoring,
|
||||||
|
title: "Account Restoring.",
|
||||||
|
message: "Account is restoring from the file.",
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
await client.deleteAccount();
|
||||||
|
await client.restoreAccount(bytes);
|
||||||
|
|
||||||
|
hideNotification(Notifications.AccountRestoring);
|
||||||
|
showNotification({
|
||||||
|
id: Notifications.MoneroRestartAfterRestoring,
|
||||||
|
title: "Monero restarting.",
|
||||||
|
message:
|
||||||
|
"The account has been restored, now the Monero node restarting.",
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
deleteSession();
|
||||||
|
navigate(ROUTES.Login);
|
||||||
|
|
||||||
|
if (await client.isMoneroNodeRunning()) {
|
||||||
|
await client.stopMoneroNode();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await client.startMoneroNode(new MoneroNodeSettings());
|
||||||
|
} catch (ex) {
|
||||||
|
console.log(ex);
|
||||||
|
throw new Error("Failed to start the monero node");
|
||||||
|
}
|
||||||
|
hideNotification(Notifications.MoneroRestartAfterRestoring);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onError: (err: Error) => {
|
||||||
|
hideNotification(Notifications.AccountRestoring);
|
||||||
|
hideNotification(Notifications.MoneroRestartAfterRestoring);
|
||||||
|
|
||||||
|
showNotification({
|
||||||
|
color: "red",
|
||||||
|
message: err?.message ?? "Unable to restore backup",
|
||||||
|
title: "Something went wrong",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
135
packages/renderer/src/pages/Account/AccountBackup.tsx
Normal file
135
packages/renderer/src/pages/Account/AccountBackup.tsx
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
import { showNotification } from "@mantine/notifications";
|
||||||
|
import { Box, createStyles, Stack } from "@mantine/core";
|
||||||
|
import { Button } from "@atoms/Buttons";
|
||||||
|
import { BodyText, Heading } from "@atoms/Typography";
|
||||||
|
import { LangKeys } from "@constants/lang";
|
||||||
|
import { useDownloadBackup } from "@hooks/haveno/useDownloadBackup";
|
||||||
|
import { useRestoreBackup } from "@hooks/haveno/useRestoreBackup";
|
||||||
|
import { AccountLayout } from "@templates/AccountLayout";
|
||||||
|
|
||||||
|
export function AccountBackup() {
|
||||||
|
const { classes } = useStyles();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const { mutateAsync: downloadBackup, isLoading: isDownloading } =
|
||||||
|
useDownloadBackup();
|
||||||
|
const { mutateAsync: restoreBackup, isLoading: isRestoring } =
|
||||||
|
useRestoreBackup();
|
||||||
|
|
||||||
|
const handleDownloadBtnClick = () => {
|
||||||
|
downloadBackup().then(() => {
|
||||||
|
showNotification({
|
||||||
|
color: "green",
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: LangKeys.AccountBackupDownloadSuccessNotif,
|
||||||
|
defaultMessage: "The backup downloaded successfully.",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const handleRestoreBtnClick = () => {
|
||||||
|
restoreBackup().then(() => {
|
||||||
|
showNotification({
|
||||||
|
color: "green",
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: LangKeys.AccountBackupRestoreSuccessNotif,
|
||||||
|
defaultMessage: "The backup restored successfully.",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AccountLayout>
|
||||||
|
<Stack spacing={40}>
|
||||||
|
<Box>
|
||||||
|
<Heading
|
||||||
|
className={classes.title}
|
||||||
|
order={3}
|
||||||
|
stringId={LangKeys.AccountBackupDownloadTitle}
|
||||||
|
>
|
||||||
|
Download your backup file
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<BodyText
|
||||||
|
stringId={LangKeys.AccountBackupDownloadDesc}
|
||||||
|
className={classes.desc}
|
||||||
|
>
|
||||||
|
To be able to restore your Haveno account you need to create a
|
||||||
|
backup file of your account. Keep it somewhere safe.
|
||||||
|
</BodyText>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
disabled={isRestoring}
|
||||||
|
loading={isDownloading}
|
||||||
|
loaderPosition="right"
|
||||||
|
onClick={handleDownloadBtnClick}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id={LangKeys.AccountBackupDownloadBtn}
|
||||||
|
defaultMessage="Download backup file"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<Heading
|
||||||
|
order={3}
|
||||||
|
stringId={LangKeys.AccountBackupRestoreTitle}
|
||||||
|
className={classes.title}
|
||||||
|
>
|
||||||
|
Restore an existing backup file
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<BodyText
|
||||||
|
stringId={LangKeys.AccountBackupRestoreDesc}
|
||||||
|
className={classes.desc}
|
||||||
|
>
|
||||||
|
When you restore an existing backup file of your Haveno account, you
|
||||||
|
will lose the account you’re using currently. Please use with
|
||||||
|
caution.
|
||||||
|
</BodyText>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
disabled={true}
|
||||||
|
loading={isRestoring}
|
||||||
|
loaderPosition="right"
|
||||||
|
flavor="neutral"
|
||||||
|
onClick={handleRestoreBtnClick}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id={LangKeys.AccountBackupRestoreBtn}
|
||||||
|
defaultMessage="Restore backup"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</AccountLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles((theme) => ({
|
||||||
|
title: {
|
||||||
|
marginBottom: theme.spacing.md,
|
||||||
|
},
|
||||||
|
desc: {
|
||||||
|
marginBottom: theme.spacing.lg,
|
||||||
|
},
|
||||||
|
}));
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
export * from "./AddPaymentAccount";
|
export * from "./AddPaymentAccount";
|
||||||
export * from "./PaymentMethods";
|
export * from "./PaymentMethods";
|
||||||
export * from "./Backup";
|
|
||||||
export * from "./Settings";
|
export * from "./Settings";
|
||||||
export * from "./PaymentAccounts";
|
export * from "./PaymentAccounts";
|
||||||
export * from "./Security";
|
export * from "./Security";
|
||||||
export * from "./Wallet";
|
export * from "./Wallet";
|
||||||
|
export * from "./AccountBackup";
|
||||||
|
Loading…
Reference in New Issue
Block a user