feat(video): add error handling and loading state for video creation

handle video creation errors by showing toast notifications and prevent multiple submissions by adding a loading state
This commit is contained in:
icarus 2025-10-12 04:21:54 +08:00
parent 5776512bf6
commit d80eac2fbe
2 changed files with 34 additions and 21 deletions

View File

@ -4649,6 +4649,7 @@
},
"video": {
"error": {
"create": "Failed to create video",
"invalid": "Invalid video",
"load": {
"message": "Failed to load the video",

View File

@ -4,6 +4,7 @@ import { useAddOpenAIVideo } from '@renderer/hooks/video/useOpenAIVideos'
import { createVideo } from '@renderer/services/ApiService'
import { Provider } from '@renderer/types'
import { Video } from '@renderer/types/video'
import { getErrorMessage } from '@renderer/utils'
import { ArrowUp } from 'lucide-react'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -20,25 +21,34 @@ const logger = loggerService.withContext('VideoPanel')
export const VideoPanel = ({ provider, video }: VideoPanelProps) => {
const { t } = useTranslation()
const [prompt, setPrompt] = useState('')
const [isProcessing, setIsProcessing] = useState(false)
const addOpenAIVideo = useAddOpenAIVideo(provider.id)
const sendRequest = useCallback(async () => {
const result = await createVideo({
type: 'openai',
params: {
prompt
},
provider
})
const video = result.video
switch (result.type) {
case 'openai':
addOpenAIVideo(video)
break
default:
logger.error(`Invalid video type ${result.type}.`)
const handleCreateVideo = useCallback(async () => {
if (isProcessing) return
setIsProcessing(true)
try {
const result = await createVideo({
type: 'openai',
params: {
prompt
},
provider
})
const video = result.video
switch (result.type) {
case 'openai':
addOpenAIVideo(video)
break
default:
logger.error(`Invalid video type ${result.type}.`)
}
} catch (e) {
window.toast.error({ title: t('video.error.create'), description: getErrorMessage(e), timeout: 5000 })
} finally {
setIsProcessing(false)
}
}, [addOpenAIVideo, prompt, provider])
}, [addOpenAIVideo, isProcessing, prompt, provider, t])
return (
<div className="flex flex-1 flex-col p-2">
@ -54,21 +64,23 @@ export const VideoPanel = ({ provider, video }: VideoPanelProps) => {
value={prompt}
onValueChange={setPrompt}
isClearable
isDisabled={isProcessing}
classNames={{ inputWrapper: 'pb-8' }}
onKeyDown={(e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
e.stopPropagation()
sendRequest()
e.preventDefault()
handleCreateVideo()
}
}}
/>
<Button
color="primary"
radius="full"
startContent={<ArrowUp size={16} className="text-primary-foreground" />}
isIconOnly
className="absolute right-1 bottom-1 h-6 w-6 min-w-0"
/>
isLoading={isProcessing}
className="absolute right-2 bottom-2 h-6 w-6 min-w-0">
<ArrowUp size={16} className="text-primary-foreground" />
</Button>
</div>
</div>
)