Market View: % suffix on price index badge, poll scrape completion for auto-refresh
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
ba6c000903
commit
ea9484e3fa
1 changed files with 30 additions and 6 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useMemo, useCallback } from 'react'
|
||||
import React, { useState, useMemo, useCallback, useEffect } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import api from '../api'
|
||||
|
||||
|
|
@ -922,18 +922,42 @@ const RateMatrixTab: React.FC = () => {
|
|||
const [showDirect, setShowDirect] = useState(false)
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
// The scrape endpoint returns immediately (runs in background), so we watch
|
||||
// scraper status until a new batch finishes, then refetch the matrix.
|
||||
const [scrapeWatch, setScrapeWatch] = useState<{ prevBatch: string | null, startedAt: number } | null>(null)
|
||||
|
||||
const dateScrapeM = useMutation({
|
||||
mutationFn: async (d: string) => {
|
||||
const st = (await api.get('/competitors/status')).data as ScraperStatus
|
||||
setScrapingDate(d)
|
||||
setScrapeWatch({ prevBatch: st?.last_scrape?.batch_id ?? null, startedAt: Date.now() })
|
||||
return (await api.post('/competitors/scrape', { from_date: d, to_date: d })).data
|
||||
},
|
||||
onSuccess: () => {
|
||||
onError: () => {
|
||||
setScrapingDate(null)
|
||||
setScrapeWatch(null)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: watchStatus } = useQuery<ScraperStatus>({
|
||||
queryKey: ['scraper-status'],
|
||||
queryFn: async () => (await api.get('/competitors/status')).data,
|
||||
enabled: scrapeWatch !== null,
|
||||
refetchInterval: scrapeWatch !== null ? 5000 : false,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (!scrapeWatch) return
|
||||
const ls = watchStatus?.last_scrape
|
||||
const finished = ls && ls.batch_id !== scrapeWatch.prevBatch && ls.status !== 'running'
|
||||
const timedOut = Date.now() - scrapeWatch.startedAt > 10 * 60 * 1000
|
||||
if (finished || timedOut) {
|
||||
queryClient.invalidateQueries({ queryKey: ['competitor-matrix'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['scraper-status'] })
|
||||
setScrapingDate(null)
|
||||
},
|
||||
onError: () => setScrapingDate(null),
|
||||
})
|
||||
setScrapeWatch(null)
|
||||
}
|
||||
}, [watchStatus, scrapeWatch, queryClient])
|
||||
|
||||
const onCellEnter = useCallback((row: number, col: number) => {
|
||||
setHoveredCell({ row, col })
|
||||
|
|
@ -1229,7 +1253,7 @@ const RateMatrixTab: React.FC = () => {
|
|||
priceIndexBadge = (
|
||||
<span style={{ display: 'block', fontSize: 9, fontWeight: 700, color: fg, background: bg,
|
||||
borderRadius: 4, padding: '0 3px', lineHeight: '14px', marginTop: 1 }}>
|
||||
{idx}
|
||||
{idx}%
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue