Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tabbed Onboarding - Additional accounts #2956

Merged
merged 28 commits into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
13db7a8
Hide post-install onboarding hints when adding more accounts
hyphenized Jan 1, 2023
589a9bd
Add navigation layout changes for onboarding additional wallets
hyphenized Jan 2, 2023
b8c3477
Allow arbitrary widths for SharedSelect
hyphenized Jan 2, 2023
cf22162
Change derivation path layout when importing additional seeds
hyphenized Jan 2, 2023
1ad8609
Add new onboarding additional wallets success screen
hyphenized Jan 2, 2023
43d5d23
Redirect to unlock wallet if trying to edit wallet accounts with sign…
hyphenized Jan 2, 2023
1e31e14
Open new onboarding flow when adding wallets from popup
hyphenized Jan 2, 2023
0b701e9
Update ui/_locales/en/messages.json
hyphenized Feb 4, 2023
1346740
Cleanup AddWallet components
hyphenized Feb 4, 2023
4d670e6
Refactor inline function in set password
hyphenized Feb 4, 2023
0e4505c
Fix i18n string casing
hyphenized Feb 4, 2023
495955e
Merge branch 'main' into tabbed-onboarding-existing-accounts
hyphenized Feb 13, 2023
cd0a99f
Fix navigation state switching during onboarding
hyphenized Feb 14, 2023
99b002e
Remove unused event from keyrings slice
hyphenized Feb 14, 2023
e583232
Refactor styles for onboarding completion screen
hyphenized Feb 14, 2023
039525f
Merge branch 'main' into tabbed-onboarding-existing-accounts
hyphenized Feb 24, 2023
f49d974
Fix incorrect onboarding navigation state check
hyphenized Mar 1, 2023
18528de
Merge branch 'main' into tabbed-onboarding-existing-accounts
hyphenized Mar 1, 2023
5c13845
Merge branch 'main' into tabbed-onboarding-existing-accounts
hyphenized Mar 3, 2023
d19932e
Onboarding revamp copy and style tweaks
hyphenized Mar 3, 2023
0c8cda9
Update pining animation
hyphenized Mar 7, 2023
4f81b5d
Merge branch 'main' into tabbed-onboarding-existing-accounts
hyphenized Mar 7, 2023
d1b4ebf
Remove intermediate ledger onboarding screen
hyphenized Mar 7, 2023
d098abf
Fix post ledger import screen, add tip to ledger onboarding screen
hyphenized Mar 9, 2023
d51472c
Update img alternate labels
hyphenized Mar 9, 2023
6862630
Cleanup tabbed onboarding files
hyphenized Mar 9, 2023
c3c1119
Update ui/_locales/en/messages.json
hyphenized Mar 9, 2023
b4b1835
Merge branch 'main' into tabbed-onboarding-existing-accounts
jagodarybacka Mar 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions background/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1096,10 +1096,6 @@ export default class Main extends BaseService<never> {
await this.keyringService.unlock(password, true)
})

keyringSliceEmitter.on("unlockKeyrings", async (password) => {
await this.keyringService.unlock(password)
})

keyringSliceEmitter.on("lockKeyrings", async () => {
await this.keyringService.lock()
})
Expand Down Expand Up @@ -1580,6 +1576,10 @@ export default class Main extends BaseService<never> {
)
}

async unlockKeyrings(password: string): Promise<boolean> {
return this.keyringService.unlock(password)
}

async getActivityDetails(txHash: string): Promise<ActivityDetail[]> {
const addressNetwork = this.store.getState().ui.selectedAccount
const transaction = await this.chainService.getTransaction(
Expand Down
5 changes: 2 additions & 3 deletions background/redux-slices/keyrings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export const initialState: KeyringsState = {

export type Events = {
createPassword: string
unlockKeyrings: string
lockKeyrings: never
generateNewKeyring: string | undefined
deriveAddress: string
Expand Down Expand Up @@ -148,8 +147,8 @@ export const deriveAddress = createBackgroundAsyncThunk(

export const unlockKeyrings = createBackgroundAsyncThunk(
"keyrings/unlockKeyrings",
async (password: string) => {
await emitter.emit("unlockKeyrings", password)
kkosiorowska marked this conversation as resolved.
Show resolved Hide resolved
async (password: string, { extra: { main } }) => {
return { success: await main.unlockKeyrings(password) }
}
)

Expand Down
38 changes: 23 additions & 15 deletions ui/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@
"stepsExplainer": "Please follow the steps below and click on Try Again!",
"step1": "Plug in a single Ledger",
"step2": "Enter pin to unlock",
"step3": "Open Ethereum App"
"step3": "Open Ethereum App",
"tip": "After clicking continue, select device and click connect"
},
"selectDevice": "Select the device",
"clickConnect": "Click connect",
Expand Down Expand Up @@ -300,23 +301,20 @@
},
"onboarding": {
"tabbed": {
"walletShortcut": "Did you know that you can open Taho using a keyboard shortcut?",
"routeBasedContent": {
"newSeed": {
"tip": "If you want an easy way to preview Taho, you can start by adding a view only account",
"tip": "If you want an easy way to preview Taho, you can start by adding a read only account.",
"action": "Add preview account"
},
"ledger": {
"tip": "Trezor integration coming soon, check out the open ",
"action": "Gitcoin bounty"
},
"addWallet": {
"tip": "Some of the code for this was written by Community contributors"
"tip": "Several of Taho's most popular features were developed by our community."
},
"viewOnly": {
"tip": "A good way to take a peek at what Taho offers"
"tip": "A good way to take a peek at what Taho offers."
},
"importSeed": {
"tip": "Taho offers the possibility of adding multiple recovery phrases"
"tip": "Taho offers the possibility of adding multiple recovery phrases."
},
"default": {
"fact1": "Fully owned by the community",
Expand All @@ -331,11 +329,15 @@
},
"addWallet": {
"title": "Use existing wallet",
"tip": "You can always add more wallets later",
"titleExisting": "Add account",
"tip": "You can always add more wallets later.",
"existingListTitle": "Existing account",
"newWalletTitle": "New wallet",
"options": {
"importSeed": "Import recovery phrase",
"ledger": "Connect to Ledger",
"readOnly": "Read-only address"
"readOnly": "Read-only address",
"createNew": "Create new wallet"
},
"importSeed": {
"title": "Import secret recovery phrase",
Expand All @@ -352,14 +354,19 @@
"title": "Read-only address",
"subtitle": "Add an Ethereum address or ENS name to view an existing wallet in Taho",
"submit": "Preview Taho",
"tip": "You can upgrade a view-only wallet later"
"tip": "You can upgrade a read-only wallet later."
}
},
"newWalletIntro": {
"title": "Before we get started",
"warning": "It's important to write down your secret recovery phrase and store it somewhere safe.<br /><br />This is the only way to recover your accounts and funds.<br /><br /><u>You will not be able to export your recovery phrase later.</u>",
"submit": "Create recovery phrase",
"tip": "You can upgrade a view-only wallet later"
"tip": "You can upgrade a read-only wallet later."
},
"unlockWallet": {
"title": "Password required",
"passwordInput": "Signing password",
"submit": "Confirm"
},
"newWalletReview": {
"title": "Save and store your recovery phrase",
Expand All @@ -375,10 +382,11 @@
"invalidStateMsg": "Verify the order and remove the ones that aren't in the right position.",
"verifyValidState": "Verify recovery phrase",
"submit": "Finalize",
"tip": "If you didn’t write it down, you can <url>start with a new phrase</url>"
"tip": "If you didn’t write it down, you can <url>start with a new phrase.</url>"
},
"complete": {
"title": "Welcome to Taho",
"titleExisting": "Account added to Taho!",
jagodarybacka marked this conversation as resolved.
Show resolved Hide resolved
"subtitle": "For faster access we recommend pinning Taho to your browser",
"animationAlt": "Pin the wallet"
}
Expand Down Expand Up @@ -624,7 +632,7 @@
}
},
"addNewChain": {
"subtitle": "Wants to add a main network to Tally Ho!",
"subtitle": "Wants to add a main network to Taho",
"name": "Name",
"chainId": "Chain ID",
"currency": "Currency",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,14 @@ export default function AccountsNotificationPanelAccounts({
size="medium"
iconSmall="add"
iconPosition="left"
linkTo="/onboarding/add-wallet"
onClick={() => {
if (isEnabled(FeatureFlags.SUPPORT_TABBED_ONBOARDING)) {
window.open("/tab.html#onboarding")
window.close()
} else {
history.push("/onboarding/add-wallet")
}
}}
>
{t("accounts.notificationPanel.addWallet")}
</SharedButton>
Expand Down
2 changes: 1 addition & 1 deletion ui/components/Ledger/LedgerPanelContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function LedgerPanelContainer({
.panel {
display: flex;
flex-flow: column;
max-width: 24rem;
max-width: 450px;
margin: 0 auto;
padding: 1rem;
}
Expand Down
71 changes: 52 additions & 19 deletions ui/components/Onboarding/OnboardingDerivationPathSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,60 @@ import React, {
KeyboardEventHandler,
ReactElement,
useEffect,
useMemo,
useRef,
useState,
} from "react"
import { useTranslation } from "react-i18next"
import { i18n } from "../../_locales/i18n"
import { I18nKey } from "../../_locales/i18n"
import SharedButton from "../Shared/SharedButton"
import SharedInput from "../Shared/SharedInput"
import SharedModal from "../Shared/SharedModal"
import SharedSelect, { Option } from "../Shared/SharedSelect"

type DerivationPath = {
value: string
label: I18nKey
hideActiveValue?: boolean
}

export enum DefaultPathIndex {
ledgerLive,
bip44,
ethTestnet,
ledgerLegacy,
rootstock,
rootstockTestnet,
}

// TODO make this network specific
const initialDerivationPaths: Option[] = [
{
const defaultDerivationPaths: Record<DefaultPathIndex, DerivationPath> = {
[DefaultPathIndex.ledgerLive]: {
value: "m/44'/60'/x'/0/0",
label: i18n.t("ledger.derivationPaths.ledgerLive"),
label: "ledger.derivationPaths.ledgerLive",
},
{
[DefaultPathIndex.bip44]: {
value: "m/44'/60'/0'/0",
label: i18n.t("ledger.derivationPaths.bip44"),
label: "ledger.derivationPaths.bip44",
},
{
[DefaultPathIndex.ethTestnet]: {
value: "m/44'/1'/0'/0",
label: i18n.t("ledger.derivationPaths.ethTestnet"),
label: "ledger.derivationPaths.ethTestnet",
},
{
[DefaultPathIndex.ledgerLegacy]: {
value: "m/44'/60'/0'",
label: i18n.t("ledger.derivationPaths.ledgerLegacy"),
label: "ledger.derivationPaths.ledgerLegacy",
hideActiveValue: true,
},
{
[DefaultPathIndex.rootstock]: {
value: "m/44'/137'/0'/0",
label: i18n.t("ledger.derivationPaths.rsk"),
label: "ledger.derivationPaths.rsk",
},
{
[DefaultPathIndex.rootstockTestnet]: {
value: "m/44'/37310'/0'/0",
label: i18n.t("ledger.derivationPaths.rskTestnet"),
label: "ledger.derivationPaths.rskTestnet",
},
]
}

const initialCustomPath = {
coinType: "0",
Expand All @@ -50,16 +66,30 @@ const initialCustomPath = {

export default function OnboardingDerivationPathSelect({
onChange,
defaultPath,
}: {
onChange: (path: string) => void
defaultPath?: DefaultPathIndex
}): ReactElement {
const { t } = useTranslation("translation", { keyPrefix: "onboarding" })
const [derivationPaths, setDerivationPaths] = useState(initialDerivationPaths)
const { t, i18n } = useTranslation("translation", { keyPrefix: "onboarding" })

const defaultPaths: Option[] = useMemo(
() =>
Object.values(defaultDerivationPaths).map((path) => ({
...path,
label: i18n.t(path.label),
})),
[i18n]
)

const [derivationPaths, setDerivationPaths] = useState<Option[]>([])

const [modalStep, setModalStep] = useState(0)
const [customPath, setCustomPath] = useState(initialCustomPath)
const [customPathLabel, setCustomPathLabel] = useState("")
const [defaultIndex, setDefaultIndex] = useState<number>()
const [defaultIndex, setDefaultIndex] = useState<number | undefined>(
defaultPath
)

// Reset value to display placeholder after adding a custom path
const customPathValue = customPath.isReset
Expand Down Expand Up @@ -113,6 +143,8 @@ export default function OnboardingDerivationPathSelect({
if (e.key === "Enter") setModalStep(1)
}

const derivationPathOptions = [...defaultPaths, ...derivationPaths]

return (
<>
<SharedModal
Expand Down Expand Up @@ -183,14 +215,15 @@ export default function OnboardingDerivationPathSelect({
</SharedModal>
<SharedSelect
label={t("derivationPath")}
options={derivationPaths}
options={derivationPathOptions}
onChange={onChange}
defaultIndex={defaultIndex}
triggerLabel={t("addCustomPath")}
onTrigger={() => setModalStep(1)}
showValue
showOptionValue
placement="top"
width="100%"
/>
<style jsx>{`
.input_wrap {
Expand Down
94 changes: 94 additions & 0 deletions ui/components/Onboarding/RouteBasedContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from "react"
import { useTranslation } from "react-i18next"
import { Route, Switch } from "react-router-dom"
import OnboardingRoutes from "../../pages/Onboarding/Tabbed/Routes"
import SharedButton from "../Shared/SharedButton"
import WalletShortcut from "./WalletShortcut"

export default function RouteBasedContent(): JSX.Element {
const { t } = useTranslation("translation", {
keyPrefix: "onboarding.tabbed.routeBasedContent",
})
return (
<Switch>
<Route key={OnboardingRoutes.NEW_SEED} path={OnboardingRoutes.NEW_SEED}>
<div className="fadeIn">
{t("newSeed.tip")}
<SharedButton
type="secondary"
size="medium"
linkTo={OnboardingRoutes.VIEW_ONLY_WALLET}
>
{t("newSeed.action")}
</SharedButton>
</div>
<style jsx>{`
div {
display: flex;
flex-direction: column;
gap: 16px;
align-items: center;
}
`}</style>
</Route>
<Route
key={OnboardingRoutes.ADD_WALLET}
path={OnboardingRoutes.ADD_WALLET}
>
<div className="fadeIn">{t("addWallet.tip")}</div>
</Route>
<Route
key={OnboardingRoutes.VIEW_ONLY_WALLET}
path={OnboardingRoutes.VIEW_ONLY_WALLET}
>
<div className="fadeIn">{t("viewOnly.tip")}</div>
</Route>
<Route
key={OnboardingRoutes.IMPORT_SEED}
path={OnboardingRoutes.IMPORT_SEED}
>
<div className="fadeIn">{t("importSeed.tip")}</div>
</Route>
<Route
key={OnboardingRoutes.ONBOARDING_COMPLETE}
path={OnboardingRoutes.ONBOARDING_COMPLETE}
>
<div className="fadeIn">
<WalletShortcut />
</div>
</Route>
<Route>
<div className="onboarding_facts fadeIn">
<p>{t("default.fact1")}</p>
<p>{t("default.fact2")}</p>
<p>{t("default.fact3")}</p>
<style jsx>
{`
.onboarding_facts {
color: var(--green-20);
display: flex;
flex-direction: column;
justify-content: center;
gap: 24px;
}

.onboarding_facts p {
margin: 0;
text-align: left;
font-size: 18px;
line-height: 24px;
}

.onboarding_facts p::before {
content: url("./images/check.svg");
width: 16px;
height: 16px;
margin-right: 16px;
}
`}
</style>
</div>
</Route>
</Switch>
)
}
Loading