Fix DownloadButton reverting to "Скачать" after completion
The button disabled its own status polling once a download reached a terminal state and fell back to the video prop it was first rendered with. On the video detail page that prop only refreshes on a full page reload (only ['feed'] was invalidated, not ['video', id]), so the button showed "Скачать" again right after a real completion until the user refreshed. Keep the polling query enabled permanently once a download starts tracking (refetchInterval alone already stops the ticking on a terminal status) and use its cache as the source of truth instead of the prop, so the button reflects the fetched status directly rather than depending on an unrelated query being invalidated and refetched in time. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
e333296170
commit
10c16ba2cb
1 changed files with 20 additions and 20 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import type { FeedVideoDto } from '../api/client'
|
import type { FeedVideoDto } from '../api/client'
|
||||||
import { downloadVideo, getDownloadStatus } from '../api/client'
|
import { downloadVideo, getDownloadStatus } from '../api/client'
|
||||||
|
|
@ -16,43 +16,43 @@ interface Props {
|
||||||
|
|
||||||
function DownloadButton({ video }: Props) {
|
function DownloadButton({ video }: Props) {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [polling, setPolling] = useState(ACTIVE_STATUSES.includes(video.local.status))
|
// Once we start tracking a download (it was already active on load, or the
|
||||||
|
// user just clicked "Скачать"), the query stays enabled for good --
|
||||||
|
// refetchInterval alone stops the ticking once the status is terminal.
|
||||||
|
// Disabling the query on completion used to make the button fall back to
|
||||||
|
// the *stale* `video` prop instead of the query's own fresh cache, which
|
||||||
|
// showed "Скачать" again until the page was manually reloaded.
|
||||||
|
const [tracking, setTracking] = useState(ACTIVE_STATUSES.includes(video.local.status))
|
||||||
|
|
||||||
const statusQuery = useQuery({
|
const statusQuery = useQuery({
|
||||||
queryKey: ['download-status', video.youtube_video_id],
|
queryKey: ['download-status', video.youtube_video_id],
|
||||||
queryFn: () => getDownloadStatus(video.youtube_video_id),
|
queryFn: () => getDownloadStatus(video.youtube_video_id),
|
||||||
enabled: polling,
|
enabled: tracking,
|
||||||
refetchInterval: (query) => (query.state.data && ACTIVE_STATUSES.includes(query.state.data.status) ? 2000 : false),
|
refetchInterval: (query) =>
|
||||||
initialData: polling
|
query.state.data && ACTIVE_STATUSES.includes(query.state.data.status) ? 2000 : false,
|
||||||
? {
|
|
||||||
status: video.local.status,
|
|
||||||
progress_percent: video.local.progress_percent,
|
|
||||||
media_url: video.local.media_url,
|
|
||||||
error_message: null,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const downloadMutation = useMutation({
|
const downloadMutation = useMutation({
|
||||||
mutationFn: () => downloadVideo(video.youtube_video_id),
|
mutationFn: () => downloadVideo(video.youtube_video_id),
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
queryClient.setQueryData(['download-status', video.youtube_video_id], data)
|
queryClient.setQueryData(['download-status', video.youtube_video_id], data)
|
||||||
setPolling(true)
|
setTracking(true)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const current = polling ? statusQuery.data : undefined
|
const status = statusQuery.data?.status ?? video.local.status
|
||||||
const status = current?.status ?? video.local.status
|
const percent = statusQuery.data?.progress_percent ?? video.local.progress_percent
|
||||||
const percent = current?.progress_percent ?? video.local.progress_percent
|
|
||||||
|
|
||||||
|
const prevStatus = useRef(status)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (current && !ACTIVE_STATUSES.includes(current.status)) {
|
if (prevStatus.current !== status) {
|
||||||
setPolling(false)
|
prevStatus.current = status
|
||||||
if (current.status === 'completed' || current.status === 'failed') {
|
if (status === 'completed' || status === 'failed') {
|
||||||
queryClient.invalidateQueries({ queryKey: ['feed'] })
|
queryClient.invalidateQueries({ queryKey: ['feed'] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['video', video.youtube_video_id] })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [current?.status, queryClient])
|
}, [status, queryClient, video.youtube_video_id])
|
||||||
|
|
||||||
if (status === 'completed') {
|
if (status === 'completed') {
|
||||||
return <span className="download-badge completed">✓ На сервере</span>
|
return <span className="download-badge completed">✓ На сервере</span>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue