Skip to content

Commit

Permalink
show error if avatar upload fails
Browse files Browse the repository at this point in the history
  • Loading branch information
TateB committed Jan 18, 2024
1 parent 5d9976a commit 0cde2d7
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 13 deletions.
8 changes: 3 additions & 5 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"typescript.enablePromptUseWorkspaceTsdk": true,
"eslint.format.enable": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll.stylelint": false
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "never"
},
"stylelint.configFile": ".stylelintrc.json",
"stylelint.validate": ["css", "typescriptreact"],
Expand All @@ -19,7 +19,5 @@
"editor.defaultFormatter": "jock.svg"
},
"jest.jestCommandLine": "pnpm run test",
"cSpell.words": [
"ensjs"
]
"cSpell.words": ["ensjs"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ describe('<AvatarUpload />', () => {
mockHandleSubmit.mockClear()
global.fetch = jest.fn().mockImplementation(() =>
Promise.resolve({
json: () => ({ message: 'failed' }),
json: () => ({ error: 'failed', status: 500 }),
}),
)

Expand All @@ -128,4 +128,22 @@ describe('<AvatarUpload />', () => {
await waitFor(() => expect(global.fetch).toBeCalled())
await waitFor(() => expect(mockHandleSubmit).not.toHaveBeenCalled())
})
it('shows error when upload fails', async () => {
mockHandleSubmit.mockClear()
global.fetch = jest.fn().mockImplementation(() =>
Promise.resolve({
json: () => ({ error: 'failed', status: 500 }),
}),
)

render(<AvatarUpload {...props} />)
fireEvent.click(screen.getByTestId('continue-button'))
fireEvent.click(screen.getByTestId('upload-button'))

await waitFor(() => expect(global.fetch).toBeCalled())
await waitFor(() => expect(mockHandleSubmit).not.toHaveBeenCalled())

expect(screen.getByTestId('avatar-upload-error')).toBeVisible()
expect(screen.getByTestId('avatar-upload-error')).toHaveTextContent('failed')
})
})
44 changes: 37 additions & 7 deletions src/components/@molecules/ProfileEditor/Avatar/AvatarUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import styled, { css } from 'styled-components'
import { bytesToHex } from 'viem'
import { useMutation, useQueryClient, useSignTypedData } from 'wagmi'

import { Button, Dialog, mq } from '@ensdomains/thorin'
import { Button, Dialog, Helper, mq } from '@ensdomains/thorin'

import { useChainName } from '@app/hooks/chain/useChainName'

Expand Down Expand Up @@ -38,6 +38,15 @@ const dataURLToBytes = (dataURL: string) => {
return bytes
}

type AvatarUploadResult =
| {
message: string
}
| {
error: string
status: number
}

const UploadComponent = ({
dataURL,
handleCancel,
Expand Down Expand Up @@ -77,7 +86,11 @@ const UploadComponent = ({
},
})

const { mutate: signAndUpload, isLoading } = useMutation(async () => {
const {
mutate: signAndUpload,
isLoading,
error,
} = useMutation<void, Error>(async () => {
let baseURL = process.env.NEXT_PUBLIC_AVUP_ENDPOINT || `https://euc.li`
if (network !== 'mainnet') {
baseURL = `${baseURL}/${network}`
Expand All @@ -96,9 +109,9 @@ const UploadComponent = ({
dataURL,
sig,
}),
}).then((res) => res.json())) as any
}).then((res) => res.json())) as AvatarUploadResult

if (fetched.message === 'uploaded') {
if ('message' in fetched && fetched.message === 'uploaded') {
queryClient.invalidateQueries({
predicate: (query) => {
const {
Expand All @@ -112,7 +125,12 @@ const UploadComponent = ({
})
return handleSubmit('upload', endpoint, dataURL)
}
throw new Error(fetched.message)

if ('error' in fetched) {
throw new Error(fetched.error)
}

throw new Error('Unknown error')
})

return (
Expand All @@ -124,11 +142,23 @@ const UploadComponent = ({
<Container>
<CroppedImagePreview data-testid="cropped-image-preview" src={dataURL} />
</Container>
{error && (
<Helper data-testid="avatar-upload-error" type="error">
{error.message}
</Helper>
)}
<Dialog.Footer
leading={<AvCancelButton handleCancel={handleCancel} />}
trailing={
<Button disabled={isLoading} onClick={() => signAndUpload()} data-testid="upload-button">
{t('input.profileEditor.tabs.avatar.image.upload.action')}
<Button
disabled={isLoading}
colorStyle={error ? 'redSecondary' : undefined}
onClick={() => signAndUpload()}
data-testid="upload-button"
>
{error
? t('action.tryAgain', { ns: 'common' })
: t('input.profileEditor.tabs.avatar.image.upload.action')}
</Button>
}
/>
Expand Down

0 comments on commit 0cde2d7

Please sign in to comment.