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 | 928x 9273x 928x 741x 372x 372x 372x 372x 57x 3x 372x 372x 54x 54x 54x 54x 36x 49x 398x 54x 49x 26x 54x 372x 372x 54x 874x 398x 372x 49x 26x 26x 49x 26x 49x 43x 4x 43x 49x | /**
* @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 }
}
|