diff --git a/apps/extension/src/App/App.tsx b/apps/extension/src/App/App.tsx index f993c3fcc9..b57f6795fb 100644 --- a/apps/extension/src/App/App.tsx +++ b/apps/extension/src/App/App.tsx @@ -1,14 +1,37 @@ import { Container } from "@namada/components"; import { useVaultContext } from "context/VaultContext"; +import { useRequester } from "hooks/useRequester"; +import { CheckDurabilityMsg } from "provider"; +import { useEffect, useState } from "react"; import { matchPath, useLocation } from "react-router-dom"; +import { Ports } from "router"; import { AppContent } from "./AppContent"; import { AppHeader } from "./Common/AppHeader"; import { Login } from "./Login"; import routes from "./routes"; +const STORE_DURABILITY_INFO = + 'Store is not durable. This might cause problems when persisting data on disk.\ + To fix this issue, please navigate to "about:config" and set "dom.indexedDB.experimental" to true.'; + export const App: React.FC = () => { const location = useLocation(); + const [warnings, setWarnings] = useState([]); + const requester = useRequester(); + + useEffect(() => { + void (async () => { + const isDurable = await requester.sendMessage( + Ports.Background, + new CheckDurabilityMsg() + ); + if (!isDurable) { + setWarnings([...warnings, STORE_DURABILITY_INFO]); + } + })(); + }, []); + const { lockStatus, unlock, passwordInitialized } = useVaultContext(); const displayReturnButton = (): boolean => { @@ -39,12 +62,13 @@ export const App: React.FC = () => { !displayReturnButton() } returnButton={displayReturnButton()} + warnings={warnings} /> } > {shouldLock ? - : } + : } ); }; diff --git a/apps/extension/src/App/AppContent.tsx b/apps/extension/src/App/AppContent.tsx index 0b64a8fcb9..2b828053a6 100644 --- a/apps/extension/src/App/AppContent.tsx +++ b/apps/extension/src/App/AppContent.tsx @@ -1,13 +1,10 @@ -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { Route, Routes, useNavigate } from "react-router-dom"; -import { Alert, Stack } from "@namada/components"; +import { Stack } from "@namada/components"; import { DerivedAccount } from "@namada/types"; import { useAccountContext, useVaultContext } from "context"; import { useQuery } from "hooks"; -import { useRequester } from "hooks/useRequester"; -import { CheckDurabilityMsg } from "provider/messages"; -import { Ports } from "router"; import { openSetupTab } from "utils"; import { DeleteAccount, @@ -17,24 +14,21 @@ import { } from "./Accounts"; import { ParentAccounts } from "./Accounts/ParentAccounts"; import { ChangePassword, ConnectedSites, Network } from "./Settings"; +import { Warnings } from "./Settings/Warnings"; import { Setup } from "./Setup"; import routes from "./routes"; import { LoadingStatus } from "./types"; -const STORE_DURABILITY_INFO = - 'Store is not durable. This might cause problems when persisting data on disk.\ - To fix this issue, please navigate to "about:config" and set "dom.indexedDB.experimental" to true.'; - -export const AppContent = (): JSX.Element => { +type Props = { + warnings?: string[]; +}; +export const AppContent = ({ warnings }: Props): JSX.Element => { const { accounts, status: accountLoadingStatus } = useAccountContext(); const { passwordInitialized } = useVaultContext(); const query = useQuery(); const redirect = query.get("redirect"); const navigate = useNavigate(); - const requester = useRequester(); - - const [isDurable, setIsDurable] = useState(); const getStartPage = (accounts: DerivedAccount[]): string => { return accounts.length === 0 ? routes.setup() : routes.viewAccountList(); @@ -61,22 +55,8 @@ export const AppContent = (): JSX.Element => { } }, [accounts, passwordInitialized, accountLoadingStatus]); - useEffect(() => { - void (async () => { - const isDurable = await requester.sendMessage( - Ports.Background, - new CheckDurabilityMsg() - ); - setIsDurable(isDurable); - })(); - }, []); - return ( - {isDurable === false && ( - {STORE_DURABILITY_INFO} - )} - } /> } /> @@ -90,6 +70,10 @@ export const AppContent = (): JSX.Element => { } /> } /> + } + /> {/* Routes that depend on a parent account existing in storage */} {accounts.length > 0 && ( <> diff --git a/apps/extension/src/App/Common/AppHeader.tsx b/apps/extension/src/App/Common/AppHeader.tsx index ad7a1fa941..a2767c0c6d 100644 --- a/apps/extension/src/App/Common/AppHeader.tsx +++ b/apps/extension/src/App/Common/AppHeader.tsx @@ -9,12 +9,14 @@ type AppHeaderProps = { returnButton: boolean; settingsButton: boolean; lockButton: boolean; + warnings?: string[]; }; export const AppHeader = ({ returnButton, settingsButton, lockButton, + warnings, }: AppHeaderProps): JSX.Element => { const navigate = useNavigate(); const [open, setOpen] = useState(false); @@ -50,7 +52,11 @@ export const AppHeader = ({ )} - setOpen(false)} open={open} /> + setOpen(false)} + open={open} + warnings={warnings} + /> ); }; diff --git a/apps/extension/src/App/Common/AppHeaderNavigation.tsx b/apps/extension/src/App/Common/AppHeaderNavigation.tsx index cfa0dcb2ac..f3c9b265f2 100644 --- a/apps/extension/src/App/Common/AppHeaderNavigation.tsx +++ b/apps/extension/src/App/Common/AppHeaderNavigation.tsx @@ -3,17 +3,19 @@ import routes from "App/routes"; import clsx from "clsx"; import { useVaultContext } from "context"; import { FaDiscord, FaXTwitter } from "react-icons/fa6"; -import { GoQuestion } from "react-icons/go"; +import { GoAlert, GoQuestion } from "react-icons/go"; import { useNavigate } from "react-router-dom"; type AppHeaderNavigationProps = { open: boolean; onClose: () => void; + warnings?: string[]; }; export const AppHeaderNavigation = ({ open, onClose, + warnings, }: AppHeaderNavigationProps): JSX.Element => { const { lock } = useVaultContext(); const navigate = useNavigate(); @@ -47,6 +49,20 @@ export const AppHeaderNavigation = ({ { "!translate-x-0": open } )} > + {warnings && warnings.length > 0 && ( + goTo(routes.warnings)} + > + + + )} + - - - + + + + diff --git a/apps/extension/src/App/Settings/Warnings.tsx b/apps/extension/src/App/Settings/Warnings.tsx new file mode 100644 index 0000000000..cd9ec90c99 --- /dev/null +++ b/apps/extension/src/App/Settings/Warnings.tsx @@ -0,0 +1,23 @@ +import { Alert, GapPatterns, Stack } from "@namada/components"; +import { PageHeader } from "App/Common"; +import clsx from "clsx"; + +type Props = { + warnings?: string[]; +}; + +export const Warnings = ({ warnings }: Props): JSX.Element => { + return ( + + + + {warnings && + warnings.map((warning, i) => ( + + {warning} + + ))} + + + ); +}; diff --git a/apps/extension/src/App/routes.ts b/apps/extension/src/App/routes.ts index fede421b9b..cfe35f64b5 100644 --- a/apps/extension/src/App/routes.ts +++ b/apps/extension/src/App/routes.ts @@ -6,6 +6,7 @@ export default { changePassword: (): string => `/change-password`, connectedSites: (): string => `/connected-sites`, network: (): string => `/network`, + warnings: (): string => `/warnings`, viewAccountList: () => `/accounts/view`, viewAccountMnemonic: (accountId: string = ":accountId") => `/accounts/mnemonic/${accountId}`,