-
-
-
+ {/* Logos + Title */}
+
+
+
@@ -352,7 +357,7 @@ export const OAuthLoginPage = () => {
h='88px'
w='88px'
borderRadius='l'
- css={{ overflow: 'hidden' }}
+ css={{ overflow: 'hidden', flexShrink: 0 }}
>
{appImage ? (
@@ -372,11 +377,17 @@ export const OAuthLoginPage = () => {
)}
- {`${messages.allow}:`}
-
- {appName}
-
+
+
+ {`${messages.allow}:`}
+
+
+ {appName}
+
+
+
+ {/* Permissions */}
{userAlreadyWriteAuthorized ? null : (
{
txParams={txParams}
/>
)}
-
- {isLoggedIn ? (
-
-
+
+ {/* Account / Sign-in section */}
+ {isLoggedIn ? (
+
+
+
{messages.signedInAs}
@@ -407,71 +416,78 @@ export const OAuthLoginPage = () => {
user={account}
/>
-
-
- {messages.signOut}
-
- {accounts.length > 0 ? (
-
- {messages.switchAccount}
-
- ) : null}
-
-
- {userAlreadyWriteAuthorized
- ? messages.continueButton
- : messages.authorizeButton}
-
-
- ) : (
-
- )}
- {generalSubmitError == null ? null : (
-
-
{generalSubmitError}
+ >
+ ) : null}
+
+ {messages.signInButton}
+
+
+
+
+ {messages.signUp}
+
- )}
-
+
+ )}
+
+ {generalSubmitError == null ? null : (
+
+ {generalSubmitError}
+
+ )}
)}
diff --git a/packages/web/src/pages/oauth-login-page/components/ContentWrapper.tsx b/packages/web/src/pages/oauth-login-page/components/ContentWrapper.tsx
index ff26cd73cde..08ec97e667a 100644
--- a/packages/web/src/pages/oauth-login-page/components/ContentWrapper.tsx
+++ b/packages/web/src/pages/oauth-login-page/components/ContentWrapper.tsx
@@ -23,6 +23,7 @@ export const ContentWrapper = ({
direction='column'
mv='3xl'
alignSelf='flex-start'
+ border='strong'
borderRadius='xl'
>
{children}
diff --git a/packages/web/src/pages/oauth-login-page/components/PermissionsSection.tsx b/packages/web/src/pages/oauth-login-page/components/PermissionsSection.tsx
index 5eb2ccd42c7..3816e03073e 100644
--- a/packages/web/src/pages/oauth-login-page/components/PermissionsSection.tsx
+++ b/packages/web/src/pages/oauth-login-page/components/PermissionsSection.tsx
@@ -1,13 +1,13 @@
import { PropsWithChildren } from 'react'
import {
+ Divider,
Flex,
IconInfo,
IconPencil,
IconVisibilityPublic,
Text
} from '@audius/harmony'
-import cn from 'classnames'
import LoadingSpinner from 'components/loading-spinner/LoadingSpinner'
@@ -15,25 +15,14 @@ import styles from '../OAuthLoginPage.module.css'
import { messages } from '../messages'
import { WriteOnceParams, WriteOnceTx } from '../utils'
-type PermissionTextProps = PropsWithChildren<{}>
-const PermissionText = ({ children }: PermissionTextProps) => {
- return (
-
- {children}
-
- )
-}
-
-type PermissionDetailProps = PropsWithChildren<{
- className?: string
-}>
+type PermissionDetailProps = PropsWithChildren<{}>
const PermissionDetail = ({ children }: PermissionDetailProps) => {
return (
-
+
{children}
-
+
)
}
@@ -62,76 +51,69 @@ export const PermissionsSection = ({
txParams?: WriteOnceParams
}) => {
return (
- <>
-
-
- {messages.permissionsRequestedHeader}
-
-
+
+
+ {messages.permissionsRequestedHeader}
+
-
-
- {scope === 'write' || scope === 'write_once' ? (
-
- ) : (
-
- )}
-
-
-
-
+ {/* First permission */}
+
+
+
+ {scope === 'write' || scope === 'write_once' ? (
+
+ ) : (
+
+ )}
+
+
{scope === 'write'
? messages.writeAccountAccess
: scope === 'write_once'
? getWriteOncePermissionTitle(tx)
: messages.readOnlyAccountAccess}
- {scope === 'write' ? (
-
-
- {messages.writeAccessGrants}
-
-
- ) : null}
- {scope === 'write_once' ? (
-
- {txParams?.wallet.slice(0, 6)}...{txParams?.wallet.slice(-4)}
-
- ) : null}
- {scope === 'read' ? (
-
-
- {messages.readOnlyGrants}
-
-
- ) : null}
-
-
-
-
-
-
- {messages.yourAccountData}
- {isLoggedIn ? (
-
- {isLoading ? (
-
- ) : userEmail ? (
- `${messages.yourAccountDataAccess}: ${userEmail}`
- ) : (
- messages.yourAccountDataAccessNoEmail
- )}
-
- ) : null}
+ {scope === 'write' ? (
+ {messages.writeAccessGrants}
+ ) : null}
+ {scope === 'write_once' ? (
+
+ {txParams?.wallet.slice(0, 6)}...{txParams?.wallet.slice(-4)}
+
+ ) : null}
+ {scope === 'read' ? (
+ {messages.readOnlyGrants}
+ ) : null}
+
+
+
+
+
+
+ {/* Second permission */}
+
+
+
+
+
+
+ {messages.yourAccountData}
+
-
+ {isLoggedIn ? (
+
+ {isLoading ? (
+
+ ) : userEmail ? (
+ `${messages.yourAccountDataAccess}: ${userEmail}`
+ ) : (
+ messages.yourAccountDataAccessNoEmail
+ )}
+
+ ) : null}
+
- >
+
)
}
diff --git a/packages/web/src/pages/oauth-login-page/messages.ts b/packages/web/src/pages/oauth-login-page/messages.ts
index e0d95b1d715..e1f177666a8 100644
--- a/packages/web/src/pages/oauth-login-page/messages.ts
+++ b/packages/web/src/pages/oauth-login-page/messages.ts
@@ -18,9 +18,9 @@ export const messages = {
signOut: 'Sign Out',
signUp: `Don't have an account? Sign up`,
switchAccount: 'Switch Account',
- authorizeButton: 'Authorize App',
+ authorizeButton: 'Sign In & Authorize',
continueButton: 'Continue',
- signInButton: 'Sign In & Authorize App',
+ signInButton: 'Sign In & Authorize',
invalidCredentialsError: 'Invalid Credentials',
miscError: 'An error has occurred. Please try again.',
accountIncompleteError:
@@ -30,7 +30,7 @@ export const messages = {
redirectURIInvalidError:
'Whoops, this is an invalid link (redirect URI missing or invalid).',
missingAppNameError: 'Whoops, this is an invalid link (app name missing).',
- otpError: 'Enter the verification code sent to your email',
+ otpPrompt: 'Enter the verification code sent to your email',
scopeError: `Whoops, this is an invalid link (scope missing or invalid).`,
connectWalletNoPostMessageError:
'Whoops, this is an invalid link (redirectUri must be `postMessage` if tx is `connectDashboardWallet`).',
@@ -48,7 +48,7 @@ export const messages = {
'Whoops, something went wrong. Please close this window and try again.',
responseModeError:
'Whoops, this is an invalid link (response mode invalid - if set, must be "fragment" or "query").',
- signedInAs: `You’re signed in as`,
+ signedInAs: `You’re Signed in as`,
missingApiKeyError: 'Whoops, this is an invalid link (app API Key missing)',
invalidApiKeyError: 'Whoops, this is an invalid link (app API Key invalid)',
approveTxToConnectProfile:
diff --git a/packages/web/src/pages/sign-in-page/ConfirmEmailPage.tsx b/packages/web/src/pages/sign-in-page/ConfirmEmailPage.tsx
index 9b4ed6fad2b..d380209273b 100644
--- a/packages/web/src/pages/sign-in-page/ConfirmEmailPage.tsx
+++ b/packages/web/src/pages/sign-in-page/ConfirmEmailPage.tsx
@@ -24,7 +24,6 @@ import {
} from 'common/store/pages/signon/selectors'
import { HarmonyTextField } from 'components/form-fields/HarmonyTextField'
import { ToastContext } from 'components/toast/ToastContext'
-import { useMedia } from 'hooks/useMedia'
import { Heading, Page, PageFooter } from 'pages/sign-up-page/components/layout'
import { useSelector } from 'utils/reducer'
@@ -40,7 +39,6 @@ const ConfirmEmailSchema = toFormikValidationSchema(confirmEmailSchema)
export const ConfirmEmailPage = () => {
const dispatch = useDispatch()
- const { isMobile } = useMedia()
const { value: email } = useSelector(getEmailField)
const { value: password } = useSelector(getPasswordField)
const { value: otp } = useSelector(getOtpField)
@@ -65,7 +63,7 @@ export const ConfirmEmailPage = () => {
onSubmit={handleSubmit}
validationSchema={ConfirmEmailSchema}
>
-
+
{
const dispatch = useDispatch()
const { isMobile } = useMedia()
- const { height: windowHeight } = useWindowSize()
- const isSmallDesktop = windowHeight < smallDesktopWindowHeight
const navigate = useNavigateToPage()
const [showForgotPassword, setShowForgotPassword] = useState(false)
const { value: existingEmail } = useSelector(getEmailField)
@@ -72,8 +71,6 @@ export const SignInPage = () => {
useEffect(() => {
if (requiresOtp) {
navigate(SIGN_IN_CONFIRM_EMAIL_PAGE)
- // This unsets the otp error so we can come back to this page
- // if necessary
dispatch(setValueField('password', existingPassword))
}
}, [navigate, requiresOtp, existingPassword, dispatch])
@@ -96,6 +93,9 @@ export const SignInPage = () => {
[dispatch]
)
+ const logoHeight = isMobile ? 48 : 56
+ const logoWidth = isMobile ? 236 : 275
+
return (
<>
{
validationSchema={SignInSchema}
validateOnChange={false}
>
-
-
-
- {isMobile || isSmallDesktop ? (
-
- ) : (
-
- )}
-
-
+
-
+
+
-
+
- {!isMobile ? : null}
{
- setShowForgotPassword(true)
- }}
+ onClick={() => setShowForgotPassword(true)}
+ >
+ {messages.forgotPassword}
+
+
+
+
+ {messages.newToAudius}{' '}
+
+ {messages.createAnAccount}
+
+
+
+ ) : (
+
+
+
+
+
+
+ setShowForgotPassword(true)}
>
- {signInPageMessages.forgotPassword}
+ {messages.forgotPassword}
+
+
+
+
+ {messages.newToAudius}{' '}
+
+ {messages.createAnAccount}
+
+
+
- {!isMobile ? (
-
- ) : null}
-
+ )}
{
const { children } = props
- const { spacing, motion, color } = useTheme()
+ const { spacing } = useTheme()
const routeOnExit = useSelector(getRouteOnExit)
const location = useLocation()
- const hideCloseButton = [
- SIGN_UP_GENRES_PAGE,
- SIGN_UP_ARTISTS_PAGE,
- SIGN_UP_APP_CTA_PAGE,
- SIGN_UP_LOADING_PAGE
- ].some((path) => {
+ const hideCloseButton = [SIGN_UP_LOADING_PAGE].some((path) => {
const match = matchPath(path, location.pathname)
return match && match.pathname === location.pathname
})
- const collapsedDesktopPageMatch = [
+ const isCompactCard = [
SIGN_IN_PAGE,
SIGN_IN_CONFIRM_EMAIL_PAGE,
SIGN_UP_PAGE,
SIGN_UP_EMAIL_PAGE,
SIGN_UP_PASSWORD_PAGE,
- SIGN_UP_REVIEW_HANDLE_PAGE,
- SIGN_UP_APP_CTA_PAGE
+ SIGN_UP_REVIEW_HANDLE_PAGE
].some((path) => {
const match = matchPath(path, location.pathname)
return match && match.pathname === location.pathname
})
- const isExpanded = !collapsedDesktopPageMatch
-
return (
+ {/* Background image + dark overlay */}
+
+
+
+ {/* Nav overlay: X close (left) + Audius logo (right) - always white in light/dark mode */}
{!hideCloseButton ? (
-
-
-
+
+
+
+
+
) : null}
-
-
{children}
-
-
-
-
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
-
-
-
+
+
)
}
-type MobileSignOnRootProps = RootProps & {
- isLoaded?: boolean
-}
-
-type PanelState = 'collapsed' | 'expanding' | 'expanded' | 'collapsing'
+type MobileSignOnRootProps = RootProps
const MobileSignOnRoot = (props: MobileSignOnRootProps) => {
- const { children, isLoaded } = props
- const [panelState, setPanelState] = useState
('collapsed')
- const { motion } = useTheme()
- const [ref, { height: panelHeight }] = useMeasure()
- const collapsedPanelHeight = useRef(panelHeight)
-
- const location = useLocation()
- const collapsedMobilePageMatch = [
- SIGN_IN_PAGE,
- SIGN_UP_PAGE,
- SIGN_UP_EMAIL_PAGE
- ].some((path) => {
- const match = matchPath(path, location.pathname)
- return match && match.pathname === location.pathname
- })
-
- const shouldPageExpand = !collapsedMobilePageMatch
-
- useLayoutEffect(() => {
- if (panelState === 'collapsed') {
- collapsedPanelHeight.current = panelHeight
- }
- }, [panelState, panelHeight])
-
- // TODO: use `onTransitionEnd`
- useEffect(() => {
- if (shouldPageExpand) {
- setPanelState('expanding')
- const timeout = setTimeout(() => {
- setPanelState('expanded')
- }, 100)
- return () => clearTimeout(timeout)
- } else if (!shouldPageExpand && panelState === 'expanded') {
- setPanelState('collapsing')
- const timeout = setTimeout(() => {
- setPanelState('collapsed')
- }, 500)
- return () => clearTimeout(timeout)
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [shouldPageExpand])
-
- const panelHeightMap = {
- collapsed: 'auto',
- expanding: panelHeight,
- expanded: '100%',
- collapsing: collapsedPanelHeight.current
- }
+ const { children } = props
return (
-
-
- {children}
-
+
-
-
- }
- />
-
- }
- />
-
- {messages.newToAudius}{' '}
-
- {messages.createAccount}
-
-
- }
- />
-
- {messages.newToAudius}{' '}
-
- {messages.createAccount}
-
-
- }
- />
-
+
+ {children}
+
)
}
+const { getSystemAppearance } = themeSelectors
+
export const SignOnPage = () => {
const { isMobile } = useMedia()
const signOnStatus = useSelector(getStatus)
const routeOnExit = useSelector(getRouteOnExit)
+ const systemAppearance = useSelector(getSystemAppearance)
+ const signOnTheme: Theme =
+ systemAppearance === SystemAppearance.DARK
+ ? 'default-dark'
+ : 'default-light'
const dispatch = useDispatch()
const navigate = useNavigate()
const [searchParams] = useSearchParams()
@@ -422,23 +287,20 @@ export const SignOnPage = () => {
}
})
- const [isLoaded, setIsLoaded] = useState(false)
const SignOnRoot = isMobile ? MobileSignOnRoot : DesktopSignOnRoot
const location = useLocation()
const isSignUp = location.pathname.startsWith(SIGN_UP_PAGE)
- useEffectOnce(() => {
- setIsLoaded(true)
- })
-
if (signOnStatus === EditingStatus.SUCCESS) {
return
}
return (
-
-
- {isSignUp ? : }
-
+
+
+
+ {isSignUp ? : }
+
+
)
}
diff --git a/packages/web/src/pages/sign-up-page/components/NavHeader.tsx b/packages/web/src/pages/sign-up-page/components/NavHeader.tsx
index 418859e458b..95cb1b38f34 100644
--- a/packages/web/src/pages/sign-up-page/components/NavHeader.tsx
+++ b/packages/web/src/pages/sign-up-page/components/NavHeader.tsx
@@ -1,36 +1,10 @@
-import { ReactNode, useCallback } from 'react'
+import { useCallback } from 'react'
-import { route } from '@audius/common/utils'
-import {
- Box,
- Flex,
- FlexProps,
- IconAudiusLogoHorizontal,
- IconCaretLeft,
- IconCloseAlt,
- PlainButton,
- useTheme
-} from '@audius/harmony'
-import { Route, Routes, useMatch, useNavigate } from 'react-router'
-
-import { getRouteOnExit } from 'common/store/pages/signon/selectors'
-import { useMedia } from 'hooks/useMedia'
-import { useSelector } from 'utils/reducer'
+import { Flex, IconCaretLeft, PlainButton } from '@audius/harmony'
+import { useMatch, useNavigate } from 'react-router'
import { useDetermineAllowedRoute } from '../utils/useDetermineAllowedRoutes'
-import { ProgressHeader } from './ProgressHeader'
-
-const {
- SIGN_IN_PAGE,
- SIGN_UP_ARTISTS_PAGE,
- SIGN_UP_EMAIL_PAGE,
- SIGN_UP_FINISH_PROFILE_PAGE,
- SIGN_UP_GENRES_PAGE,
- SIGN_UP_HANDLE_PAGE,
- SIGN_UP_PAGE
-} = route
-
const useIsBackAllowed = () => {
const match = useMatch('/signup/:currentPath')
const matchSignIn = useMatch('/signin/:currentPath')
@@ -50,171 +24,33 @@ const useIsBackAllowed = () => {
return false
}
-type HeaderRootProps = FlexProps & {
- children: ReactNode
-}
-
-const HeaderRoot = (props: HeaderRootProps) => {
- const { children, ...other } = props
+export const NavHeader = () => {
const isBackAllowed = useIsBackAllowed()
- const { spacing } = useTheme()
+ const navigate = useNavigate()
+
+ const handleBack = useCallback(() => {
+ navigate(-1)
+ }, [navigate])
+
+ if (!isBackAllowed) return null
return (
- {children}
-
- )
-}
-
-export const NavHeader = () => {
- const isBackAllowed = useIsBackAllowed()
- const navigate = useNavigate()
- const { isMobile } = useMedia()
- const { iconSizes } = useTheme()
- const routeOnExit = useSelector(getRouteOnExit)
-
- const handleClose = useCallback(() => {
- navigate(routeOnExit)
- }, [navigate, routeOnExit])
-
- const audiusLogo =
-
- return (
-
-
-
-
- ) : null
- }
- />
-
-
-
- ) : null
- }
+
-
-
-
- ) : null
- }
- />
- {!isMobile ? (
- <>
-
-
- {audiusLogo}
-
-
-
- }
- />
-
-
- {audiusLogo}
-
-
-
- }
- />
-
-
- {audiusLogo}
-
-
-
- }
- />
-
-
- {audiusLogo}
-
-
-
- }
- />
- >
- ) : null}
-
- {isBackAllowed ? (
- <>
- navigate(-1)}
- iconLeft={IconCaretLeft}
- variant='subdued'
- />
- {audiusLogo}
-
- >
- ) : (
-
- {audiusLogo}
-
- )}
-
- }
- />
-
+
)
}
diff --git a/packages/web/src/pages/sign-up-page/components/layout.tsx b/packages/web/src/pages/sign-up-page/components/layout.tsx
index 2022d714dbc..0fcd9a25257 100644
--- a/packages/web/src/pages/sign-up-page/components/layout.tsx
+++ b/packages/web/src/pages/sign-up-page/components/layout.tsx
@@ -16,8 +16,6 @@ import {
Flex,
FlexProps,
IconArrowRight,
- Paper,
- PaperProps,
Text
} from '@audius/harmony'
import styled, { CSSObject } from '@emotion/styled'
@@ -187,10 +185,10 @@ type PageFooterProps = {
buttonProps?: ButtonProps
centered?: boolean
sticky?: boolean
-} & Omit
+} & Omit
export const PageFooter = (props: PageFooterProps) => {
- const { prefix, postfix, buttonProps, centered, sticky, ...other } = props
+ const { prefix, postfix, buttonProps, sticky, ...other } = props
const { isMobile } = useMedia()
// On the MobileCTAPage we use this footer outside a formik context, hence the default values
const { isSubmitting, touched, isValid } = useFormikContext() ?? {
@@ -203,22 +201,17 @@ export const PageFooter = (props: PageFooterProps) => {
const showButtonsSideBySide = !isMobile && postfix && !prefix
return (
-
@@ -229,7 +222,7 @@ export const PageFooter = (props: PageFooterProps) => {
justifyContent='space-between'
alignItems='center'
gap='l'
- css={centered ? { maxWidth: 343 } : undefined}
+ css={{ maxWidth: '100%' }}
>
{postfix}
+
)
}
diff --git a/packages/web/src/pages/sign-up-page/pages/CreateEmailPage.tsx b/packages/web/src/pages/sign-up-page/pages/CreateEmailPage.tsx
index cb408447de7..0a472052fd0 100644
--- a/packages/web/src/pages/sign-up-page/pages/CreateEmailPage.tsx
+++ b/packages/web/src/pages/sign-up-page/pages/CreateEmailPage.tsx
@@ -3,15 +3,12 @@ import { useCallback, useMemo } from 'react'
import { useQueryContext } from '@audius/common/api'
import { createEmailPageMessages } from '@audius/common/messages'
import { emailSchema } from '@audius/common/schemas'
-import { useExternalWalletSignUpModal } from '@audius/common/store'
import { route } from '@audius/common/utils'
import {
- Box,
Button,
Flex,
+ IconAudiusLogoHorizontal,
IconArrowRight,
- IconAudiusLogoHorizontalColor,
- IconMetamask,
Text,
TextLink
} from '@audius/harmony'
@@ -19,40 +16,38 @@ import { useQueryClient } from '@tanstack/react-query'
import { Form, Formik } from 'formik'
import { useDispatch, useSelector } from 'react-redux'
import { Link } from 'react-router'
-import { useWindowSize } from 'react-use'
import { toFormikValidationSchema } from 'zod-formik-adapter'
-import audiusLogoColored from 'assets/img/audiusLogoColored.png'
-import audiusLogoWhite from 'assets/img/audiusLogoWhite.png'
import { setValueField, startSignUp } from 'common/store/pages/signon/actions'
import { getEmailField } from 'common/store/pages/signon/selectors'
-import PreloadImage from 'components/preload-image/PreloadImage'
import { useMedia } from 'hooks/useMedia'
import { useNavigateToPage } from 'hooks/useNavigateToPage'
import { identify } from 'services/analytics'
-import { isDarkMode } from 'utils/theme/theme'
-import { ExternalWalletSignUpModal } from '../components/ExternalWalletSignUpModal'
import { NewEmailField } from '../components/NewEmailField'
-import { Heading, Page } from '../components/layout'
+import { Heading } from '../components/layout'
const { SIGN_IN_PAGE, SIGN_UP_PASSWORD_PAGE } = route
-const smallDesktopWindowHeight = 900
+const messages = {
+ ...createEmailPageMessages,
+ title: 'Sign Up',
+ mobileTitle: 'Sign Up For Audius',
+ alreadyHaveAccount: 'Already have an account?',
+ logIn: 'Log In',
+ mobileLogIn: 'Sign In',
+ continueButton: 'Continue',
+ mobileSignUpButton: 'Sign Up Free'
+}
type SignUpEmailValues = {
email: string
- withMetaMask?: boolean
}
export const CreateEmailPage = () => {
const { isMobile } = useMedia()
- const { height: windowHeight } = useWindowSize()
- const isSmallDesktop = windowHeight < smallDesktopWindowHeight
const dispatch = useDispatch()
const navigate = useNavigateToPage()
- const { onOpen: openExternalWalletSignUpModal } =
- useExternalWalletSignUpModal()
const existingEmailValue = useSelector(getEmailField)
const queryContext = useQueryContext()
const queryClient = useQueryClient()
@@ -68,26 +63,17 @@ export const CreateEmailPage = () => {
const handleSubmit = useCallback(
async (values: SignUpEmailValues) => {
- const { email, withMetaMask } = values
+ const { email } = values
dispatch(startSignUp())
dispatch(setValueField('email', email))
- identify({
- email
- })
- if (withMetaMask) {
- openExternalWalletSignUpModal()
- } else {
- navigate(SIGN_UP_PASSWORD_PAGE)
- }
+ identify({ email })
+ navigate(SIGN_UP_PASSWORD_PAGE)
},
- [dispatch, navigate, openExternalWalletSignUpModal]
+ [dispatch, navigate]
)
- const signInLink = (
-
- {createEmailPageMessages.signIn}
-
- )
+ const logoHeight = isMobile ? 48 : 56
+ const logoWidth = isMobile ? 236 : 275
return (
{
validateOnMount={!!existingEmailValue}
validateOnChange={false}
>
- {({ isSubmitting, setFieldValue, submitForm }) => (
-
-
- {isMobile || isSmallDesktop ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
-
-
-
- {createEmailPageMessages.haveAccount} {signInLink}
-
-
- {!isMobile && window.ethereum ? (
-
+ {({ isSubmitting }) =>
+ isMobile ? (
+
+
+
+
+
+
+
-
-
- {createEmailPageMessages.metaMaskNotRecommended}{' '}
-
- {createEmailPageMessages.learnMore}
+
+ {messages.alreadyHaveAccount}{' '}
+
+ {messages.mobileLogIn}
- ) : null}
-
- )}
+
+ ) : (
+
+
+
+
+
+
+
+
+ {messages.alreadyHaveAccount}{' '}
+
+ {messages.logIn}
+
+
+
+
+
+ )
+ }
)
}
diff --git a/packages/web/src/pages/sign-up-page/pages/FinishProfilePage.tsx b/packages/web/src/pages/sign-up-page/pages/FinishProfilePage.tsx
index 68567d91f56..c7a935f78bf 100644
--- a/packages/web/src/pages/sign-up-page/pages/FinishProfilePage.tsx
+++ b/packages/web/src/pages/sign-up-page/pages/FinishProfilePage.tsx
@@ -8,7 +8,7 @@ import {
} from '@audius/common/schemas'
import { MAX_DISPLAY_NAME_LENGTH } from '@audius/common/services'
import { route } from '@audius/common/utils'
-import { Button, Flex, Paper, Text, useTheme } from '@audius/harmony'
+import { Flex, Paper, Text, useTheme } from '@audius/harmony'
import { Formik, Form, useFormikContext } from 'formik'
import { useDispatch, useSelector } from 'react-redux'
import { useNavigate } from 'react-router'
@@ -25,7 +25,6 @@ import {
getCoverPhotoField,
getEmailField,
getHandleField,
- getLinkedSocialOnFirstPage,
getNameField,
getProfileImageField
} from 'common/store/pages/signon/selectors'
@@ -34,11 +33,10 @@ import { useMedia } from 'hooks/useMedia'
import { AccountHeader } from '../components/AccountHeader'
import { ImageFieldValue } from '../components/ImageField'
-import { OutOfText } from '../components/OutOfText'
import { Heading, Page, PageFooter } from '../components/layout'
import { useFastReferral } from '../hooks/useFastReferral'
-const { SIGN_UP_GENRES_PAGE, SIGN_UP_LOADING_PAGE } = route
+const { SIGN_UP_LOADING_PAGE } = route
type FinishProfileValues = {
profileImage?: ImageFieldValue
@@ -55,11 +53,9 @@ const ImageUploadErrorText = () => {
if (errors.coverPhoto === finishProfilePageMessages.coverPhotoUploadError) {
errorText = errors.coverPhoto
}
- // Profile image error takes priority
if (
errors.profileImage === finishProfilePageMessages.profileImageUploadError
) {
- // If both images have errors, we show a combined error message
if (errorText !== undefined) {
errorText = finishProfilePageMessages.bothImageUploadError
} else {
@@ -88,12 +84,10 @@ export const FinishProfilePage = () => {
const { value: savedDisplayName } = useSelector(getNameField)
const handle = useSelector(getHandleField)
const email = useSelector(getEmailField)
- const linkedSocialOnFirstPage = useSelector(getLinkedSocialOnFirstPage)
const savedCoverPhoto = useSelector(getCoverPhotoField)
const savedProfileImage = useSelector(getProfileImageField)
const isFastReferral = useFastReferral()
- // If the user comes back from a later page we start with whats in the store
const initialValues = {
profileImage: savedProfileImage || undefined,
coverPhoto: savedCoverPhoto || undefined,
@@ -136,12 +130,10 @@ export const FinishProfilePage = () => {
}
dispatch(setFinishedPhase1(true))
if (isFastReferral) {
- // Fast referral: create account immediately and skip genre/artist selection
dispatch(signUp())
- navigate(SIGN_UP_LOADING_PAGE)
+ navigate(SIGN_UP_LOADING_PAGE, { replace: true })
} else {
- // Normal flow: don't create account yet, let user select genres/artists first
- navigate(SIGN_UP_GENRES_PAGE)
+ navigate('/signup/select-genres', { replace: true })
}
},
[dispatch, isFastReferral, navigate]
@@ -164,14 +156,9 @@ export const FinishProfilePage = () => {
autoFocusInputRef={displayNameInputRef}
>
- )
- }
heading={finishProfilePageMessages.header}
description={finishProfilePageMessages.description}
- centered={!isMobile}
+ centered
/>
{
}}
/>
- navigate(-1)}
- >
- {finishProfilePageMessages.goBack}
-
- )
- }
- />
+
)}
diff --git a/packages/web/src/pages/sign-up-page/pages/PickHandlePage.tsx b/packages/web/src/pages/sign-up-page/pages/PickHandlePage.tsx
index cf892e7d634..63a47f61f9f 100644
--- a/packages/web/src/pages/sign-up-page/pages/PickHandlePage.tsx
+++ b/packages/web/src/pages/sign-up-page/pages/PickHandlePage.tsx
@@ -17,7 +17,6 @@ import { useNavigateToPage } from 'hooks/useNavigateToPage'
import { restrictedHandles } from 'utils/restrictedHandles'
import { HandleField } from '../components/HandleField'
-import { OutOfText } from '../components/OutOfText'
import { Heading, Page, PageFooter } from '../components/layout'
import { useFastReferral } from '../hooks/useFastReferral'
@@ -77,7 +76,6 @@ export const PickHandlePage = () => {
autoFocusInputRef={handleInputRef}
>
}
heading={pickHandlePageMessages.title}
description={pickHandlePageMessages.description}
centered={!isMobile}
diff --git a/packages/web/src/pages/sign-up-page/pages/SelectArtistsPage.tsx b/packages/web/src/pages/sign-up-page/pages/SelectArtistsPage.tsx
index 9d30fd87d74..6f23b7f3ff2 100644
--- a/packages/web/src/pages/sign-up-page/pages/SelectArtistsPage.tsx
+++ b/packages/web/src/pages/sign-up-page/pages/SelectArtistsPage.tsx
@@ -29,11 +29,11 @@ import { useNavigateToPage } from 'hooks/useNavigateToPage'
import { env } from 'services/env'
import { useSelector } from 'utils/reducer'
-import { AccountHeader } from '../components/AccountHeader'
import { PreviewArtistHint } from '../components/PreviewArtistHint'
import {
Heading,
HiddenLegend,
+ Page,
PageFooter,
ScrollView
} from '../components/layout'
@@ -50,12 +50,10 @@ const initialValues: SelectArtistsValues = {
selectedArtists: []
}
-// This is a workaround for local dev environments that don't have any artists
-// This will ensure any errors set on mount get cleared out
const DevModeClearErrors = () => {
const { setErrors } = useFormikContext()
useEffect(() => {
- setErrors({}) // empty all errors
+ setErrors({})
}, [setErrors])
return null
}
@@ -67,9 +65,9 @@ export const SelectArtistsPage = () => {
const [currentGenre, setCurrentGenre] = useState('Featured')
const dispatch = useDispatch()
const navigate = useNavigateToPage()
- const { color } = useTheme()
const headerContainerRef = useRef(null)
const { isMobile } = useMedia()
+ const { color } = useTheme()
const handleChangeGenre = useCallback((e: ChangeEvent) => {
setCurrentGenre(e.target.value)
@@ -79,13 +77,11 @@ export const SelectArtistsPage = () => {
(values: SelectArtistsValues) => {
const { selectedArtists } = values
- // Only add artists if some were selected
if (selectedArtists.length > 0) {
const artistsIDArray = [...selectedArtists].map((a) => Number(a))
dispatch(addFollowArtists(artistsIDArray))
}
- // Always create the account (whether artists selected or not)
dispatch(signUp())
if (isMobile) {
@@ -116,11 +112,9 @@ export const SelectArtistsPage = () => {
? isFeaturedArtistsPending
: isTopArtistsPending
- // Note: this doesn't catch when running `web:prod`
const isDevEnvironment =
env.ENVIRONMENT === 'development' ||
window.localStorage.getItem('FORCE_DEV') === 'true'
- // This a workaround flag for local envs that don't have any artists and get stuck at this screen
const noArtistsSkipValidation =
(!artists || artists.length === 0) && isDevEnvironment
@@ -140,7 +134,11 @@ export const SelectArtistsPage = () => {
const artistContent = artists?.length ? (
artists.map((user) => (
-
+
))
) : (
@@ -155,52 +153,29 @@ export const SelectArtistsPage = () => {
{({ values, isValid, isSubmitting, isValidating }) => {
const { selectedArtists } = values
return (
-
-
+
{noArtistsSkipValidation && !isValid ? (
) : undefined}
-
+
{
genre as GenreLabel
)
return (
- // TODO: max of 6, kebab overflow
{
pv='xl'
ph={isMobile ? 'l' : 'xl'}
css={{
- minHeight: 500,
+ minHeight: 400,
minWidth: !isMobile ? 530 : undefined
}}
direction='column'
@@ -253,33 +227,59 @@ export const SelectArtistsPage = () => {
gap={isMobile ? 's' : 'm'}
wrap='wrap'
justifyContent='center'
+ css={
+ !isMobile
+ ? {
+ display: 'grid',
+ gridTemplateColumns: 'repeat(4, 1fr)',
+ maxWidth: 720,
+ margin: '0 auto',
+ width: '100%',
+ boxSizing: 'border-box'
+ }
+ : undefined
+ }
>
{isLoading
? range(9).map((index) => (
-
+
))
: artistContent}
-
-
- {selectArtistsPageMessages.selected}{' '}
- {selectedArtists.length || 0}/3
-
-
- }
- />
-
+ >
+
+
+ {selectArtistsPageMessages.selected}{' '}
+ {selectedArtists.length || 0}/3
+
+
+ }
+ />
+
+
)
}}
diff --git a/packages/web/src/pages/sign-up-page/pages/SelectGenresPage.tsx b/packages/web/src/pages/sign-up-page/pages/SelectGenresPage.tsx
index d2cb795d2f5..2be81dac721 100644
--- a/packages/web/src/pages/sign-up-page/pages/SelectGenresPage.tsx
+++ b/packages/web/src/pages/sign-up-page/pages/SelectGenresPage.tsx
@@ -16,9 +16,8 @@ import { SelectablePillField } from 'components/form-fields/SelectablePillField'
import { useMedia } from 'hooks/useMedia'
import { useNavigateToPage } from 'hooks/useNavigateToPage'
-import { AccountHeader } from '../components/AccountHeader'
import { SkipButton } from '../components/SkipButton'
-import { Heading, Page, PageFooter, ScrollView } from '../components/layout'
+import { Heading, Page, PageFooter } from '../components/layout'
const { SIGN_UP_ARTISTS_PAGE } = route
@@ -48,7 +47,6 @@ export const SelectGenresPage = () => {
(label: string): MouseEventHandler =>
(e) => {
if ((e.target as HTMLInputElement).checked) {
- // add to genres list
const newGenres = [...currentGenres, label as Genre]
dispatch(
make(Name.CREATE_ACCOUNT_SELECT_GENRE, {
@@ -58,7 +56,6 @@ export const SelectGenresPage = () => {
)
setCurrentGenres(newGenres)
} else {
- // remove from genres list
const newGenres = [...currentGenres]
const genreIndex = currentGenres.indexOf(label as Genre)
newGenres.splice(genreIndex, 1)
@@ -67,57 +64,49 @@ export const SelectGenresPage = () => {
}
return (
-
-
-
- {() => (
-
+ {() => (
+
+
+
-
-
- {selectableGenres.map((genre) => {
- const { label, value } = genre
- return (
-
- )
- })}
-
+ {selectableGenres.map((genre) => {
+ const { label, value } = genre
+ return (
+
+ )
+ })}
- } />
-
- )}
-
-
+
+ } />
+
+ )}
+
)
}
diff --git a/packages/web/src/pages/sign-up-page/utils/useDetermineAllowedRoutes.ts b/packages/web/src/pages/sign-up-page/utils/useDetermineAllowedRoutes.ts
index 4747ae21bfe..f3036210430 100644
--- a/packages/web/src/pages/sign-up-page/utils/useDetermineAllowedRoutes.ts
+++ b/packages/web/src/pages/sign-up-page/utils/useDetermineAllowedRoutes.ts
@@ -54,7 +54,11 @@ export const useDetermineAllowedRoute = () => {
correctedRoute: FEED_PAGE
}
}
- const attemptedPath = requestedRoute.toString().replace('/signup/', '')
+ // Normalize path: strip /signup/ or signup/ prefix and trailing slash so "select-genres" always matches
+ const attemptedPath = requestedRoute
+ .toString()
+ .replace(/^\/?signup\/?/, '')
+ .replace(/^\/|\/$/g, '')
// Have to type as string[] to avoid too narrow of a type for comparing against
let allowedRoutes: string[] = [SignUpPath.createEmail]
@@ -124,18 +128,36 @@ export const useDetermineAllowedRoute = () => {
}
}
- const isAllowedRoute = allowedRoutes.includes(attemptedPath)
- // If requested route is allowed return that, otherwise return the last step in the route stack
- const correctedPath =
+ let isAllowedRoute = allowedRoutes.includes(attemptedPath)
+ // When past account phase, ensure select-genres is always allowed so we never redirect to a later step
+ if (
+ pastAccountPhase &&
+ attemptedPath === SignUpPath.selectGenres &&
+ !isAllowedRoute
+ ) {
+ isAllowedRoute = true
+ }
+ // If requested route is allowed return that, otherwise return the appropriate step
+ let correctedPath =
attemptedPath === '/signup' && hasAlreadySignedUp
? allowedRoutes[allowedRoutes.length - 1]
: isAllowedRoute
? attemptedPath
- : // IF we attempted to go to /signup directly, that means it was a link from somewhere else in the app, so we should start back at the beginning
- attemptedPath === '/signup'
+ : attemptedPath === 'signup' || attemptedPath === ''
? allowedRoutes[0]
: allowedRoutes[allowedRoutes.length - 1]
+ // After finish-profile we must show select-genres before select-artists: if we're past account phase
+ // and would redirect to select-artists but user hasn't done genres yet, send them to select-genres
+ if (
+ pastAccountPhase &&
+ !isAllowedRoute &&
+ correctedPath === SignUpPath.selectArtists &&
+ !(signUpState.genres && signUpState.genres.length > 0)
+ ) {
+ correctedPath = SignUpPath.selectGenres
+ }
+
if (correctedPath === SignUpPath.completedRedirect) {
setIsWelcomeModalOpen(true)
}