diff --git a/apps/desktop/src/Router.tsx b/apps/desktop/src/Router.tsx index 3662d56e5..72d9d64d4 100644 --- a/apps/desktop/src/Router.tsx +++ b/apps/desktop/src/Router.tsx @@ -8,13 +8,12 @@ import { useResetBeaconConnections, } from "@umami/state"; import { noop } from "lodash"; -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { HashRouter, Navigate, Route, Routes } from "react-router-dom"; import { AnnouncementBanner } from "./components/AnnouncementBanner"; import { SocialLoginWarningModal } from "./components/SocialLoginWarningModal/SocialLoginWarningModal"; import { BeaconProvider } from "./utils/beacon/BeaconProvider"; -import { persistor } from "./utils/persistor"; import { useDeeplinkHandler } from "./utils/useDeeplinkHandler"; import { AddressBookView } from "./views/addressBook/AddressBookView"; import { BatchPage } from "./views/batch/BatchPage"; @@ -34,51 +33,6 @@ export const Router = () => { useDeeplinkHandler(); const isLoggedIn = useImplicitAccounts().length > 0; - const [backupData, setBackupData] = useState({}); - - useEffect(() => { - // @ts-ignore - window.electronAPI.onBackupData((_, backupData) => { - console.log(backupData); - setBackupData(backupData); - }); - }, []); - - useEffect(() => { - if (Object.keys(backupData).length > 0) { - try { - const accountsValue = backupData["persist:accounts"].accountsValue.slice(1); // Remove the \u0001 prefix - const rootValue = backupData["persist:root"].rootValue.slice(1); // Remove the \u0001 prefix - // Step 2: Parse the outer JSON string - const parsedAccounts = JSON.parse(accountsValue); - const sanitizedRootValue = backupData["persist:root"].rootValue.replaceAll( - /[\u0000-\u001F\u007F-\u009F]/g, - "" - ); - const parsedRootValue = JSON.parse(sanitizedRootValue); - - // Step 3: Parse the inner strings as needed - parsedAccounts.items = JSON.parse(parsedAccounts.items); - parsedAccounts.seedPhrases = JSON.parse(parsedAccounts.seedPhrases); - parsedAccounts.secretKeys = JSON.parse(parsedAccounts.secretKeys); - parsedAccounts._persist = JSON.parse(parsedAccounts._persist); - parsedAccounts.current = JSON.parse(parsedAccounts.current); - - - console.log(parsedAccounts, "parsedAccounts"); - console.log(parsedRootValue, "parsedRootValue"); - - persistor.pause(); - // localStorage.clear(); - localStorage.setItem("persist:accounts", JSON.stringify(parsedAccounts)); - localStorage.setItem("persist:root", JSON.stringify(parsedRootValue)); - // window.location.reload(); - } catch (error) { - console.error("Error during backup restoration", error); - } - } - }, [backupData]); - return isLoggedIn ? : ; }; diff --git a/packages/state/.eslintrc.cjs b/packages/state/.eslintrc.cjs index 9235a456a..bec5bb76c 100644 --- a/packages/state/.eslintrc.cjs +++ b/packages/state/.eslintrc.cjs @@ -5,4 +5,12 @@ module.exports = { parser: "@typescript-eslint/parser", tsconfigRootDir: __dirname, }, + overrides: [ + { + files: ["*.ts", "*.tsx"], + rules: { + "import/no-unused-modules": "off", + }, + }, + ], }; diff --git a/packages/state/src/reducer.ts b/packages/state/src/reducer.ts index f516ea652..cb5416c42 100644 --- a/packages/state/src/reducer.ts +++ b/packages/state/src/reducer.ts @@ -1,5 +1,11 @@ import { combineReducers } from "@reduxjs/toolkit"; -import { type Storage, persistReducer } from "redux-persist"; +import { + type PersistConfig, + type PersistedState, + type Storage, + getStoredState, + persistReducer, +} from "redux-persist"; import createWebStorage from "redux-persist/lib/storage/createWebStorage"; import { createAsyncMigrate } from "./createAsyncMigrate"; @@ -32,14 +38,89 @@ const getTestStorage = () => { : TEST_STORAGE; }; +export const processMigrationData = (backupData: any) => { + try { + const processedData: { accounts: any; root: any } = { + accounts: null, + root: null, + }; + + console.log(backupData, "backupData"); + + if (backupData["persist:accounts"]?.accountsValue) { + const accountsValue = backupData["persist:accounts"].accountsValue.slice(1); + processedData.accounts = JSON.parse(accountsValue); + + for (const item in processedData.accounts) { + processedData.accounts[item] = JSON.parse(processedData.accounts[item]); + } + } + + if (backupData["persist:root"]?.rootValue) { + const sanitizedRootValue = backupData["persist:root"].rootValue.replaceAll( + // eslint-disable-next-line no-control-regex + /[\u0000-\u001F\u007F-\u009F]/g, + "" + ); + + processedData.root = JSON.parse(sanitizedRootValue); + + for (const item in processedData.root) { + processedData.root[item] = JSON.parse(processedData.root[item]); + } + } + + return processedData; + } catch (error) { + console.error("Error processing backup data:", error); + return null; + } +}; + export const makeReducer = (storage_: Storage | undefined) => { const storage = storage_ || getTestStorage() || createWebStorage("local"); + // Custom getStoredState function to handle migration + const customGetStoredState = async (config: PersistConfig): Promise => { + try { + // First try to get state from current storage + const state = (await getStoredState(config)) as PersistedState; + console.log(state, "state"); + if (state) { + return state; + } + + // If no state, check if we have backup data + // @ts-ignore + if (window.electronAPI) { + return new Promise(resolve => { + // @ts-ignore + window.electronAPI.onBackupData((_, data) => { + if (data) { + const processed = processMigrationData(data); + console.log(processed, "processed"); + if (processed) { + // Return the processed state based on config key + // @ts-ignore + return resolve(config.key === "root" ? processed.root : processed.accounts); + } + } + resolve(undefined); + }); + }); + } + } catch (err) { + console.error("Error getting stored state:", err); + return undefined; + } + }; + const rootPersistConfig = { key: "root", version: VERSION, storage, blacklist: ["accounts"], + getStoredState: customGetStoredState, migrate: createAsyncMigrate(mainStoreMigrations, { debug: false }), }; @@ -47,6 +128,7 @@ export const makeReducer = (storage_: Storage | undefined) => { key: "accounts", version: VERSION, storage, + getStoredState: customGetStoredState, migrate: createAsyncMigrate(accountsMigrations, { debug: false }), blacklist: ["password"], };