Skip to content

Commit

Permalink
Add verification flow (#1827)
Browse files Browse the repository at this point in the history
  • Loading branch information
OKendigelyan authored Sep 5, 2024
1 parent 5e732fa commit e72eb4e
Show file tree
Hide file tree
Showing 38 changed files with 802 additions and 95 deletions.
5 changes: 4 additions & 1 deletion apps/web/src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ export { default as ChevronDownIcon } from "./chevron-down.svg";
export { default as ChevronRightIcon } from "./chevron-right.svg";
export { default as CloseIcon } from "./close.svg";
export { default as CodeSandboxIcon } from "./code-sandbox.svg";
export { default as CoinIcon } from "./coin.svg";
export { default as ContactIcon } from "./contact-s.svg";
export { default as ContractIcon } from "./contract.svg";
export { default as CopyIcon } from "./copy.svg";
export { default as CoinIcon } from "./coin.svg";
export { default as CrossedCircleIcon } from "./crossed-circle.svg";
export { default as DelegateIcon } from "./delegate-s.svg";
export { default as DownloadIcon } from "./download.svg";
Expand Down Expand Up @@ -42,10 +42,12 @@ export { default as MenuIcon } from "./menu.svg";
export { default as MoonIcon } from "./moon.svg";
export { default as MultisigIcon } from "./multisig.svg";
export { default as OutgoingArrowIcon } from "./outgoing-arrow.svg";
export { default as PencilIcon } from "./pencil.svg";
export { default as PlusIcon } from "./plus.svg";
export { default as PyramidIcon } from "./pyramid.svg";
export { default as RadioIcon } from "./radio.svg";
export { default as RedditIcon } from "./reddit.svg";
export { default as ScanIcon } from "./scan.svg";
export { default as SearchIcon } from "./search.svg";
export { default as SelectorIcon } from "./selector.svg";
export { default as SettingsIcon } from "./settings.svg";
Expand All @@ -60,6 +62,7 @@ export { default as UserIcon } from "./user.svg";
export { default as UserPlusIcon } from "./user-plus.svg";
export { default as VerifiedIcon } from "./verified.svg";
export { default as WalletIcon } from "./wallet.svg";
export { default as WindowCloseIcon } from "./window-close.svg";
export { TokenIcon } from "./TokenIcon";

import CloseIcon from "./close.svg";
Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/assets/icons/pencil.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions apps/web/src/assets/icons/scan.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions apps/web/src/assets/icons/window-close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion apps/web/src/components/AccountCard/AccountBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ArrowDownLeftIcon, WalletIcon } from "../../assets/icons";
import { useColor } from "../../styles/useColor";
import { AccountInfoModal } from "../AccountSelectorModal";
import { IconButtonWithText } from "../IconButtonWithText";
import { useIsAccountVerified } from "../Onboarding/useIsAccountVerified";
import { useIsAccountVerified } from "../Onboarding/VerificationFlow";

export const AccountBalance = () => {
const color = useColor();
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/AccountCard/SendTezButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useCurrentAccount } from "@umami/state";

import { ArrowUpRightIcon } from "../../assets/icons";
import { IconButtonWithText } from "../IconButtonWithText/IconButtonWithText";
import { useIsAccountVerified } from "../Onboarding/useIsAccountVerified";
import { useIsAccountVerified } from "../Onboarding/VerificationFlow";
import { FormPage as SendTezFormPage } from "../SendFlow/Tez/FormPage";

export const SendTezButton = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { useColor } from "../../styles/useColor";
import { AccountTile } from "../AccountTile";
import { ModalCloseButton } from "../CloseButton";
import { OnboardOptionsModal } from "../Onboarding/OnboardOptions";
import { useIsAccountVerified } from "../Onboarding/useIsAccountVerified";
import { useIsAccountVerified } from "../Onboarding/VerificationFlow";

export const AccountSelectorModal = () => {
const accounts = useImplicitAccounts();
Expand Down
27 changes: 0 additions & 27 deletions apps/web/src/components/EmptyMessage/VerifyMessage.test.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion apps/web/src/components/EmptyMessage/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { EmptyMessage } from "./EmptyMessage";
export { VerifyMessage } from "./VerifyMessage";
export type { EmptyMessageProps } from "./EmptyMessage";
2 changes: 1 addition & 1 deletion apps/web/src/components/Menu/AdvancedMenu/AdvancedMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useDynamicDrawerContext } from "@umami/components";

import { AlertCircleIcon, LockIcon, RadioIcon } from "../../../assets/icons";
import { useIsAccountVerified } from "../../Onboarding/useIsAccountVerified";
import { useIsAccountVerified } from "../../Onboarding/VerificationFlow";
import { ChangePasswordMenu } from "../ChangePasswordMenu/ChangePasswordMenu";
import { ErrorLogsMenu } from "../ErrorLogsMenu/ErrorLogsMenu";
import { GenericMenu } from "../GenericMenu";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
UserPlusIcon,
} from "../../assets/icons";
import { OnboardOptionsModal } from "../Onboarding/OnboardOptions";
import { useIsAccountVerified } from "../Onboarding/useIsAccountVerified";
import { useIsAccountVerified } from "../Onboarding/VerificationFlow";

export const Menu = () => {
const { openWith: openModal } = useDynamicModalContext();
Expand Down
43 changes: 43 additions & 0 deletions apps/web/src/components/MnemonicWord/MnemonicWord.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { GridItem, type GridItemProps, Text } from "@chakra-ui/react";
import { MnemonicAutocomplete } from "@umami/components";
import { type ComponentProps } from "react";

import { useColor } from "../../styles/useColor";

type MnemonicWordProps = {
index: number;
word?: string;
autocompleteProps?: ComponentProps<typeof MnemonicAutocomplete>;
} & GridItemProps;

export const MnemonicWord = ({ index, word, autocompleteProps, ...props }: MnemonicWordProps) => {
const color = useColor();

return (
<GridItem {...props}>
<Text
position="absolute"
zIndex={1}
marginTop={{ lg: "11px", base: "8px" }}
marginLeft={{ lg: "16px", base: "10px" }}
color={color("300")}
textAlign="right"
size={{ lg: "lg", base: "xs" }}
>
{String(index + 1).padStart(2, "0")}.
</Text>
{autocompleteProps && <MnemonicAutocomplete {...autocompleteProps} />}
{word && (
<Text
alignSelf="center"
paddingRight="10px"
paddingLeft={{ base: "30px", lg: "48px" }}
fontSize={{ base: "xs", lg: "lg" }}
fontWeight="medium"
>
{word}
</Text>
)}
</GridItem>
);
};
1 change: 1 addition & 0 deletions apps/web/src/components/MnemonicWord/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { MnemonicWord } from "./MnemonicWord";
32 changes: 11 additions & 21 deletions apps/web/src/components/Onboarding/ImportWallet/SeedPhraseTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,18 @@ import {
Button,
Flex,
Grid,
GridItem,
Heading,
Icon,
Text,
} from "@chakra-ui/react";
import { MnemonicAutocomplete, useDynamicModalContext, useMultiForm } from "@umami/components";
import { useDynamicModalContext, useMultiForm } from "@umami/components";
import { useAsyncActionHandler } from "@umami/state";
import { validateMnemonic } from "bip39";
import { range } from "lodash";
import { FormProvider, useFieldArray } from "react-hook-form";

import { CloseIcon } from "../../../assets/icons";
import { useColor } from "../../../styles/useColor";
import { MnemonicWord } from "../../MnemonicWord";
import { RadioButtons } from "../../RadioButtons";
import { SetupPassword } from "../SetupPassword";

Expand Down Expand Up @@ -114,21 +113,11 @@ export const SeedPhraseTab = () => {

<Grid gridRowGap="16px" gridColumnGap="12px" gridTemplateColumns="repeat(3, 1fr)">
{fields.map((field, index) => (
<GridItem key={field.id}>
<Text
position="absolute"
zIndex={1}
marginTop={{ lg: "10px", base: "8px" }}
marginLeft={{ lg: "16px", base: "10px" }}
color={color("black")}
textAlign="right"
size={{ lg: "lg", base: "xs" }}
>
{String(index + 1).padStart(2, "0")}.
</Text>
<MnemonicAutocomplete
inputName={`mnemonic.${index}.val`}
inputProps={{
<MnemonicWord
key={field.id}
autocompleteProps={{
inputName: `mnemonic.${index}.val`,
inputProps: {
...register(`mnemonic.${index}.val`, { required: true }),
// eslint-disable-next-line @typescript-eslint/no-misused-promises
onPaste: async e => {
Expand All @@ -137,9 +126,10 @@ export const SeedPhraseTab = () => {
},
variant: "mnemonic",
placeholder: `word #${index + 1}`,
}}
/>
</GridItem>
},
}}
index={index}
/>
))}
</Grid>
<Button gap="4px" onClick={clearAll} variant="ghost">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const OnboardOptions = ({ children }: PropsWithChildren) => {
const { openWith } = useDynamicModalContext();

return (
<Flex alignItems="center" flexDirection="column">
<Flex alignItems="center" flexDirection="column" width="full">
<Heading color={color("900")} size="lg">
Continue with:
</Heading>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,41 @@ import {
type UmamiStore,
generate24WordMnemonic,
makeStore,
useGetDecryptedMnemonic,
useIsPasswordSet,
useRestoreFromMnemonic,
useRestoreFromSecretKey,
} from "@umami/state";
import { mnemonic1 } from "@umami/test-utils";

import { SetupPassword } from "./SetupPassword";
import { act, fireEvent, renderInModal, screen, userEvent, waitFor } from "../../../testUtils";
import {
act,
dynamicModalContextMock,
fireEvent,
renderInModal,
screen,
userEvent,
waitFor,
} from "../../../testUtils";
import { CURVES } from "../AdvancedAccountSettings";
import { ImportantNoticeModal } from "../VerificationFlow/ImportantNoticeModal";

jest.mock("@umami/state", () => ({
...jest.requireActual("@umami/state"),
useRestoreFromMnemonic: jest.fn(),
useRestoreFromSecretKey: jest.fn(),
generate24WordMnemonic: jest.fn(),
useGetDecryptedMnemonic: jest.fn(),
useIsPasswordSet: jest.fn(),
}));

const password = "password";

beforeEach(() => {
jest.mocked(useGetDecryptedMnemonic).mockReturnValue(() => Promise.resolve(mnemonic1));
});

describe("<SetupPassword />", () => {
describe.each(["mnemonic", "secret_key"] as const)("%s mode", mode => {
describe("validations", () => {
Expand Down Expand Up @@ -250,4 +267,26 @@ describe("<SetupPassword />", () => {
});
});
});

describe("verification mode", () => {
it("renders the verification screen", async () => {
jest.mocked(useIsPasswordSet).mockReturnValue(true);
const { openWith } = dynamicModalContextMock;
const user = userEvent.setup();

await renderInModal(<SetupPassword mode="verification" />);

const passwordInput = screen.getByLabelText("Password");

await act(() => user.type(passwordInput, password));

const submitButton = screen.getByRole("button", { name: "Confirm" });

await act(() => user.click(submitButton));

expect(openWith).toHaveBeenCalledWith(<ImportantNoticeModal mnemonic={mnemonic1} />, {
size: "xl",
});
});
});
});
Loading

1 comment on commit e72eb4e

@github-actions
Copy link

Choose a reason for hiding this comment

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

Title Lines Statements Branches Functions
apps/desktop Coverage: 84%
83.95% (1789/2131) 79.09% (840/1062) 78.57% (451/574)
apps/web Coverage: 84%
83.95% (1789/2131) 79.09% (840/1062) 78.57% (451/574)
packages/components Coverage: 96%
96.89% (125/129) 98.07% (51/52) 84.21% (32/38)
packages/core Coverage: 82%
83.05% (196/236) 73.55% (89/121) 82.14% (46/56)
packages/crypto Coverage: 100%
100% (28/28) 100% (3/3) 100% (5/5)
packages/data-polling Coverage: 98%
96.55% (140/145) 95.45% (21/22) 92.85% (39/42)
packages/multisig Coverage: 98%
98.4% (123/125) 89.47% (17/19) 100% (33/33)
packages/social-auth Coverage: 100%
100% (21/21) 100% (11/11) 100% (3/3)
packages/state Coverage: 84%
83.64% (772/923) 80.78% (164/203) 78.22% (291/372)
packages/tezos Coverage: 86%
85.57% (89/104) 89.47% (17/19) 82.75% (24/29)
packages/tzkt Coverage: 86%
84.05% (58/69) 81.25% (13/16) 76.92% (30/39)

Please sign in to comment.