Skip to content

Commit

Permalink
feat: notify about needed account re import (#1452)
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuszjasiuk authored Jan 3, 2025
1 parent 1945c61 commit f27adef
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 80 deletions.
124 changes: 79 additions & 45 deletions apps/extension/src/App/Accounts/ParentAccounts.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useContext } from "react";
import { useNavigate } from "react-router-dom";
import { useContext, useEffect } from "react";
import { Outlet, useNavigate } from "react-router-dom";

import {
ActionButton,
GapPatterns,
KeyListItem,
Stack,
} from "@namada/components";
import { DerivedAccount } from "@namada/types";
import { AccountType, DerivedAccount } from "@namada/types";
import { ParentAccountsFooter } from "App/Accounts/ParentAccountsFooter";
import { PageHeader } from "App/Common";
import routes from "App/routes";
Expand All @@ -20,8 +20,37 @@ import { openSetupTab } from "utils";
*/
export const ParentAccounts = (): JSX.Element => {
const navigate = useNavigate();
const { activeAccountId, parentAccounts, changeActiveAccountId } =
useContext(AccountContext);
const {
activeAccountId,
parentAccounts,
accounts: allAccounts,
changeActiveAccountId,
} = useContext(AccountContext);

// We check which accounts need to be re-imported
const accounts = allAccounts
.filter(
(account) => account.parentId || account.type === AccountType.Ledger
)
.map((account) => {
const outdated =
account.type !== AccountType.Ledger &&
typeof account.pseudoExtendedKey === "undefined";

// The only account without a parent is the ledger account
const parent =
parentAccounts.find((pa) => pa.id === account.parentId) || account;

return { ...parent, outdated };
});

useEffect(() => {
const hasOutdatedAccounts = accounts.some((account) => account.outdated);
// If there are outdated accounts, we redirect to the update required page
if (hasOutdatedAccounts) {
navigate(routes.accountsUpdateRequired());
}
}, []);

const goToSetupPage = async (): Promise<void> => {
await openSetupTab();
Expand All @@ -44,47 +73,52 @@ export const ParentAccounts = (): JSX.Element => {
};

return (
<Stack
gap={GapPatterns.TitleContent}
full
className="max-h-[calc(100vh-40px)]"
>
<PageHeader title="Select Account" />
<Stack gap={4} className="flex-1 overflow-auto">
<nav className="grid items-end grid-cols-[auto_min-content]">
<p className="text-white font-medium text-xs">Set default keys</p>
<div className="w-26">
<ActionButton size="xs" onClick={goToSetupPage}>
Add Keys
</ActionButton>
</div>
</nav>
<Stack as="ul" gap={3} className="flex-1 overflow-auto">
{[...parentAccounts].reverse().map((account, idx) => (
<KeyListItem
key={`key-listitem-${account.id}`}
as="li"
alias={account.alias}
type={account.type}
dropdownPosition={
idx > 2 && idx > parentAccounts.length - 4 ? "bottom" : "top"
}
isMainKey={activeAccountId === account.id}
onRename={() => goToRenameAccount(account)}
onDelete={() => goToDeletePage(account)}
onViewAccount={() => goToViewAccount(account)}
onViewRecoveryPhrase={() => goToViewRecoveryPhrase(account)}
onSelectAccount={() => {
changeActiveAccountId(
account.id,
account.type as ParentAccount
);
}}
/>
))}
<>
<Stack
gap={GapPatterns.TitleContent}
full
className="max-h-[calc(100vh-40px)]"
>
<PageHeader title="Select Account" />
<Stack gap={4} className="flex-1 overflow-auto">
<nav className="grid items-end grid-cols-[auto_min-content]">
<p className="text-white font-medium text-xs">Set default keys</p>
<div className="w-26">
<ActionButton size="xs" onClick={goToSetupPage}>
Add Keys
</ActionButton>
</div>
</nav>
<Stack as="ul" gap={3} className="flex-1 overflow-auto">
{[...accounts].reverse().map((account, idx) => (
<KeyListItem
key={`key-listitem-${account.id}`}
as="li"
alias={account.alias}
type={account.type}
outdated={account.outdated}
dropdownPosition={
idx > 2 && idx > accounts.length - 4 ? "bottom" : "top"
}
isMainKey={activeAccountId === account.id}
onRename={() => goToRenameAccount(account)}
onDelete={() => goToDeletePage(account)}
onViewAccount={() => goToViewAccount(account)}
onViewRecoveryPhrase={() => goToViewRecoveryPhrase(account)}
onSelectAccount={() => {
changeActiveAccountId(
account.id,
account.type as ParentAccount
);
}}
/>
))}
</Stack>
<ParentAccountsFooter />
</Stack>
<ParentAccountsFooter />
</Stack>
</Stack>

<Outlet />
</>
);
};
88 changes: 88 additions & 0 deletions apps/extension/src/App/Accounts/UpdateRequired.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import clsx from "clsx";
import { IoClose } from "react-icons/io5";
import { PiWarning } from "react-icons/pi";
import { useNavigate } from "react-router-dom";

import { Modal, Stack } from "@namada/components";
import routes from "App/routes";
import updateRequried from "./assets/update-required.png";

export const UpdateRequired = (): JSX.Element => {
const navigate = useNavigate();

const onCloseModal = (): void => {
navigate(routes.viewAccountList());
};

return (
<Modal
onClose={onCloseModal}
className={clsx(
"w-full left-auto right-0 top-0 bottom-0 translate-x-0",
"translate-y-0 pointer-events-none",
"p-5"
)}
>
<div
className={clsx(
"flex flex-col pointer-events-auto",
"w-full h-full",
"bg-rblack border rounded-md border-yellow-300 p-3"
)}
>
<header className="relative">
<button
onClick={onCloseModal}
className="absolute right-0 top-3 flex items-center h-full text-2xl text-white hover:text-yellow"
>
<IoClose />
</button>
</header>
<div className="flex flex-1">
<Stack className="px-5">
<Stack gap={1}>
<img
src={updateRequried}
alt=""
className="w-[108px] self-center mt-2"
/>
<h1 className="text-white text-center text-md">
Account update required!
</h1>
</Stack>
<p className="text-yellow text-center">
Accounts marked with an exclamation symbol
<br />
<span className="font-md">
(<PiWarning className="inline w-[14px] h-[14px]" />){" "}
</span>
need to be re-imported to support shielded transfers.*
</p>
<Stack className="p-5 rounded-md bg-neutral-900 text-white" gap={2}>
<h2 className="font-medium">To Re-import your account:</h2>
<ol className="list-decimal pl-3 pr-1 space-y-2">
<li>
If necessary. Re-copy and note
down your seed phrase / private
key
<br />
<span className="text-yellow">
Accounts CAN NOT be re-imported without the seed phrase
</span>
</li>
<li>Delete the marked account from 
the keychain</li>
<li>
Re-Import the account using your seed phrase / private key
</li>
</ol>
</Stack>
<p className="text-yellow text-center leading-3">
* Ledger accounts will receive shielded
<br /> functions in a separate update in an
<br /> upcoming release
</p>
</Stack>
</div>
</div>
</Modal>
);
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/extension/src/App/Accounts/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./DeleteAccount";
export * from "./RenameAccount";
export * from "./UpdateRequired";
export * from "./ViewAccount";
export * from "./ViewMnemonic";
11 changes: 7 additions & 4 deletions apps/extension/src/App/AppContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { openSetupTab } from "utils";
import {
DeleteAccount,
RenameAccount,
UpdateRequired,
ViewAccount,
ViewMnemonic,
} from "./Accounts";
Expand Down Expand Up @@ -86,10 +87,12 @@ export const AppContent = ({ warnings }: Props): JSX.Element => {
path={routes.viewAccountMnemonic()}
element={<ViewMnemonic />}
/>
<Route
path={routes.viewAccountList()}
element={<ParentAccounts />}
/>
<Route path={routes.viewAccountList()} element={<ParentAccounts />}>
<Route
path={routes.accountsUpdateRequired()}
element={<UpdateRequired />}
/>
</Route>
</>
)}
</Routes>
Expand Down
1 change: 1 addition & 0 deletions apps/extension/src/App/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default {
network: (): string => `/network`,
warnings: (): string => `/warnings`,
viewAccountList: () => `/accounts/view`,
accountsUpdateRequired: () => `/accounts/view/update-required`,
viewAccountMnemonic: (accountId: string = ":accountId") =>
`/accounts/mnemonic/${accountId}`,
viewAccount: (accountId: string = ":accountId") =>
Expand Down
1 change: 1 addition & 0 deletions apps/extension/src/react-app.env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "*.png";
8 changes: 8 additions & 0 deletions apps/extension/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ module.exports = {
and: [/\.(ts|tsx|md)$/],
},
},
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: require.resolve("file-loader"),
},
],
},
],
},
resolve: {
Expand Down
Loading

1 comment on commit f27adef

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.