Skip to content

Commit f2d6ee2

Browse files
authored
implement UX fixes and design for mnemonic phrase views (#9)
* content script update * whitelist PR preview env * adding UI work for mnemonic phrase screen plus some url whitelisting improvemnents * rm debugger * implement UX fixes and design for mnemonic phrase views
1 parent 3b8f47f commit f2d6ee2

File tree

10 files changed

+262
-125
lines changed

10 files changed

+262
-125
lines changed

background/backgroundComponents/messageListener.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ const initMessageListener = () => {
139139
const recoverAccount = () => {
140140
const { password, recoverMnemonic } = request;
141141
let wallet;
142+
let applicationState;
142143
try {
143144
wallet = fromMnemonic(recoverMnemonic);
144145
} catch (e) {
@@ -147,10 +148,13 @@ const initMessageListener = () => {
147148

148149
if (wallet) {
149150
_storeAccount({ mnemonicPhrase: recoverMnemonic, password, wallet });
150-
localStorage.setItem(
151-
APPLICATION_ID,
152-
APPLICATION_STATE.MNEMONIC_PHRASE_CONFIRMED,
153-
);
151+
152+
// if we don't have an application state, assign them one
153+
applicationState =
154+
localStorage.getItem(APPLICATION_ID) ||
155+
APPLICATION_STATE.MNEMONIC_PHRASE_CONFIRMED;
156+
157+
localStorage.setItem(APPLICATION_ID, applicationState);
154158
}
155159

156160
sendResponse({

src/App.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from "react";
33
import { configureStore } from "@reduxjs/toolkit";
44
import { combineReducers } from "redux";
55
import { Provider } from "react-redux";
6-
import styled, { createGlobalStyle } from "styled-components";
6+
import { createGlobalStyle } from "styled-components";
77

88
import { COLOR_PALETTE } from "styles";
99
import { reducer as auth } from "ducks/authServices";
@@ -21,13 +21,6 @@ html, body, #root {
2121
}
2222
`;
2323

24-
const Wrapper = styled.div`
25-
display: flex;
26-
flex-flow: column;
27-
height: 100%;
28-
text-align: left;
29-
`;
30-
3124
const store = configureStore({
3225
reducer: combineReducers({
3326
auth,
@@ -39,10 +32,8 @@ export const history = createHashHistory();
3932
export function App() {
4033
return (
4134
<Provider store={store}>
42-
<Wrapper>
43-
<GlobalStyle />
44-
<Router />
45-
</Wrapper>
35+
<GlobalStyle />
36+
<Router />
4637
</Provider>
4738
);
4839
}

src/Router.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,27 @@ import SignTransaction from "views/SignTransaction";
2727
import UnlockAccount from "views/UnlockAccount";
2828
import Welcome from "views/Welcome";
2929

30+
const Loading = () => <p> Loading...</p>;
31+
3032
const ProtectedRoute = (props: RouteProps) => {
3133
const location = useLocation();
3234
const applicationState = useSelector(applicationStateSelector);
3335
const authenticated = useSelector(authenticatedSelector);
3436
const publicKey = useSelector(publicKeySelector);
3537

3638
if (applicationState === APPLICATION_STATE.APPLICATION_LOADING) {
37-
return <p>loading...</p>;
39+
return <Loading />;
3840
}
3941
if (!publicKey || !authenticated) {
42+
if (applicationState === APPLICATION_STATE.APPLICATION_STARTED) {
43+
return (
44+
<Redirect
45+
to={{
46+
pathname: "/",
47+
}}
48+
/>
49+
);
50+
}
4051
return (
4152
<Redirect
4253
to={{
@@ -54,7 +65,9 @@ const HomeRoute = () => {
5465
const location = useLocation();
5566
const applicationState = useSelector(applicationStateSelector);
5667
const publicKey = useSelector(publicKeySelector);
57-
68+
if (applicationState === APPLICATION_STATE.APPLICATION_LOADING) {
69+
return <Loading />;
70+
}
5871
if (!publicKey) {
5972
if (applicationState === APPLICATION_STATE.MNEMONIC_PHRASE_CONFIRMED) {
6073
return <UnlockAccount />;
Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import React from "react";
22
import styled from "styled-components";
3+
import { COLOR_PALETTE } from "styles";
4+
import { Button } from "styles/Basics";
35
import Header from "./Header";
46

5-
const H1 = styled.h1`
7+
const HeaderEl = styled.h1`
8+
color: ${COLOR_PALETTE.primary};
69
font-weight: 200;
710
font-size: 2.5rem;
811
line-height: 3.4rem;
912
margin: 1rem 0;
13+
max-width: 21rem;
1014
`;
1115

1216
const Screen = styled.div`
@@ -18,35 +22,40 @@ const Screen = styled.div`
1822
`;
1923

2024
const HalfScreen = styled.div`
21-
padding: 0 30px;
22-
width: 355px;
25+
padding: 0 1.6rem;
26+
width: 30rem;
2327
2428
:nth-child(1) {
25-
margin-top: -20px;
29+
margin-top: -8.125rem;
2630
}
2731
`;
2832

33+
const BackButton = styled(Button)`
34+
margin: 1rem 0 0 2.75rem;
35+
`;
36+
2937
const Fullscreen = ({
38+
goBack,
3039
header,
31-
icon: [src, alt],
40+
icon: { src, alt },
3241
children,
3342
}: {
43+
goBack?: () => void;
3444
header: string;
35-
icon: [string, string];
45+
icon: { src: string; alt: string };
3646
children: JSX.Element;
37-
}) => {
38-
return (
39-
<>
40-
<Header />
41-
<Screen>
42-
<HalfScreen>
43-
<img src={src} alt={alt} />
44-
<H1>{header}</H1>
45-
</HalfScreen>
46-
<HalfScreen>{children}</HalfScreen>
47-
</Screen>
48-
</>
49-
);
50-
};
47+
}) => (
48+
<>
49+
<Header />
50+
{goBack ? <BackButton onClick={goBack}>&lt; Back</BackButton> : null}
51+
<Screen>
52+
<HalfScreen>
53+
<img src={src} alt={alt} />
54+
<HeaderEl>{header}</HeaderEl>
55+
</HalfScreen>
56+
<HalfScreen>{children}</HalfScreen>
57+
</Screen>
58+
</>
59+
);
5160

5261
export default Fullscreen;

src/components/mnemonicPhrase/ConfirmMnemonicPhrase.tsx

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,52 @@ import styled from "styled-components";
33
import { shuffle } from "lodash";
44
import { useDispatch, useSelector } from "react-redux";
55
import { confirmMnemonicPhrase, authErrorSelector } from "ducks/authServices";
6-
import { ErrorMessage } from "components/form";
6+
import { ErrorMessage, FormButton } from "components/form";
7+
import { COLOR_PALETTE } from "styles";
8+
import { Button } from "styles/Basics";
79
import CheckButton from "./basics/CheckButton";
810

9-
const ConfirmInput = styled.textarea`
10-
background: #d3d3d3;
11+
const ConfirmInput = styled.div`
12+
background: #d2d8e5;
1113
border: 0;
12-
border-radius: 5px;
13-
color: purple;
14-
font-size: 14px;
15-
padding: 20px 30px;
16-
width: 60%;
14+
border-radius: 30px;
15+
box-sizing: border-box;
16+
color: ${COLOR_PALETTE.primary};
17+
font-size: 1.125rem;
18+
height: 160px;
19+
padding: 2.3rem;
20+
resize: none;
21+
width: 100%;
1722
margin-bottom: 20px;
23+
text-align: center;
24+
`;
25+
26+
const ClearButton = styled(Button)`
27+
background: ${COLOR_PALETTE.primaryGradient};
28+
border-radius: 7px;
29+
color: #fff;
30+
font-weight: 800;
31+
height: 24px;
32+
margin-left: 7px;
33+
width: 24px;
1834
`;
1935

2036
const ConfirmMnemonicPhrase = ({
2137
mnemonicPhrase,
22-
setReadyToConfirm,
2338
}: {
2439
mnemonicPhrase: string;
25-
setReadyToConfirm: (readyToConfirm: boolean) => void;
2640
}) => {
2741
const dispatch = useDispatch();
28-
const words = useRef(shuffle(mnemonicPhrase.split(" ")));
42+
const words = shuffle(mnemonicPhrase.split(" "));
43+
const wordState = useRef(
44+
words.reduce(
45+
(obj, current, i) => ({
46+
...obj,
47+
[`${current}-${i}`]: false,
48+
}),
49+
{},
50+
),
51+
);
2952
const [selectedWords, setSelectedWords] = useState<string[]>([]);
3053
const authError = useSelector(authErrorSelector);
3154

@@ -40,16 +63,31 @@ const ConfirmMnemonicPhrase = ({
4063
});
4164
};
4265

66+
const initialWordState = wordState.current;
67+
68+
const [checkboxState, setCheckboxState] = useState(initialWordState);
69+
70+
const wordStateArr: [string, boolean][] = Object.entries(checkboxState);
71+
4372
const wordBubbles = () =>
44-
words.current.map((word) => (
73+
wordStateArr.map(([wordKey, value]) => (
4574
<CheckButton
4675
onChange={(e) => {
76+
setCheckboxState((prev) => ({ ...prev, [wordKey]: !value }));
4777
updatePhrase(e.target);
4878
}}
49-
word={word}
79+
key={wordKey}
80+
wordKey={wordKey}
81+
value={value}
82+
word={wordKey.replace(/-.*/, "")}
5083
/>
5184
));
5285

86+
const clearFields = () => {
87+
setSelectedWords([]);
88+
setCheckboxState(initialWordState);
89+
};
90+
5391
const handleSubmit = (e: React.FormEvent) => {
5492
e.preventDefault();
5593
dispatch(confirmMnemonicPhrase(selectedWords.join(" ")));
@@ -58,16 +96,18 @@ const ConfirmMnemonicPhrase = ({
5896
<>
5997
<form onSubmit={handleSubmit}>
6098
<div>
61-
<ConfirmInput readOnly value={selectedWords.join(" ")} />
99+
<ConfirmInput>
100+
{selectedWords.join(" ")}
101+
{selectedWords.length ? (
102+
<ClearButton type="button" onClick={clearFields}>
103+
X
104+
</ClearButton>
105+
) : null}
106+
</ConfirmInput>
62107
<ErrorMessage authError={authError}></ErrorMessage>
63108
</div>
64109
{wordBubbles()}
65-
<div>
66-
<button type="submit">Confirm</button>
67-
</div>
68-
<div>
69-
<button onClick={() => setReadyToConfirm(false)}>Go back</button>
70-
</div>
110+
<FormButton type="submit">Confirm</FormButton>
71111
</form>
72112
</>
73113
);

0 commit comments

Comments
 (0)