Skip to content

Commit

Permalink
refactor: onboarding after install
Browse files Browse the repository at this point in the history
  • Loading branch information
fbwoolf committed Jun 19, 2021
1 parent d807ddc commit 097234e
Show file tree
Hide file tree
Showing 12 changed files with 1,067 additions and 1,057 deletions.
5 changes: 5 additions & 0 deletions .changeset/wicked-mails-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@stacks/wallet-web': minor
---

This adds using the app url to redirect and reload the app after the extension is installed.
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@
"@rehooks/document-title": "1.0.2",
"@stacks/auth": "2.0.0-beta.1",
"@stacks/blockchain-api-client": "0.61.0",
"@stacks/connect": "5.5.0",
"@stacks/connect-react": "10.0.0",
"@stacks/connect-ui": "5.1.2",
"@stacks/connect": "6.0.0",
"@stacks/connect-react": "11.0.0",
"@stacks/network": "2.0.0-beta.0",
"@stacks/rpc-client": "1.0.3",
"@stacks/transactions": "2.0.0-beta.1",
Expand Down Expand Up @@ -99,8 +98,6 @@
},
"devDependencies": {
"@actions/core": "1.3.0",
"@changesets/changelog-github": "0.4.0",
"@changesets/cli": "2.16.0",
"@babel/core": "7.14.3",
"@babel/plugin-proposal-class-properties": "7.13.0",
"@babel/plugin-transform-regenerator": "7.13.15",
Expand All @@ -111,6 +108,8 @@
"@babel/runtime": "7.14.0",
"@blockstack/stacks-blockchain-api-types": "0.55.3",
"@blockstack/stacks-blockchain-sidecar-types": "0.0.22",
"@changesets/changelog-github": "0.4.0",
"@changesets/cli": "2.16.0",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.0-beta.8",
"@schemastore/web-manifest": "0.0.5",
"@stacks/prettier-config": "0.0.8",
Expand Down Expand Up @@ -148,8 +147,8 @@
"copy-webpack-plugin": "8.1.1",
"cross-env": "7.0.3",
"crypto-browserify": "3.12.0",
"download": "8.0.0",
"deepmerge": "4.2.2",
"download": "8.0.0",
"esbuild-loader": "2.13.1",
"eslint": "7.28.0",
"eslint-plugin-jest": "24.3.6",
Expand Down Expand Up @@ -194,6 +193,7 @@
"@stacks/ui-core": "7.3.0",
"@stacks/ui-theme": "7.5.0",
"@stacks/ui-utils": "7.5.0",
"@stacks/connect-ui": "5.1.5",
"@tabler/icons": "1.41.2",
"bn.js": "5.2.0",
"buffer": "6.0.3",
Expand Down
2 changes: 1 addition & 1 deletion scripts/generate-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const manifest = {
author: 'Hiro PBC',
description:
'Stacks Wallet. Use the Stacks blockchain to access privacy-friendly apps, and keep data in your control.',
permissions: ['activeTab'],
permissions: ['tabs'],
manifest_version: 2,
background: {
scripts: ['background.js'],
Expand Down
44 changes: 44 additions & 0 deletions src/background/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,33 @@ import { CONTENT_SCRIPT_PORT } from '@content-scripts/content-script';
import { VaultActions } from '@background/vault-types';
import { ExternalMethods, MessageFromContentScript } from '@content-scripts/message-types';

function setAppParamOfSourceInstallingExtension() {
// The app url is saved for use after onboarding
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const appUrl = urlParams.get('app');
// Left for testing only
// const appUrl = 'http://localhost:3000/';
if (appUrl) window.localStorage.setItem('appUrl', appUrl);
}

function getAppParamOfSourceInstallingExtension() {
const appUrl = window.localStorage.getItem('appUrl') || undefined;
return appUrl;
}

// Listen for install event
chrome.runtime.onInstalled.addListener(async details => {
if (details.reason === 'install' && !IS_TEST_ENV) {
setAppParamOfSourceInstallingExtension();
const appUrl = getAppParamOfSourceInstallingExtension();
// Reload the app tab right after install to detect the extension
chrome.tabs.query({ lastFocusedWindow: true }, async tabs => {
const appTab = tabs?.find(tab => tab.url === appUrl);
if (appTab?.id) {
await chrome.tabs.reload(appTab?.id);
}
});
await chrome.tabs.create({
url: chrome.runtime.getURL(`full-page.html#${ScreenPaths.INSTALLED}`),
});
Expand Down Expand Up @@ -61,10 +85,30 @@ chrome.runtime.onConnect.addListener(port => {
}
});

function redirectToAppTab() {
const appUrl = getAppParamOfSourceInstallingExtension();
chrome.tabs.query({ lastFocusedWindow: true }, async tabs => {
const appTab = tabs?.find(tab => tab.url === appUrl);
if (appTab?.id) {
await chrome.tabs.update(appTab?.id, { active: true });
} else {
// Only open a new tab if the user has closed the app tab
await chrome.tabs.create({
url: appUrl,
});
}
});
}

// Listen for events triggered by the background memory vault
chrome.runtime.onMessage.addListener((message: VaultActions, sender, sendResponse) => {
// Only respond to internal messages from our UI, not content scripts in other applications
if (!sender.url?.startsWith(chrome.runtime.getURL(''))) return;
// Go back to app tab after setting password
if (message.method === 'completeOnboarding') {
// Delay redirect for a smoother transition
setTimeout(() => redirectToAppTab(), 500);
}
void vaultMessageHandler(message).then(sendResponse).catch(sendResponse);
// Return true to specify that we are responding async
return true;
Expand Down
4 changes: 3 additions & 1 deletion src/background/vault-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type SetPassword = VaultMessage<InternalMethods.setPassword, string>;
export type UnlockWallet = VaultMessage<InternalMethods.unlockWallet, string>;
export type LockWallet = VaultMessage<InternalMethods.lockWallet, undefined>;
export type SwitchAccount = VaultMessage<InternalMethods.switchAccount, number>;
export type CompleteOnboarding = VaultMessage<InternalMethods.completeOnboarding, undefined>;

export type VaultActions =
| GetWallet
Expand All @@ -27,4 +28,5 @@ export type VaultActions =
| SetPassword
| UnlockWallet
| SwitchAccount
| LockWallet;
| LockWallet
| CompleteOnboarding;
7 changes: 7 additions & 0 deletions src/background/vault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface InMemoryVault {
wallet?: SDKWallet;
currentAccountIndex?: number;
hasSetPassword: boolean;
hasCompletedOnboarding: boolean;
}

const encryptedKeyIdentifier = 'stacks-wallet-encrypted-key' as const;
Expand All @@ -31,6 +32,7 @@ const defaultVault: InMemoryVault = {
encryptedSecretKey: undefined,
hasSetPassword: false,
salt: undefined,
hasCompletedOnboarding: false,
} as const;

function getHasSetPassword() {
Expand Down Expand Up @@ -96,6 +98,11 @@ function throwUnhandledMethod(message: VaultActions) {
// Reducer to manage the state of the vault
export const vaultReducer = async (message: VaultActions): Promise<InMemoryVault> => {
switch (message.method) {
case InternalMethods.completeOnboarding:
return {
...inMemoryVault,
hasCompletedOnboarding: true,
};
case InternalMethods.getWallet:
return {
...inMemoryVault,
Expand Down
6 changes: 6 additions & 0 deletions src/common/hooks/use-vault-messenger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ export const useVaultMessenger = () => {
};
const doLockWallet = messageWrapper({ method: InternalMethods.lockWallet, payload: undefined });

const doCompleteOnboarding = messageWrapper({
method: InternalMethods.completeOnboarding,
payload: undefined,
});

return {
getWallet,
doMakeWallet,
Expand All @@ -107,5 +112,6 @@ export const useVaultMessenger = () => {
doStoreSeed,
doUnlockWallet,
doSwitchAccount,
doCompleteOnboarding,
};
};
2 changes: 1 addition & 1 deletion src/components/account-gate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const AccountGate: React.FC = memo(({ children }) => {
if (step === Step.VIEW_KEY) {
return <SaveYourKeyView hideActions handleNext={() => setStep(Step.SET_PASSWORD)} />;
} else if (step === Step.SET_PASSWORD) {
return <SetPasswordPage />;
return <SetPasswordPage redirect />;
}
}
if (!isSignedIn && encryptedSecretKey) {
Expand Down
1 change: 1 addition & 0 deletions src/content-scripts/message-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export enum InternalMethods {
unlockWallet = 'unlockWallet',
lockWallet = 'lockWallet',
switchAccount = 'switchAccount',
completeOnboarding = 'completeOnboarding',
}

export type ExtensionMethods = ExternalMethods | InternalMethods;
Expand Down
58 changes: 0 additions & 58 deletions src/manifest.json

This file was deleted.

7 changes: 5 additions & 2 deletions src/pages/set-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { USERNAMES_ENABLED } from '@common/constants';
import { validatePassword, blankPasswordValidation } from '@common/validation/validate-password';
import { Body, Caption } from '@components/typography';
import { Header } from '@components/header';
import { useVaultMessenger } from '@common/hooks/use-vault-messenger';

const HUMAN_REACTION_DEBOUNCE_TIME = 250;

Expand All @@ -33,11 +34,11 @@ export const SetPasswordPage: React.FC<SetPasswordProps> = ({
const { doSetPassword, wallet, doFinishSignIn } = useWallet();
const doChangeScreen = useDoChangeScreen();
const { decodedAuthRequest } = useOnboardingState();
const { doCompleteOnboarding } = useVaultMessenger();

const submit = useCallback(
async (password: string) => {
if (!wallet) throw 'Please log in before setting a password.';
setLoading(true);
await doSetPassword(password);
if (accountGate) return;
if (decodedAuthRequest) {
Expand Down Expand Up @@ -70,11 +71,13 @@ export const SetPasswordPage: React.FC<SetPasswordProps> = ({
setLoading(true);
if (strengthResult.meetsAllStrengthRequirements) {
await submit(password);
// Sends message to background script
void doCompleteOnboarding();
return;
}
setLoading(false);
},
[strengthResult, submit]
[strengthResult, submit, doCompleteOnboarding]
);

const validationSchema = yup.object({
Expand Down
Loading

0 comments on commit 097234e

Please sign in to comment.