Skip to content

Commit

Permalink
feat: add onboarding flow for web extension (#3582)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cifko authored Nov 17, 2021
1 parent 35790d6 commit 0c47bc8
Show file tree
Hide file tree
Showing 30 changed files with 22,210 additions and 64 deletions.
21,700 changes: 21,660 additions & 40 deletions applications/tari_web_extension/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions applications/tari_web_extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
"@wasm-tool/wasm-pack-plugin": "1.5.0",
"customize-cra": "^1.0.0",
"react-app-rewired": "^2.1.8",
"sass": "^1.43.4",
"scss": "^0.2.4",
"text-encoding": "^0.7.0",
"wasm-loader": "^1.3.0"
},
Expand Down
10 changes: 10 additions & 0 deletions applications/tari_web_extension/public/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ const getSelectedAsset = () => ({ successful: true, selected: selectedAsset });

const loginRefresh = () => ({ successful: !!credentials, token: credentials });

const getSeedWords = () => ({
successful: true,
seedWords:
"theme panther ladder custom field aspect misery shine bundle worry senior velvet brush tourist glide jump example vanish embody enemy struggle air extend empty",
});

function messageCallback(request, sender, sendResponse) {
console.log(request);
switch (request?.action) {
case "tari-login":
credentials = "token";
Expand All @@ -38,6 +45,9 @@ function messageCallback(request, sender, sendResponse) {
case "tari-login-refresh":
sendResponse(loginRefresh());
break;
case "tari-get-seedwords":
sendResponse(getSeedWords());
break;
default:
console.log("unknown message", request?.action);
break;
Expand Down
3 changes: 1 addition & 2 deletions applications/tari_web_extension/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
Expand All @@ -26,7 +25,7 @@
-->
<title>React App</title>
</head>
<body style="width:357px; height:600px; margin:0px;">
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
Expand Down
5 changes: 0 additions & 5 deletions applications/tari_web_extension/src/app.css

This file was deleted.

34 changes: 21 additions & 13 deletions applications/tari_web_extension/src/app.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
import "./app.css";
import "./app.scss";
import React, { useEffect } from "react";
import { MemoryRouter, Navigate, Route, Routes } from "react-router";
import Assets from "./screens/assets/assets";
import Login from "./screens/login/login";
import { Navigate, Route, Routes } from "react-router";
import { useDispatch, useSelector } from "react-redux";
import { getCredentials, refreshLogin } from "./redux/loginSlice";
import {
getCredentials,
getCredentialsCalled,
refreshLogin,
} from "./redux/loginSlice";
import Onboarding from "./onboarding/Onboarding";
import { HashRouter } from "react-router-dom";
import Popup from "./popup/Popup";

export default function App() {
const credentials = useSelector(getCredentials);
const credentialsCalled = useSelector(getCredentialsCalled);
const dispatch = useDispatch();
useEffect(() => {
dispatch(refreshLogin());
}, [dispatch]);

if (!credentials) {
if (!window.location.href.includes("#/onboarding") && credentialsCalled) {
window.open("#/onboarding");
}
}
return (
<div className="main">
<MemoryRouter>
<HashRouter>
<Routes>
<Route path="/assets" element={<Assets />} />
<Route
path="*"
element={credentials ? <Navigate to="/assets" /> : <Login />}
/>
<Route path="/onboarding/*" element={<Onboarding />} />
<Route path="/popup/*" element={<Popup />} />
<Route path="" element={<Navigate replace to="popup" />} />
</Routes>
</MemoryRouter>
</HashRouter>
</div>
);
}
7 changes: 7 additions & 0 deletions applications/tari_web_extension/src/app.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*,
*::after,
*::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from "react";

export default function Complete() {
window.close();
return (
<div className="screen">
<div className="caption">Complete</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import "./confirmseedwords.scss";
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { useLocation } from "react-router";

export default function ConfirmSeedWords() {
const [wordsOrder, setWordsOrder] = useState([]);
const location = useLocation();
const seedWords = location.state.seedWords.split(" ");
const alphabeticalSeedWords = [...seedWords];
alphabeticalSeedWords.sort();
const onWordClick = (word) => {
if (wordsOrder.includes(word)) {
// remove
setWordsOrder(wordsOrder.filter((value) => value !== word));
} else {
// add
setWordsOrder([...wordsOrder, word]);
}
};
const checkSeedWords = () =>
JSON.stringify(seedWords) === JSON.stringify(wordsOrder);

return (
<div className="screen">
<div className="caption">ConfirmSeedWords</div>
<div className="ordered">
<div className="ordered-items">
{wordsOrder.map((word) => (
<div key={word} className="seed-word">
{word}
</div>
))}
</div>
</div>
<div className="unordered">
{alphabeticalSeedWords.map((word) => (
<div
key={word}
className={`seed-word seed-word-button ${
wordsOrder.includes(word) ? "seed-word-button-pressed" : ""
}`}
onClick={() => onWordClick(word)}
>
{word}
</div>
))}
</div>
<Link
to="../complete"
className={`button ${checkSeedWords() || 1 ? "" : "disabled-button"}`}
>
Next
</Link>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.ordered {
display: block;
margin: 20px;
width: 40%;
border: 1px solid;
padding: 10px;
border-radius: 5px;
height: calc(
4 * 42px + 3 * 10px + 2 * 10px + 2px
); // 4 buttons (42px height, 10px padding, 2px border) + 3 gaps (10px)
.ordered-items {
display: grid;
width: 100%;
height: auto;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
row-gap: 10px;
column-gap: 10px;
}
}

.unordered {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
row-gap: 10px;
column-gap: 10px;
margin: 20px;
width: 40%;
}

.seed-word {
justify-self: stretch;
border: 2px solid #ffaaaa;
border-radius: 5px;
text-align: center;
padding: 10px;
color: red;
height: 42px;
}

.seed-word-button-pressed {
background-color: #ff2222;
color: white;
}

.seed-word-button:hover {
border-color: #ff0000;
cursor: pointer;
}

.seed-word-button-pressed:hover {
background-color: #dd0000;
color: white;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
import { login } from "../../redux/loginSlice";

export default function CreateWallet() {
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const dispatch = useDispatch();

const onPasswordChange = (e) => {
setPassword(e.target.value);
};

const onConfirmPasswordChange = (e) => {
setConfirmPassword(e.target.value);
};

const checkPasswords = () =>
password === confirmPassword && password.length >= 6;

const createWallet = () => {
console.log("dispatching login");
const username = "username";
dispatch(login({ username, password }));
};

return (
<div className="screen">
<div className="caption">Create Password</div>
New password (....)
<input
name="password"
value={password}
type="password"
onChange={onPasswordChange}
></input>
Confirm password
<input
name="confirm-password"
value={confirmPassword}
type="password"
onChange={onConfirmPasswordChange}
></input>
<Link
to="../seed-phrase"
className={`button ${checkPasswords() ? "" : "disabled-button"}`}
onClick={createWallet}
>
Create
</Link>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import "./importwallet.scss";
import React, { useState } from "react";
import { Link } from "react-router-dom";

export default function ImportWallet() {
const [seedWords, setSeedWords] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const onSeedPhraseChange = (e) => {
setSeedWords(e.target.value);
};
const onPasswordChange = (e) => {
setPassword(e.target.value);
};

const onConfirmPasswordChange = (e) => {
setConfirmPassword(e.target.value);
};

const checkSeedWords = () => seedWords.split(" ").length === 24;

const checkPasswords = () =>
password === confirmPassword && password.length >= 6;

const checkForm = () => checkSeedWords() && checkPasswords();

return (
<div className="screen">
<div className="caption">ImportWallet</div>
<textarea
className="seedwords"
value={seedWords}
onChange={onSeedPhraseChange}
/>
New password (....)
<input
name="password"
value={password}
type="password"
onChange={onPasswordChange}
></input>
Confirm password
<input
name="confirm-password"
value={confirmPassword}
type="password"
onChange={onConfirmPasswordChange}
></input>
<Link
to="../complete"
className={`button ${checkForm() ? "" : "disabled-button"}`}
>
Next
</Link>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.screen {
.seedwords {
width: 30%;
max-width: 30%;
height: 5em;
padding: 10px;
font-size: larger;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
}
16 changes: 16 additions & 0 deletions applications/tari_web_extension/src/onboarding/Improve/Improve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from "react";
import { useLocation } from "react-router";
import { Link } from "react-router-dom";

export default function Improve() {
const location = useLocation();
const { next } = location.state;
return (
<div className="screen">
<div className="caption">Help us improve</div>
<Link to={next} className="button">
I Agree
</Link>
</div>
);
}
Loading

0 comments on commit 0c47bc8

Please sign in to comment.