Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 16 additions & 1 deletion packages/web/src/common/store/pages/signon/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const VALIDATE_HANDLE_FAILED = 'SIGN_ON/VALIDATE_HANDLE_FAILED'
export const HIDE_PREVIEW_HINT = 'SIGN_ON/HIDE_PREVIEW_HINT'
export const FOLLOW_ARTISTS = 'SIGN_ON/FOLLOW_ARTISTS'
export const SET_ACCOUNT_READY = 'SIGN_ON/SET_ACCOUNT_READY'
export const SET_IDENTITY_ACCOUNT_READY = 'SIGN_ON/SET_IDENTITY_ACCOUNT_READY'

export const CHECK_EMAIL = 'SIGN_ON/CHECK_EMAIL'

Expand Down Expand Up @@ -191,6 +192,7 @@ export type SignUpFailedParams = {
error: string
phase: string
redirectRoute?: string
shouldRedirect?: boolean
shouldReport: boolean
shouldToast: boolean
message?: string
Expand All @@ -201,6 +203,7 @@ export const signUpFailed = ({
error,
phase,
redirectRoute,
shouldRedirect,
shouldReport,
shouldToast,
message,
Expand All @@ -210,6 +213,7 @@ export const signUpFailed = ({
error,
phase,
redirectRoute,
shouldRedirect,
shouldReport,
shouldToast,
message,
Expand Down Expand Up @@ -285,6 +289,14 @@ export function setAccountReady() {
return { type: SET_ACCOUNT_READY }
}

/**
* Marks the Identity portion of signup complete so core account creation can
* be retried without registering the email again.
*/
export function setIdentityAccountReady() {
return { type: SET_IDENTITY_ACCOUNT_READY }
}

/**
* Adds the user ids to be followed on account completion
* @param userIds The user ids to add as selected and follow
Expand Down Expand Up @@ -326,7 +338,10 @@ export const nextPage = (isMobile: boolean) => ({ type: NEXT_PAGE, isMobile })
export const previousPage = () => ({ type: PREVIOUS_PAGE })
export const goToPage = (page: Pages) => ({ type: GO_TO_PAGE, page })

export const signUpTimeout = () => ({ type: SIGN_UP_TIMEOUT })
export const signUpTimeout = () => ({
type: SIGN_UP_TIMEOUT,
shouldRedirect: false
})
export const updateRouteOnCompletion = (route: string) => ({
type: UPDATE_ROUTE_ON_COMPLETION,
route
Expand Down
5 changes: 4 additions & 1 deletion packages/web/src/common/store/pages/signon/errorSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ function* handleSignOnError(
const SIGN_IN_ERROR_PREFIX = 'SIGN_ON/SIGN_IN_ERROR_'

// Determine whether the error should redirect to /error and whether it should report it.
const shouldRedirect = !noRedirectSet.has(action.type)
const shouldRedirect =
'shouldRedirect' in action
? (action.shouldRedirect ?? !noRedirectSet.has(action.type))
: !noRedirectSet.has(action.type)

const shouldReport = 'shouldReport' in action ? action.shouldReport : true

Expand Down
52 changes: 52 additions & 0 deletions packages/web/src/common/store/pages/signon/getSignOnRoute.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {
SIGN_IN_PAGE,
SIGN_UP_FINISH_PROFILE_PAGE,
SIGN_UP_HANDLE_PAGE,
SIGN_UP_PASSWORD_PAGE
} from '@audius/common/src/utils/route'
import { describe, expect, it } from 'vitest'

import { getSignOnRoute } from './getSignOnRoute'
import { Pages } from './types'

describe('getSignOnRoute', () => {
it('routes Identity-only accounts to handle selection', () => {
expect(
getSignOnRoute({
signIn: false,
page: Pages.PROFILE,
hasHandle: false
})
).toBe(SIGN_UP_HANDLE_PAGE)
})

it('routes indexed incomplete accounts to profile completion', () => {
expect(
getSignOnRoute({
signIn: false,
page: Pages.PROFILE,
hasHandle: true
})
).toBe(SIGN_UP_FINISH_PROFILE_PAGE)
})

it('preserves the guest password resume route', () => {
expect(
getSignOnRoute({
signIn: false,
page: Pages.PASSWORD,
hasHandle: true
})
).toBe(SIGN_UP_PASSWORD_PAGE)
})

it('routes sign-in requests to sign in regardless of page state', () => {
expect(
getSignOnRoute({
signIn: true,
page: Pages.PROFILE,
hasHandle: true
})
).toBe(SIGN_IN_PAGE)
})
})
37 changes: 37 additions & 0 deletions packages/web/src/common/store/pages/signon/getSignOnRoute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
SIGN_IN_PAGE,
SIGN_UP_FINISH_PROFILE_PAGE,
SIGN_UP_HANDLE_PAGE,
SIGN_UP_PAGE,
SIGN_UP_PASSWORD_PAGE
} from '@audius/common/src/utils/route'

import { Pages } from './types'

type GetSignOnRouteParams = {
signIn: boolean
page: string | null
hasHandle: boolean
}

/**
* Maps the legacy sign-on page state to the URL-based signup flow.
* Incomplete Identity-only accounts have no handle yet, so PROFILE resumes at
* handle selection; accounts with an indexed handle resume at profile details.
*/
export const getSignOnRoute = ({
signIn,
page,
hasHandle
}: GetSignOnRouteParams) => {
if (signIn) return SIGN_IN_PAGE

switch (page) {
case Pages.PASSWORD:
return SIGN_UP_PASSWORD_PAGE
case Pages.PROFILE:
return hasHandle ? SIGN_UP_FINISH_PROFILE_PAGE : SIGN_UP_HANDLE_PAGE
default:
return SIGN_UP_PAGE
}
}
14 changes: 14 additions & 0 deletions packages/web/src/common/store/pages/signon/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { route } from '@audius/common/utils'

import {
SET_ACCOUNT_READY,
SET_IDENTITY_ACCOUNT_READY,
SET_FIELD,
SET_VALUE_FIELD,
VALIDATE_EMAIL,
Expand All @@ -21,6 +22,7 @@ import {
FINISH_SIGN_UP,
SIGN_UP_SUCCEEDED,
SIGN_UP_FAILED,
SIGN_UP_TIMEOUT,
SIGN_IN,
SIGN_IN_FAILED,
SIGN_IN_SUCCEEDED,
Expand Down Expand Up @@ -85,6 +87,12 @@ const actionsMap = {
accountReady: true
}
},
[SET_IDENTITY_ACCOUNT_READY](state) {
return {
...state,
accountAlreadyExisted: true
}
},
[RESET_SIGN_ON](state) {
return {
...initialState,
Expand Down Expand Up @@ -299,6 +307,12 @@ const actionsMap = {
status: 'failure'
}
},
[SIGN_UP_TIMEOUT](state, action) {
return {
...state,
status: 'failure'
}
},
[SIGN_IN](state, action) {
return {
...state,
Expand Down
23 changes: 23 additions & 0 deletions packages/web/src/common/store/pages/signon/reducer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, expect, it } from 'vitest'

import { setIdentityAccountReady, signUpTimeout } from './actions'
import reducer from './reducer'

describe('sign-on resumable signup state', () => {
it('preserves the Identity completion checkpoint for retries', () => {
const state = reducer(undefined, setIdentityAccountReady())

expect(state.accountAlreadyExisted).toBe(true)
})

it('turns a confirmation timeout into a retryable failure', () => {
const loadingState = {
...reducer(undefined, { type: 'TEST/INIT' }),
status: 'loading'
}
const timeoutAction = signUpTimeout()

expect(reducer(loadingState, timeoutAction).status).toBe('failure')
expect(timeoutAction.shouldRedirect).toBe(false)
})
})
Loading
Loading