diff --git a/apps/desktop-e2e/tsconfig.json b/apps/desktop-e2e/tsconfig.json
index 240053e44..627f12aeb 100644
--- a/apps/desktop-e2e/tsconfig.json
+++ b/apps/desktop-e2e/tsconfig.json
@@ -17,8 +17,7 @@
"preserveSymlinks": true
},
"ts-node": {
- "esm": true,
- "files": true
+ "esm": true
},
"include": ["src", ".eslintrc.cjs", "cucumber.cjs"]
}
diff --git a/apps/desktop/src/Router.tsx b/apps/desktop/src/Router.tsx
index c5d0458c4..2c19fa1c7 100644
--- a/apps/desktop/src/Router.tsx
+++ b/apps/desktop/src/Router.tsx
@@ -4,6 +4,7 @@ import { useDataPolling } from "@umami/data-polling";
import {
WalletClient,
useCurrentAccount,
+ useGetUserAlerts,
useImplicitAccounts,
useResetBeaconConnections,
} from "@umami/state";
@@ -42,12 +43,13 @@ const LoggedInRouterWithPolling = () => {
useDataPolling();
const modalDisclosure = useDynamicModal();
const currentUser = useCurrentAccount();
+ const getUserAlerts = useGetUserAlerts();
useEffect(() => {
if (currentUser?.type === "social") {
- const isInformed = localStorage.getItem("user:isSocialLoginWarningShown");
+ const isInformed = getUserAlerts("isSocialLoginWarningShown");
- if (!isInformed || !JSON.parse(isInformed)) {
+ if (!isInformed) {
void modalDisclosure.openWith(, { closeOnEsc: false });
}
}
diff --git a/apps/desktop/src/components/SocialLoginWarningModal/SocialLoginWarningModal.test.tsx b/apps/desktop/src/components/SocialLoginWarningModal/SocialLoginWarningModal.test.tsx
index 69478cde4..c05e65f93 100644
--- a/apps/desktop/src/components/SocialLoginWarningModal/SocialLoginWarningModal.test.tsx
+++ b/apps/desktop/src/components/SocialLoginWarningModal/SocialLoginWarningModal.test.tsx
@@ -1,3 +1,5 @@
+import { type UmamiStore, makeStore } from "@umami/state";
+
import { SocialLoginWarningModal } from "./SocialLoginWarningModal";
import {
act,
@@ -8,13 +10,15 @@ import {
waitFor,
} from "../../mocks/testUtils";
+let store: UmamiStore;
+
beforeEach(() => {
- localStorage.clear();
+ store = makeStore();
});
describe("", () => {
it("renders the modal with correct title and content", async () => {
- render();
+ render(, { store });
await waitFor(() => {
expect(screen.getByText("Important notice about your social account wallet")).toBeVisible();
@@ -28,7 +32,7 @@ describe("", () => {
});
it("disables 'Continue' button when checkbox is not checked", () => {
- render();
+ render(, { store });
const button = screen.getByRole("button", { name: "Continue" });
expect(button).toBeDisabled();
@@ -36,7 +40,7 @@ describe("", () => {
it("enables 'Continue' button when checkbox is checked", async () => {
const user = userEvent.setup();
- render();
+ render(, { store });
const checkbox = screen.getByRole("checkbox", {
name: "I understand and accept the risks.",
@@ -50,7 +54,7 @@ describe("", () => {
it("sets localStorage and closes modal when 'Continue' is clicked", async () => {
const { onClose } = dynamicModalContextMock;
const user = userEvent.setup();
- render();
+ render(, { store });
const checkbox = screen.getByRole("checkbox", {
name: "I understand and accept the risks.",
@@ -61,7 +65,7 @@ describe("", () => {
await act(() => user.click(continueButton));
await waitFor(() => {
- expect(localStorage.getItem("user:isSocialLoginWarningShown")).toBe("true");
+ expect(store.getState().accounts.alerts.isSocialLoginWarningShown).toBe(true);
});
expect(onClose).toHaveBeenCalled();
@@ -69,7 +73,7 @@ describe("", () => {
it("toggles checkbox state correctly", async () => {
const user = userEvent.setup();
- render();
+ render(, { store });
const checkbox = screen.getByRole("checkbox", {
name: "I understand and accept the risks.",
diff --git a/apps/desktop/src/components/SocialLoginWarningModal/SocialLoginWarningModal.tsx b/apps/desktop/src/components/SocialLoginWarningModal/SocialLoginWarningModal.tsx
index f30c4c58a..97271ed29 100644
--- a/apps/desktop/src/components/SocialLoginWarningModal/SocialLoginWarningModal.tsx
+++ b/apps/desktop/src/components/SocialLoginWarningModal/SocialLoginWarningModal.tsx
@@ -11,6 +11,7 @@ import {
Text,
} from "@chakra-ui/react";
import { useDynamicModalContext } from "@umami/components";
+import { accountsActions, useAppDispatch } from "@umami/state";
import { useState } from "react";
import { WarningIcon } from "../../assets/icons";
@@ -19,9 +20,10 @@ import colors from "../../style/colors";
export const SocialLoginWarningModal = () => {
const { onClose } = useDynamicModalContext();
const [isAgreed, setIsAgreed] = useState(false);
+ const dispatch = useAppDispatch();
const handleInform = () => {
- localStorage.setItem("user:isSocialLoginWarningShown", "true");
+ dispatch(accountsActions.setAlerts({ key: "isSocialLoginWarningShown", value: true }));
onClose();
};
diff --git a/apps/web/src/Layout.tsx b/apps/web/src/Layout.tsx
index 6e6027c41..5a79cd78e 100644
--- a/apps/web/src/Layout.tsx
+++ b/apps/web/src/Layout.tsx
@@ -1,7 +1,7 @@
import { Grid, GridItem } from "@chakra-ui/react";
import { useDynamicModalContext } from "@umami/components";
import { useDataPolling } from "@umami/data-polling";
-import { useCurrentAccount } from "@umami/state";
+import { accountsActions, useAppDispatch, useCurrentAccount, useGetUserAlerts } from "@umami/state";
import { useEffect } from "react";
import { Footer } from "./components/Footer";
@@ -16,28 +16,30 @@ export const Layout = () => {
useDataPolling();
const { openWith } = useDynamicModalContext();
const currentUser = useCurrentAccount();
+ const getUserAlerts = useGetUserAlerts();
+ const dispatch = useAppDispatch();
useEffect(() => {
const CLOSING_DELAY = 300;
const warnings = [
{
- key: "user:isSocialLoginWarningShown",
+ key: "isSocialLoginWarningShown",
component: ,
options: { closeOnEsc: false },
isEnabled: () => currentUser?.type === "social",
},
{
- key: "user:isExtensionsWarningShown",
+ key: "isExtensionsWarningShown",
component: ,
options: { closeOnEsc: false, size: "xl" },
isEnabled: () => true,
},
- ];
+ ] as const;
const warningsToShow = warnings.filter(warning => {
- const isInformed = localStorage.getItem(warning.key);
- return (!isInformed || !JSON.parse(isInformed)) && warning.isEnabled();
+ const isInformed = getUserAlerts(warning.key);
+ return !isInformed && warning.isEnabled();
});
const showWarnings = async () => {
@@ -47,7 +49,7 @@ export const Layout = () => {
void openWith(warning.component, {
...warning.options,
onClose: () => {
- localStorage.setItem(warning.key, "true");
+ dispatch(accountsActions.setAlerts({ key: warning.key, value: true }));
resolve(true);
},
})
diff --git a/packages/state/src/hooks/getAccountData.ts b/packages/state/src/hooks/getAccountData.ts
index 722386a0d..d684028f6 100644
--- a/packages/state/src/hooks/getAccountData.ts
+++ b/packages/state/src/hooks/getAccountData.ts
@@ -15,7 +15,7 @@ import { useDispatch } from "react-redux";
import { useGetAccountBalance } from "./assets";
import { useMultisigAccounts } from "./multisig";
import { useAppSelector } from "./useAppSelector";
-import { accountsActions } from "../slices";
+import { type AccountsState, accountsActions } from "../slices";
export const useSeedPhrases = () => useAppSelector(s => s.accounts.seedPhrases);
@@ -215,3 +215,9 @@ export const useGetDecryptedMnemonic = () => {
return decrypt(encryptedMnemonic, password);
};
};
+
+export const useGetUserAlerts = () => {
+ const alerts = useAppSelector(s => s.accounts.alerts);
+
+ return (key: keyof AccountsState["alerts"]) => alerts[key];
+};
diff --git a/packages/state/src/slices/accounts/State.ts b/packages/state/src/slices/accounts/State.ts
index bd971b7ac..839db7085 100644
--- a/packages/state/src/slices/accounts/State.ts
+++ b/packages/state/src/slices/accounts/State.ts
@@ -9,4 +9,8 @@ export type AccountsState = {
secretKeys: Record;
current?: RawPkh | undefined;
password?: string | undefined;
+ alerts: {
+ isSocialLoginWarningShown: boolean;
+ isExtensionsWarningShown: boolean;
+ };
};
diff --git a/packages/state/src/slices/accounts/accounts.ts b/packages/state/src/slices/accounts/accounts.ts
index 91bfb7235..bb16ee00d 100644
--- a/packages/state/src/slices/accounts/accounts.ts
+++ b/packages/state/src/slices/accounts/accounts.ts
@@ -20,6 +20,10 @@ export const accountsInitialState: AccountsState = {
seedPhrases: {},
secretKeys: {},
password: "",
+ alerts: {
+ isSocialLoginWarningShown: false,
+ isExtensionsWarningShown: false,
+ },
};
/**
@@ -144,6 +148,15 @@ export const accountsSlice = createSlice({
setPassword: (state, { payload }: { payload: string }) => {
state.password = payload;
},
+ setAlerts: (
+ state,
+ { payload }: { payload: { key: keyof AccountsState["alerts"]; value: boolean } }
+ ) => {
+ state.alerts = {
+ ...state.alerts,
+ [payload.key]: payload.value,
+ };
+ },
},
});