[Video] Upload errors and UI improvements (#5092)

* surface errors in UI

* style progress indicator

* remove job status progress

* rm log

* fix webm ext
This commit is contained in:
Samuel Newman 2024-09-03 15:09:09 +01:00 committed by GitHub
parent f9d736653c
commit 0e1de19903
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 155 additions and 60 deletions

View file

@ -6,7 +6,8 @@ import {useLingui} from '@lingui/react'
import {QueryClient, useQuery, useQueryClient} from '@tanstack/react-query'
import {logger} from '#/logger'
import {VideoTooLargeError} from 'lib/media/video/errors'
import {isWeb} from '#/platform/detection'
import {ServerError, VideoTooLargeError} from 'lib/media/video/errors'
import {CompressedVideo} from 'lib/media/video/types'
import {useCompressVideoMutation} from 'state/queries/video/compress-video'
import {useVideoAgent} from 'state/queries/video/util'
@ -58,7 +59,12 @@ function reducer(queryClient: QueryClient) {
abortController: new AbortController(),
}
} else if (action.type === 'SetAsset') {
updatedState = {...state, asset: action.asset}
updatedState = {
...state,
asset: action.asset,
status: 'compressing',
error: undefined,
}
} else if (action.type === 'SetDimensions') {
updatedState = {
...state,
@ -67,11 +73,11 @@ function reducer(queryClient: QueryClient) {
: undefined,
}
} else if (action.type === 'SetVideo') {
updatedState = {...state, video: action.video}
updatedState = {...state, video: action.video, status: 'uploading'}
} else if (action.type === 'SetJobStatus') {
updatedState = {...state, jobStatus: action.jobStatus}
} else if (action.type === 'SetBlobRef') {
updatedState = {...state, blobRef: action.blobRef}
updatedState = {...state, blobRef: action.blobRef, status: 'done'}
}
return updatedState
}
@ -108,10 +114,6 @@ export function useUploadVideo({
type: 'SetBlobRef',
blobRef,
})
dispatch({
type: 'SetStatus',
status: 'idle',
})
onSuccess()
},
})
@ -125,10 +127,17 @@ export function useUploadVideo({
setJobId(response.jobId)
},
onError: e => {
dispatch({
type: 'SetError',
error: _(msg`An error occurred while uploading the video.`),
})
if (e instanceof ServerError) {
dispatch({
type: 'SetError',
error: e.message,
})
} else {
dispatch({
type: 'SetError',
error: _(msg`An error occurred while uploading the video.`),
})
}
logger.error('Error uploading video', {safeMessage: e})
},
setProgress: p => {
@ -141,6 +150,13 @@ export function useUploadVideo({
onProgress: p => {
dispatch({type: 'SetProgress', progress: p})
},
onSuccess: (video: CompressedVideo) => {
dispatch({
type: 'SetVideo',
video,
})
onVideoCompressed(video)
},
onError: e => {
if (e instanceof VideoTooLargeError) {
dispatch({
@ -150,36 +166,28 @@ export function useUploadVideo({
} else {
dispatch({
type: 'SetError',
// @TODO better error message from server, left untranslated on purpose
error: 'An error occurred while compressing the video.',
error: _(msg`An error occurred while compressing the video.`),
})
logger.error('Error compressing video', {safeMessage: e})
}
},
onSuccess: (video: CompressedVideo) => {
dispatch({
type: 'SetVideo',
video,
})
dispatch({
type: 'SetStatus',
status: 'uploading',
})
onVideoCompressed(video)
},
signal: state.abortController.signal,
})
const selectVideo = (asset: ImagePickerAsset) => {
dispatch({
type: 'SetAsset',
asset,
})
dispatch({
type: 'SetStatus',
status: 'compressing',
})
onSelectVideo(asset)
switch (getMimeType(asset)) {
case 'video/mp4':
case 'video/mpeg':
case 'video/webm':
dispatch({
type: 'SetAsset',
asset,
})
onSelectVideo(asset)
break
default:
throw new Error(_(msg`Unsupported video type: ${getMimeType(asset)}`))
}
}
const clearVideo = () => {
@ -241,6 +249,21 @@ const useUploadStatusQuery = ({
isError,
setJobId: (_jobId: string) => {
setJobId(_jobId)
setEnabled(true)
},
}
}
function getMimeType(asset: ImagePickerAsset) {
if (isWeb) {
const [mimeType] = asset.uri.slice('data:'.length).split(';base64,')
if (!mimeType) {
throw new Error('Could not determine mime type')
}
return mimeType
}
if (!asset.mimeType) {
throw new Error('Could not determine mime type')
}
return asset.mimeType
}