Skip to content

Commit

Permalink
[C-3489, C-3516] Sign up QA #3 (#7016)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjeffers authored Dec 27, 2023
1 parent 2e7f47e commit 29cf448
Show file tree
Hide file tree
Showing 27 changed files with 290 additions and 171 deletions.
1 change: 1 addition & 0 deletions packages/common/src/messages/sign-on/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const finishProfilePageMessages = {
'Your photos & display name is how others see you. Customize with special character, spaces, emojis, whatever!',
displayName: 'Display Name',
inputPlaceholder: 'express yourself 💫',
uploadProfilePhoto: 'Upload a profile photo to continue',
goBack: 'Go back'
}

Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/schemas/sign-on/pickHandleSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const pickHandleSchema = ({
}) => {
return z.object({
handle: z
.string()
.string({ required_error: 'handle required' })
.max(MAX_HANDLE_LENGTH, pickHandleErrorMessages.handleTooLong)
.regex(/^[a-zA-Z0-9_.]*$/, pickHandleErrorMessages.badCharacterError)
.refine(
Expand Down
18 changes: 18 additions & 0 deletions packages/common/src/schemas/sign-on/selectGenresSchema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
import { z } from 'zod'

import { GENRES, Genre, convertGenreLabelToValue } from 'utils/genres'

const excludedGenres = new Set<string>([
Genre.COMEDY,
Genre.KIDS,
Genre.SOUNDTRACK,
Genre.DEVOTIONAL,
Genre.AUDIOBOOKS,
Genre.SPOKEN_WORK
])

export const selectableGenres = GENRES.filter(
(genre) => !excludedGenres.has(genre)
).map((genre) => ({
value: genre,
label: convertGenreLabelToValue(genre)
}))

export const selectGenresSchema = z.object({
genres: z.array(z.string()).min(3)
})
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,14 @@ export const FollowButton = (props: FollowButtonProps) => {
}

const { color, cornerRadius } = useTheme()

const textColor =
checkedValue || isHovering || isPressing
? color.static.white
: color.primary.primary

const rootCss: CSSObject = {
cursor: 'pointer',
minWidth: size === 'small' ? 128 : 152,
width: '100%',
userSelect: 'none',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type IconButtonProps = {
ripple?: boolean
'aria-label': string
} & Pick<IconProps, 'color' | 'size' | 'shadow'> &
Pick<BaseButtonProps, 'onClick' | 'disabled'>
Pick<BaseButtonProps, 'onClick' | 'disabled' | 'className'>

/**
* The icon component allows you to pass in an icon and
Expand All @@ -32,7 +32,8 @@ export const IconButton = (props: IconButtonProps) => {
background: 'transparent',
border: 'none',
borderRadius: '50%',
padding: spacing.xs
padding: spacing.xs,
overflow: 'unset'
}

const rippleCss: CSSObject = {
Expand Down
4 changes: 2 additions & 2 deletions packages/mobile/src/screens/sign-on-screen/SignOnStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CreatePasswordScreen } from './screens/CreatePasswordScreen'
import { FinishProfileScreen } from './screens/FinishProfileScreen'
import { PickHandleScreen } from './screens/PickHandleScreen'
import { SelectArtistsScreen } from './screens/SelectArtistScreen'
import { SelectGenreScreen } from './screens/SelectGenreScreen'
import { SelectGenresScreen } from './screens/SelectGenresScreen'
import { SignOnScreen } from './screens/SignOnScreen'

const Stack = createNativeStackNavigator()
Expand All @@ -24,7 +24,7 @@ export const SignOnStack = () => {
<Stack.Screen name='CreatePassword' component={CreatePasswordScreen} />
<Stack.Screen name='PickHandle' component={PickHandleScreen} />
<Stack.Screen name='FinishProfile' component={FinishProfileScreen} />
<Stack.Screen name='SelectGenre' component={SelectGenreScreen} />
<Stack.Screen name='SelectGenre' component={SelectGenresScreen} />
<Stack.Screen name='SelectArtists' component={SelectArtistsScreen} />
</Stack.Navigator>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
emailSchemaMessages,
createEmailPageMessages as messages
} from '@audius/common'
import { ErrorMessage } from 'formik'

import { Hint, IconError, Text } from '@audius/harmony-native'

type EmailInUseHintProps = {
onChangeScreen: (screen: string) => void
}

export const EmailInUseHint = (props: EmailInUseHintProps) => {
const { onChangeScreen } = props

return (
<ErrorMessage name='email'>
{(errorMessage) =>
errorMessage === emailSchemaMessages.emailInUse ? (
<Hint icon={IconError}>
<Text variant='body' size='m' textAlign='center'>
{emailSchemaMessages.emailInUse}{' '}
<Text onPress={() => onChangeScreen('sign-in')} color='accent'>
{messages.signIn}
</Text>
</Text>
</Hint>
) : null
}
</ErrorMessage>
)
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import { useCallback, useMemo } from 'react'

import {
emailSchema,
emailSchemaMessages,
useAudiusQueryContext,
createEmailPageMessages as messages
} from '@audius/common'
import { css } from '@emotion/native'
import { setValueField } from 'common/store/pages/signon/actions'
import { getEmailField } from 'common/store/pages/signon/selectors'
import { Formik } from 'formik'
Expand All @@ -18,11 +16,10 @@ import { Button } from 'app/components/core'
import { TextField } from 'app/components/fields'
import { useNavigation } from 'app/hooks/useNavigation'

import { EmailInUseHint } from '../components/EmailInUseHint'
import { SocialMediaLoginOptions } from '../components/SocialMediaLoginOptions'
import { Heading } from '../components/layout'
import { Divider } from '../components/temp-harmony/Divider'
import { Hint } from '../components/temp-harmony/Hint'
import IconExclamation from '../components/temp-harmony/IconExclamation.svg'
import type { SignUpScreenParamList } from '../types'

import type { SignOnScreenProps } from './types'
Expand Down Expand Up @@ -59,7 +56,7 @@ export const CreateEmailScreen = (props: SignOnScreenProps) => {
onSubmit={handleSubmit}
validationSchema={emailFormikSchema}
>
{({ handleSubmit, errors }) => (
{({ handleSubmit }) => (
<>
<Heading
heading={messages.title}
Expand All @@ -80,23 +77,7 @@ export const CreateEmailScreen = (props: SignOnScreenProps) => {
noGutter
onChangeText={onChangeEmail}
/>
{errors.email === emailSchemaMessages.emailInUse ? (
<Hint icon={IconExclamation}>
<Text
variant='body'
size='m'
style={css({ textAlign: 'center' })}
>
{emailSchemaMessages.emailInUse}{' '}
<Text
onPress={() => onChangeScreen('sign-in')}
color='accent'
>
{messages.signIn}
</Text>
</Text>
</Hint>
) : null}
<EmailInUseHint onChangeScreen={onChangeScreen} />
<Divider>
<Text variant='body' size='s' color='subdued'>
{messages.socialsDividerText}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ import {
import { setField, setValueField } from 'common/store/pages/signon/actions'
import { Formik, useField } from 'formik'
import type { ImageURISource } from 'react-native'
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'
import { useDispatch, useSelector } from 'react-redux'
import { toFormikValidationSchema } from 'zod-formik-adapter'

import { Paper, useTheme } from '@audius/harmony-native'
import { Paper, useTheme, Text } from '@audius/harmony-native'
import { TextField } from 'app/components/fields'
import { useNavigation } from 'app/hooks/useNavigation'
import { launchSelectImageActionSheet } from 'app/utils/launchSelectImageActionSheet'
Expand All @@ -25,6 +26,8 @@ import { AccountHeader } from '../components/AccountHeader'
import { Heading, Page, PageFooter } from '../components/layout'
import type { SignUpScreenParamList } from '../types'

const AnimatedText = Animated.createAnimatedComponent(Text)

const finishProfileFormikSchema = toFormikValidationSchema(finishProfileSchema)

const initialValues = {
Expand Down Expand Up @@ -80,7 +83,10 @@ export const FinishProfileScreen = () => {
})}
/>
</Paper>
<PageFooter onSubmit={handleSubmit} />
<PageFooter
prefix={<UploadProfilePhotoHelperText />}
onSubmit={handleSubmit}
/>
</Page>
)}
</Formik>
Expand Down Expand Up @@ -133,3 +139,23 @@ const AccountHeaderField = () => {
/>
)
}

const UploadProfilePhotoHelperText = () => {
const [{ value: displayName }, { touched }] = useField('displayName')
const [{ value: profileImage }] = useField('profileImage')
const isVisible = displayName && touched && !profileImage
const { motion } = useTheme()

if (!isVisible) return null

return (
<AnimatedText
variant='body'
textAlign='center'
entering={FadeIn.duration(motion.calm.duration)}
exiting={FadeOut.duration(motion.calm.duration)}
>
{messages.uploadProfilePhoto}
</AnimatedText>
)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { memo, useCallback, useEffect, useState } from 'react'

import type { GENRES } from '@audius/common'
import {
GENRES,
convertGenreLabelToValue,
selectGenresPageMessages as messages,
selectGenresSchema
selectGenresSchema,
selectableGenres
} from '@audius/common'
import { setField } from 'common/store/pages/signon/actions'
import { Formik, useField } from 'formik'
Expand All @@ -19,24 +19,19 @@ import { ReadOnlyAccountHeader } from '../components/AccountHeader'
import { Heading, Page, PageFooter, gutterSize } from '../components/layout'
import type { SignUpScreenParamList } from '../types'

const genres = GENRES.map((genre) => ({
value: genre,
label: convertGenreLabelToValue(genre)
}))

type Genre = typeof GENRES[number]
type SelectGenreValues = { genres: typeof GENRES }
type SelectGenresValue = { genres: typeof GENRES }

const initialValues: SelectGenreValues = { genres: [] }
const initialValues: SelectGenresValue = { genres: [] }

/* Memoized SelectablePill to fix a performance issue.
* The code below is arranged so that the pills don't need to re-render,
* And the memoization here is just forcing it to never re-render. */
const MemoSelectablePill = memo(SelectablePill, () => true)

const SelectGenreFieldArray = () => {
const SelectGenresFieldArray = () => {
// Storing values as state alongside Formik purely because setState provides access to the previous values
const [formValues, setFormValues] = useState<SelectGenreValues['genres']>(
const [formValues, setFormValues] = useState<SelectGenresValue['genres']>(
initialValues.genres
)
const [, , { setValue }] = useField('genres')
Expand All @@ -63,7 +58,7 @@ const SelectGenreFieldArray = () => {
return (
<ScrollView testID='genreScrollView'>
<Flex gap='s' direction='row' wrap='wrap'>
{genres.map((genre) => (
{selectableGenres.map((genre) => (
<MemoSelectablePill
label={genre.label}
onPress={() => {
Expand All @@ -78,12 +73,12 @@ const SelectGenreFieldArray = () => {
)
}

export const SelectGenreScreen = () => {
export const SelectGenresScreen = () => {
const dispatch = useDispatch()
const navigation = useNavigation<SignUpScreenParamList>()

const handleSubmit = useCallback(
(values: SelectGenreValues) => {
(values: SelectGenresValue) => {
const genres = values.genres
dispatch(setField('genres', genres))
navigation.navigate('SelectArtists')
Expand All @@ -108,7 +103,7 @@ export const SelectGenreScreen = () => {
heading={messages.header}
description={messages.description}
/>
<SelectGenreFieldArray />
<SelectGenresFieldArray />
</Flex>
<PageFooter
buttonProps={{ disabled: !(dirty && isValid) }}
Expand Down
7 changes: 4 additions & 3 deletions packages/web/src/components/form-fields/HarmonyTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ export const HarmonyTextField = (props: HarmonyTextFieldProps) => {
transformValueOnChange,
transformValueOnBlur,
debouncedValidationMs,
helperText,
...other
} = props
const [field, { touched, error }, { setError }] = useField(name)
const { value } = field
const { validateField } = useFormikContext()
const { validateField, submitCount } = useFormikContext()

const debouncedValidateField = useDebouncedCallback(
(field: string) => validateField(field),
Expand All @@ -44,13 +45,13 @@ export const HarmonyTextField = (props: HarmonyTextFieldProps) => {
}
}, [debouncedValidationMs, debouncedValidateField, name, value])

const hasError = Boolean(touched && error)
const hasError = Boolean(touched && error && submitCount > 0)

return (
<TextInput
{...field}
error={hasError}
helperText={hasError ? error : undefined}
helperText={helperText ?? (hasError ? error : undefined)}
onChange={(e) => {
if (clearErrorOnChange) {
setError(undefined)
Expand Down
1 change: 1 addition & 0 deletions packages/web/src/pages/sign-in-page/SignInPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const SignInPage = () => {
justifyContent='space-between'
h='100%'
p='2xl'
pt='unit20'
pb={!isMobile ? 'unit14' : undefined}
>
<Flex as={Form} direction='column' gap='2xl'>
Expand Down
Loading

0 comments on commit 29cf448

Please sign in to comment.