Skip to content

Commit

Permalink
feat: send user back into unfinished onboarding flow
Browse files Browse the repository at this point in the history
  • Loading branch information
hstove committed Mar 12, 2020
1 parent 58b220a commit c5d497c
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 24 deletions.
7 changes: 5 additions & 2 deletions packages/app/src/common/hooks/use-analytics.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useSelector, useDispatch } from 'react-redux';
import { selectDecodedAuthRequest } from '@store/onboarding/selectors';
import { doTrack as track, doTrackScreenChange } from '@common/track';
import { doChangeScreen as changeScreen } from '@store/onboarding/actions';
import { ScreenPaths } from '@store/onboarding/types';
import { doChangeScreen as changeScreen, doSetOnboardingPath } from '@store/onboarding/actions';
import { ScreenPaths, persistedScreens } from '@store/onboarding/types';
import { useAppDetails } from './useAppDetails';
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
Expand Down Expand Up @@ -33,6 +33,9 @@ export const useAnalytics = () => {
};

const doChangeScreen = (path: ScreenPaths) => {
if (persistedScreens.includes(path)) {
dispatch(doSetOnboardingPath(path));
}
doTrackScreenChange(path, authRequest);
return doNavigatePage(path);
};
Expand Down
13 changes: 12 additions & 1 deletion packages/app/src/common/hooks/use-onboarding-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
selectMagicRecoveryCode,
selectOnboardingProgress,
selectUsername,
selectOnboardingPath,
} from '@store/onboarding/selectors';

export const useOnboardingState = () => {
Expand All @@ -17,6 +18,16 @@ export const useOnboardingState = () => {
const magicRecoveryCode = useSelector(selectMagicRecoveryCode);
const isOnboardingInProgress = useSelector(selectOnboardingProgress);
const username = useSelector(selectUsername);
const onboardingPath = useSelector(selectOnboardingPath);

return { secretKey, screen, authRequest, decodedAuthRequest, magicRecoveryCode, isOnboardingInProgress, username };
return {
secretKey,
screen,
authRequest,
decodedAuthRequest,
magicRecoveryCode,
isOnboardingInProgress,
username,
onboardingPath,
};
};
28 changes: 16 additions & 12 deletions packages/app/src/components/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const Routes: React.FC = () => {
const dispatch = useDispatch();
const { doChangeScreen } = useAnalytics();
const { identities } = useWallet();
const { isOnboardingInProgress, decodedAuthRequest } = useOnboardingState();
const { isOnboardingInProgress, decodedAuthRequest, onboardingPath } = useOnboardingState();
const authRequest = authenticationInit();

useEffect(() => {
Expand All @@ -38,6 +38,9 @@ export const Routes: React.FC = () => {
const isSignedIn = !isOnboardingInProgress && identities.length;

const getSignUpElement = () => {
if (onboardingPath) {
return <Navigate to={onboardingPath} />;
}
if (isSignedIn) {
return <Navigate to={{ pathname: '/', hash: `connect/choose-account?${location.hash.split('?')[1]}` }} />;
}
Expand All @@ -47,6 +50,16 @@ export const Routes: React.FC = () => {
return <Create next={() => doChangeScreen(ScreenPaths.SECRET_KEY)} />;
};

const getUsernameElement = () => {
if (onboardingPath) {
return <Username />;
}
if (isSignedIn) {
return <Navigate to={'/connect/choose-account'} />;
}
return <Username />;
};

return (
<RoutesDom>
<Route path="/" element={<Home />} />
Expand All @@ -63,16 +76,7 @@ export const Routes: React.FC = () => {
/>
}
/>
<Route
path="/sign-up/username"
element={
isSignedIn ? (
<Navigate to={'/connect/choose-account'} />
) : (
<Username next={() => doChangeScreen(ScreenPaths.GENERATION)} />
)
}
/>
<Route path="/sign-up/username" element={getUsernameElement()} />
{/*Sign In*/}
<Route
path="/sign-in"
Expand All @@ -91,7 +95,7 @@ export const Routes: React.FC = () => {
path="/sign-in/recover"
element={<DecryptRecoveryCode next={() => doChangeScreen(ScreenPaths.CHOOSE_ACCOUNT)} />}
/>
<Route path="/sign-in/add-account" element={<Username next={() => doChangeScreen(ScreenPaths.GENERATION)} />} />;
<Route path="/sign-in/add-account" element={<Username />} />;
<Route
path="/connect/choose-account"
element={
Expand Down
7 changes: 2 additions & 5 deletions packages/app/src/pages/username.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,9 @@ const errorTextMap = {
[IdentityNameValidityError.UNAVAILABLE]: identityNameUnavailableError,
};

interface UsernameProps {
next: () => void;
}
interface UsernameProps {}

export const Username: React.FC<UsernameProps> = ({ next }) => {
export const Username: React.FC<UsernameProps> = () => {
const { pathname } = useLocation();

const { wallet } = useWallet();
Expand Down Expand Up @@ -78,7 +76,6 @@ export const Username: React.FC<UsernameProps> = ({ next }) => {

if (!wallet) {
dispatch(doSetUsername(username));
next();
return;
}

Expand Down
6 changes: 2 additions & 4 deletions packages/app/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { persistReducer, persistStore } from 'redux-persist';
import thunk from 'redux-thunk';
import storage from 'redux-persist/lib/storage';
import { walletReducer, WalletState } from './wallet';
import { permissionsReducer, PermissionsState } from './permissions';
import { WalletTransform } from './transforms';
import { WalletTransform, OnboardingTransform } from './transforms';
import { onboardingReducer } from './onboarding/reducer';
import { OnboardingState } from './onboarding/types';

Expand All @@ -21,8 +20,7 @@ const reducers = combineReducers<AppState>({
const persistConfig = {
storage,
key: 'blockstack-redux',
transforms: [WalletTransform],
whitelist: ['settings', 'wallet', 'permissions'],
transforms: [WalletTransform, OnboardingTransform],
};

const persistedReducer = persistReducer(persistConfig, reducers);
Expand Down
7 changes: 7 additions & 0 deletions packages/app/src/store/onboarding/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
SAVE_AUTH_REQUEST,
SET_MAGIC_RECOVERY_CODE,
SET_USERNAME,
SET_ONBOARDING_PATH,
} from './types';
import { decodeToken } from 'jsontokens';
import { doGenerateWallet, didGenerateWallet, WalletActions } from '../wallet';
Expand Down Expand Up @@ -55,6 +56,11 @@ export const doSetUsername = (username: string): OnboardingActions => ({
username,
});

export const doSetOnboardingPath = (onboardingPath?: ScreenPaths): OnboardingActions => ({
type: SET_ONBOARDING_PATH,
onboardingPath,
});

export function doCreateSecretKey(): ThunkAction<void, AppState, {}, OnboardingActions | WalletActions> {
return async dispatch => {
const wallet = await dispatch(doGenerateWallet(DEFAULT_PASSWORD));
Expand Down Expand Up @@ -168,6 +174,7 @@ export function doFinishSignIn(
transitPublicKey: decodedAuthRequest.public_keys[0],
});
finalizeAuthResponse({ decodedAuthRequest, authRequest, authResponse });
dispatch(doSetOnboardingPath(undefined));
dispatch(didGenerateWallet(wallet));
dispatch(doSetOnboardingProgress(false));
};
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/store/onboarding/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ScreenPaths,
SET_MAGIC_RECOVERY_CODE,
SET_USERNAME,
SET_ONBOARDING_PATH,
} from './types';

const initialState: OnboardingState = {
Expand Down Expand Up @@ -58,6 +59,11 @@ export const onboardingReducer: Reducer<OnboardingState, OnboardingActions> = (
...state,
onboardingInProgress: action.payload,
};
case SET_ONBOARDING_PATH:
return {
...state,
onboardingPath: action.onboardingPath,
};
default:
return state;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/store/onboarding/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ export const selectUsername = (state: AppState) => state.onboarding.username;
export const selectAppURL = (state: AppState) => state.onboarding.appURL;

export const selectOnboardingProgress = (state: AppState) => state.onboarding.onboardingInProgress;

export const selectOnboardingPath = (state: AppState) => state.onboarding.onboardingPath;
10 changes: 10 additions & 0 deletions packages/app/src/store/onboarding/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const SAVE_KEY = 'ONBOARDING/SAVE_KEY';
export const SAVE_AUTH_REQUEST = 'ONBOARDING/SAVE_AUTH_REQUEST';
export const SET_MAGIC_RECOVERY_CODE = 'ONBOARDING/SET_MAGIC_RECOVERY_CODE';
export const SET_USERNAME = 'ONBOARDING/SET_USERNAME';
export const SET_ONBOARDING_PATH = 'ONBOARDING/SET_ONBOARDING_PATH';

export enum ScreenName {
CHOOSE_ACCOUNT = 'screens/CHOOSE_ACCOUNT',
Expand Down Expand Up @@ -34,6 +35,8 @@ export enum ScreenPaths {
HOME = '/',
}

export const persistedScreens = [ScreenPaths.SECRET_KEY, ScreenPaths.SAVE_KEY, ScreenPaths.USERNAME];

// TODO: clarify usage of password for local key encryption
export const DEFAULT_PASSWORD = 'password';

Expand All @@ -48,6 +51,7 @@ export interface OnboardingState {
magicRecoveryCode?: string;
username?: string;
onboardingInProgress?: boolean;
onboardingPath?: ScreenPaths;
}

interface OnboardingProgressAction {
Expand Down Expand Up @@ -84,10 +88,16 @@ interface SetUsername {
username: string;
}

interface SetOnboardingPath {
type: typeof SET_ONBOARDING_PATH;
onboardingPath?: ScreenPaths;
}

export type OnboardingActions =
| OnboardingProgressAction
| ChangePageAction
| StoreSecretKey
| SetMagicRecoveryCode
| SaveAuthRequest
| SetOnboardingPath
| SetUsername;
18 changes: 18 additions & 0 deletions packages/app/src/store/transforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,21 @@ export const WalletTransform = createTransform(
},
{ whitelist: ['wallet'] }
);

interface InboundOnboardingState {
onboardingPath?: string;
}

/**
* For the onboarding reducer, we only want to persist the 'onboarding path'.
* This allows users to jump back into the step they left off on, if they close the onboarding window.
*/
export const OnboardingTransform = createTransform(
(inboundState: InboundOnboardingState) => ({
onboardingPath: inboundState.onboardingPath,
}),
outboundState => {
return { ...outboundState };
},
{ whitelist: ['onboarding'] }
);

0 comments on commit c5d497c

Please sign in to comment.