Skip to content

Commit

Permalink
refactor: also record new user's auth0 avatar link
Browse files Browse the repository at this point in the history
fix: disable submit button on success

test: fix tests
  • Loading branch information
viet nguyen committed Jun 6, 2023
1 parent d1e8ddf commit 1a6d2c3
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 43 deletions.
24 changes: 11 additions & 13 deletions src/components/media/__tests__/UserGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

import type UserGalleryType from '../UserGallery'
import { IUserProfile } from '../../../js/types'
import { mediaList } from './data'
import { UserPublicPage } from '../../../js/types/User'

jest.mock('next/router')

Expand All @@ -26,15 +26,15 @@ const { pushFn, replaceFn } = jest.requireMock('next/router')
const useResponsiveMock = jest.spyOn(useResponsive, 'default')
useResponsiveMock.mockReturnValue({ isDesktop: false, isMobile: true, isTablet: true })

const userProfile: IUserProfile = {
authProviderId: '123',
uuid: '12233455667',
name: 'cat blue',
nick: 'cool_nick_2022',
avatar: 'something',
bio: 'totem eatsum',
roles: [],
loginsCount: 2
const userProfile: UserPublicPage = {
profile: {
userUuid: 'de7a092e-5c3c-445d-a863-b5fbe145e016',
displayName: 'cat blue',
username: 'cool_nick_2022',
avatar: 'https://example.com/avatar.jpg',
bio: 'totem eatsum'
},
mediaList
}

let UserGallery: typeof UserGalleryType
Expand All @@ -55,11 +55,9 @@ describe('Image gallery', () => {

render(
<UserGallery
auth={{ isAuthenticated: false, isAuthorized: false }}
uid={username}
postId={null}
userProfile={userProfile}
initialImageList={mediaList}
userPublicPage={userProfile}
/>)

const images = screen.getAllByRole('img')
Expand Down
48 changes: 28 additions & 20 deletions src/components/users/__tests__/PublicProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import '@testing-library/jest-dom/extend-expect'
import { render, screen } from '@testing-library/react'
import { v4 as uuidv4 } from 'uuid'

import { IUserProfile } from '../../../js/types'
import type PublicProfileType from '../PublicProfile'
import { UserPublicProfile } from '../../../js/types/User'

const mockedUseSession = jest.fn()

Expand All @@ -23,15 +23,21 @@ jest.mock('../ImportFromMtnProj', () => {

jest.requireMock('next-auth/react')

const userProfile: IUserProfile = {
authProviderId: '123',
uuid: uuidv4(),
name: 'cat blue',
nick: 'cool_nick_2022',
avatar: 'something',
const userProfile: Required<UserPublicProfile> = {
userUuid: uuidv4().toString(),
displayName: 'cat blue',
username: 'cool_nick_2022',
avatar: 'https://example.com/myavatar.jpg',
bio: 'totem eatsum',
roles: [],
loginsCount: 2
website: 'https://example.com'
}

const mockAuth0UserMetadata = {
user: {
metadata: {
uuid: userProfile.userUuid
}
}
}

let PublicProfile: typeof PublicProfileType
Expand All @@ -41,32 +47,34 @@ beforeAll(async () => {
PublicProfile = module.default
})

test('PublicProfile when the user has logged in', async () => {
test('Profile detail when the user is logged in.', async () => {
mockedUseSession
.mockClear()
.mockReturnValue({ status: 'authenticated' })
.mockReturnValue({
status: 'authenticated',
data: mockAuth0UserMetadata
})

render(<PublicProfile userProfile={userProfile} />)

expect(mockedUseSession).toBeCalled()
expect(screen.queryByRole('button')).toBeDefined()

expect(screen.queryByText(userProfile.name)).not.toBeNull()
expect(screen.queryByText(userProfile.nick)).not.toBeNull()
expect(screen.getByRole('link', { name: /edit/i })).toHaveAttribute('href', '/account/changeUsername')

expect(screen.queryByText(userProfile.displayName)).not.toBeNull()
expect(screen.queryByText(userProfile.username)).not.toBeNull()
expect(screen.queryByText(userProfile.bio)).not.toBeNull()
expect(screen.getByRole('link', { name: /example\.com/ })).toHaveAttribute('href', userProfile.website)
})

test('EditProfileButton null when the user hasn\'t logged in', async () => {
test('Username edit link is not present when the user is logged out.', async () => {
mockedUseSession
.mockClear()
.mockReturnValue({ status: '' })

render(<PublicProfile userProfile={userProfile} />)

expect(mockedUseSession).toBeCalled()
expect(screen.queryByRole('button')).toBeNull()

expect(screen.queryByText(userProfile.name)).not.toBeNull()
expect(screen.queryByText(userProfile.nick)).not.toBeNull()
expect(screen.queryByText(userProfile.bio)).not.toBeNull()
expect(screen.queryByRole('link', { name: /edit/i })).toBeNull()
expect(screen.queryByText(userProfile.username)).not.toBeNull()
})
11 changes: 7 additions & 4 deletions src/components/users/account/UsernameChangeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,15 @@ export const UsernameChangeForm: React.FC = () => {

const userUuid = session.data?.user.metadata.uuid
const email = session.data?.user.email
const avatar = session.data?.user.image

const form = useForm<FormProps>({
mode: 'onChange',
defaultValues: { username: initials?.username },
delayError: 500
})

const { handleSubmit, reset, watch, setError, clearErrors, formState: { isValid, isDirty, isValidating, isSubmitting } } = form
const { handleSubmit, reset, watch, setError, clearErrors, formState: { isValid, isDirty, isValidating, isSubmitting, isSubmitSuccessful } } = form

const submitHandler = async ({ username }: FormProps): Promise<void> => {
if (userUuid == null) {
Expand All @@ -88,9 +89,10 @@ export const UsernameChangeForm: React.FC = () => {
await updateUsername({
userUuid,
username,
...isNewUser && email != null && { email } // email is required for new users
...isNewUser && email != null && { email }, // email is required for new users
...isNewUser && avatar != null && { avatar } // get Auth0 avatar for new users
})
void router.push('/')
void router.push(`/u/${username}`)
toast.info('Username updated')
} catch (e) {
reset()
Expand Down Expand Up @@ -140,6 +142,7 @@ export const UsernameChangeForm: React.FC = () => {
}
}, [session.data?.user])

const shouldDisableSumit = !isValid || isSubmitting || !isDirty || userUuid == null || isSubmitSuccessful
return (
<div className='w-full lg:max-w-md'>
{isNewUser
Expand Down Expand Up @@ -172,7 +175,7 @@ export const UsernameChangeForm: React.FC = () => {

<button
type='submit'
disabled={!isValid || isSubmitting || !isDirty || userUuid == null}
disabled={shouldDisableSumit}
className='mt-10 btn btn-primary btn-solid btn-block md:btn-wide'
>Save
</button>
Expand Down
6 changes: 3 additions & 3 deletions src/js/graphql/gql/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const QUERY_GET_USER_PUBLIC_PAGE = gql`
}
`

export const MUTATION_UPDATE_USERNAME = gql`
mutation ($username: String!, $userUuid: ID!, $email: String) {
updateUserProfile(input: { userUuid: $userUuid, username: $username, email: $email })
export const MUTATION_UPDATE_PROFILE = gql`
mutation ($username: String!, $userUuid: ID!, $email: String, $avatar: String) {
updateUserProfile(input: { userUuid: $userUuid, username: $username, email: $email, avatar: $avatar })
}`
5 changes: 3 additions & 2 deletions src/js/hooks/useUserProfileCmd.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { toast } from 'react-toastify'
import AwesomeDebouncePromise from 'awesome-debounce-promise'

import { graphqlClient } from '../graphql/Client'
import { MUTATION_UPDATE_USERNAME, QUERY_GET_USERNAME_BY_UUID, QUERY_DOES_USERNAME_EXIST, QUERY_GET_USER_PUBLIC_PAGE } from '../graphql/gql/users'
import { MUTATION_UPDATE_PROFILE, QUERY_GET_USERNAME_BY_UUID, QUERY_DOES_USERNAME_EXIST, QUERY_GET_USER_PUBLIC_PAGE } from '../graphql/gql/users'
import { Username } from '../types'

interface GetUsernameByIdInput {
Expand All @@ -12,6 +12,7 @@ interface UpdateUsernameInput {
userUuid: string
username: string
email?: string
avatar?: string
}

type GetUsernameById = (input: GetUsernameByIdInput) => Promise<Username | null>
Expand Down Expand Up @@ -52,7 +53,7 @@ export default function useUserProfileCmd ({ accessToken = '' }: UseUserProfileC

const updateUsername = async (input: UpdateUsernameInput): Promise<boolean> => {
const res = await graphqlClient.query<{ updateUserProfile: boolean }, UpdateUsernameInput>({
query: MUTATION_UPDATE_USERNAME,
query: MUTATION_UPDATE_PROFILE,
variables: {
...input
},
Expand Down
3 changes: 3 additions & 0 deletions src/js/hooks/useUsernameCheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export default function useUsernameCheck (): void {

useEffect(() => {
const uuid = data?.user.metadata.uuid
if (router.asPath.startsWith('/auth/')) {
return
}
if (status === 'authenticated' && uuid != null) {
void getUsernameById({ userUuid: uuid }).then(usernameInfo => {
if (usernameInfo === null) {
Expand Down
1 change: 0 additions & 1 deletion src/pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export default NextAuth({
debug: false,
events: {},
pages: {
// signIn: '/auth/signin'
verifyRequest: '/auth/verify-request'
},
theme: {
Expand Down
5 changes: 5 additions & 0 deletions src/styles/defaults.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ html {
@apply font-sans text-base text-base-content;
}

a:active, a:focus {
outline: 0 !important;
border: none;
}

/******** App's root container *********/
/* Max width=3xl */
.root-container-default {
Expand Down

0 comments on commit 1a6d2c3

Please sign in to comment.