Skip to content

Commit

Permalink
feat: setting up advanced options
Browse files Browse the repository at this point in the history
  • Loading branch information
jurevans committed Oct 4, 2024
1 parent e524538 commit 09de813
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 56 deletions.
45 changes: 45 additions & 0 deletions apps/extension/src/Setup/Common/AdvancedOptions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Bip44Path } from "@namada/types";
import React, { useState } from "react";
import { AdvancedOptionsMenu } from "./AdvancedOptionsMenu";
import Bip39PassphraseForm from "./Bip39PassphraseForm";
import Bip44Form from "./Bip44Form";

type Props = {
path: Bip44Path;
passphrase: string;
setPath: (path: Bip44Path) => void;
setPassphrase: (passphrase: string) => void;
};

export enum Option {
Menu = "menu",
Passphrase = "passphrase",
Path = "path",
}

export const AdvancedOptions: React.FC<Props> = ({
path,
passphrase,
setPath,
setPassphrase,
}) => {
const [view, setView] = useState<Option>(Option.Menu);

return (
<div className="bg-black">
{view === Option.Menu && (
<AdvancedOptionsMenu
onPathClick={() => setView(Option.Path)}
onPassphraseClick={() => setView(Option.Passphrase)}
/>
)}
{view === Option.Path && <Bip44Form path={path} setPath={setPath} />}
{view === Option.Passphrase && (
<Bip39PassphraseForm
passphrase={passphrase}
setPassphrase={setPassphrase}
/>
)}
</div>
);
};
18 changes: 18 additions & 0 deletions apps/extension/src/Setup/Common/AdvancedOptionsMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Stack } from "@namada/components";
import React from "react";

type Props = {
onPathClick: () => void;
onPassphraseClick: () => void;
};
export const AdvancedOptionsMenu: React.FC<Props> = ({
onPathClick,
onPassphraseClick,
}) => {
return (
<Stack as="ul" gap={2} direction="vertical" className="[&_li]:text-white">
<li onClick={onPathClick}>Set Custom Derivation Path</li>
<li onClick={onPassphraseClick}>Import with BIP39 Passphrase</li>
</Stack>
);
};
42 changes: 42 additions & 0 deletions apps/extension/src/Setup/Common/Bip39PassphraseForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from "react";

import { Alert, Input, Stack } from "@namada/components";

type Props = {
passphrase: string;
setPassphrase: (passphrase: string) => void;
};

const Bip39PassphraseForm: React.FC<Props> = ({
passphrase,
setPassphrase,
}) => {
return (
<div className="flex flex-col w-full px-3">
<div className="mb-2 [&_input]:w-[92%]">
<div className="my-3">
<Alert type={"warning"} title={"Please note"} className="mb-3">
<Stack gap={6}>
<p className="text-[13px] leading-[1.25] text-white">
This import option is only users who have created a Namada
account using the Namada protocol CLI v.0.17.0 or older, and
used a BIP39 passphrase. Do not input your Namada extension
password
</p>
<Input
data-testid="setup-import-keys-passphrase-input"
label="Enter your passphrase"
placeholder="Optional passphrase for your seed phrase."
hideIcon={true}
onChange={(e) => setPassphrase(e.target.value)}
value={passphrase}
/>
</Stack>
</Alert>
</div>
</div>
</div>
);
};

export default Bip39PassphraseForm;
7 changes: 5 additions & 2 deletions apps/extension/src/Setup/Common/Bip44Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ type Props = {
};

const Bip44Form: React.FC<Props> = ({ path, setPath }) => {
const [customPath, setCustomPath] = useState(path);
const [customPath, setCustomPath] = useState({
...path,
index: 1,
});
const { coinType } = chains.namada.bip44;

const handleNumericChange = (
Expand All @@ -20,7 +23,7 @@ const Bip44Form: React.FC<Props> = ({ path, setPath }) => {
const result = e.target.value.replace(/\D/g, "") || "0";
setCustomPath({
...customPath,
[key]: result,
[key]: parseInt(result),
});
};

Expand Down
1 change: 1 addition & 0 deletions apps/extension/src/Setup/Common/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./AccountAlias";
export * from "./Bip39PassphraseForm";
export * from "./Bip44Form";
export * from "./Completion";
export * from "./ContainerHeader";
Expand Down
78 changes: 24 additions & 54 deletions apps/extension/src/Setup/ImportAccount/SeedPhraseImport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import {
RadioGroup,
Stack,
} from "@namada/components";
import { Bip44Path } from "@namada/types";
import { assertNever } from "@namada/utils";
import { SeedPhraseList } from "Setup/Common";
import { AccountSecret, ValidateMnemonicMsg } from "background/keyring";
import { useRequester } from "hooks/useRequester";
import { GoX } from "react-icons/go";
import { Ports } from "router";
import { SeedPhraseList } from "Setup/Common";
import { AdvancedOptions } from "Setup/Common/AdvancedOptions";
import { fillArray, filterPrivateKeyPrefix, validatePrivateKey } from "utils";

type Props = {
Expand All @@ -32,9 +33,15 @@ enum MnemonicTypes {
export const SeedPhraseImport: React.FC<Props> = ({ onConfirm }) => {
const requester = useRequester();
const [privateKey, setPrivateKey] = useState("");
const [showAdvanced, setShowAdvanced] = useState(false);
const [passphrase, setPassphrase] = useState("");
const [path, setPath] = useState<Bip44Path>({
account: 0,
change: 0,
index: 0,
});
const [bip39Passphrase, setBip39Passphrase] = useState("");
const [invalidWordIndex, setInvalidWordIndex] = useState<number>();
const [showPassphrase, setShowPassphrase] = useState(false);
const [mnemonicType, setMnemonicType] = useState<MnemonicTypes>(
MnemonicTypes.TwelveWords
);
Expand Down Expand Up @@ -68,7 +75,7 @@ export const SeedPhraseImport: React.FC<Props> = ({ onConfirm }) => {
const isSubmitButtonDisabled =
mnemonicType === MnemonicTypes.PrivateKey ?
privateKey === "" || privateKeyError !== ""
: mnemonics.slice(0, mnemonicType).some((mnemonic) => !mnemonic);
: mnemonics.slice(0, mnemonicType).some((mnemonic) => !mnemonic);

const onPaste = useCallback(
(index: number, e: React.ClipboardEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -146,31 +153,13 @@ export const SeedPhraseImport: React.FC<Props> = ({ onConfirm }) => {
setInvalidWordIndex(invalidWordIndex);
typeof invalidWordIndex === "number" ?
setMnemonicError(`Word #${invalidWordIndex + 1} is invalid!`)
: setMnemonicError(error);
: setMnemonicError(error);
} else {
setMnemonicError(error);
}
}
}
}, [mnemonics, mnemonicType, privateKey, passphrase, showPassphrase]);

const onPassphraseChange = useCallback(
(value: string) => {
setPassphrase(value);
},
[passphrase]
);

const onShowPassphraseChange = useCallback(
(e: React.MouseEvent) => {
e.preventDefault();
if (!showPassphrase) {
setPassphrase("");
}
setShowPassphrase(!showPassphrase);
},
[showPassphrase]
);
}, [mnemonics, mnemonicType, privateKey, passphrase, showAdvanced]);

return (
<>
Expand Down Expand Up @@ -215,7 +204,7 @@ export const SeedPhraseImport: React.FC<Props> = ({ onConfirm }) => {
]}
onChange={(value: string) => {
if (Number(value) === MnemonicTypes.PrivateKey) {
setShowPassphrase(false);
setShowAdvanced(false);
setPassphrase("");
}
setMnemonicType(Number(value));
Expand Down Expand Up @@ -246,41 +235,22 @@ export const SeedPhraseImport: React.FC<Props> = ({ onConfirm }) => {
)}
</Stack>
<Stack direction="vertical" gap={4}>
{showPassphrase && (
<div className="relative">
<div onClick={onShowPassphraseChange}>
<i className="block text-lg absolute top-5 right-4 text-white cursor-pointer">
<GoX />
</i>
</div>
<Alert type={"warning"} title={"Please note"} className="mb-3">
<Stack gap={6}>
<p className="text-[13px] leading-[1.25] text-white">
This import option is only users who have created a Namada
account using the Namada protocol CLI v.0.17.0 or older, and
used a BIP39 passphrase. Do not input your Namada extension
password
</p>
<Input
data-testid="setup-import-keys-passphrase-input"
label="Enter your passphrase"
placeholder="Optional passphrase for your seed phrase."
hideIcon={true}
onChange={(e) => onPassphraseChange(e.target.value)}
value={passphrase}
/>
</Stack>
</Alert>
</div>
{showAdvanced && (
<AdvancedOptions
path={path}
passphrase={bip39Passphrase}
setPath={setPath}
setPassphrase={setBip39Passphrase}
/>
)}
{!showPassphrase && mnemonicType !== MnemonicTypes.PrivateKey && (
{mnemonicType !== MnemonicTypes.PrivateKey && !showAdvanced && (
<LinkButton
data-testid="setup-import-keys-use-passphrase-button"
className="text-xs !text-neutral-400"
onClick={onShowPassphraseChange}
onClick={() => setShowAdvanced(true)}
type="button" // makes enter key ignore this and submit form
>
Import with BIP39 Passphrase
Advanced
</LinkButton>
)}
<ActionButton
Expand Down

0 comments on commit 09de813

Please sign in to comment.