Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | 929x 9264x 929x 742x 376x 376x 376x 376x 54x 376x 376x 54x 54x 54x 54x 36x 376x 54x 54x 376x 376x 54x 875x 54x 376x | /**
* @see frontend/docs/UX/layer-contracts/L1-data-layer.md §9.6
* @see frontend/src/lib/onlineDetector.ts
*
* Offline-tilan seuranta hook. Kaikki arvot johdetaan automaattisesti:
* - isOnline OnlineDetector-palvelusta (lazy-luku navigator.onLine:sta
* + window online/offline -eventtien kuuntelu)
* - pendingCount mutationOutboxista
* - lastSynced queryClientin tuoreimmasta dataUpdatedAt:stä
*
* Ei placeholder-proppeja — kaikki johdetaan automaattisesti.
*/
import { useState, useEffect } from 'react'
import { useQueryClient } from '@tanstack/react-query'
import { subscribeOutbox, getOutboxEntries } from '@/lib/mutationOutbox'
import { getOnlineDetector } from '@/lib/onlineDetector'
export interface OfflineStateResult {
isOnline: boolean
pendingCount: number
lastSynced: Date | null
}
function computeLastSynced(queryClient: ReturnType<typeof useQueryClient>): Date | null {
const queries = queryClient.getQueryCache().getAll()
const timestamps = queries
.map((q) => q.state.dataUpdatedAt)
.filter((t): t is number => t > 0)
if (timestamps.length === 0) return null
return new Date(Math.max(...timestamps))
}
export function useOfflineState(): OfflineStateResult {
const queryClient = useQueryClient()
const detector = getOnlineDetector()
const [isOnline, setIsOnline] = useState(() => detector.isOnline())
useEffect(() => {
return detector.subscribe(() => setIsOnline(detector.isOnline()))
}, [detector])
const [pendingCount, setPendingCount] = useState(0)
useEffect(() => {
let cancelled = false
getOutboxEntries().then((entries) => {
if (!cancelled) setPendingCount(entries.length)
})
return () => { cancelled = true }
}, [])
useEffect(() => {
const unsubscribe = subscribeOutbox(() => {
getOutboxEntries().then((entries) => {
setPendingCount(entries.length)
})
})
return unsubscribe
}, [])
const [lastSynced, setLastSynced] = useState<Date | null>(() =>
computeLastSynced(queryClient),
)
useEffect(() => {
const unsubscribe = queryClient.getQueryCache().subscribe(() => {
setLastSynced(computeLastSynced(queryClient))
})
return unsubscribe
}, [queryClient])
return { isOnline, pendingCount, lastSynced }
}
|