Skip to content

Commit

Permalink
feat/253 - Ledger connection setup page (anoma#274)
Browse files Browse the repository at this point in the history
* Add main dependency

* Add basic pages for Ledger connection flow

* Continue refactoring routes for Setup pages in extension

* Add placeholder route and components for Import Account

* Remove BrowserRouter

* Update routes to support original flow

* Fix back-button issue on AccountCreation

* minor styling

* Adding test code to launch USB approval screen for Ledger

* Add basic Ledger class and connection form with alias

* Fix encoding type for public key

* Make alias required in Account Creation, fix alias+path formatting

* Minor clean up

* Complete basic functions of Ledger class

* Only return publicKey in hex for now

* Provide alternate transport to init method, add user feedback on success

* Clean up

* Final clean up before updating versions

* Refactor styled components to re-use common components

* Further updates to make setup processes consistent

* Fix improper nesting

* buttons on Ledger form should be conditional

* Updated to support NamadaApp v0.0.4

* Add back reference to slip-044 doc

* clean up
  • Loading branch information
jurevans authored May 23, 2023
1 parent c805cbd commit 25488fb
Show file tree
Hide file tree
Showing 35 changed files with 886 additions and 613 deletions.
5 changes: 5 additions & 0 deletions apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
"@anoma/types": "0.1.0",
"@anoma/utils": "0.1.0",
"@cosmjs/encoding": "^0.29.0",
"@ledgerhq/hw-transport": "^6.28.3",
"@ledgerhq/hw-transport-webhid": "^6.27.14",
"@ledgerhq/hw-transport-webusb": "^6.27.14",
"@zondax/ledger-namada": "^0.0.2",
"buffer": "^6.0.3",
"dompurify": "^3.0.2",
"framer-motion": "6.2.4",
Expand Down Expand Up @@ -70,6 +74,7 @@
"file-loader": "^6.2.0",
"jest": "^29.0.1",
"jest-environment-jsdom": "^29.3.1",
"leb128": "^0.0.5",
"merge-jsons-webpack-plugin": "^2.0.1",
"mockzilla": "^0.14.0",
"rimraf": "^3.0.2",
Expand Down
10 changes: 10 additions & 0 deletions apps/extension/src/App/Accounts/AccountListing.components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,18 @@ export const Details = styled.div`
flex: 3;
`;

export const DerivationPathContainer = styled.div`
display: flex;
flex-direction: row;
`;

export const DerivationPath = styled.div``;

export const ParentAlias = styled.div`
font-weight: 600;
padding-right: 4px;
`;

export const Address = styled.div`
font-family: monospace;
font-size: 10px;
Expand Down
12 changes: 8 additions & 4 deletions apps/extension/src/App/Accounts/AccountListing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
Alias,
DerivationPath,
Button,
ParentAlias,
DerivationPathContainer,
} from "./AccountListing.components";
import { shortenAddress } from "@anoma/utils";

Expand Down Expand Up @@ -45,10 +47,12 @@ const AccountListing = ({ account, parentAlias }: Props): JSX.Element => {
return (
<AccountListingContainer>
<Details>
<DerivationPath>
{isChildAccount && parentAlias}
{formatDerivationPath(isChildAccount, path, type)}
</DerivationPath>
<DerivationPathContainer>
{isChildAccount && <ParentAlias>{parentAlias}</ParentAlias>}
<DerivationPath>
{formatDerivationPath(isChildAccount, path, type)}
</DerivationPath>
</DerivationPathContainer>
{alias && <Alias>{alias}</Alias>}
<Address>{shortenAddress(address)}</Address>
</Details>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,50 +1,4 @@
import styled from "styled-components";
import { motion } from "framer-motion";

export const AccountCreationContainer = styled.div`
display: flex;
flex-direction: column;
justify-content: start;
align-items: center;
box-sizing: border-box;
background-color: ${(props) => props.theme.colors.utility1.main80};
border: 1px solid ${(props) => props.theme.colors.utility1.main80};
border-radius: 8px;
color: ${(props) => props.theme.colors.utility2.main80};
padding: 0 36px;
height: 100%;
min-height: 400px;
width: 480px;
transition: background-color 0.3s linear;
`;

export const MotionContainer = styled(motion.div)`
height: 100%;
box-sizing: border-box;
`;

export const TopSection = styled.section`
display: flex;
justify-content: start;
align-items: center;
width: 100%;
margin: 32px 0;
`;

export const TopSectionHeaderContainer = styled.section`
display: flex;
justify-content: center;
width: 100%;
align-items: center;
`;

export const TopSectionButtonContainer = styled.section`
display: flex;
justify-content: center;
align-items: center;
width: 48px;
min-height: 50px;
`;

export const RouteContainer = styled.div`
display: flex;
Expand Down
193 changes: 16 additions & 177 deletions apps/extension/src/Setup/AccountCreation/AccountCreation.tsx
Original file line number Diff line number Diff line change
@@ -1,207 +1,46 @@
import React, { useState, useEffect, useContext } from "react";
import { Routes, Route, useNavigate, useLocation } from "react-router-dom";
import React, { useContext } from "react";
import { useNavigate, Outlet } from "react-router-dom";
import { AnimatePresence } from "framer-motion";
import { ThemeContext } from "styled-components";

import { ExtensionRequester } from "extension";
import { AccountCreationRoute, accountCreationSteps } from "./types";

import { Icon, IconName, IconSize } from "@anoma/components";
import { RouteContainer } from "./AccountCreation.components";
import {
Start,
Password,
SeedPhrase,
SeedPhraseConfirmation,
Completion,
} from "./Steps";
import {
AccountCreationContainer,
TopSection,
TopSectionHeaderContainer,
TopSectionButtonContainer,
RouteContainer,
MotionContainer,
} from "./AccountCreation.components";
import { AccountCreationDetails } from "Setup/AccountCreation/types";

type AnimatedTransitionProps = {
elementKey: string;
children: JSX.Element;
};

/**
* This is a utility to facilitate the animated transitions.
*/
const AnimatedTransition: React.FC<AnimatedTransitionProps> = (props) => {
const { children, elementKey } = props;
return (
<MotionContainer
key={elementKey}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
{children}
</MotionContainer>
);
};

type Props = {
requester: ExtensionRequester;
};
SubViewContainer,
} from "Setup/Setup.components";

/**
* The main purpose of this is to coordinate the flow for creating a new account.
* It persists the data between the screens in the flow.
*/
const AccountCreation: React.FC<Props> = ({ requester }) => {
const [accountCreationDetails, setAccountCreationDetails] =
useState<AccountCreationDetails>({
alias: "",
});
const [seedPhrase, setSeedPhrase] = useState<string[]>();
const [stepIndex, setStepIndex] = useState(0);

const AccountCreation: React.FC = () => {
const themeContext = useContext(ThemeContext);
const navigate = useNavigate();

const location = useLocation();

// info for disabling the back button in the last step
const isLastIndex = accountCreationSteps.length - 1 === stepIndex;

useEffect(() => {
// at the load we redirect to the first step
// this way we do not need to expose the flow routes to outside
navigate(AccountCreationRoute.Start);
}, []);

const navigateToNext = (): void => {
setStepIndex((stepIndex) => stepIndex + 1);
navigate(`${accountCreationSteps[stepIndex + 1]}`);
};

const navigateToPrevious = (): void => {
setStepIndex((stepIndex) => {
return stepIndex - 1;
});
navigate(`${accountCreationSteps[stepIndex - 1]}`);
};

return (
<AccountCreationContainer>
<SubViewContainer>
<TopSection>
<TopSectionButtonContainer>
{!isLastIndex && stepIndex !== 0 && (
<a
onClick={() => {
navigateToPrevious();
}}
style={{ cursor: "pointer" }}
>
<Icon
iconName={IconName.ChevronLeft}
strokeColorOverride={themeContext.colors.utility2.main60}
iconSize={IconSize.L}
/>
</a>
)}
<a onClick={() => navigate(-1)} style={{ cursor: "pointer" }}>
<Icon
iconName={IconName.ChevronLeft}
strokeColorOverride={themeContext.colors.utility2.main60}
iconSize={IconSize.L}
/>
</a>
</TopSectionButtonContainer>
<TopSectionHeaderContainer></TopSectionHeaderContainer>
<TopSectionButtonContainer></TopSectionButtonContainer>
</TopSection>
<RouteContainer>
<AnimatePresence exitBeforeEnter>
<Routes location={location} key={location.pathname}>
<Route
path={`/${AccountCreationRoute.Start}`}
element={
<AnimatedTransition elementKey={AccountCreationRoute.Start}>
<Start
onClick={() => {
navigateToNext();
}}
/>
</AnimatedTransition>
}
/>

<Route
path={`/${AccountCreationRoute.SeedPhrase}`}
element={
<AnimatedTransition
elementKey={AccountCreationRoute.SeedPhrase}
>
<SeedPhrase
requester={requester}
accountCreationDetails={accountCreationDetails}
defaultSeedPhrase={seedPhrase}
onConfirm={(seedPhrase: string[]) => {
setSeedPhrase(seedPhrase);
navigateToNext();
}}
/>
</AnimatedTransition>
}
/>
<Route
path={`/${AccountCreationRoute.SeedPhraseConfirmation}`}
element={
<AnimatedTransition
elementKey={AccountCreationRoute.SeedPhraseConfirmation}
>
<SeedPhraseConfirmation
seedPhrase={seedPhrase || []}
onConfirm={() => navigateToNext()}
/>
</AnimatedTransition>
}
/>
<Route
path={`/${AccountCreationRoute.Password}`}
element={
<AnimatedTransition elementKey={AccountCreationRoute.Password}>
<Password
accountCreationDetails={accountCreationDetails}
onSetAccountCreationDetails={(
accountCreationDetailsDelta
) => {
setAccountCreationDetails((accountCreationDetails) => {
return {
...accountCreationDetails,
...accountCreationDetailsDelta,
};
});
}}
onSubmitAccountCreationDetails={(
accountCreationDetails
) => {
setAccountCreationDetails(accountCreationDetails);
navigateToNext();
}}
/>
</AnimatedTransition>
}
/>
<Route
path={`/${AccountCreationRoute.Completion}`}
element={
<AnimatedTransition
elementKey={AccountCreationRoute.Completion}
>
<Completion
alias={accountCreationDetails.alias || ""}
requester={requester}
mnemonic={seedPhrase || []}
password={accountCreationDetails.password || ""}
/>
</AnimatedTransition>
}
/>
</Routes>
<Outlet />
</AnimatePresence>
</RouteContainer>
</AccountCreationContainer>
</SubViewContainer>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,12 @@ export const CompletionViewContainer = styled.div`
height: 100%;
`;

export const Header1 = styled.h1`
margin: 8px 0;
color: ${(props) => props.theme.colors.utility2.main};
`;

export const BodyText = styled.p`
text-align: center;
font-weight: 300;
color: ${(props) => props.theme.colors.utility2.main80};
`;

export const CompletionViewUpperPartContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
`;

export const ButtonsContainer = styled.div`
display: flex;
justify-content: center;
width: 100%;
`;

export const ButtonContainer = styled.div`
width: 120px;
`;

export const ImageContainer = styled.div`
margin: 0 0 48px;
`;
Loading

0 comments on commit 25488fb

Please sign in to comment.