Skip to content

Commit

Permalink
[C-5381] Fast sign-up for referrals (#10440)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjeffers authored Nov 14, 2024
1 parent e27ee23 commit 927b5fd
Show file tree
Hide file tree
Showing 16 changed files with 130 additions and 28 deletions.
16 changes: 16 additions & 0 deletions packages/common/src/schemas/sign-on/finishProfileSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,19 @@ export const finishProfileSchema = z.object({
})
.optional()
})

export const finishReferralProfileSchema = z.object({
displayName: z
.string({ required_error: 'Display name is required.' })
.max(MAX_DISPLAY_NAME_LENGTH, ''),
profileImage: z
.object({
url: z.string().optional()
})
.optional(),
coverPhoto: z
.object({
url: z.string().optional()
})
.optional()
})
4 changes: 3 additions & 1 deletion packages/common/src/utils/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ export enum SignUpPath {
selectArtists = 'select-artists',
loading = 'loading',
appCta = 'app-cta',
completedRedirect = 'completed'
completedRedirect = 'completed',
completedReferrerRedirect = 'completed-referrer'
}
export const SIGN_UP_EMAIL_PAGE = `/signup/${SignUpPath.createEmail}`
export const SIGN_UP_START_PAGE = SIGN_UP_EMAIL_PAGE // entry point for sign up if needing to redirect to the beginning
Expand All @@ -106,6 +107,7 @@ export const SIGN_UP_ARTISTS_PAGE = `/signup/${SignUpPath.selectArtists}`
export const SIGN_UP_APP_CTA_PAGE = `/signup/${SignUpPath.appCta}`
export const SIGN_UP_LOADING_PAGE = `/signup/${SignUpPath.loading}`
export const SIGN_UP_COMPLETED_REDIRECT = `/signup/${SignUpPath.completedRedirect}`
export const SIGN_UP_COMPLETED_REFERRER_REDIRECT = `/signup/${SignUpPath.completedReferrerRedirect}`

// Param routes.
export const NOTIFICATION_USERS_PAGE = '/notification/:notificationId/users'
Expand Down
1 change: 1 addition & 0 deletions packages/web/src/common/store/pages/signon/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,7 @@ function* followArtists(
...(referrer == null ? [] : [referrer])
])
]

for (const userId of userIdsToFollow) {
yield* put(
socialActions.followUser(userId as number, FollowSource.SIGN_UP)
Expand Down
6 changes: 5 additions & 1 deletion packages/web/src/components/track/TrackTileStats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ export const TrackTileStats = (props: TrackTileStatsProps) => {
)

if (isLoading || !track) {
return <Skeleton w='30%' h={isMobile ? 16 : 20} />
return (
<Flex h='2xl' alignItems='center'>
<Skeleton w='40%' h={isMobile ? 16 : 20} />
</Flex>
)
}

const { is_unlisted } = track
Expand Down
14 changes: 8 additions & 6 deletions packages/web/src/components/track/mobile/PlaylistTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,14 @@ const PlaylistTile = (props: PlaylistTileProps & ExtraProps) => {
</UserLink>
</Flex>
</div>
<CollectionTileStats
collectionId={id}
isTrending={isTrending}
rankIndex={index}
size={TrackTileSize.SMALL}
/>
<Flex ph='s'>
<CollectionTileStats
collectionId={id}
isTrending={isTrending}
rankIndex={index}
size={TrackTileSize.SMALL}
/>
</Flex>
<TrackList
activeTrackUid={props.activeTrackUid}
goToCollectionPage={props.goToCollectionPage}
Expand Down
4 changes: 3 additions & 1 deletion packages/web/src/components/welcome-modal/WelcomeModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback, useEffect } from 'react'

import { imageProfilePicEmpty } from '@audius/common/assets'
import { welcomeModalMessages } from '@audius/common/messages'
import { Name, SquareSizes } from '@audius/common/models'
import { accountSelectors } from '@audius/common/store'
Expand Down Expand Up @@ -47,7 +48,8 @@ export const WelcomeModal = () => {
const userName = nameField ?? accountName
const [isOpen, setIsOpen] = useModalState('Welcome')

const profileImage = profileImageField?.url ?? presavedProfilePic
const profileImage =
profileImageField?.url ?? (presavedProfilePic || imageProfilePicEmpty)

const Root = isMobile ? Drawer : Modal
const onClose = useCallback(() => {
Expand Down
5 changes: 5 additions & 0 deletions packages/web/src/pages/sign-up-page/SignUpPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import { RouteContextProvider } from './utils/RouteContext'

const {
FEED_PAGE,
TRENDING_PAGE,
SIGN_UP_APP_CTA_PAGE,
SIGN_UP_ARTISTS_PAGE,
SIGN_UP_COMPLETED_REDIRECT,
SIGN_UP_COMPLETED_REFERRER_REDIRECT: SIGN_UP_REFERRER_COMPLETED_REDIRECT,
SIGN_UP_CREATE_LOGIN_DETAILS,
SIGN_UP_EMAIL_PAGE,
SIGN_UP_FINISH_PROFILE_PAGE,
Expand Down Expand Up @@ -104,6 +106,9 @@ export const SignUpPage = () => {
<SignUpRoute exact path={SIGN_UP_COMPLETED_REDIRECT}>
<Redirect to={FEED_PAGE} />
</SignUpRoute>
<SignUpRoute exact path={SIGN_UP_REFERRER_COMPLETED_REDIRECT}>
<Redirect to={TRENDING_PAGE} />
</SignUpRoute>
<SignUpRoute path='*' />
</Switch>
</RouteContextProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { imageProfilePicEmpty } from '@audius/common/assets'
import { Name, SquareSizes } from '@audius/common/models'
import { accountSelectors } from '@audius/common/store'
import {
Expand Down Expand Up @@ -113,7 +114,8 @@ export const AccountHeader = (props: AccountHeaderProps) => {
const { isMobile } = useMedia()
const isSmallSize = isEditing || isMobile || size === 'small'

const savedProfileImage = profileImageField?.url ?? accountProfilePic
const savedProfileImage =
profileImageField?.url || accountProfilePic || imageProfilePicEmpty

return (
<Box w='100%'>
Expand Down
17 changes: 17 additions & 0 deletions packages/web/src/pages/sign-up-page/components/SkipButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useCallback } from 'react'

import { route } from '@audius/common/utils'
import { PlainButton } from '@audius/harmony'

import { useNavigateToPage } from 'hooks/useNavigateToPage'

const { SIGN_UP_LOADING_PAGE } = route

export const SkipButton = () => {
const navigate = useNavigateToPage()
const handleSkip = useCallback(() => {
navigate(SIGN_UP_LOADING_PAGE)
}, [navigate])

return <PlainButton onClick={handleSkip}>Skip this step</PlainButton>
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export const CreateEmailPage = () => {
>
{({ isSubmitting, setFieldValue, submitForm }) => (
<Page as={Form} pt={isMobile ? 'xl' : 'unit13'}>
<Box alignSelf={isSmallDesktop ? 'flex-start' : 'center'}>
<Box alignSelf='center'>
{isMobile || isSmallDesktop ? (
<IconAudiusLogoHorizontalColor />
) : (
Expand Down
26 changes: 19 additions & 7 deletions packages/web/src/pages/sign-up-page/pages/FinishProfilePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { useCallback, useRef } from 'react'

import { finishProfilePageMessages } from '@audius/common/messages'
import { Name } from '@audius/common/models'
import { finishProfileSchema } from '@audius/common/schemas'
import {
finishProfileSchema,
finishReferralProfileSchema
} from '@audius/common/schemas'
import { MAX_DISPLAY_NAME_LENGTH } from '@audius/common/services'
import { route } from '@audius/common/utils'
import { Flex, Paper, PlainButton, Text, useTheme } from '@audius/harmony'
Expand All @@ -25,7 +28,8 @@ import {
getIsSocialConnected,
getLinkedSocialOnFirstPage,
getNameField,
getProfileImageField
getProfileImageField,
getReferrer
} from 'common/store/pages/signon/selectors'
import { HarmonyTextField } from 'components/form-fields/HarmonyTextField'
import { useMedia } from 'hooks/useMedia'
Expand All @@ -36,7 +40,7 @@ import { ImageFieldValue } from '../components/ImageField'
import { OutOfText } from '../components/OutOfText'
import { Heading, Page, PageFooter } from '../components/layout'

const { SIGN_UP_GENRES_PAGE } = route
const { SIGN_UP_GENRES_PAGE, SIGN_UP_LOADING_PAGE } = route

export type FinishProfileValues = {
profileImage?: ImageFieldValue
Expand All @@ -45,6 +49,7 @@ export type FinishProfileValues = {
}

const formSchema = toFormikValidationSchema(finishProfileSchema)
const referralformSchema = toFormikValidationSchema(finishReferralProfileSchema)

const ImageUploadErrorText = () => {
const { errors } = useFormikContext<FinishProfileValues>()
Expand Down Expand Up @@ -89,6 +94,7 @@ export const FinishProfilePage = () => {
const linkedSocialOnFirstPage = useSelector(getLinkedSocialOnFirstPage)
const savedCoverPhoto = useSelector(getCoverPhotoField)
const savedProfileImage = useSelector(getProfileImageField)
const hasReferrer = useSelector(getReferrer)

// If the user comes back from a later page we start with whats in the store
const initialValues = {
Expand Down Expand Up @@ -130,17 +136,21 @@ export const FinishProfilePage = () => {
dispatch(setField('coverPhoto', coverPhoto))
}
dispatch(setFinishedPhase1(true))
navigate(SIGN_UP_GENRES_PAGE)
dispatch(signUp())
if (hasReferrer && isMobile) {
navigate(SIGN_UP_LOADING_PAGE)
} else {
navigate(SIGN_UP_GENRES_PAGE)
}
},
[navigate, dispatch]
[dispatch, hasReferrer, isMobile, navigate]
)

return (
<Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={formSchema}
validationSchema={hasReferrer ? referralformSchema : formSchema}
validateOnMount
validateOnChange
>
Expand Down Expand Up @@ -188,7 +198,9 @@ export const FinishProfilePage = () => {
centered
sticky
buttonProps={{ disabled: !isValid }}
prefix={isMobile ? <UploadProfilePhotoHelperText /> : null}
prefix={
isMobile && !hasReferrer ? <UploadProfilePhotoHelperText /> : null
}
postfix={
isMobile || isSocialConnected ? null : (
<PlainButton variant='subdued' onClick={history.goBack}>
Expand Down
19 changes: 16 additions & 3 deletions packages/web/src/pages/sign-up-page/pages/LoadingAccountPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ import { route } from '@audius/common/utils'
import { Flex } from '@audius/harmony'
import { useSelector } from 'react-redux'

import { getStatus } from 'common/store/pages/signon/selectors'
import {
getStatus,
getReferrer,
getAccountReady
} from 'common/store/pages/signon/selectors'
import { EditingStatus } from 'common/store/pages/signon/types'
import LoadingSpinner from 'components/loading-spinner/LoadingSpinner'
import { useMedia } from 'hooks/useMedia'
import { useNavigateToPage } from 'hooks/useNavigateToPage'

import { Heading, Page } from '../components/layout'
Expand All @@ -22,15 +27,23 @@ const messages = {
// The user just waits here until the account is created and before being shown the welcome modal on the trending page
export const LoadingAccountPage = () => {
const navigate = useNavigateToPage()
const hasReferrer = useSelector(getReferrer)
const accountReady = useSelector(getAccountReady)
const { isMobile } = useMedia()

const accountCreationStatus = useSelector(getStatus)

const isAccountReady =
hasReferrer && isMobile
? accountReady
: accountCreationStatus === EditingStatus.SUCCESS

useEffect(() => {
if (accountCreationStatus === EditingStatus.SUCCESS) {
if (isAccountReady) {
navigate(SIGN_UP_COMPLETED_REDIRECT)
}
// TODO: what to do in an error scenario? Any way to recover to a valid step?
}, [navigate, accountCreationStatus])
}, [navigate, isAccountReady])

return (
<Page gap='3xl' justifyContent='center' alignItems='center' pb='3xl'>
Expand Down
9 changes: 7 additions & 2 deletions packages/web/src/pages/sign-up-page/pages/PickHandlePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {
import {
getHandleField,
getIsSocialConnected,
getLinkedSocialOnFirstPage
getLinkedSocialOnFirstPage,
getReferrer
} from 'common/store/pages/signon/selectors'
import { ToastContext } from 'components/toast/ToastContext'
import { useMedia } from 'hooks/useMedia'
Expand Down Expand Up @@ -117,18 +118,22 @@ export const PickHandlePage = () => {
const { value: handle } = useSelector(getHandleField)
const isLinkingSocialOnFirstPage = useSelector(getLinkedSocialOnFirstPage)
const handleInputRef = useRef<HTMLInputElement>(null)
const hasReferrer = useSelector(getReferrer)

const handleSubmit = useCallback(
(values: PickHandleValues) => {
const { handle } = values
dispatch(setValueField('handle', handle))
if (hasReferrer) {
dispatch(setValueField('name', handle))
}
navigate(
isLinkingSocialOnFirstPage
? SIGN_UP_CREATE_LOGIN_DETAILS
: SIGN_UP_FINISH_PROFILE_PAGE
)
},
[dispatch, navigate, isLinkingSocialOnFirstPage]
[dispatch, hasReferrer, navigate, isLinkingSocialOnFirstPage]
)

const handleCompleteSocialMediaLogin = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
addFollowArtists,
completeFollowArtists
} from 'common/store/pages/signon/actions'
import { getGenres } from 'common/store/pages/signon/selectors'
import { getGenres, getReferrer } from 'common/store/pages/signon/selectors'
import {
FollowArtistCard,
FollowArtistTileSkeleton
Expand All @@ -33,6 +33,7 @@ import { useSelector } from 'utils/reducer'

import { AccountHeader } from '../components/AccountHeader'
import { PreviewArtistHint } from '../components/PreviewArtistHint'
import { SkipButton } from '../components/SkipButton'
import {
Heading,
HiddenLegend,
Expand Down Expand Up @@ -71,6 +72,7 @@ export const SelectArtistsPage = () => {
const navigate = useNavigateToPage()
const { color } = useTheme()
const headerContainerRef = useRef<HTMLDivElement | null>(null)
const hasReferrer = useSelector(getReferrer)
const { isMobile } = useMedia()

const handleChangeGenre = useCallback((e: ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -262,6 +264,7 @@ export const SelectArtistsPage = () => {
disabled: !isValid || isSubmitting,
isLoading: isSubmitting || isValidating
}}
prefix={isMobile && hasReferrer ? <SkipButton /> : null}
postfix={
<Text variant='body'>
{selectArtistsPageMessages.selected}{' '}
Expand Down
14 changes: 10 additions & 4 deletions packages/web/src/pages/sign-up-page/pages/SelectGenresPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import { toFormikValidationSchema } from 'zod-formik-adapter'

import { make } from 'common/store/analytics/actions'
import { setField } from 'common/store/pages/signon/actions'
import { getGenres } from 'common/store/pages/signon/selectors'
import { getGenres, getReferrer } from 'common/store/pages/signon/selectors'
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'

const { SIGN_UP_ARTISTS_PAGE } = route
Expand All @@ -29,6 +30,8 @@ export const SelectGenresPage = () => {

const [currentGenres, setCurrentGenres] = useState<Genre[]>([])
const savedGenres = useSelector(getGenres)
const hasReferrer = useSelector(getReferrer)
const { isMobile } = useMedia()

const initialValues: SelectGenresValue = {
genres: (savedGenres as Genre[]) ?? []
Expand Down Expand Up @@ -64,8 +67,6 @@ export const SelectGenresPage = () => {
}
}

const { isMobile } = useMedia()

return (
<ScrollView gap={isMobile ? '2xl' : '3xl'}>
<AccountHeader mode='viewing' />
Expand Down Expand Up @@ -114,7 +115,12 @@ export const SelectGenresPage = () => {
})}
</Flex>
</Flex>
<PageFooter centered sticky buttonProps={{ disabled: !isValid }} />
<PageFooter
centered
sticky
buttonProps={{ disabled: !isValid }}
prefix={isMobile && hasReferrer ? <SkipButton /> : null}
/>
</Page>
)}
</Formik>
Expand Down
Loading

0 comments on commit 927b5fd

Please sign in to comment.