Skip to content

Commit

Permalink
Simplifying code with Context API (anoma#440)
Browse files Browse the repository at this point in the history
* feat(extension): using React context to manage state

* refactor(extension): removing unused component

* refactor(extension, app): refactoring route management

* New pages: Rename key, View Mnemonic, and fixing bugs (anoma#441)

* feat(extension, app): adding Vault context

* feat(extension): creating view mnemonic page

* feat(extension, setup): reflecting changes on SeedPhraseInstructions and reusing a few components

* feat(extension): fixing inital loading state

* feat(extension): adding rename page

* feat(extension): adding navigation menu

* feat(extension): handling passwords with session storage

* feat(extension): storing hashed password in session storage

* feat(extension,app): adding back some global styles

* refactor(extension, app): making ViewAccount code clearer

* fix(extension,app): fixing 404 route
  • Loading branch information
pedrorezende authored Nov 14, 2023
1 parent c890c2d commit 95022f6
Show file tree
Hide file tree
Showing 60 changed files with 1,346 additions and 591 deletions.
3 changes: 2 additions & 1 deletion apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"buffer": "^6.0.3",
"dompurify": "^3.0.2",
"framer-motion": "6.2.4",
"js-sha256": "^0.10.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^6.0.0",
Expand All @@ -66,7 +67,7 @@
"@types/react-dom": "^17.0.11",
"@types/styled-components": "^5.1.26",
"@types/uuid": "^8.3.4",
"@types/webextension-polyfill": "^0.9.0",
"@types/webextension-polyfill": "^0.10.6",
"@types/zxcvbn": "^4.4.1",
"copy-webpack-plugin": "^11.0.0",
"dotenv": "^16.0.3",
Expand Down
33 changes: 13 additions & 20 deletions apps/extension/src/App/Accounts/DeleteAccount/DeleteAccount.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { useCallback, useEffect, useState } from "react";
import { useCallback, useContext, useEffect, useState } from "react";

import { AccountType, DerivedAccount } from "@namada/types";
import { CheckPasswordMsg } from "background/vault";
import { AccountContext } from "context";
import { useRequester } from "hooks/useRequester";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { Ports } from "router";
import routes from "App/routes";

import {
ActionButton,
Expand All @@ -11,13 +19,6 @@ import {
Stack,
Text,
} from "@namada/components";
import { AccountType, DerivedAccount } from "@namada/types";
import { formatRouterPath } from "@namada/utils";
import { AccountManagementRoute, TopLevelRoute } from "App/types";
import { CheckPasswordMsg } from "background/vault";
import { useRequester } from "hooks/useRequester";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { Ports } from "router";

enum Status {
Unsubmitted,
Expand All @@ -26,18 +27,15 @@ enum Status {
Failed,
}

export type Props = {
onDelete: (accountId: string) => void;
};

export type DeleteAccountLocationState = {
account?: DerivedAccount;
};

export const DeleteAccount: React.FC<Props> = ({ onDelete }) => {
export const DeleteAccount = (): JSX.Element => {
// TODO: When state is not passed, query by accountId
const { state }: { state: DeleteAccountLocationState } = useLocation();
const { accountId = "" } = useParams();
const { remove: onRemoveAccount } = useContext(AccountContext);

const [password, setPassword] = useState("");
const [status, setStatus] = useState<Status>(Status.Unsubmitted);
Expand Down Expand Up @@ -71,7 +69,7 @@ export const DeleteAccount: React.FC<Props> = ({ onDelete }) => {
return;
}

await onDelete(accountId);
await onRemoveAccount(accountId);
} catch (error) {
setLoadingState("");
setErrorMessage(`${error}`);
Expand All @@ -83,12 +81,7 @@ export const DeleteAccount: React.FC<Props> = ({ onDelete }) => {

useEffect(() => {
if (!accountId || !state.account) {
navigate(
formatRouterPath([
TopLevelRoute.Accounts,
AccountManagementRoute.ViewAccounts,
])
);
navigate(routes.viewAccountList());
}
}, [accountId, state]);

Expand Down
75 changes: 23 additions & 52 deletions apps/extension/src/App/Accounts/ParentAccounts.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import { useContext } from "react";
import { useNavigate } from "react-router-dom";
import browser from "webextension-polyfill";

Expand All @@ -7,66 +7,45 @@ import {
GapPatterns,
Heading,
KeyListItem,
LinkButton,
Stack,
Text,
} from "@namada/components";
import { DerivedAccount } from "@namada/types";
import { formatRouterPath } from "@namada/utils";
import routes from "App/routes";
import { ParentAccount } from "background/keyring";
import { AccountManagementRoute, TopLevelRoute } from "../types";
import { AccountContext } from "context";
import { useVaultContext } from "context/VaultContext";
import { SettingsHeader } from "./ParentAccounts.components";

type ParentAccountsProps = {
activeAccountId: string;
parentAccounts: DerivedAccount[];
onChangeActiveAccount: (
accountId: string,
accountType: ParentAccount
) => void;
onLockApp: () => void;
};

/**
* Represents the extension's settings page.
*/
export const ParentAccounts: React.FC<ParentAccountsProps> = ({
activeAccountId,
onLockApp,
parentAccounts,
onChangeActiveAccount,
}) => {
export const ParentAccounts = (): JSX.Element => {
const navigate = useNavigate();
const { lock } = useVaultContext();
const { activeAccountId, parentAccounts, changeActiveAccountId } =
useContext(AccountContext);

const goToSetupPage = (): void => {
browser.tabs.create({
url: browser.runtime.getURL("setup.html"),
});
};

const goToViewAccount = (account: DerivedAccount): void => {
navigate(
formatRouterPath([
TopLevelRoute.Accounts,
AccountManagementRoute.ViewAccount.replace(
":accountId",
account.id
).replace(":type", account.type),
])
);
navigate(routes.viewAccount(account.id));
};

const goToDeletePage = (account: DerivedAccount): void => {
navigate(
formatRouterPath([
TopLevelRoute.Accounts,
AccountManagementRoute.DeleteAccount.replace(":accountId", account.id),
]),
{ state: { account } }
);
navigate(routes.deleteAccount(account.id), { state: { account } });
};

const goToViewRecoveryPhrase = (account: DerivedAccount): void => {
navigate(routes.viewAccountMnemonic(account.id));
};

const goToConnectedSites = (): void => {
navigate(formatRouterPath([TopLevelRoute.ConnectedSites]));
const goToRenameAccount = (account: DerivedAccount): void => {
navigate(routes.renameAccount(account.id), { state: { account } });
};

return (
Expand All @@ -85,32 +64,24 @@ export const ParentAccounts: React.FC<ParentAccountsProps> = ({
key={`key-listitem-${account.id}`}
as="li"
alias={account.alias}
type={account.type}
isMainKey={activeAccountId === account.id}
onRename={() => {}}
onRename={() => goToRenameAccount(account)}
onDelete={() => goToDeletePage(account)}
onViewAccount={() => goToViewAccount(account)}
onViewRecoveryPhrase={() => goToViewRecoveryPhrase(account)}
onSelectAccount={() => {
onChangeActiveAccount(
changeActiveAccountId(
account.id,
account.type as ParentAccount
);
}}
/>
))}
</Stack>
<ActionButton
onClick={goToConnectedSites}
variant="secondary"
size="sm"
>
View Connected Sites
</ActionButton>
<ActionButton onClick={() => navigate("/change-password")} size="sm">
Change password
</ActionButton>
<LinkButton onClick={onLockApp} size="sm">
<ActionButton onClick={() => lock()} variant="secondary" size="sm">
Lock Wallet
</LinkButton>
</ActionButton>
</Stack>
</Stack>
);
Expand Down
73 changes: 73 additions & 0 deletions apps/extension/src/App/Accounts/RenameAccount/RenameAccount.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {
Input,
GapPatterns,
Heading,
Stack,
ActionButton,
} from "@namada/components";
import routes from "App/routes";
import { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { DerivedAccount } from "@namada/types";
import { useAccountContext } from "context";

type RenameAccountParamsType = {
accountId: string;
};

export const RenameAccount = (): JSX.Element => {
const { accountId } = useParams<RenameAccountParamsType>();
const { getById, rename } = useAccountContext();
const [account, setAccount] = useState<DerivedAccount | undefined>();
const [error, setError] = useState("");
const [alias, setAlias] = useState("");

const navigate = useNavigate();

const handleSubmit = async (e: React.FormEvent): Promise<void> => {
e.preventDefault();

try {
if (!accountId) {
throw new Error("Invalid account id");
}
await rename(accountId, alias);
} catch (err) {
setError(`${err}`);
}
};

useEffect(() => {
if (!accountId) {
navigate(routes.viewAccountList());
return;
}

const account = getById(accountId);
if (!account) {
throw new Error("Invalid account provided");
}

setAccount(account);
}, [accountId]);

return (
<Stack gap={GapPatterns.TitleContent}>
<Heading>Rename Key</Heading>
{account && (
<Stack as="form" gap={GapPatterns.FormFields} onSubmit={handleSubmit}>
<Input readOnly label="Current name" value={account.alias} />
<Input
autoFocus
label="New name"
placeholder="Ex: Special Account"
value={alias}
onChange={(e) => setAlias(e.target.value)}
error={error}
/>
<ActionButton>Rename</ActionButton>
</Stack>
)}
</Stack>
);
};
1 change: 1 addition & 0 deletions apps/extension/src/App/Accounts/RenameAccount/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./RenameAccount";
Loading

0 comments on commit 95022f6

Please sign in to comment.