import { useEffect, useState } from 'react' import { useQueryClient } from '@tanstack/react-query' import { Switch } from '@cfdm/ui/components/switch' import { formatRelative } from '@/lib/format' import { isLiveRefresh, setLiveRefresh } from '@/lib/live-refresh' function useLatestDataUpdatedAt() { const queryClient = useQueryClient() const [updatedAt, setUpdatedAt] = useState(0) useEffect(() => { const cache = queryClient.getQueryCache() let queued = false let active = true const read = () => { let latest = 0 for (const query of cache.getAll()) { if (query.getObserversCount() === 0) continue if (query.state.dataUpdatedAt > latest) latest = query.state.dataUpdatedAt } setUpdatedAt((prev) => (prev === latest ? prev : latest)) } // Cache notifies synchronously while another route renders (observerAdded). const schedule = () => { if (queued) return queued = true queueMicrotask(() => { queued = false if (active) read() }) } read() const unsubscribe = cache.subscribe(schedule) return () => { active = false unsubscribe() } }, [queryClient]) return updatedAt } function formatUpdatedAt(updatedAt: number) { if (updatedAt === 0) return '—' return formatRelative(new Date(updatedAt).toISOString()) } /** Компактный статус свежести слева от AppsMenu. */ export function DataFreshness() { const queryClient = useQueryClient() const updatedAt = useLatestDataUpdatedAt() const [live, setLive] = useState(() => isLiveRefresh()) const [label, setLabel] = useState('—') useEffect(() => { const read = () => setLabel(formatUpdatedAt(updatedAt)) read() if (updatedAt === 0) return const timer = window.setInterval(read, 15_000) return () => window.clearInterval(timer) }, [updatedAt]) function handleCheckedChange(checked: boolean) { const next = Boolean(checked) setLiveRefresh(queryClient, next) setLive(next) } return (
Обновлено{' '} {live ? 'Live' : 'Пауза'}