Skip to content

Commit

Permalink
refactor: revamp multi wallet stages for mnemonics
Browse files Browse the repository at this point in the history
  • Loading branch information
shawnbusuttil committed Apr 16, 2024
1 parent d444b4e commit 8c1da31
Show file tree
Hide file tree
Showing 20 changed files with 133 additions and 317 deletions.
10 changes: 0 additions & 10 deletions apps/browser-extension-wallet/src/lib/translations/en.json
Expand Up @@ -1264,13 +1264,6 @@
"core.walletSetupConnectHardwareWalletStep.connectDevice": "Just connect your device to your computer, unlock and open the Cardano app to hit continue.",
"core.walletSetupConnectHardwareWalletStep.connectDeviceFull": "Just connect your device to your computer and unlock it to continue. If you're using a Ledger device, make sure you open the Cardano App.",
"core.walletSetupRestoreStep.title": "Restoring your wallet",
"core.walletSetupMnemonicStep.writePassphrase": "Write down your secret passphrase",
"core.walletSetupMnemonicStep.enterPassphrase": "Enter your secret passphrase",
"core.walletSetupMnemonicStep.enterPassphraseDescription": "Please enter each word of your recovery phrase in the right order to verify it and recover your wallet.",
"core.walletSetupMnemonicStep.body": "Now let's check you've got the correct secret passphrase. Enter each word of your passphrase in the right order to verify it.",
"core.walletSetupMnemonicStep.passphraseInfo1": "Make sure you create an offline backup of your secret passphrase.",
"core.walletSetupMnemonicStep.passphraseInfo2": "Do not store your backup digitally.",
"core.walletSetupMnemonicStep.passphraseInfo3": "Find out more.",
"core.walletSetupMnemonicStep.passphraseError": "Make sure the words of your recovery phrase are in the right order and spelled correctly.",
"core.walletSetupMnemonicStepRevamp.writePassphraseTitle": "Start by saving your recovery phrase",
"core.walletSetupMnemonicStepRevamp.enterPassphrase": "Enter your recovery passphrase",
Expand All @@ -1281,9 +1274,6 @@
"core.walletSetupMnemonicStepRevamp.passphraseError": "Make sure the words of your recovery phrase are in the right order and spelled correctly.",
"core.walletSetupMnemonicStepRevamp.copyToClipboard": "Copy to clipboard",
"core.walletSetupMnemonicStepRevamp.pasteFromClipboard": "Paste from clipboard",
"core.walletSetupMnemonicIntroStep.title": "Keeping your wallet secure",
"core.walletSetupMnemonicIntroStep.description": "Consider your recovery phrase as the master key to your wallet, and the only way to access your funds.",
"core.walletSetupMnemonicIntroStep.link": "Read More.",
"core.mnemonicVideoPopupContent.title": "Keeping your wallet secure",
"core.mnemonicVideoPopupContent.description": "Learn about what is a recovery phrase, and how to keep it safe from the video below.",
"core.mnemonicVideoPopupContent.link": "Read More.",
Expand Down
3 changes: 0 additions & 3 deletions apps/browser-extension-wallet/src/routes/wallet-paths.ts
Expand Up @@ -26,7 +26,6 @@ export const walletRoutePaths = {
create: {
root: '/new-wallet/create',
setup: '/new-wallet/create/setup',
keepSecure: '/new-wallet/create/keep-secure',
recoveryPhrase: '/new-wallet/create/recovery-phrase',
allDone: '/new-wallet/create/all-done'
},
Expand All @@ -40,8 +39,6 @@ export const walletRoutePaths = {
restore: {
root: '/new-wallet/restore',
setup: '/new-wallet/restore/setup',
keepSecure: '/new-wallet/restore/keep-secure',
selectRecoveryPhraseLength: '/new-wallet/restore/select-recovery-phrase-length',
enterRecoveryPhrase: '/new-wallet/restore/enter-recovery-phrase',
allDone: '/new-wallet/restore/all-done'
}
Expand Down

This file was deleted.

This file was deleted.

Expand Up @@ -21,7 +21,14 @@ import { fireEvent, render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { Providers } from './types';
import { walletRoutePaths } from '@routes';
import { createAssetsRoute, fillMnemonic, getNextButton, mnemonicWords, setupStep } from '../tests/utils';
import {
DEFAULT_MNEMONIC_LENGTH,
createAssetsRoute,
fillMnemonic,
getNextButton,
mnemonicWords,
setupStep
} from '../tests/utils';
import { StoreProvider } from '@src/stores';
import { APP_MODE_BROWSER } from '@src/utils/constants';
import { AppSettingsProvider, DatabaseProvider } from '@providers';
Expand All @@ -36,31 +43,12 @@ jest.mock('@providers/AnalyticsProvider', () => ({
})
}));

const keepWalletSecureStep = async () => {
const nextButton = getNextButton();

fireEvent.click(nextButton);

await screen.findByText('Write down your secret passphrase');
};

const recoveryPhraseStep = async () => {
const nextButton = getNextButton();

// 08/24
fireEvent.click(nextButton);
// 16/24
fireEvent.click(nextButton);
// 24/24
fireEvent.click(nextButton);

const step1 = 8;
const step2 = 16;
const step3 = 24;

await fillMnemonic(0, step1);
await fillMnemonic(step1, step2);
await fillMnemonic(step2, step3);
await fillMnemonic(0, DEFAULT_MNEMONIC_LENGTH);

await screen.findByText('Total wallet balance');
};
Expand Down Expand Up @@ -102,7 +90,6 @@ describe('Multi Wallet Setup/Create Wallet', () => {
);

await setupStep();
await keepWalletSecureStep();
await recoveryPhraseStep();
});

Expand Down
Expand Up @@ -4,7 +4,6 @@ import { Setup } from './steps/Setup';
import { NewRecoveryPhrase } from './steps/NewRecoveryPhrase';
import { CreateWalletProvider } from './context';
import { walletRoutePaths } from '@routes';
import { KeepWalletSecure } from './steps/KeepWalletSecure';
import { Providers } from './types';

const {
Expand All @@ -19,7 +18,6 @@ export const CreateWallet = ({ providers }: Props): JSX.Element => (
<CreateWalletProvider providers={providers}>
<Switch>
<Route path={create.setup} component={Setup} />
<Route path={create.keepSecure} component={KeepWalletSecure} />
<Route path={create.recoveryPhrase} component={NewRecoveryPhrase} />
</Switch>
</CreateWalletProvider>
Expand Down

This file was deleted.

@@ -1,4 +1,4 @@
import { MnemonicStage, WalletSetupMnemonicStep } from '@lace/core';
import { MnemonicStage, MnemonicVideoPopupContent, WalletSetupMnemonicStepRevamp } from '@lace/core';
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router';
Expand All @@ -10,13 +10,10 @@ import { useWalletManager } from '@hooks/useWalletManager';
import { useAnalyticsContext } from '@providers/AnalyticsProvider';
import { PostHogAction } from '@lace/common';
import { getWalletAccountsQtyString } from '@src/utils/get-wallet-count-string';
import { postHogOnboardingActions } from '@providers/AnalyticsProvider/analyticsTracker';

const wordList = wordlists.english;

const PASSPHRASE_STEP_1 = 0;
const PASSPHRASE_STEP_2 = 1;
const PASSPHRASE_STEP_3 = 2;

interface State {
isResetMnemonicModalOpen: boolean;
resetMnemonicStage: MnemonicStage;
Expand All @@ -33,15 +30,25 @@ export const NewRecoveryPhrase = (): JSX.Element => {
resetMnemonicStage: 'writedown'
}));

const [isBackFromNextStep, setIsBackFromNextStep] = useState(false);

const walletSetupMnemonicStepTranslations = {
writePassphrase: t('core.walletSetupMnemonicStep.writePassphrase'),
body: t('core.walletSetupMnemonicStep.body'),
enterPassphrase: t('core.walletSetupMnemonicStep.enterPassphrase'),
enterPassphraseDescription: t('core.walletSetupMnemonicStep.enterPassphraseDescription'),
passphraseInfo1: t('core.walletSetupMnemonicStep.passphraseInfo1'),
passphraseInfo2: t('core.walletSetupMnemonicStep.passphraseInfo2'),
passphraseInfo3: t('core.walletSetupMnemonicStep.passphraseInfo3'),
passphraseError: t('core.walletSetupMnemonicStep.passphraseError')
writePassphraseTitle: t('core.walletSetupMnemonicStepRevamp.writePassphraseTitle'),
enterPassphrase: t('core.walletSetupMnemonicStepRevamp.enterPassphrase'),
enterPassphraseDescription: t('core.walletSetupMnemonicStepRevamp.enterPassphraseDescription'),
writePassphraseSubtitle1: t('core.walletSetupMnemonicStepRevamp.writePassphraseSubtitle1'),
writePassphraseSubtitle2: t('core.walletSetupMnemonicStepRevamp.writePassphraseSubtitle2'),
passphraseError: t('core.walletSetupMnemonicStepRevamp.passphraseError'),
enterPassphraseLength: t('core.walletSetupMnemonicStepRevamp.enterPassphraseLength'),
copyToClipboard: t('core.walletSetupMnemonicStepRevamp.copyToClipboard'),
pasteFromClipboard: t('core.walletSetupMnemonicStepRevamp.pasteFromClipboard')
};

const mnemonicVideoPopupContentTranslations = {
title: t('core.mnemonicVideoPopupContent.title'),
description: t('core.mnemonicVideoPopupContent.description'),
linkText: t('core.mnemonicVideoPopupContent.link'),
closeButton: t('core.mnemonicVideoPopupContent.closeButton')
};

const clearSecrets = useCallback(() => {
Expand All @@ -64,33 +71,43 @@ export const NewRecoveryPhrase = (): JSX.Element => {

return (
<>
<WalletSetupMnemonicStep
<WalletSetupMnemonicStepRevamp
mnemonic={data.mnemonic}
onReset={(resetStage) =>
setState((s) => ({ ...s, isResetMnemonicModalOpen: true, resetMnemonicStage: resetStage }))
}
onReset={(resetStage) => {
setState((s) => ({ ...s, isResetMnemonicModalOpen: true, resetMnemonicStage: resetStage }));
resetStage === 'input' && setIsBackFromNextStep(false);
}}
renderVideoPopupContent={({ onClose }) => (
<MnemonicVideoPopupContent
translations={mnemonicVideoPopupContentTranslations}
videoSrc={process.env.YOUTUBE_RECOVERY_PHRASE_VIDEO_URL}
onClose={() => {
onClose();
void analytics.sendEventToPostHog(
postHogOnboardingActions.create.RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK
);
}}
/>
)}
onNext={saveWallet}
onStepNext={(stage: MnemonicStage, step: number) => {
switch (step) {
case PASSPHRASE_STEP_1:
stage === 'input'
? analytics.sendEventToPostHog(PostHogAction.MultiwalletCreateEnterPassphrase01NextClick)
: analytics.sendEventToPostHog(PostHogAction.MultiwalletCreateWritePassphrase01NextClick);
break;
case PASSPHRASE_STEP_2:
stage === 'input'
? analytics.sendEventToPostHog(PostHogAction.MultiwalletCreateEnterPassphrase09NextClick)
: analytics.sendEventToPostHog(PostHogAction.MultiwalletCreateWritePassphrase09NextClick);
break;
case PASSPHRASE_STEP_3:
stage === 'input'
? analytics.sendEventToPostHog(PostHogAction.MultiwalletCreateEnterPassphrase17NextClick)
: analytics.sendEventToPostHog(PostHogAction.MultiwalletCreateWritePassphrase17NextClick);
}
onStepNext={(mnemonicStage: MnemonicStage) => {
mnemonicStage === 'writedown'
? analytics.sendEventToPostHog(postHogOnboardingActions.create.SAVE_RECOVERY_PHRASE_NEXT_CLICK)
: analytics.sendEventToPostHog(postHogOnboardingActions.create.ENTER_RECOVERY_PHRASE_NEXT_CLICK);
}}
translations={walletSetupMnemonicStepTranslations}
suggestionList={wordList}
passphraseInfoLink={`${process.env.FAQ_URL}?question=what-happens-if-i-lose-my-recovery-phrase`}
onWatchVideoClick={() =>
analytics.sendEventToPostHog(postHogOnboardingActions.create.RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK)
}
onCopyToClipboard={() =>
analytics.sendEventToPostHog(postHogOnboardingActions.create.RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK)
}
onPasteFromClipboard={() =>
analytics.sendEventToPostHog(postHogOnboardingActions.create.RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK)
}
isBackFromNextStep={isBackFromNextStep}
/>
{state.isResetMnemonicModalOpen && (
<WarningModal
Expand Down
Expand Up @@ -36,7 +36,7 @@ export const Setup = (): JSX.Element => {
analytics.sendEventToPostHog(PostHogAction.MultiWalletCreateWalletNamePasswordNextClick);
setName(walletName);
setPassword(password);
history.push(walletRoutePaths.newWallet.create.keepSecure);
history.push(walletRoutePaths.newWallet.create.recoveryPhrase);
}}
translations={translations}
/>
Expand Down
Expand Up @@ -18,11 +18,11 @@ jest.doMock('@hooks/useWalletManager', () => ({

import React from 'react';
import '@testing-library/jest-dom';
import { fireEvent, render, screen } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { Providers } from './types';
import { walletRoutePaths } from '@routes';
import { createAssetsRoute, fillMnemonic, getNextButton, setupStep } from '../tests/utils';
import { DEFAULT_MNEMONIC_LENGTH, createAssetsRoute, fillMnemonic, setupStep } from '../tests/utils';
import { StoreProvider } from '@src/stores';
import { APP_MODE_BROWSER } from '@src/utils/constants';
import { AppSettingsProvider, DatabaseProvider } from '@providers';
Expand All @@ -37,34 +37,8 @@ jest.mock('@providers/AnalyticsProvider', () => ({
})
}));

const keepWalletSecureStep = async () => {
const nextButton = getNextButton();

fireEvent.click(nextButton);

await screen.findByText('Recovery phrase length');
};

const selectRecoveryPhraseLengthStep = async () => {
const nextButton = getNextButton();

const defaultLength = screen.queryByTestId('24-word-passphrase-radio-button');
fireEvent.click(defaultLength);

fireEvent.click(nextButton);

await screen.findByText('Enter your secret passphrase');
};

const recoveryPhraseStep = async () => {
const step1 = 8;
const step2 = 16;
const step3 = 24;

await fillMnemonic(0, step1);
await fillMnemonic(step1, step2);
await fillMnemonic(step2, step3);

await fillMnemonic(0, DEFAULT_MNEMONIC_LENGTH);
await screen.findByText('Total wallet balance');
};

Expand Down Expand Up @@ -109,9 +83,7 @@ describe('Multi Wallet Setup/Restore Wallet', () => {
</AppSettingsProvider>
);

await setupStep();
await keepWalletSecureStep();
await selectRecoveryPhraseLengthStep();
await setupStep('restore');
await recoveryPhraseStep();
});
});
@@ -1,10 +1,8 @@
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { Setup } from './steps/Setup';
import { SelectRecoveryPhraseLength } from './steps/SelectRecoveryPhraseLength';
import { RestoreRecoveryPhrase } from './steps/RestoreRecoveryPhrase';
import { RestoreWalletProvider } from './context';
import { KeepWalletSecure } from './steps/KeepWalletSecure';
import { walletRoutePaths } from '@routes';
import { Providers } from './types';

Expand All @@ -20,8 +18,6 @@ export const RestoreWallet = ({ providers }: Props): JSX.Element => (
<RestoreWalletProvider providers={providers}>
<Switch>
<Route path={restore.setup} component={Setup} />
<Route path={restore.keepSecure} component={KeepWalletSecure} />
<Route path={restore.selectRecoveryPhraseLength} component={SelectRecoveryPhraseLength} />
<Route path={restore.enterRecoveryPhrase} component={RestoreRecoveryPhrase} />
</Switch>
</RestoreWalletProvider>
Expand Down

0 comments on commit 8c1da31

Please sign in to comment.